aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@linbit.com>2011-07-06 09:03:31 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2014-02-17 10:46:44 -0500
commitb6f85ef9538b2111a8ba0bbfae9aaebabfc94961 (patch)
treeada222b0aff93fc6848d7365e92f933be9a29d84
parent270eb5c97258b9ae157d768fb19a42a685b41740 (diff)
drbd: Iterate over all connections
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>
-rw-r--r--drivers/block/drbd/drbd_main.c55
-rw-r--r--drivers/block/drbd/drbd_nl.c68
2 files changed, 70 insertions, 53 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)
2661 2661
2662enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned int minor, int vnr) 2662enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned int minor, int vnr)
2663{ 2663{
2664 struct drbd_connection *connection = first_connection(resource); 2664 struct drbd_connection *connection;
2665 struct drbd_device *device; 2665 struct drbd_device *device;
2666 struct drbd_peer_device *peer_device; 2666 struct drbd_peer_device *peer_device, *tmp_peer_device;
2667 struct gendisk *disk; 2667 struct gendisk *disk;
2668 struct request_queue *q; 2668 struct request_queue *q;
2669 int id; 2669 int id;
@@ -2679,18 +2679,8 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i
2679 return ERR_NOMEM; 2679 return ERR_NOMEM;
2680 kref_init(&device->kref); 2680 kref_init(&device->kref);
2681 2681
2682 peer_device = kzalloc(sizeof(struct drbd_peer_device), GFP_KERNEL);
2683 if (!peer_device)
2684 goto out_no_peer_device;
2685
2686 INIT_LIST_HEAD(&device->peer_devices);
2687 list_add(&peer_device->peer_devices, &device->peer_devices);
2688 kref_get(&resource->kref); 2682 kref_get(&resource->kref);
2689 device->resource = resource; 2683 device->resource = resource;
2690 kref_get(&connection->kref);
2691 peer_device->connection = connection;
2692 peer_device->device = device;
2693
2694 device->minor = minor; 2684 device->minor = minor;
2695 device->vnr = vnr; 2685 device->vnr = vnr;
2696 2686
@@ -2761,15 +2751,27 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i
2761 } 2751 }
2762 kref_get(&device->kref); 2752 kref_get(&device->kref);
2763 2753
2764 id = idr_alloc(&connection->peer_devices, peer_device, vnr, vnr + 1, GFP_KERNEL); 2754 INIT_LIST_HEAD(&device->peer_devices);
2765 if (id < 0) { 2755 for_each_connection(connection, resource) {
2766 if (id == -ENOSPC) { 2756 peer_device = kzalloc(sizeof(struct drbd_peer_device), GFP_KERNEL);
2767 err = ERR_INVALID_REQUEST; 2757 if (!peer_device)
2768 drbd_msg_put_info("requested volume exists already"); 2758 goto out_idr_remove_from_resource;
2759 peer_device->connection = connection;
2760 peer_device->device = device;
2761
2762 list_add(&peer_device->peer_devices, &device->peer_devices);
2763 kref_get(&device->kref);
2764
2765 id = idr_alloc(&connection->peer_devices, peer_device, vnr, vnr + 1, GFP_KERNEL);
2766 if (id < 0) {
2767 if (id == -ENOSPC) {
2768 err = ERR_INVALID_REQUEST;
2769 drbd_msg_put_info("requested volume exists already");
2770 }
2771 goto out_idr_remove_from_resource;
2769 } 2772 }
2770 goto out_idr_remove_from_resource; 2773 kref_get(&connection->kref);
2771 } 2774 }
2772 kref_get(&device->kref);
2773 2775
2774 if (init_submitter(device)) { 2776 if (init_submitter(device)) {
2775 err = ERR_NOMEM; 2777 err = ERR_NOMEM;
@@ -2780,7 +2782,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i
2780 add_disk(disk); 2782 add_disk(disk);
2781 2783
2782 /* inherit the connection state */ 2784 /* inherit the connection state */
2783 device->state.conn = connection->cstate; 2785 device->state.conn = first_connection(resource)->cstate;
2784 if (device->state.conn == C_WF_REPORT_PARAMS) 2786 if (device->state.conn == C_WF_REPORT_PARAMS)
2785 drbd_connected(device); 2787 drbd_connected(device);
2786 2788
@@ -2789,6 +2791,17 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i
2789out_idr_remove_vol: 2791out_idr_remove_vol:
2790 idr_remove(&connection->peer_devices, vnr); 2792 idr_remove(&connection->peer_devices, vnr);
2791out_idr_remove_from_resource: 2793out_idr_remove_from_resource:
2794 for_each_connection(connection, resource) {
2795 peer_device = idr_find(&connection->peer_devices, vnr);
2796 if (peer_device) {
2797 idr_remove(&connection->peer_devices, vnr);
2798 kref_put(&connection->kref, drbd_destroy_connection);
2799 }
2800 }
2801 for_each_peer_device_safe(peer_device, tmp_peer_device, device) {
2802 list_del(&peer_device->peer_devices);
2803 kfree(peer_device);
2804 }
2792 idr_remove(&resource->devices, vnr); 2805 idr_remove(&resource->devices, vnr);
2793out_idr_remove_minor: 2806out_idr_remove_minor:
2794 idr_remove(&drbd_devices, minor); 2807 idr_remove(&drbd_devices, minor);
@@ -2802,9 +2815,7 @@ out_no_io_page:
2802out_no_disk: 2815out_no_disk:
2803 blk_cleanup_queue(q); 2816 blk_cleanup_queue(q);
2804out_no_q: 2817out_no_q:
2805 kref_put(&connection->kref, drbd_destroy_connection);
2806 kref_put(&resource->kref, drbd_destroy_resource); 2818 kref_put(&resource->kref, drbd_destroy_resource);
2807out_no_peer_device:
2808 kfree(device); 2819 kfree(device);
2809 return err; 2820 return err;
2810} 2821}
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index 33bc23fc55bb..8ebcf88b0c1b 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -560,8 +560,16 @@ drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force)
560 int forced = 0; 560 int forced = 0;
561 union drbd_state mask, val; 561 union drbd_state mask, val;
562 562
563 if (new_role == R_PRIMARY) 563 if (new_role == R_PRIMARY) {
564 request_ping(first_peer_device(device)->connection); /* Detect a dead peer ASAP */ 564 struct drbd_connection *connection;
565
566 /* Detect dead peers as soon as possible. */
567
568 rcu_read_lock();
569 for_each_connection(connection, device->resource)
570 request_ping(connection);
571 rcu_read_unlock();
572 }
565 573
566 mutex_lock(device->state_mutex); 574 mutex_lock(device->state_mutex);
567 575
@@ -3387,8 +3395,10 @@ out:
3387 3395
3388int drbd_adm_down(struct sk_buff *skb, struct genl_info *info) 3396int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
3389{ 3397{
3398 struct drbd_resource *resource;
3399 struct drbd_connection *connection;
3400 struct drbd_device *device;
3390 int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */ 3401 int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */
3391 struct drbd_peer_device *peer_device;
3392 unsigned i; 3402 unsigned i;
3393 3403
3394 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE); 3404 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)
3397 if (retcode != NO_ERROR) 3407 if (retcode != NO_ERROR)
3398 goto out; 3408 goto out;
3399 3409
3410 resource = adm_ctx.resource;
3400 /* demote */ 3411 /* demote */
3401 idr_for_each_entry(&adm_ctx.connection->peer_devices, peer_device, i) { 3412 for_each_connection(connection, resource) {
3402 retcode = drbd_set_role(peer_device->device, R_SECONDARY, 0); 3413 struct drbd_peer_device *peer_device;
3414
3415 idr_for_each_entry(&connection->peer_devices, peer_device, i) {
3416 retcode = drbd_set_role(peer_device->device, R_SECONDARY, 0);
3417 if (retcode < SS_SUCCESS) {
3418 drbd_msg_put_info("failed to demote");
3419 goto out;
3420 }
3421 }
3422
3423 retcode = conn_try_disconnect(connection, 0);
3403 if (retcode < SS_SUCCESS) { 3424 if (retcode < SS_SUCCESS) {
3404 drbd_msg_put_info("failed to demote"); 3425 drbd_msg_put_info("failed to disconnect");
3405 goto out; 3426 goto out;
3406 } 3427 }
3407 } 3428 }
3408 3429
3409 retcode = conn_try_disconnect(adm_ctx.connection, 0);
3410 if (retcode < SS_SUCCESS) {
3411 drbd_msg_put_info("failed to disconnect");
3412 goto out;
3413 }
3414
3415 /* detach */ 3430 /* detach */
3416 idr_for_each_entry(&adm_ctx.connection->peer_devices, peer_device, i) { 3431 idr_for_each_entry(&resource->devices, device, i) {
3417 retcode = adm_detach(peer_device->device, 0); 3432 retcode = adm_detach(device, 0);
3418 if (retcode < SS_SUCCESS || retcode > NO_ERROR) { 3433 if (retcode < SS_SUCCESS || retcode > NO_ERROR) {
3419 drbd_msg_put_info("failed to detach"); 3434 drbd_msg_put_info("failed to detach");
3420 goto out; 3435 goto out;
@@ -3424,13 +3439,14 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
3424 /* If we reach this, all volumes (of this connection) are Secondary, 3439 /* If we reach this, all volumes (of this connection) are Secondary,
3425 * Disconnected, Diskless, aka Unconfigured. Make sure all threads have 3440 * Disconnected, Diskless, aka Unconfigured. Make sure all threads have
3426 * actually stopped, state handling only does drbd_thread_stop_nowait(). */ 3441 * actually stopped, state handling only does drbd_thread_stop_nowait(). */
3427 drbd_thread_stop(&adm_ctx.connection->worker); 3442 for_each_connection(connection, resource)
3443 drbd_thread_stop(&connection->worker);
3428 3444
3429 /* Now, nothing can fail anymore */ 3445 /* Now, nothing can fail anymore */
3430 3446
3431 /* delete volumes */ 3447 /* delete volumes */
3432 idr_for_each_entry(&adm_ctx.connection->peer_devices, peer_device, i) { 3448 idr_for_each_entry(&resource->devices, device, i) {
3433 retcode = adm_del_minor(peer_device->device); 3449 retcode = adm_del_minor(device);
3434 if (retcode != NO_ERROR) { 3450 if (retcode != NO_ERROR) {
3435 /* "can not happen" */ 3451 /* "can not happen" */
3436 drbd_msg_put_info("failed to delete volume"); 3452 drbd_msg_put_info("failed to delete volume");
@@ -3438,21 +3454,11 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
3438 } 3454 }
3439 } 3455 }
3440 3456
3441 /* delete connection */ 3457 list_del_rcu(&resource->resources);
3442 if (conn_lowest_minor(adm_ctx.connection) < 0) { 3458 synchronize_rcu();
3443 struct drbd_resource *resource = adm_ctx.connection->resource; 3459 drbd_free_resource(resource);
3444 3460 retcode = NO_ERROR;
3445 list_del_rcu(&resource->resources);
3446 synchronize_rcu();
3447 drbd_free_resource(resource);
3448 3461
3449 retcode = NO_ERROR;
3450 } else {
3451 /* "can not happen" */
3452 retcode = ERR_RES_IN_USE;
3453 drbd_msg_put_info("failed to delete connection");
3454 }
3455 goto out;
3456out: 3462out:
3457 drbd_adm_finish(info, retcode); 3463 drbd_adm_finish(info, retcode);
3458 return 0; 3464 return 0;