diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2011-05-05 10:13:10 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-11-08 10:55:48 -0500 |
commit | c141ebda031a0550d75634f7c94f7c85c2d5c9f5 (patch) | |
tree | dd514cc2bf29f73a00e677b963950b2f349a0042 /drivers/block/drbd/drbd_nl.c | |
parent | ec0bddbc5574ea5903cec8f30ed57777f14d86a8 (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.c | 43 |
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 | ||
344 | int conn_khelper(struct drbd_tconn *tconn, char *cmd) | 349 | int 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 | ||
2740 | out: | 2745 | out: |
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); | ||
3024 | out: | 3027 | out: |
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); | ||
3059 | out: | 3060 | out: |
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; |
3145 | out_unlock: | ||
3146 | up_read(&drbd_cfg_rwsem); | ||
3147 | out: | 3136 | out: |
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); |