Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+33 −22
Original line number Diff line number Diff line
@@ -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,6 +2751,17 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i
	}
	kref_get(&device->kref);

	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) {
@@ -2769,7 +2770,8 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i
			}
			goto out_idr_remove_from_resource;
		}
	kref_get(&device->kref);
		kref_get(&connection->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 @@ enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned i
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;
}
+37 −31
Original line number Diff line number Diff line
@@ -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 @@ 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)
{
	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,8 +3407,12 @@ 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) {
	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");
@@ -3406,15 +3420,16 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
			}
		}

	retcode = conn_try_disconnect(adm_ctx.connection, 0);
		retcode = conn_try_disconnect(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);

	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;