diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2011-04-20 11:47:29 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-11-08 10:49:03 -0500 |
commit | 91fd4dad64ce7ac48c4c30c7756c6d3c41e8ad0a (patch) | |
tree | 893fd0577cee16c9b5e7534724047f10856f7df4 /drivers/block/drbd/drbd_nl.c | |
parent | 44ed167da74825bfb7950d45a4f83bce3e84921c (diff) |
drbd: Proper locking for updates to net_conf under RCU
Removing the get_net_conf()/put_net_conf() functions
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block/drbd/drbd_nl.c')
-rw-r--r-- | drivers/block/drbd/drbd_nl.c | 68 |
1 files changed, 30 insertions, 38 deletions
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 34be84260bee..f86e882efcac 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c | |||
@@ -589,11 +589,12 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) | |||
589 | put_ldev(mdev); | 589 | put_ldev(mdev); |
590 | } | 590 | } |
591 | } else { | 591 | } else { |
592 | rcu_read_lock(); | 592 | mutex_lock(&mdev->tconn->net_conf_update); |
593 | nc = rcu_dereference(mdev->tconn->net_conf); | 593 | nc = mdev->tconn->net_conf; |
594 | if (nc) | 594 | if (nc) |
595 | nc->want_lose = 0; | 595 | nc->want_lose = 0; /* without copy; single bit op is atomic */ |
596 | rcu_read_unlock(); | 596 | mutex_unlock(&mdev->tconn->net_conf_update); |
597 | |||
597 | set_disk_ro(mdev->vdisk, false); | 598 | set_disk_ro(mdev->vdisk, false); |
598 | if (get_ldev(mdev)) { | 599 | if (get_ldev(mdev)) { |
599 | if (((mdev->state.conn < C_CONNECTED || | 600 | if (((mdev->state.conn < C_CONNECTED || |
@@ -1760,17 +1761,16 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) | |||
1760 | 1761 | ||
1761 | conn_reconfig_start(tconn); | 1762 | conn_reconfig_start(tconn); |
1762 | 1763 | ||
1763 | rcu_read_lock(); | 1764 | mutex_lock(&tconn->net_conf_update); |
1764 | old_conf = rcu_dereference(tconn->net_conf); | 1765 | old_conf = tconn->net_conf; |
1765 | 1766 | ||
1766 | if (!old_conf) { | 1767 | if (!old_conf) { |
1767 | drbd_msg_put_info("net conf missing, try connect"); | 1768 | drbd_msg_put_info("net conf missing, try connect"); |
1768 | retcode = ERR_INVALID_REQUEST; | 1769 | retcode = ERR_INVALID_REQUEST; |
1769 | goto fail_rcu_unlock; | 1770 | goto fail; |
1770 | } | 1771 | } |
1771 | 1772 | ||
1772 | *new_conf = *old_conf; | 1773 | *new_conf = *old_conf; |
1773 | rcu_read_unlock(); | ||
1774 | 1774 | ||
1775 | err = net_conf_from_attrs_for_change(new_conf, info); | 1775 | err = net_conf_from_attrs_for_change(new_conf, info); |
1776 | if (err) { | 1776 | if (err) { |
@@ -1785,13 +1785,10 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) | |||
1785 | 1785 | ||
1786 | /* re-sync running */ | 1786 | /* re-sync running */ |
1787 | rsr = conn_resync_running(tconn); | 1787 | rsr = conn_resync_running(tconn); |
1788 | rcu_read_lock(); | ||
1789 | old_conf = rcu_dereference(tconn->net_conf); | ||
1790 | if (rsr && old_conf && strcmp(new_conf->csums_alg, old_conf->csums_alg)) { | 1788 | if (rsr && old_conf && strcmp(new_conf->csums_alg, old_conf->csums_alg)) { |
1791 | retcode = ERR_CSUMS_RESYNC_RUNNING; | 1789 | retcode = ERR_CSUMS_RESYNC_RUNNING; |
1792 | goto fail_rcu_unlock; | 1790 | goto fail; |
1793 | } | 1791 | } |
1794 | rcu_read_unlock(); | ||
1795 | 1792 | ||
1796 | if (!rsr && new_conf->csums_alg[0]) { | 1793 | if (!rsr && new_conf->csums_alg[0]) { |
1797 | csums_tfm = crypto_alloc_hash(new_conf->csums_alg, 0, CRYPTO_ALG_ASYNC); | 1794 | csums_tfm = crypto_alloc_hash(new_conf->csums_alg, 0, CRYPTO_ALG_ASYNC); |
@@ -1809,15 +1806,12 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) | |||
1809 | 1806 | ||
1810 | /* online verify running */ | 1807 | /* online verify running */ |
1811 | ovr = conn_ov_running(tconn); | 1808 | ovr = conn_ov_running(tconn); |
1812 | rcu_read_lock(); | 1809 | if (ovr) { |
1813 | old_conf = rcu_dereference(tconn->net_conf); | ||
1814 | if (ovr && old_conf) { | ||
1815 | if (strcmp(new_conf->verify_alg, old_conf->verify_alg)) { | 1810 | if (strcmp(new_conf->verify_alg, old_conf->verify_alg)) { |
1816 | retcode = ERR_VERIFY_RUNNING; | 1811 | retcode = ERR_VERIFY_RUNNING; |
1817 | goto fail_rcu_unlock; | 1812 | goto fail; |
1818 | } | 1813 | } |
1819 | } | 1814 | } |
1820 | rcu_read_unlock(); | ||
1821 | 1815 | ||
1822 | if (!ovr && new_conf->verify_alg[0]) { | 1816 | if (!ovr && new_conf->verify_alg[0]) { |
1823 | verify_tfm = crypto_alloc_hash(new_conf->verify_alg, 0, CRYPTO_ALG_ASYNC); | 1817 | verify_tfm = crypto_alloc_hash(new_conf->verify_alg, 0, CRYPTO_ALG_ASYNC); |
@@ -1834,8 +1828,6 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) | |||
1834 | } | 1828 | } |
1835 | 1829 | ||
1836 | rcu_assign_pointer(tconn->net_conf, new_conf); | 1830 | rcu_assign_pointer(tconn->net_conf, new_conf); |
1837 | synchronize_rcu(); | ||
1838 | kfree(old_conf); | ||
1839 | 1831 | ||
1840 | if (!rsr) { | 1832 | if (!rsr) { |
1841 | crypto_free_hash(tconn->csums_tfm); | 1833 | crypto_free_hash(tconn->csums_tfm); |
@@ -1848,15 +1840,21 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) | |||
1848 | verify_tfm = NULL; | 1840 | verify_tfm = NULL; |
1849 | } | 1841 | } |
1850 | 1842 | ||
1843 | mutex_unlock(&tconn->net_conf_update); | ||
1844 | synchronize_rcu(); | ||
1845 | kfree(old_conf); | ||
1846 | |||
1851 | if (tconn->cstate >= C_WF_REPORT_PARAMS) | 1847 | if (tconn->cstate >= C_WF_REPORT_PARAMS) |
1852 | drbd_send_sync_param(minor_to_mdev(conn_lowest_minor(tconn))); | 1848 | drbd_send_sync_param(minor_to_mdev(conn_lowest_minor(tconn))); |
1853 | 1849 | ||
1854 | fail_rcu_unlock: | 1850 | goto done; |
1855 | rcu_read_unlock(); | 1851 | |
1856 | fail: | 1852 | fail: |
1853 | mutex_unlock(&tconn->net_conf_update); | ||
1857 | crypto_free_hash(csums_tfm); | 1854 | crypto_free_hash(csums_tfm); |
1858 | crypto_free_hash(verify_tfm); | 1855 | crypto_free_hash(verify_tfm); |
1859 | kfree(new_conf); | 1856 | kfree(new_conf); |
1857 | done: | ||
1860 | conn_reconfig_done(tconn); | 1858 | conn_reconfig_done(tconn); |
1861 | out: | 1859 | out: |
1862 | drbd_adm_finish(info, retcode); | 1860 | drbd_adm_finish(info, retcode); |
@@ -2032,32 +2030,26 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) | |||
2032 | } | 2030 | } |
2033 | 2031 | ||
2034 | conn_flush_workqueue(tconn); | 2032 | conn_flush_workqueue(tconn); |
2035 | spin_lock_irq(&tconn->req_lock); | 2033 | |
2036 | rcu_read_lock(); | 2034 | mutex_lock(&tconn->net_conf_update); |
2037 | old_conf = rcu_dereference(tconn->net_conf); | 2035 | old_conf = tconn->net_conf; |
2038 | if (old_conf != NULL) { | 2036 | if (old_conf) { |
2039 | retcode = ERR_NET_CONFIGURED; | 2037 | retcode = ERR_NET_CONFIGURED; |
2040 | rcu_read_unlock(); | 2038 | mutex_unlock(&tconn->net_conf_update); |
2041 | spin_unlock_irq(&tconn->req_lock); | ||
2042 | goto fail; | 2039 | goto fail; |
2043 | } | 2040 | } |
2044 | rcu_assign_pointer(tconn->net_conf, new_conf); | 2041 | rcu_assign_pointer(tconn->net_conf, new_conf); |
2045 | 2042 | ||
2046 | crypto_free_hash(tconn->cram_hmac_tfm); | 2043 | conn_free_crypto(tconn); |
2047 | tconn->cram_hmac_tfm = tfm; | 2044 | tconn->cram_hmac_tfm = tfm; |
2048 | |||
2049 | crypto_free_hash(tconn->integrity_w_tfm); | ||
2050 | tconn->integrity_w_tfm = integrity_w_tfm; | 2045 | tconn->integrity_w_tfm = integrity_w_tfm; |
2051 | |||
2052 | crypto_free_hash(tconn->integrity_r_tfm); | ||
2053 | tconn->integrity_r_tfm = integrity_r_tfm; | 2046 | tconn->integrity_r_tfm = integrity_r_tfm; |
2047 | tconn->int_dig_in = int_dig_in; | ||
2048 | tconn->int_dig_vv = int_dig_vv; | ||
2054 | 2049 | ||
2055 | kfree(tconn->int_dig_in); | 2050 | mutex_unlock(&tconn->net_conf_update); |
2056 | kfree(tconn->int_dig_vv); | 2051 | |
2057 | tconn->int_dig_in=int_dig_in; | 2052 | retcode = conn_request_state(tconn, NS(conn, C_UNCONNECTED), CS_VERBOSE); |
2058 | tconn->int_dig_vv=int_dig_vv; | ||
2059 | retcode = _conn_request_state(tconn, NS(conn, C_UNCONNECTED), CS_VERBOSE); | ||
2060 | spin_unlock_irq(&tconn->req_lock); | ||
2061 | 2053 | ||
2062 | rcu_read_lock(); | 2054 | rcu_read_lock(); |
2063 | idr_for_each_entry(&tconn->volumes, mdev, i) { | 2055 | idr_for_each_entry(&tconn->volumes, mdev, i) { |