Commit b6f85ef9 authored by Andreas Gruenbacher's avatar Andreas Gruenbacher Committed by Philipp Reisner

drbd: Iterate over all connections

in drbd_adm_down(), drbd_create_device() and drbd_set_role()
Signed-off-by: default avatarAndreas Gruenbacher <agruen@linbit.com>
Signed-off-by: default avatarPhilipp Reisner <philipp.reisner@linbit.com>
parent 270eb5c9
...@@ -2661,9 +2661,9 @@ static int init_submitter(struct drbd_device *device) ...@@ -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) 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_device *device;
struct drbd_peer_device *peer_device; struct drbd_peer_device *peer_device, *tmp_peer_device;
struct gendisk *disk; struct gendisk *disk;
struct request_queue *q; struct request_queue *q;
int id; int id;
...@@ -2679,18 +2679,8 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i ...@@ -2679,18 +2679,8 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i
return ERR_NOMEM; return ERR_NOMEM;
kref_init(&device->kref); 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); kref_get(&resource->kref);
device->resource = resource; device->resource = resource;
kref_get(&connection->kref);
peer_device->connection = connection;
peer_device->device = device;
device->minor = minor; device->minor = minor;
device->vnr = vnr; device->vnr = vnr;
...@@ -2761,15 +2751,27 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i ...@@ -2761,15 +2751,27 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i
} }
kref_get(&device->kref); kref_get(&device->kref);
id = idr_alloc(&connection->peer_devices, peer_device, vnr, vnr + 1, GFP_KERNEL); INIT_LIST_HEAD(&device->peer_devices);
if (id < 0) { for_each_connection(connection, resource) {
if (id == -ENOSPC) { peer_device = kzalloc(sizeof(struct drbd_peer_device), GFP_KERNEL);
err = ERR_INVALID_REQUEST; if (!peer_device)
drbd_msg_put_info("requested volume exists already"); 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)) { if (init_submitter(device)) {
err = ERR_NOMEM; err = ERR_NOMEM;
...@@ -2780,7 +2782,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i ...@@ -2780,7 +2782,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i
add_disk(disk); add_disk(disk);
/* inherit the connection state */ /* inherit the connection state */
device->state.conn = connection->cstate; device->state.conn = first_connection(resource)->cstate;
if (device->state.conn == C_WF_REPORT_PARAMS) if (device->state.conn == C_WF_REPORT_PARAMS)
drbd_connected(device); drbd_connected(device);
...@@ -2789,6 +2791,17 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i ...@@ -2789,6 +2791,17 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i
out_idr_remove_vol: out_idr_remove_vol:
idr_remove(&connection->peer_devices, vnr); idr_remove(&connection->peer_devices, vnr);
out_idr_remove_from_resource: 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); idr_remove(&resource->devices, vnr);
out_idr_remove_minor: out_idr_remove_minor:
idr_remove(&drbd_devices, minor); idr_remove(&drbd_devices, minor);
...@@ -2802,9 +2815,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i ...@@ -2802,9 +2815,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i
out_no_disk: out_no_disk:
blk_cleanup_queue(q); blk_cleanup_queue(q);
out_no_q: out_no_q:
kref_put(&connection->kref, drbd_destroy_connection);
kref_put(&resource->kref, drbd_destroy_resource); kref_put(&resource->kref, drbd_destroy_resource);
out_no_peer_device:
kfree(device); kfree(device);
return err; return err;
} }
......
...@@ -560,8 +560,16 @@ drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force) ...@@ -560,8 +560,16 @@ drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force)
int forced = 0; int forced = 0;
union drbd_state mask, val; union drbd_state mask, val;
if (new_role == R_PRIMARY) if (new_role == R_PRIMARY) {
request_ping(first_peer_device(device)->connection); /* Detect a dead peer ASAP */ 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); mutex_lock(device->state_mutex);
...@@ -3387,8 +3395,10 @@ int drbd_adm_del_minor(struct sk_buff *skb, struct genl_info *info) ...@@ -3387,8 +3395,10 @@ int drbd_adm_del_minor(struct sk_buff *skb, struct genl_info *info)
int drbd_adm_down(struct sk_buff *skb, struct genl_info *info) 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 */ int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */
struct drbd_peer_device *peer_device;
unsigned i; unsigned i;
retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE); 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,24 +3407,29 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR) if (retcode != NO_ERROR)
goto out; goto out;
resource = adm_ctx.resource;
/* demote */ /* demote */
idr_for_each_entry(&adm_ctx.connection->peer_devices, peer_device, i) { for_each_connection(connection, resource) {
retcode = drbd_set_role(peer_device->device, R_SECONDARY, 0); 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) { if (retcode < SS_SUCCESS) {
drbd_msg_put_info("failed to demote"); drbd_msg_put_info("failed to disconnect");
goto out; goto out;
} }
} }
retcode = conn_try_disconnect(adm_ctx.connection, 0);
if (retcode < SS_SUCCESS) {
drbd_msg_put_info("failed to disconnect");
goto out;
}
/* detach */ /* detach */
idr_for_each_entry(&adm_ctx.connection->peer_devices, peer_device, i) { idr_for_each_entry(&resource->devices, device, i) {
retcode = adm_detach(peer_device->device, 0); retcode = adm_detach(device, 0);
if (retcode < SS_SUCCESS || retcode > NO_ERROR) { if (retcode < SS_SUCCESS || retcode > NO_ERROR) {
drbd_msg_put_info("failed to detach"); drbd_msg_put_info("failed to detach");
goto out; goto out;
...@@ -3424,13 +3439,14 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info) ...@@ -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, /* If we reach this, all volumes (of this connection) are Secondary,
* Disconnected, Diskless, aka Unconfigured. Make sure all threads have * Disconnected, Diskless, aka Unconfigured. Make sure all threads have
* actually stopped, state handling only does drbd_thread_stop_nowait(). */ * 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 */ /* Now, nothing can fail anymore */
/* delete volumes */ /* delete volumes */
idr_for_each_entry(&adm_ctx.connection->peer_devices, peer_device, i) { idr_for_each_entry(&resource->devices, device, i) {
retcode = adm_del_minor(peer_device->device); retcode = adm_del_minor(device);
if (retcode != NO_ERROR) { if (retcode != NO_ERROR) {
/* "can not happen" */ /* "can not happen" */
drbd_msg_put_info("failed to delete volume"); 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,21 +3454,11 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
} }
} }
/* delete connection */ list_del_rcu(&resource->resources);
if (conn_lowest_minor(adm_ctx.connection) < 0) { synchronize_rcu();
struct drbd_resource *resource = adm_ctx.connection->resource; drbd_free_resource(resource);
retcode = NO_ERROR;
list_del_rcu(&resource->resources);
synchronize_rcu();
drbd_free_resource(resource);
retcode = NO_ERROR;
} else {
/* "can not happen" */
retcode = ERR_RES_IN_USE;
drbd_msg_put_info("failed to delete connection");
}
goto out;
out: out:
drbd_adm_finish(info, retcode); drbd_adm_finish(info, retcode);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment