aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd/drbd_nl.c
diff options
context:
space:
mode:
authorPhilipp Reisner <philipp.reisner@linbit.com>2011-04-20 11:47:29 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2012-11-08 10:49:03 -0500
commit91fd4dad64ce7ac48c4c30c7756c6d3c41e8ad0a (patch)
tree893fd0577cee16c9b5e7534724047f10856f7df4 /drivers/block/drbd/drbd_nl.c
parent44ed167da74825bfb7950d45a4f83bce3e84921c (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.c68
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) {