diff options
Diffstat (limited to 'fs/ocfs2/cluster/heartbeat.c')
-rw-r--r-- | fs/ocfs2/cluster/heartbeat.c | 96 |
1 files changed, 93 insertions, 3 deletions
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 979113479c66..2bd7f788cf34 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c | |||
@@ -1335,6 +1335,7 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg, | |||
1335 | ret = wait_event_interruptible(o2hb_steady_queue, | 1335 | ret = wait_event_interruptible(o2hb_steady_queue, |
1336 | atomic_read(®->hr_steady_iterations) == 0); | 1336 | atomic_read(®->hr_steady_iterations) == 0); |
1337 | if (ret) { | 1337 | if (ret) { |
1338 | /* We got interrupted (hello ptrace!). Clean up */ | ||
1338 | spin_lock(&o2hb_live_lock); | 1339 | spin_lock(&o2hb_live_lock); |
1339 | hb_task = reg->hr_task; | 1340 | hb_task = reg->hr_task; |
1340 | reg->hr_task = NULL; | 1341 | reg->hr_task = NULL; |
@@ -1345,7 +1346,16 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg, | |||
1345 | goto out; | 1346 | goto out; |
1346 | } | 1347 | } |
1347 | 1348 | ||
1348 | ret = count; | 1349 | /* Ok, we were woken. Make sure it wasn't by drop_item() */ |
1350 | spin_lock(&o2hb_live_lock); | ||
1351 | hb_task = reg->hr_task; | ||
1352 | spin_unlock(&o2hb_live_lock); | ||
1353 | |||
1354 | if (hb_task) | ||
1355 | ret = count; | ||
1356 | else | ||
1357 | ret = -EIO; | ||
1358 | |||
1349 | out: | 1359 | out: |
1350 | if (filp) | 1360 | if (filp) |
1351 | fput(filp); | 1361 | fput(filp); |
@@ -1523,6 +1533,15 @@ static void o2hb_heartbeat_group_drop_item(struct config_group *group, | |||
1523 | if (hb_task) | 1533 | if (hb_task) |
1524 | kthread_stop(hb_task); | 1534 | kthread_stop(hb_task); |
1525 | 1535 | ||
1536 | /* | ||
1537 | * If we're racing a dev_write(), we need to wake them. They will | ||
1538 | * check reg->hr_task | ||
1539 | */ | ||
1540 | if (atomic_read(®->hr_steady_iterations) != 0) { | ||
1541 | atomic_set(®->hr_steady_iterations, 0); | ||
1542 | wake_up(&o2hb_steady_queue); | ||
1543 | } | ||
1544 | |||
1526 | config_item_put(item); | 1545 | config_item_put(item); |
1527 | } | 1546 | } |
1528 | 1547 | ||
@@ -1665,7 +1684,67 @@ void o2hb_setup_callback(struct o2hb_callback_func *hc, | |||
1665 | } | 1684 | } |
1666 | EXPORT_SYMBOL_GPL(o2hb_setup_callback); | 1685 | EXPORT_SYMBOL_GPL(o2hb_setup_callback); |
1667 | 1686 | ||
1668 | int o2hb_register_callback(struct o2hb_callback_func *hc) | 1687 | static struct o2hb_region *o2hb_find_region(const char *region_uuid) |
1688 | { | ||
1689 | struct o2hb_region *p, *reg = NULL; | ||
1690 | |||
1691 | assert_spin_locked(&o2hb_live_lock); | ||
1692 | |||
1693 | list_for_each_entry(p, &o2hb_all_regions, hr_all_item) { | ||
1694 | if (!strcmp(region_uuid, config_item_name(&p->hr_item))) { | ||
1695 | reg = p; | ||
1696 | break; | ||
1697 | } | ||
1698 | } | ||
1699 | |||
1700 | return reg; | ||
1701 | } | ||
1702 | |||
1703 | static int o2hb_region_get(const char *region_uuid) | ||
1704 | { | ||
1705 | int ret = 0; | ||
1706 | struct o2hb_region *reg; | ||
1707 | |||
1708 | spin_lock(&o2hb_live_lock); | ||
1709 | |||
1710 | reg = o2hb_find_region(region_uuid); | ||
1711 | if (!reg) | ||
1712 | ret = -ENOENT; | ||
1713 | spin_unlock(&o2hb_live_lock); | ||
1714 | |||
1715 | if (ret) | ||
1716 | goto out; | ||
1717 | |||
1718 | ret = o2nm_depend_this_node(); | ||
1719 | if (ret) | ||
1720 | goto out; | ||
1721 | |||
1722 | ret = o2nm_depend_item(®->hr_item); | ||
1723 | if (ret) | ||
1724 | o2nm_undepend_this_node(); | ||
1725 | |||
1726 | out: | ||
1727 | return ret; | ||
1728 | } | ||
1729 | |||
1730 | static void o2hb_region_put(const char *region_uuid) | ||
1731 | { | ||
1732 | struct o2hb_region *reg; | ||
1733 | |||
1734 | spin_lock(&o2hb_live_lock); | ||
1735 | |||
1736 | reg = o2hb_find_region(region_uuid); | ||
1737 | |||
1738 | spin_unlock(&o2hb_live_lock); | ||
1739 | |||
1740 | if (reg) { | ||
1741 | o2nm_undepend_item(®->hr_item); | ||
1742 | o2nm_undepend_this_node(); | ||
1743 | } | ||
1744 | } | ||
1745 | |||
1746 | int o2hb_register_callback(const char *region_uuid, | ||
1747 | struct o2hb_callback_func *hc) | ||
1669 | { | 1748 | { |
1670 | struct o2hb_callback_func *tmp; | 1749 | struct o2hb_callback_func *tmp; |
1671 | struct list_head *iter; | 1750 | struct list_head *iter; |
@@ -1681,6 +1760,12 @@ int o2hb_register_callback(struct o2hb_callback_func *hc) | |||
1681 | goto out; | 1760 | goto out; |
1682 | } | 1761 | } |
1683 | 1762 | ||
1763 | if (region_uuid) { | ||
1764 | ret = o2hb_region_get(region_uuid); | ||
1765 | if (ret) | ||
1766 | goto out; | ||
1767 | } | ||
1768 | |||
1684 | down_write(&o2hb_callback_sem); | 1769 | down_write(&o2hb_callback_sem); |
1685 | 1770 | ||
1686 | list_for_each(iter, &hbcall->list) { | 1771 | list_for_each(iter, &hbcall->list) { |
@@ -1702,16 +1787,21 @@ out: | |||
1702 | } | 1787 | } |
1703 | EXPORT_SYMBOL_GPL(o2hb_register_callback); | 1788 | EXPORT_SYMBOL_GPL(o2hb_register_callback); |
1704 | 1789 | ||
1705 | void o2hb_unregister_callback(struct o2hb_callback_func *hc) | 1790 | void o2hb_unregister_callback(const char *region_uuid, |
1791 | struct o2hb_callback_func *hc) | ||
1706 | { | 1792 | { |
1707 | BUG_ON(hc->hc_magic != O2HB_CB_MAGIC); | 1793 | BUG_ON(hc->hc_magic != O2HB_CB_MAGIC); |
1708 | 1794 | ||
1709 | mlog(ML_HEARTBEAT, "on behalf of %p for funcs %p\n", | 1795 | mlog(ML_HEARTBEAT, "on behalf of %p for funcs %p\n", |
1710 | __builtin_return_address(0), hc); | 1796 | __builtin_return_address(0), hc); |
1711 | 1797 | ||
1798 | /* XXX Can this happen _with_ a region reference? */ | ||
1712 | if (list_empty(&hc->hc_item)) | 1799 | if (list_empty(&hc->hc_item)) |
1713 | return; | 1800 | return; |
1714 | 1801 | ||
1802 | if (region_uuid) | ||
1803 | o2hb_region_put(region_uuid); | ||
1804 | |||
1715 | down_write(&o2hb_callback_sem); | 1805 | down_write(&o2hb_callback_sem); |
1716 | 1806 | ||
1717 | list_del_init(&hc->hc_item); | 1807 | list_del_init(&hc->hc_item); |