OSDN Git Service

drbd: Converted drbd_cfg_mutex into drbd_cfg_rwsem
authorPhilipp Reisner <philipp.reisner@linbit.com>
Wed, 13 Apr 2011 21:21:29 +0000 (14:21 -0700)
committerPhilipp Reisner <philipp.reisner@linbit.com>
Thu, 8 Nov 2012 15:45:17 +0000 (16:45 +0100)
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
drivers/block/drbd/drbd_int.h
drivers/block/drbd/drbd_main.c
drivers/block/drbd/drbd_nl.c

index c49dc08..7896a64 100644 (file)
@@ -171,7 +171,9 @@ drbd_insert_fault(struct drbd_conf *mdev, unsigned int type) {
 extern struct ratelimit_state drbd_ratelimit_state;
 extern struct idr minors;
 extern struct list_head drbd_tconns;
-extern struct mutex drbd_cfg_mutex;
+extern struct rw_semaphore drbd_cfg_rwsem;
+/* drbd_cfg_rwsem protects: drbd_tconns list,
+   note: non sleeping iterations over the idrs are protoected by RCU */
 
 /* on the wire */
 enum drbd_packet {
index 5abbdaf..86fd4c8 100644 (file)
@@ -120,7 +120,7 @@ module_param_string(usermode_helper, usermode_helper, sizeof(usermode_helper), 0
  */
 struct idr minors;
 struct list_head drbd_tconns;  /* list of struct drbd_tconn */
-DEFINE_MUTEX(drbd_cfg_mutex);
+DECLARE_RWSEM(drbd_cfg_rwsem);
 
 struct kmem_cache *drbd_request_cache;
 struct kmem_cache *drbd_ee_cache;      /* peer requests */
@@ -2330,14 +2330,14 @@ struct drbd_tconn *conn_by_name(const char *name)
        if (!name || !name[0])
                return NULL;
 
-       mutex_lock(&drbd_cfg_mutex);
+       down_read(&drbd_cfg_rwsem);
        list_for_each_entry(tconn, &drbd_tconns, all_tconn) {
                if (!strcmp(tconn->name, name))
                        goto found;
        }
        tconn = NULL;
 found:
-       mutex_unlock(&drbd_cfg_mutex);
+       up_read(&drbd_cfg_rwsem);
        return tconn;
 }
 
@@ -2404,9 +2404,9 @@ struct drbd_tconn *drbd_new_tconn(const char *name)
                DRBD_ON_NO_DATA_DEF, /* on_no_data */
        };
 
-       mutex_lock(&drbd_cfg_mutex);
+       down_write(&drbd_cfg_rwsem);
        list_add_tail(&tconn->all_tconn, &drbd_tconns);
-       mutex_unlock(&drbd_cfg_mutex);
+       up_write(&drbd_cfg_rwsem);
 
        return tconn;
 
index 60c171b..424dcb3 100644 (file)
@@ -1905,7 +1905,7 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
        new_my_addr = (struct sockaddr *)&new_conf->my_addr;
        new_peer_addr = (struct sockaddr *)&new_conf->peer_addr;
 
-       /* No need to take drbd_cfg_mutex here.  All reconfiguration is
+       /* No need to take drbd_cfg_rwsem here.  All reconfiguration is
         * strictly serialized on genl_lock(). We are protected against
         * concurrent reconfiguration/addition/deletion */
        list_for_each_entry(oconn, &drbd_tconns, all_tconn) {
@@ -2581,7 +2581,7 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb)
         */
 
        /* synchronize with drbd_new_tconn/drbd_free_tconn */
-       mutex_lock(&drbd_cfg_mutex);
+       down_read(&drbd_cfg_rwsem);
 next_tconn:
        /* revalidate iterator position */
        list_for_each_entry(tmp, &drbd_tconns, all_tconn) {
@@ -2642,7 +2642,7 @@ next_tconn:
         }
 
 out:
-       mutex_unlock(&drbd_cfg_mutex);
+       up_read(&drbd_cfg_rwsem);
        /* where to start the next iteration */
         cb->args[0] = (long)pos;
         cb->args[1] = (pos == tconn) ? volume + 1 : 0;
@@ -2894,9 +2894,9 @@ int drbd_adm_delete_minor(struct sk_buff *skb, struct genl_info *info)
        if (retcode != NO_ERROR)
                goto out;
 
-       mutex_lock(&drbd_cfg_mutex);
+       down_write(&drbd_cfg_rwsem);
        retcode = adm_delete_minor(adm_ctx.mdev);
-       mutex_unlock(&drbd_cfg_mutex);
+       up_write(&drbd_cfg_rwsem);
        /* if this was the last volume of this connection,
         * this will terminate all threads */
        if (retcode == NO_ERROR)
@@ -2924,7 +2924,7 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       mutex_lock(&drbd_cfg_mutex);
+       down_read(&drbd_cfg_rwsem);
        /* demote */
        idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) {
                retcode = drbd_set_role(mdev, R_SECONDARY, 0);
@@ -2951,14 +2951,17 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
                        goto out_unlock;
                }
        }
+       up_read(&drbd_cfg_rwsem);
 
        /* delete volumes */
+       down_write(&drbd_cfg_rwsem);
        idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) {
                retcode = adm_delete_minor(mdev);
                if (retcode != NO_ERROR) {
                        /* "can not happen" */
                        drbd_msg_put_info("failed to delete volume");
-                       goto out_unlock;
+                       up_write(&drbd_cfg_rwsem);
+                       goto out;
                }
        }
 
@@ -2973,10 +2976,12 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
                /* "can not happen" */
                retcode = ERR_CONN_IN_USE;
                drbd_msg_put_info("failed to delete connection");
-               goto out_unlock;
        }
+
+       up_write(&drbd_cfg_rwsem);
+       goto out;
 out_unlock:
-       mutex_unlock(&drbd_cfg_mutex);
+       up_read(&drbd_cfg_rwsem);
 out:
        drbd_adm_finish(info, retcode);
        return 0;
@@ -2992,14 +2997,14 @@ int drbd_adm_delete_connection(struct sk_buff *skb, struct genl_info *info)
        if (retcode != NO_ERROR)
                goto out;
 
-       mutex_lock(&drbd_cfg_mutex);
+       down_write(&drbd_cfg_rwsem);
        if (conn_lowest_minor(adm_ctx.tconn) < 0) {
                drbd_free_tconn(adm_ctx.tconn);
                retcode = NO_ERROR;
        } else {
                retcode = ERR_CONN_IN_USE;
        }
-       mutex_unlock(&drbd_cfg_mutex);
+       up_write(&drbd_cfg_rwsem);
 
 out:
        drbd_adm_finish(info, retcode);