struct drbd_tconn *conn_create(const char *name);
extern void conn_destroy(struct kref *kref);
-struct drbd_tconn *conn_by_name(const char *name);
+struct drbd_tconn *conn_get_by_name(const char *name);
extern void conn_free_crypto(struct drbd_tconn *tconn);
extern int proc_details;
INIT_LIST_HEAD(&wq->q);
}
-struct drbd_tconn *conn_by_name(const char *name)
+struct drbd_tconn *conn_get_by_name(const char *name)
{
struct drbd_tconn *tconn;
down_read(&drbd_cfg_rwsem);
list_for_each_entry(tconn, &drbd_tconns, all_tconn) {
- if (!strcmp(tconn->name, name))
+ if (!strcmp(tconn->name, name)) {
+ kref_get(&tconn->kref);
goto found;
+ }
}
tconn = NULL;
found:
adm_ctx.minor = d_in->minor;
adm_ctx.mdev = minor_to_mdev(d_in->minor);
- adm_ctx.tconn = conn_by_name(adm_ctx.conn_name);
+ adm_ctx.tconn = conn_get_by_name(adm_ctx.conn_name);
if (!adm_ctx.mdev && (flags & DRBD_ADM_NEED_MINOR)) {
drbd_msg_put_info("unknown minor");
drbd_msg_put_info("minor exists as different volume");
return ERR_INVALID_REQUEST;
}
- if (adm_ctx.mdev && !adm_ctx.tconn)
- adm_ctx.tconn = adm_ctx.mdev->tconn;
+
return NO_ERROR;
fail:
struct nlattr *nla;
const char *conn_name = NULL;
+ if (adm_ctx.tconn) {
+ kref_put(&adm_ctx.tconn->kref, &conn_destroy);
+ adm_ctx.tconn = NULL;
+ }
+
if (!adm_ctx.reply_skb)
return -ENOMEM;
if (!nla)
return -EINVAL;
conn_name = nla_data(nla);
- tconn = conn_by_name(conn_name);
+ tconn = conn_get_by_name(conn_name);
+
if (!tconn)
return -ENODEV;
+ kref_put(&tconn->kref, &conn_destroy); /* get_one_status() (re)validates tconn by itself */
+
/* prime iterators, and set "filter" mode mark:
* only dump this tconn. */
cb->args[0] = (long)tconn;