drbd: Iterate over all connections
[deliverable/linux.git] / drivers / block / drbd / drbd_main.c
index 358eb3445f724d2b9fa8f1e3d926d383e2d8fd47..54df98fa288183f7d9e35d0bcfbbada55ce58c61 100644 (file)
@@ -2327,7 +2327,7 @@ static void drbd_cleanup(void)
        drbd_genl_unregister();
 
        idr_for_each_entry(&drbd_devices, device, i)
-               drbd_delete_minor(device);
+               drbd_delete_device(device);
 
        /* not _rcu since, no other updater anymore. Genl already unregistered */
        for_each_resource_safe(resource, tmp, &drbd_resources) {
@@ -2659,11 +2659,11 @@ static int init_submitter(struct drbd_device *device)
        return 0;
 }
 
-enum drbd_ret_code drbd_create_minor(struct drbd_connection *connection, unsigned int minor, int vnr)
+enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned int minor, int vnr)
 {
-       struct drbd_resource *resource = 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_minor(struct drbd_connection *connection, unsigne
                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_minor(struct drbd_connection *connection, unsigne
        }
        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_minor(struct drbd_connection *connection, unsigne
        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_minor(struct drbd_connection *connection, unsigne
 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,14 +2815,12 @@ 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;
 }
 
-void drbd_delete_minor(struct drbd_device *device)
+void drbd_delete_device(struct drbd_device *device)
 {
        struct drbd_resource *resource = device->resource;
        struct drbd_connection *connection;
This page took 0.026031 seconds and 5 git commands to generate.