mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-14 09:47:20 +00:00
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>
This commit is contained in:
parent
1d04122599
commit
9dc9fbb357
@ -828,6 +828,7 @@ enum {
|
|||||||
struct drbd_tconn { /* is a resource from the config file */
|
struct drbd_tconn { /* is a resource from the config file */
|
||||||
char *name; /* Resource name */
|
char *name; /* Resource name */
|
||||||
struct list_head all_tconn; /* linked on global drbd_tconns */
|
struct list_head all_tconn; /* linked on global drbd_tconns */
|
||||||
|
struct kref kref;
|
||||||
struct idr volumes; /* <tconn, vnr> to mdev mapping */
|
struct idr volumes; /* <tconn, vnr> to mdev mapping */
|
||||||
enum drbd_conns cstate; /* Only C_STANDALONE to C_WF_REPORT_PARAMS */
|
enum drbd_conns cstate; /* Only C_STANDALONE to C_WF_REPORT_PARAMS */
|
||||||
unsigned susp:1; /* IO suspended by user */
|
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);
|
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);
|
extern void drbd_delete_device(struct drbd_conf *mdev);
|
||||||
|
|
||||||
struct drbd_tconn *drbd_new_tconn(const char *name);
|
struct drbd_tconn *conn_create(const char *name);
|
||||||
extern void drbd_free_tconn(struct drbd_tconn *tconn);
|
extern void conn_destroy(struct kref *kref);
|
||||||
struct drbd_tconn *conn_by_name(const char *name);
|
struct drbd_tconn *conn_by_name(const char *name);
|
||||||
extern void conn_free_crypto(struct drbd_tconn *tconn);
|
extern void conn_free_crypto(struct drbd_tconn *tconn);
|
||||||
|
|
||||||
|
@ -509,6 +509,8 @@ restart:
|
|||||||
conn_info(tconn, "Terminating %s\n", current->comm);
|
conn_info(tconn, "Terminating %s\n", current->comm);
|
||||||
|
|
||||||
/* Release mod reference taken when thread was started */
|
/* Release mod reference taken when thread was started */
|
||||||
|
|
||||||
|
kref_put(&tconn->kref, &conn_destroy);
|
||||||
module_put(THIS_MODULE);
|
module_put(THIS_MODULE);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@ -546,6 +548,8 @@ int drbd_thread_start(struct drbd_thread *thi)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kref_get(&thi->tconn->kref);
|
||||||
|
|
||||||
init_completion(&thi->stop);
|
init_completion(&thi->stop);
|
||||||
thi->reset_cpu_mask = 1;
|
thi->reset_cpu_mask = 1;
|
||||||
thi->t_state = RUNNING;
|
thi->t_state = RUNNING;
|
||||||
@ -558,6 +562,7 @@ int drbd_thread_start(struct drbd_thread *thi)
|
|||||||
if (IS_ERR(nt)) {
|
if (IS_ERR(nt)) {
|
||||||
conn_err(tconn, "Couldn't start thread\n");
|
conn_err(tconn, "Couldn't start thread\n");
|
||||||
|
|
||||||
|
kref_put(&tconn->kref, &conn_destroy);
|
||||||
module_put(THIS_MODULE);
|
module_put(THIS_MODULE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2237,6 +2242,8 @@ static void drbd_release_all_peer_reqs(struct drbd_conf *mdev)
|
|||||||
/* caution. no locking. */
|
/* caution. no locking. */
|
||||||
void drbd_delete_device(struct drbd_conf *mdev)
|
void drbd_delete_device(struct drbd_conf *mdev)
|
||||||
{
|
{
|
||||||
|
struct drbd_tconn *tconn = mdev->tconn;
|
||||||
|
|
||||||
idr_remove(&mdev->tconn->volumes, mdev->vnr);
|
idr_remove(&mdev->tconn->volumes, mdev->vnr);
|
||||||
idr_remove(&minors, mdev_to_minor(mdev));
|
idr_remove(&minors, mdev_to_minor(mdev));
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
@ -2272,6 +2279,8 @@ void drbd_delete_device(struct drbd_conf *mdev)
|
|||||||
put_disk(mdev->vdisk);
|
put_disk(mdev->vdisk);
|
||||||
blk_cleanup_queue(mdev->rq_queue);
|
blk_cleanup_queue(mdev->rq_queue);
|
||||||
kfree(mdev);
|
kfree(mdev);
|
||||||
|
|
||||||
|
kref_put(&tconn->kref, &conn_destroy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drbd_cleanup(void)
|
static void drbd_cleanup(void)
|
||||||
@ -2409,7 +2418,7 @@ void conn_free_crypto(struct drbd_tconn *tconn)
|
|||||||
tconn->int_dig_vv = NULL;
|
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;
|
struct drbd_tconn *tconn;
|
||||||
|
|
||||||
@ -2455,6 +2464,7 @@ struct drbd_tconn *drbd_new_tconn(const char *name)
|
|||||||
};
|
};
|
||||||
|
|
||||||
down_write(&drbd_cfg_rwsem);
|
down_write(&drbd_cfg_rwsem);
|
||||||
|
kref_init(&tconn->kref);
|
||||||
list_add_tail(&tconn->all_tconn, &drbd_tconns);
|
list_add_tail(&tconn->all_tconn, &drbd_tconns);
|
||||||
up_write(&drbd_cfg_rwsem);
|
up_write(&drbd_cfg_rwsem);
|
||||||
|
|
||||||
@ -2471,9 +2481,10 @@ fail:
|
|||||||
return NULL;
|
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);
|
idr_destroy(&tconn->volumes);
|
||||||
|
|
||||||
free_cpumask_var(tconn->cpu_mask);
|
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)
|
if (!mdev)
|
||||||
return ERR_NOMEM;
|
return ERR_NOMEM;
|
||||||
|
|
||||||
|
kref_get(&tconn->kref);
|
||||||
mdev->tconn = tconn;
|
mdev->tconn = tconn;
|
||||||
|
|
||||||
mdev->minor = minor;
|
mdev->minor = minor;
|
||||||
mdev->vnr = vnr;
|
mdev->vnr = vnr;
|
||||||
|
|
||||||
@ -2605,6 +2618,7 @@ out_no_disk:
|
|||||||
blk_cleanup_queue(q);
|
blk_cleanup_queue(q);
|
||||||
out_no_q:
|
out_no_q:
|
||||||
kfree(mdev);
|
kfree(mdev);
|
||||||
|
kref_put(&tconn->kref, &conn_destroy);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,6 +479,7 @@ static int _try_outdate_peer_async(void *data)
|
|||||||
|
|
||||||
conn_try_outdate_peer(tconn);
|
conn_try_outdate_peer(tconn);
|
||||||
|
|
||||||
|
kref_put(&tconn->kref, &conn_destroy);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -486,9 +487,12 @@ void conn_try_outdate_peer_async(struct drbd_tconn *tconn)
|
|||||||
{
|
{
|
||||||
struct task_struct *opa;
|
struct task_struct *opa;
|
||||||
|
|
||||||
|
kref_get(&tconn->kref);
|
||||||
opa = kthread_run(_try_outdate_peer_async, tconn, "drbd_async_h");
|
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");
|
conn_err(tconn, "out of mem, failed to invoke fence-peer helper\n");
|
||||||
|
kref_put(&tconn->kref, &conn_destroy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum drbd_state_rv
|
enum drbd_state_rv
|
||||||
@ -2627,7 +2631,7 @@ int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
|
|||||||
* on each iteration.
|
* on each iteration.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* synchronize with drbd_new_tconn/drbd_free_tconn */
|
/* synchronize with conn_create()/conn_destroy() */
|
||||||
down_read(&drbd_cfg_rwsem);
|
down_read(&drbd_cfg_rwsem);
|
||||||
/* revalidate iterator position */
|
/* revalidate iterator position */
|
||||||
list_for_each_entry(tmp, &drbd_tconns, all_tconn) {
|
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;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!drbd_new_tconn(adm_ctx.conn_name))
|
if (!conn_create(adm_ctx.conn_name))
|
||||||
retcode = ERR_NOMEM;
|
retcode = ERR_NOMEM;
|
||||||
out:
|
out:
|
||||||
drbd_adm_finish(info, retcode);
|
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);
|
down_write(&drbd_cfg_rwsem);
|
||||||
retcode = adm_delete_minor(adm_ctx.mdev);
|
retcode = adm_delete_minor(adm_ctx.mdev);
|
||||||
up_write(&drbd_cfg_rwsem);
|
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:
|
out:
|
||||||
drbd_adm_finish(info, retcode);
|
drbd_adm_finish(info, retcode);
|
||||||
return 0;
|
return 0;
|
||||||
@ -3078,7 +3078,9 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
|
|||||||
|
|
||||||
/* delete connection */
|
/* delete connection */
|
||||||
if (conn_lowest_minor(adm_ctx.tconn) < 0) {
|
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;
|
retcode = NO_ERROR;
|
||||||
} else {
|
} else {
|
||||||
/* "can not happen" */
|
/* "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);
|
down_write(&drbd_cfg_rwsem);
|
||||||
if (conn_lowest_minor(adm_ctx.tconn) < 0) {
|
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;
|
retcode = NO_ERROR;
|
||||||
} else {
|
} else {
|
||||||
retcode = ERR_CONN_IN_USE;
|
retcode = ERR_CONN_IN_USE;
|
||||||
|
@ -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));
|
//conn_err(tconn, STATE_FMT, STATE_ARGS("nms", nms));
|
||||||
after_all_state_ch(tconn);
|
after_all_state_ch(tconn);
|
||||||
|
kref_put(&tconn->kref, &conn_destroy);
|
||||||
|
|
||||||
return 0;
|
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->ns_max = ns_max;
|
||||||
acscw->flags = flags;
|
acscw->flags = flags;
|
||||||
acscw->w.cb = w_after_conn_state_ch;
|
acscw->w.cb = w_after_conn_state_ch;
|
||||||
|
kref_get(&tconn->kref);
|
||||||
acscw->w.tconn = tconn;
|
acscw->w.tconn = tconn;
|
||||||
drbd_queue_work(&tconn->data.work, &acscw->w);
|
drbd_queue_work(&tconn->data.work, &acscw->w);
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user