diff options
Diffstat (limited to 'drivers/block/drbd/drbd_main.c')
-rw-r--r-- | drivers/block/drbd/drbd_main.c | 20 |
1 files changed, 17 insertions, 3 deletions
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index b9c103f16ae7..11427f59c5af 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -509,6 +509,8 @@ restart: 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 @@ fail: 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 @@ out_no_disk: blk_cleanup_queue(q); out_no_q: kfree(mdev); + kref_put(&tconn->kref, &conn_destroy); return err; } |