aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd/drbd_nl.c
diff options
context:
space:
mode:
authorPhilipp Reisner <philipp.reisner@linbit.com>2011-05-05 10:13:10 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2012-11-08 10:55:48 -0500
commitc141ebda031a0550d75634f7c94f7c85c2d5c9f5 (patch)
treedd514cc2bf29f73a00e677b963950b2f349a0042 /drivers/block/drbd/drbd_nl.c
parentec0bddbc5574ea5903cec8f30ed57777f14d86a8 (diff)
drbd: Removing drbd_cfg_rwsem
* Updates to all configuration items is done under genl_lock(). Including removal of mdevs or tconns. * All read non sleeping read sides are protected by rcu * All sleeping read sides keep reference counts to keep the objects alive 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.c43
1 files changed, 15 insertions, 28 deletions
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index a0cf0005baf9..72ce3b0d0e03 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -335,10 +335,15 @@ static void conn_md_sync(struct drbd_tconn *tconn)
335 struct drbd_conf *mdev; 335 struct drbd_conf *mdev;
336 int vnr; 336 int vnr;
337 337
338 down_read(&drbd_cfg_rwsem); 338 rcu_read_lock();
339 idr_for_each_entry(&tconn->volumes, mdev, vnr) 339 idr_for_each_entry(&tconn->volumes, mdev, vnr) {
340 kref_get(&mdev->kref);
341 rcu_read_unlock();
340 drbd_md_sync(mdev); 342 drbd_md_sync(mdev);
341 up_read(&drbd_cfg_rwsem); 343 kref_put(&mdev->kref, &drbd_minor_destroy);
344 rcu_read_lock();
345 }
346 rcu_read_unlock();
342} 347}
343 348
344int conn_khelper(struct drbd_tconn *tconn, char *cmd) 349int conn_khelper(struct drbd_tconn *tconn, char *cmd)
@@ -1193,12 +1198,12 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
1193 rcu_assign_pointer(mdev->rs_plan_s, new_plan); 1198 rcu_assign_pointer(mdev->rs_plan_s, new_plan);
1194 } 1199 }
1195 1200
1201 mutex_unlock(&mdev->tconn->conf_update);
1196 drbd_md_sync(mdev); 1202 drbd_md_sync(mdev);
1197 1203
1198 if (mdev->state.conn >= C_CONNECTED) 1204 if (mdev->state.conn >= C_CONNECTED)
1199 drbd_send_sync_param(mdev); 1205 drbd_send_sync_param(mdev);
1200 1206
1201 mutex_unlock(&mdev->tconn->conf_update);
1202 synchronize_rcu(); 1207 synchronize_rcu();
1203 kfree(old_disk_conf); 1208 kfree(old_disk_conf);
1204 kfree(old_plan); 1209 kfree(old_plan);
@@ -2013,7 +2018,7 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
2013 new_my_addr = (struct sockaddr *)&new_conf->my_addr; 2018 new_my_addr = (struct sockaddr *)&new_conf->my_addr;
2014 new_peer_addr = (struct sockaddr *)&new_conf->peer_addr; 2019 new_peer_addr = (struct sockaddr *)&new_conf->peer_addr;
2015 2020
2016 /* No need to take drbd_cfg_rwsem here. All reconfiguration is 2021 /* No need for _rcu here. All reconfiguration is
2017 * strictly serialized on genl_lock(). We are protected against 2022 * strictly serialized on genl_lock(). We are protected against
2018 * concurrent reconfiguration/addition/deletion */ 2023 * concurrent reconfiguration/addition/deletion */
2019 list_for_each_entry(oconn, &drbd_tconns, all_tconn) { 2024 list_for_each_entry(oconn, &drbd_tconns, all_tconn) {
@@ -2672,7 +2677,7 @@ int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
2672 */ 2677 */
2673 2678
2674 /* synchronize with conn_create()/conn_destroy() */ 2679 /* synchronize with conn_create()/conn_destroy() */
2675 down_read(&drbd_cfg_rwsem); 2680 rcu_read_lock();
2676 /* revalidate iterator position */ 2681 /* revalidate iterator position */
2677 list_for_each_entry_rcu(tmp, &drbd_tconns, all_tconn) { 2682 list_for_each_entry_rcu(tmp, &drbd_tconns, all_tconn) {
2678 if (pos == NULL) { 2683 if (pos == NULL) {
@@ -2738,7 +2743,7 @@ next_tconn:
2738 } 2743 }
2739 2744
2740out: 2745out:
2741 up_read(&drbd_cfg_rwsem); 2746 rcu_read_unlock();
2742 /* where to start the next iteration */ 2747 /* where to start the next iteration */
2743 cb->args[0] = (long)pos; 2748 cb->args[0] = (long)pos;
2744 cb->args[1] = (pos == tconn) ? volume + 1 : 0; 2749 cb->args[1] = (pos == tconn) ? volume + 1 : 0;
@@ -3018,9 +3023,7 @@ int drbd_adm_add_minor(struct sk_buff *skb, struct genl_info *info)
3018 goto out; 3023 goto out;
3019 } 3024 }
3020 3025
3021 down_write(&drbd_cfg_rwsem);
3022 retcode = conn_new_minor(adm_ctx.tconn, dh->minor, adm_ctx.volume); 3026 retcode = conn_new_minor(adm_ctx.tconn, dh->minor, adm_ctx.volume);
3023 up_write(&drbd_cfg_rwsem);
3024out: 3027out:
3025 drbd_adm_finish(info, retcode); 3028 drbd_adm_finish(info, retcode);
3026 return 0; 3029 return 0;
@@ -3053,9 +3056,7 @@ int drbd_adm_delete_minor(struct sk_buff *skb, struct genl_info *info)
3053 if (retcode != NO_ERROR) 3056 if (retcode != NO_ERROR)
3054 goto out; 3057 goto out;
3055 3058
3056 down_write(&drbd_cfg_rwsem);
3057 retcode = adm_delete_minor(adm_ctx.mdev); 3059 retcode = adm_delete_minor(adm_ctx.mdev);
3058 up_write(&drbd_cfg_rwsem);
3059out: 3060out:
3060 drbd_adm_finish(info, retcode); 3061 drbd_adm_finish(info, retcode);
3061 return 0; 3062 return 0;
@@ -3078,52 +3079,43 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
3078 goto out; 3079 goto out;
3079 } 3080 }
3080 3081
3081 down_read(&drbd_cfg_rwsem);
3082 /* demote */ 3082 /* demote */
3083 idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) { 3083 idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) {
3084 retcode = drbd_set_role(mdev, R_SECONDARY, 0); 3084 retcode = drbd_set_role(mdev, R_SECONDARY, 0);
3085 if (retcode < SS_SUCCESS) { 3085 if (retcode < SS_SUCCESS) {
3086 drbd_msg_put_info("failed to demote"); 3086 drbd_msg_put_info("failed to demote");
3087 goto out_unlock; 3087 goto out;
3088 } 3088 }
3089 } 3089 }
3090 up_read(&drbd_cfg_rwsem);
3091 3090
3092 /* disconnect; may stop the receiver;
3093 * must not hold the drbd_cfg_rwsem */
3094 retcode = conn_try_disconnect(adm_ctx.tconn, 0); 3091 retcode = conn_try_disconnect(adm_ctx.tconn, 0);
3095 if (retcode < SS_SUCCESS) { 3092 if (retcode < SS_SUCCESS) {
3096 drbd_msg_put_info("failed to disconnect"); 3093 drbd_msg_put_info("failed to disconnect");
3097 goto out; 3094 goto out;
3098 } 3095 }
3099 3096
3100 down_read(&drbd_cfg_rwsem);
3101 /* detach */ 3097 /* detach */
3102 idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) { 3098 idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) {
3103 retcode = adm_detach(mdev); 3099 retcode = adm_detach(mdev);
3104 if (retcode < SS_SUCCESS) { 3100 if (retcode < SS_SUCCESS) {
3105 drbd_msg_put_info("failed to detach"); 3101 drbd_msg_put_info("failed to detach");
3106 goto out_unlock; 3102 goto out;
3107 } 3103 }
3108 } 3104 }
3109 up_read(&drbd_cfg_rwsem);
3110 3105
3111 /* If we reach this, all volumes (of this tconn) are Secondary, 3106 /* If we reach this, all volumes (of this tconn) are Secondary,
3112 * Disconnected, Diskless, aka Unconfigured. Make sure all threads have 3107 * Disconnected, Diskless, aka Unconfigured. Make sure all threads have
3113 * actually stopped, state handling only does drbd_thread_stop_nowait(). 3108 * actually stopped, state handling only does drbd_thread_stop_nowait(). */
3114 * This needs to be done without holding drbd_cfg_rwsem. */
3115 drbd_thread_stop(&adm_ctx.tconn->worker); 3109 drbd_thread_stop(&adm_ctx.tconn->worker);
3116 3110
3117 /* Now, nothing can fail anymore */ 3111 /* Now, nothing can fail anymore */
3118 3112
3119 /* delete volumes */ 3113 /* delete volumes */
3120 down_write(&drbd_cfg_rwsem);
3121 idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) { 3114 idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) {
3122 retcode = adm_delete_minor(mdev); 3115 retcode = adm_delete_minor(mdev);
3123 if (retcode != NO_ERROR) { 3116 if (retcode != NO_ERROR) {
3124 /* "can not happen" */ 3117 /* "can not happen" */
3125 drbd_msg_put_info("failed to delete volume"); 3118 drbd_msg_put_info("failed to delete volume");
3126 up_write(&drbd_cfg_rwsem);
3127 goto out; 3119 goto out;
3128 } 3120 }
3129 } 3121 }
@@ -3140,10 +3132,7 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
3140 retcode = ERR_CONN_IN_USE; 3132 retcode = ERR_CONN_IN_USE;
3141 drbd_msg_put_info("failed to delete connection"); 3133 drbd_msg_put_info("failed to delete connection");
3142 } 3134 }
3143 up_write(&drbd_cfg_rwsem);
3144 goto out; 3135 goto out;
3145out_unlock:
3146 up_read(&drbd_cfg_rwsem);
3147out: 3136out:
3148 drbd_adm_finish(info, retcode); 3137 drbd_adm_finish(info, retcode);
3149 return 0; 3138 return 0;
@@ -3159,7 +3148,6 @@ int drbd_adm_delete_connection(struct sk_buff *skb, struct genl_info *info)
3159 if (retcode != NO_ERROR) 3148 if (retcode != NO_ERROR)
3160 goto out; 3149 goto out;
3161 3150
3162 down_write(&drbd_cfg_rwsem);
3163 if (conn_lowest_minor(adm_ctx.tconn) < 0) { 3151 if (conn_lowest_minor(adm_ctx.tconn) < 0) {
3164 list_del_rcu(&adm_ctx.tconn->all_tconn); 3152 list_del_rcu(&adm_ctx.tconn->all_tconn);
3165 synchronize_rcu(); 3153 synchronize_rcu();
@@ -3169,7 +3157,6 @@ int drbd_adm_delete_connection(struct sk_buff *skb, struct genl_info *info)
3169 } else { 3157 } else {
3170 retcode = ERR_CONN_IN_USE; 3158 retcode = ERR_CONN_IN_USE;
3171 } 3159 }
3172 up_write(&drbd_cfg_rwsem);
3173 3160
3174 if (retcode == NO_ERROR) 3161 if (retcode == NO_ERROR)
3175 drbd_thread_stop(&adm_ctx.tconn->worker); 3162 drbd_thread_stop(&adm_ctx.tconn->worker);