Commit 9dc9fbb3 authored by Philipp Reisner's avatar Philipp Reisner
Browse files

drbd: Basic refcounting for drbd_tconn



References hold by:
 * Each (running) drbd thread has a reference on tconn
 * Each mdev has a referenc on tconn
 * Beeing in the all_tconn list counts for one reference
 * Each after_conn_state_chg_work has a reference to tconn

Signed-off-by: default avatarPhilipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: default avatarLars Ellenberg <lars.ellenberg@linbit.com>
parent 1d041225
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -828,6 +828,7 @@ enum {
struct drbd_tconn {			/* is a resource from the config file */
	char *name;			/* Resource name */
	struct list_head all_tconn;	/* linked on global drbd_tconns */
	struct kref kref;
	struct idr volumes;		/* <tconn, vnr> to mdev mapping */
	enum drbd_conns cstate;		/* Only C_STANDALONE to C_WF_REPORT_PARAMS */
	unsigned susp:1;		/* IO suspended by user */
@@ -1378,8 +1379,8 @@ extern int conn_lowest_minor(struct drbd_tconn *tconn);
enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor, int vnr);
extern void drbd_delete_device(struct drbd_conf *mdev);

struct drbd_tconn *drbd_new_tconn(const char *name);
extern void drbd_free_tconn(struct drbd_tconn *tconn);
struct drbd_tconn *conn_create(const char *name);
extern void conn_destroy(struct kref *kref);
struct drbd_tconn *conn_by_name(const char *name);
extern void conn_free_crypto(struct drbd_tconn *tconn);

+17 −3
Original line number Diff line number Diff line
@@ -509,6 +509,8 @@ static int drbd_thread_setup(void *arg)
	conn_info(tconn, "Terminating %s\n", current->comm);

	/* Release mod reference taken when thread was started */

	kref_put(&tconn->kref, &conn_destroy);
	module_put(THIS_MODULE);
	return retval;
}
@@ -546,6 +548,8 @@ int drbd_thread_start(struct drbd_thread *thi)
			return false;
		}

		kref_get(&thi->tconn->kref);

		init_completion(&thi->stop);
		thi->reset_cpu_mask = 1;
		thi->t_state = RUNNING;
@@ -558,6 +562,7 @@ int drbd_thread_start(struct drbd_thread *thi)
		if (IS_ERR(nt)) {
			conn_err(tconn, "Couldn't start thread\n");

			kref_put(&tconn->kref, &conn_destroy);
			module_put(THIS_MODULE);
			return false;
		}
@@ -2237,6 +2242,8 @@ static void drbd_release_all_peer_reqs(struct drbd_conf *mdev)
/* caution. no locking. */
void drbd_delete_device(struct drbd_conf *mdev)
{
	struct drbd_tconn *tconn = mdev->tconn;

	idr_remove(&mdev->tconn->volumes, mdev->vnr);
	idr_remove(&minors, mdev_to_minor(mdev));
	synchronize_rcu();
@@ -2272,6 +2279,8 @@ void drbd_delete_device(struct drbd_conf *mdev)
	put_disk(mdev->vdisk);
	blk_cleanup_queue(mdev->rq_queue);
	kfree(mdev);

	kref_put(&tconn->kref, &conn_destroy);
}

static void drbd_cleanup(void)
@@ -2409,7 +2418,7 @@ void conn_free_crypto(struct drbd_tconn *tconn)
	tconn->int_dig_vv = NULL;
}

struct drbd_tconn *drbd_new_tconn(const char *name)
struct drbd_tconn *conn_create(const char *name)
{
	struct drbd_tconn *tconn;

@@ -2455,6 +2464,7 @@ struct drbd_tconn *drbd_new_tconn(const char *name)
	};

	down_write(&drbd_cfg_rwsem);
	kref_init(&tconn->kref);
	list_add_tail(&tconn->all_tconn, &drbd_tconns);
	up_write(&drbd_cfg_rwsem);

@@ -2471,9 +2481,10 @@ struct drbd_tconn *drbd_new_tconn(const char *name)
	return NULL;
}

void drbd_free_tconn(struct drbd_tconn *tconn)
void conn_destroy(struct kref *kref)
{
	list_del(&tconn->all_tconn);
	struct drbd_tconn *tconn = container_of(kref, struct drbd_tconn, kref);

	idr_destroy(&tconn->volumes);

	free_cpumask_var(tconn->cpu_mask);
@@ -2503,7 +2514,9 @@ enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor,
	if (!mdev)
		return ERR_NOMEM;

	kref_get(&tconn->kref);
	mdev->tconn = tconn;

	mdev->minor = minor;
	mdev->vnr = vnr;

@@ -2605,6 +2618,7 @@ enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor,
	blk_cleanup_queue(q);
out_no_q:
	kfree(mdev);
	kref_put(&tconn->kref, &conn_destroy);
	return err;
}

+13 −9
Original line number Diff line number Diff line
@@ -479,6 +479,7 @@ static int _try_outdate_peer_async(void *data)

	conn_try_outdate_peer(tconn);

	kref_put(&tconn->kref, &conn_destroy);
	return 0;
}

@@ -486,9 +487,12 @@ void conn_try_outdate_peer_async(struct drbd_tconn *tconn)
{
	struct task_struct *opa;

	kref_get(&tconn->kref);
	opa = kthread_run(_try_outdate_peer_async, tconn, "drbd_async_h");
	if (IS_ERR(opa))
	if (IS_ERR(opa)) {
		conn_err(tconn, "out of mem, failed to invoke fence-peer helper\n");
		kref_put(&tconn->kref, &conn_destroy);
	}
}

enum drbd_state_rv
@@ -2627,7 +2631,7 @@ int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
	 * on each iteration.
	 */

	/* synchronize with drbd_new_tconn/drbd_free_tconn */
	/* synchronize with conn_create()/conn_destroy() */
	down_read(&drbd_cfg_rwsem);
	/* revalidate iterator position */
	list_for_each_entry(tmp, &drbd_tconns, all_tconn) {
@@ -2932,7 +2936,7 @@ int drbd_adm_create_connection(struct sk_buff *skb, struct genl_info *info)
		goto out;
	}

	if (!drbd_new_tconn(adm_ctx.conn_name))
	if (!conn_create(adm_ctx.conn_name))
		retcode = ERR_NOMEM;
out:
	drbd_adm_finish(info, retcode);
@@ -3005,10 +3009,6 @@ int drbd_adm_delete_minor(struct sk_buff *skb, struct genl_info *info)
	down_write(&drbd_cfg_rwsem);
	retcode = adm_delete_minor(adm_ctx.mdev);
	up_write(&drbd_cfg_rwsem);
	/* if this was the last volume of this connection,
	 * this will terminate all threads */
	if (retcode == NO_ERROR)
		conn_reconfig_done(adm_ctx.tconn);
out:
	drbd_adm_finish(info, retcode);
	return 0;
@@ -3078,7 +3078,9 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)

	/* delete connection */
	if (conn_lowest_minor(adm_ctx.tconn) < 0) {
		drbd_free_tconn(adm_ctx.tconn);
		list_del(&adm_ctx.tconn->all_tconn);
		kref_put(&adm_ctx.tconn->kref, &conn_destroy);

		retcode = NO_ERROR;
	} else {
		/* "can not happen" */
@@ -3107,7 +3109,9 @@ int drbd_adm_delete_connection(struct sk_buff *skb, struct genl_info *info)

	down_write(&drbd_cfg_rwsem);
	if (conn_lowest_minor(adm_ctx.tconn) < 0) {
		drbd_free_tconn(adm_ctx.tconn);
		list_del(&adm_ctx.tconn->all_tconn);
		kref_put(&adm_ctx.tconn->kref, &conn_destroy);

		retcode = NO_ERROR;
	} else {
		retcode = ERR_CONN_IN_USE;
+2 −0
Original line number Diff line number Diff line
@@ -1460,6 +1460,7 @@ static int w_after_conn_state_ch(struct drbd_work *w, int unused)

	//conn_err(tconn, STATE_FMT, STATE_ARGS("nms", nms));
	after_all_state_ch(tconn);
	kref_put(&tconn->kref, &conn_destroy);

	return 0;
}
@@ -1686,6 +1687,7 @@ _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_
		acscw->ns_max = ns_max;
		acscw->flags = flags;
		acscw->w.cb = w_after_conn_state_ch;
		kref_get(&tconn->kref);
		acscw->w.tconn = tconn;
		drbd_queue_work(&tconn->data.work, &acscw->w);
	} else {