]> git.ipfire.org Git - people/ms/linux.git/commitdiff
drbd: Iterate over all connections
authorAndreas Gruenbacher <agruen@linbit.com>
Wed, 6 Jul 2011 13:03:31 +0000 (15:03 +0200)
committerPhilipp Reisner <philipp.reisner@linbit.com>
Mon, 17 Feb 2014 15:46:44 +0000 (16:46 +0100)
in drbd_adm_down(), drbd_create_device() and drbd_set_role()

Signed-off-by: Andreas Gruenbacher <agruen@linbit.com>
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
drivers/block/drbd/drbd_main.c
drivers/block/drbd/drbd_nl.c

index b00a8d74f6cb5d606472e14c600c399033dca889..54df98fa288183f7d9e35d0bcfbbada55ce58c61 100644 (file)
@@ -2661,9 +2661,9 @@ static int init_submitter(struct drbd_device *device)
 
 enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned int minor, int vnr)
 {
-       struct drbd_connection *connection = first_connection(resource);
+       struct drbd_connection *connection;
        struct drbd_device *device;
-       struct drbd_peer_device *peer_device;
+       struct drbd_peer_device *peer_device, *tmp_peer_device;
        struct gendisk *disk;
        struct request_queue *q;
        int id;
@@ -2679,18 +2679,8 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i
                return ERR_NOMEM;
        kref_init(&device->kref);
 
-       peer_device = kzalloc(sizeof(struct drbd_peer_device), GFP_KERNEL);
-       if (!peer_device)
-               goto out_no_peer_device;
-
-       INIT_LIST_HEAD(&device->peer_devices);
-       list_add(&peer_device->peer_devices, &device->peer_devices);
        kref_get(&resource->kref);
        device->resource = resource;
-       kref_get(&connection->kref);
-       peer_device->connection = connection;
-       peer_device->device = device;
-
        device->minor = minor;
        device->vnr = vnr;
 
@@ -2761,15 +2751,27 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i
        }
        kref_get(&device->kref);
 
-       id = idr_alloc(&connection->peer_devices, peer_device, vnr, vnr + 1, GFP_KERNEL);
-       if (id < 0) {
-               if (id == -ENOSPC) {
-                       err = ERR_INVALID_REQUEST;
-                       drbd_msg_put_info("requested volume exists already");
+       INIT_LIST_HEAD(&device->peer_devices);
+       for_each_connection(connection, resource) {
+               peer_device = kzalloc(sizeof(struct drbd_peer_device), GFP_KERNEL);
+               if (!peer_device)
+                       goto out_idr_remove_from_resource;
+               peer_device->connection = connection;
+               peer_device->device = device;
+
+               list_add(&peer_device->peer_devices, &device->peer_devices);
+               kref_get(&device->kref);
+
+               id = idr_alloc(&connection->peer_devices, peer_device, vnr, vnr + 1, GFP_KERNEL);
+               if (id < 0) {
+                       if (id == -ENOSPC) {
+                               err = ERR_INVALID_REQUEST;
+                               drbd_msg_put_info("requested volume exists already");
+                       }
+                       goto out_idr_remove_from_resource;
                }
-               goto out_idr_remove_from_resource;
+               kref_get(&connection->kref);
        }
-       kref_get(&device->kref);
 
        if (init_submitter(device)) {
                err = ERR_NOMEM;
@@ -2780,7 +2782,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i
        add_disk(disk);
 
        /* inherit the connection state */
-       device->state.conn = connection->cstate;
+       device->state.conn = first_connection(resource)->cstate;
        if (device->state.conn == C_WF_REPORT_PARAMS)
                drbd_connected(device);
 
@@ -2789,6 +2791,17 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i
 out_idr_remove_vol:
        idr_remove(&connection->peer_devices, vnr);
 out_idr_remove_from_resource:
+       for_each_connection(connection, resource) {
+               peer_device = idr_find(&connection->peer_devices, vnr);
+               if (peer_device) {
+                       idr_remove(&connection->peer_devices, vnr);
+                       kref_put(&connection->kref, drbd_destroy_connection);
+               }
+       }
+       for_each_peer_device_safe(peer_device, tmp_peer_device, device) {
+               list_del(&peer_device->peer_devices);
+               kfree(peer_device);
+       }
        idr_remove(&resource->devices, vnr);
 out_idr_remove_minor:
        idr_remove(&drbd_devices, minor);
@@ -2802,9 +2815,7 @@ out_no_io_page:
 out_no_disk:
        blk_cleanup_queue(q);
 out_no_q:
-       kref_put(&connection->kref, drbd_destroy_connection);
        kref_put(&resource->kref, drbd_destroy_resource);
-out_no_peer_device:
        kfree(device);
        return err;
 }
index 33bc23fc55bb29bde1dc3625802b77e741b0a513..8ebcf88b0c1b01566622d81e4d93e79119bc60e1 100644 (file)
@@ -560,8 +560,16 @@ drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force)
        int forced = 0;
        union drbd_state mask, val;
 
-       if (new_role == R_PRIMARY)
-               request_ping(first_peer_device(device)->connection); /* Detect a dead peer ASAP */
+       if (new_role == R_PRIMARY) {
+               struct drbd_connection *connection;
+
+               /* Detect dead peers as soon as possible.  */
+
+               rcu_read_lock();
+               for_each_connection(connection, device->resource)
+                       request_ping(connection);
+               rcu_read_unlock();
+       }
 
        mutex_lock(device->state_mutex);
 
@@ -3387,8 +3395,10 @@ out:
 
 int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_resource *resource;
+       struct drbd_connection *connection;
+       struct drbd_device *device;
        int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */
-       struct drbd_peer_device *peer_device;
        unsigned i;
 
        retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE);
@@ -3397,24 +3407,29 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
        if (retcode != NO_ERROR)
                goto out;
 
+       resource = adm_ctx.resource;
        /* demote */
-       idr_for_each_entry(&adm_ctx.connection->peer_devices, peer_device, i) {
-               retcode = drbd_set_role(peer_device->device, R_SECONDARY, 0);
+       for_each_connection(connection, resource) {
+               struct drbd_peer_device *peer_device;
+
+               idr_for_each_entry(&connection->peer_devices, peer_device, i) {
+                       retcode = drbd_set_role(peer_device->device, R_SECONDARY, 0);
+                       if (retcode < SS_SUCCESS) {
+                               drbd_msg_put_info("failed to demote");
+                               goto out;
+                       }
+               }
+
+               retcode = conn_try_disconnect(connection, 0);
                if (retcode < SS_SUCCESS) {
-                       drbd_msg_put_info("failed to demote");
+                       drbd_msg_put_info("failed to disconnect");
                        goto out;
                }
        }
 
-       retcode = conn_try_disconnect(adm_ctx.connection, 0);
-       if (retcode < SS_SUCCESS) {
-               drbd_msg_put_info("failed to disconnect");
-               goto out;
-       }
-
        /* detach */
-       idr_for_each_entry(&adm_ctx.connection->peer_devices, peer_device, i) {
-               retcode = adm_detach(peer_device->device, 0);
+       idr_for_each_entry(&resource->devices, device, i) {
+               retcode = adm_detach(device, 0);
                if (retcode < SS_SUCCESS || retcode > NO_ERROR) {
                        drbd_msg_put_info("failed to detach");
                        goto out;
@@ -3424,13 +3439,14 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
        /* If we reach this, all volumes (of this connection) are Secondary,
         * Disconnected, Diskless, aka Unconfigured. Make sure all threads have
         * actually stopped, state handling only does drbd_thread_stop_nowait(). */
-       drbd_thread_stop(&adm_ctx.connection->worker);
+       for_each_connection(connection, resource)
+               drbd_thread_stop(&connection->worker);
 
        /* Now, nothing can fail anymore */
 
        /* delete volumes */
-       idr_for_each_entry(&adm_ctx.connection->peer_devices, peer_device, i) {
-               retcode = adm_del_minor(peer_device->device);
+       idr_for_each_entry(&resource->devices, device, i) {
+               retcode = adm_del_minor(device);
                if (retcode != NO_ERROR) {
                        /* "can not happen" */
                        drbd_msg_put_info("failed to delete volume");
@@ -3438,21 +3454,11 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
-       /* delete connection */
-       if (conn_lowest_minor(adm_ctx.connection) < 0) {
-               struct drbd_resource *resource = adm_ctx.connection->resource;
-
-               list_del_rcu(&resource->resources);
-               synchronize_rcu();
-               drbd_free_resource(resource);
+       list_del_rcu(&resource->resources);
+       synchronize_rcu();
+       drbd_free_resource(resource);
+       retcode = NO_ERROR;
 
-               retcode = NO_ERROR;
-       } else {
-               /* "can not happen" */
-               retcode = ERR_RES_IN_USE;
-               drbd_msg_put_info("failed to delete connection");
-       }
-       goto out;
 out:
        drbd_adm_finish(info, retcode);
        return 0;