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: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index fff11ae..23c34ba 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -479,6 +479,7 @@
conn_try_outdate_peer(tconn);
+ kref_put(&tconn->kref, &conn_destroy);
return 0;
}
@@ -486,9 +487,12 @@
{
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 @@
* 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 @@
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 @@
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 @@
/* 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 @@
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;