aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilipp Reisner <philipp.reisner@linbit.com>2011-04-24 10:53:19 +0200
committerPhilipp Reisner <philipp.reisner@linbit.com>2012-11-08 16:49:06 +0100
commit0ace9dfabec3c1e96a1cd9fe0791ecbe6737c2f9 (patch)
treede80467afbc59c4d98cdf6a3defa55fee051ac98
parent9dc9fbb35733c8ea97fe9b1cfc5499c7a625805c (diff)
downloadvexpress-lsk-0ace9dfabec3c1e96a1cd9fe0791ecbe6737c2f9.tar.gz
drbd: Take a reference on tconn when finding a tconn by name
Rule #3 of kref.txt Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
-rw-r--r--drivers/block/drbd/drbd_int.h2
-rw-r--r--drivers/block/drbd/drbd_main.c6
-rw-r--r--drivers/block/drbd/drbd_nl.c15
3 files changed, 16 insertions, 7 deletions
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index 3abf982ec55..7797879d326 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -1381,7 +1381,7 @@ extern void drbd_delete_device(struct drbd_conf *mdev);
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;
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 11427f59c5a..f0a0e1759ba 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -2362,7 +2362,7 @@ static void drbd_init_workqueue(struct drbd_work_queue* wq)
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;
@@ -2371,8 +2371,10 @@ struct drbd_tconn *conn_by_name(const char *name)
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:
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index 23c34baa75a..272c4a08ee4 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -195,7 +195,7 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
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");
@@ -223,8 +223,7 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
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:
@@ -238,6 +237,11 @@ static int drbd_adm_finish(struct genl_info *info, int retcode)
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;
@@ -2748,10 +2752,13 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb)
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;