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 */
 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);
 
 
        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;
 }
                        return false;
                }
 
+               kref_get(&thi->tconn->kref);
+
                init_completion(&thi->stop);
                thi->reset_cpu_mask = 1;
                thi->t_state = RUNNING;
                if (IS_ERR(nt)) {
                        conn_err(tconn, "Couldn't start thread\n");
 
+                       kref_put(&tconn->kref, &conn_destroy);
                        module_put(THIS_MODULE);
                        return false;
                }
 /* 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();
        put_disk(mdev->vdisk);
        blk_cleanup_queue(mdev->rq_queue);
        kfree(mdev);
+
+       kref_put(&tconn->kref, &conn_destroy);
 }
 
 static void drbd_cleanup(void)
        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;
 
        };
 
        down_write(&drbd_cfg_rwsem);
+       kref_init(&tconn->kref);
        list_add_tail(&tconn->all_tconn, &drbd_tconns);
        up_write(&drbd_cfg_rwsem);
 
        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);
        if (!mdev)
                return ERR_NOMEM;
 
+       kref_get(&tconn->kref);
        mdev->tconn = tconn;
+
        mdev->minor = minor;
        mdev->vnr = vnr;
 
        blk_cleanup_queue(q);
 out_no_q:
        kfree(mdev);
+       kref_put(&tconn->kref, &conn_destroy);
        return err;
 }
 
 
 
        conn_try_outdate_peer(tconn);
 
+       kref_put(&tconn->kref, &conn_destroy);
        return 0;
 }
 
 {
        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
         * 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) {
                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);
        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;
 
        /* 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" */
 
        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;
 
 
        //conn_err(tconn, STATE_FMT, STATE_ARGS("nms", nms));
        after_all_state_ch(tconn);
+       kref_put(&tconn->kref, &conn_destroy);
 
        return 0;
 }
                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 {