Skip to content

Commit

Permalink
drbd: Take a reference on tconn when finding a tconn by name
Browse files Browse the repository at this point in the history
Rule #3 of kref.txt

Signed-off-by: Philipp Reisner <[email protected]>
Signed-off-by: Lars Ellenberg <[email protected]>
  • Loading branch information
Philipp-Reisner committed Nov 8, 2012
1 parent 9dc9fbb commit 0ace9df
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 7 deletions.
2 changes: 1 addition & 1 deletion drivers/block/drbd/drbd_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 4 additions & 2 deletions drivers/block/drbd/drbd_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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:
Expand Down
15 changes: 11 additions & 4 deletions drivers/block/drbd/drbd_nl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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:
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 0ace9df

Please sign in to comment.