diff options
Diffstat (limited to 'drivers/block/drbd/drbd_main.c')
-rw-r--r-- | drivers/block/drbd/drbd_main.c | 55 |
1 files changed, 33 insertions, 22 deletions
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index b00a8d74f6cb..54df98fa2881 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -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; } |