提交 08f75463 编写于 作者: A Alex Elder 提交者: Sage Weil

rbd: protect against duplicate client creation

If more than one rbd image has the same ceph cluster configuration
(same options, same set of monitors, same keys) they normally share
a single rbd client.

When an image is getting mapped, rbd looks to see if an existing
client can be used, and creates a new one if not.

The lookup and creation are not done under a common lock though, so
mapping two images concurrently could lead to duplicate clients
getting set up needlessly.  This isn't a major problem, but it's
wasteful and different from what's intended.

This patch fixes that by using the control mutex to protect
both the lookup and (if needed) creation of the client.  It
was previously used just when creating.

This resolves:
    http://tracker.ceph.com/issues/3094Signed-off-by: NAlex Elder <elder@inktank.com>
Reviewed-by: NJosh Durgin <josh.durgin@inktank.com>
上级 3b5cf2a2
...@@ -520,7 +520,7 @@ static const struct block_device_operations rbd_bd_ops = { ...@@ -520,7 +520,7 @@ static const struct block_device_operations rbd_bd_ops = {
/* /*
* Initialize an rbd client instance. Success or not, this function * Initialize an rbd client instance. Success or not, this function
* consumes ceph_opts. * consumes ceph_opts. Caller holds ctl_mutex.
*/ */
static struct rbd_client *rbd_client_create(struct ceph_options *ceph_opts) static struct rbd_client *rbd_client_create(struct ceph_options *ceph_opts)
{ {
...@@ -535,30 +535,25 @@ static struct rbd_client *rbd_client_create(struct ceph_options *ceph_opts) ...@@ -535,30 +535,25 @@ static struct rbd_client *rbd_client_create(struct ceph_options *ceph_opts)
kref_init(&rbdc->kref); kref_init(&rbdc->kref);
INIT_LIST_HEAD(&rbdc->node); INIT_LIST_HEAD(&rbdc->node);
mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
rbdc->client = ceph_create_client(ceph_opts, rbdc, 0, 0); rbdc->client = ceph_create_client(ceph_opts, rbdc, 0, 0);
if (IS_ERR(rbdc->client)) if (IS_ERR(rbdc->client))
goto out_mutex; goto out_rbdc;
ceph_opts = NULL; /* Now rbdc->client is responsible for ceph_opts */ ceph_opts = NULL; /* Now rbdc->client is responsible for ceph_opts */
ret = ceph_open_session(rbdc->client); ret = ceph_open_session(rbdc->client);
if (ret < 0) if (ret < 0)
goto out_err; goto out_client;
spin_lock(&rbd_client_list_lock); spin_lock(&rbd_client_list_lock);
list_add_tail(&rbdc->node, &rbd_client_list); list_add_tail(&rbdc->node, &rbd_client_list);
spin_unlock(&rbd_client_list_lock); spin_unlock(&rbd_client_list_lock);
mutex_unlock(&ctl_mutex);
dout("%s: rbdc %p\n", __func__, rbdc); dout("%s: rbdc %p\n", __func__, rbdc);
return rbdc; return rbdc;
out_client:
out_err:
ceph_destroy_client(rbdc->client); ceph_destroy_client(rbdc->client);
out_mutex: out_rbdc:
mutex_unlock(&ctl_mutex);
kfree(rbdc); kfree(rbdc);
out_opt: out_opt:
if (ceph_opts) if (ceph_opts)
...@@ -682,11 +677,13 @@ static struct rbd_client *rbd_get_client(struct ceph_options *ceph_opts) ...@@ -682,11 +677,13 @@ static struct rbd_client *rbd_get_client(struct ceph_options *ceph_opts)
{ {
struct rbd_client *rbdc; struct rbd_client *rbdc;
mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
rbdc = rbd_client_find(ceph_opts); rbdc = rbd_client_find(ceph_opts);
if (rbdc) /* using an existing client */ if (rbdc) /* using an existing client */
ceph_destroy_options(ceph_opts); ceph_destroy_options(ceph_opts);
else else
rbdc = rbd_client_create(ceph_opts); rbdc = rbd_client_create(ceph_opts);
mutex_unlock(&ctl_mutex);
return rbdc; return rbdc;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册