Skip to content

Commit 1643dfa

Browse files
committed
rbd: introduce a per-device ordered workqueue
This is going to be used for re-registering watch requests and exclusive-lock tasks: acquire/request lock, notify-acquired, release lock, notify-released. Some refactoring in the map/unmap paths was necessary to give this workqueue a meaningful name: "rbdX-tasks". Signed-off-by: Ilya Dryomov <[email protected]> Reviewed-by: Mike Christie <[email protected]>
1 parent 033268a commit 1643dfa

File tree

1 file changed

+71
-80
lines changed

1 file changed

+71
-80
lines changed

drivers/block/rbd.c

Lines changed: 71 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,8 @@ static int atomic_dec_return_safe(atomic_t *v)
128128
/*
129129
* An RBD device name will be "rbd#", where the "rbd" comes from
130130
* RBD_DRV_NAME above, and # is a unique integer identifier.
131-
* MAX_INT_FORMAT_WIDTH is used in ensuring DEV_NAME_LEN is big
132-
* enough to hold all possible device names.
133131
*/
134132
#define DEV_NAME_LEN 32
135-
#define MAX_INT_FORMAT_WIDTH ((5 * sizeof (int)) / 2 + 1)
136133

137134
/*
138135
* block device image metadata (in-memory version)
@@ -353,10 +350,12 @@ struct rbd_device {
353350
struct ceph_object_id header_oid;
354351
struct ceph_object_locator header_oloc;
355352

356-
struct ceph_file_layout layout;
353+
struct ceph_file_layout layout; /* used for all rbd requests */
357354

358355
struct ceph_osd_linger_request *watch_handle;
359356

357+
struct workqueue_struct *task_wq;
358+
360359
struct rbd_spec *parent_spec;
361360
u64 parent_overlap;
362361
atomic_t parent_ref;
@@ -3944,18 +3943,28 @@ static void rbd_spec_free(struct kref *kref)
39443943
kfree(spec);
39453944
}
39463945

3947-
static void rbd_dev_release(struct device *dev)
3946+
static void rbd_dev_free(struct rbd_device *rbd_dev)
39483947
{
3949-
struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
3950-
bool need_put = !!rbd_dev->opts;
3951-
39523948
ceph_oid_destroy(&rbd_dev->header_oid);
39533949
ceph_oloc_destroy(&rbd_dev->header_oloc);
39543950

39553951
rbd_put_client(rbd_dev->rbd_client);
39563952
rbd_spec_put(rbd_dev->spec);
39573953
kfree(rbd_dev->opts);
39583954
kfree(rbd_dev);
3955+
}
3956+
3957+
static void rbd_dev_release(struct device *dev)
3958+
{
3959+
struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
3960+
bool need_put = !!rbd_dev->opts;
3961+
3962+
if (need_put) {
3963+
destroy_workqueue(rbd_dev->task_wq);
3964+
ida_simple_remove(&rbd_dev_id_ida, rbd_dev->dev_id);
3965+
}
3966+
3967+
rbd_dev_free(rbd_dev);
39593968

39603969
/*
39613970
* This is racy, but way better than putting module outside of
@@ -3966,19 +3975,16 @@ static void rbd_dev_release(struct device *dev)
39663975
module_put(THIS_MODULE);
39673976
}
39683977

3969-
static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc,
3970-
struct rbd_spec *spec,
3971-
struct rbd_options *opts)
3978+
static struct rbd_device *__rbd_dev_create(struct rbd_client *rbdc,
3979+
struct rbd_spec *spec)
39723980
{
39733981
struct rbd_device *rbd_dev;
39743982

3975-
rbd_dev = kzalloc(sizeof (*rbd_dev), GFP_KERNEL);
3983+
rbd_dev = kzalloc(sizeof(*rbd_dev), GFP_KERNEL);
39763984
if (!rbd_dev)
39773985
return NULL;
39783986

39793987
spin_lock_init(&rbd_dev->lock);
3980-
rbd_dev->flags = 0;
3981-
atomic_set(&rbd_dev->parent_ref, 0);
39823988
INIT_LIST_HEAD(&rbd_dev->node);
39833989
init_rwsem(&rbd_dev->header_rwsem);
39843990

@@ -3992,25 +3998,55 @@ static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc,
39923998

39933999
rbd_dev->rbd_client = rbdc;
39944000
rbd_dev->spec = spec;
3995-
rbd_dev->opts = opts;
3996-
3997-
/* Initialize the layout used for all rbd requests */
39984001

39994002
rbd_dev->layout.stripe_unit = 1 << RBD_MAX_OBJ_ORDER;
40004003
rbd_dev->layout.stripe_count = 1;
40014004
rbd_dev->layout.object_size = 1 << RBD_MAX_OBJ_ORDER;
40024005
rbd_dev->layout.pool_id = spec->pool_id;
40034006
RCU_INIT_POINTER(rbd_dev->layout.pool_ns, NULL);
40044007

4005-
/*
4006-
* If this is a mapping rbd_dev (as opposed to a parent one),
4007-
* pin our module. We have a ref from do_rbd_add(), so use
4008-
* __module_get().
4009-
*/
4010-
if (rbd_dev->opts)
4011-
__module_get(THIS_MODULE);
4008+
return rbd_dev;
4009+
}
4010+
4011+
/*
4012+
* Create a mapping rbd_dev.
4013+
*/
4014+
static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc,
4015+
struct rbd_spec *spec,
4016+
struct rbd_options *opts)
4017+
{
4018+
struct rbd_device *rbd_dev;
4019+
4020+
rbd_dev = __rbd_dev_create(rbdc, spec);
4021+
if (!rbd_dev)
4022+
return NULL;
4023+
4024+
rbd_dev->opts = opts;
4025+
4026+
/* get an id and fill in device name */
4027+
rbd_dev->dev_id = ida_simple_get(&rbd_dev_id_ida, 0,
4028+
minor_to_rbd_dev_id(1 << MINORBITS),
4029+
GFP_KERNEL);
4030+
if (rbd_dev->dev_id < 0)
4031+
goto fail_rbd_dev;
4032+
4033+
sprintf(rbd_dev->name, RBD_DRV_NAME "%d", rbd_dev->dev_id);
4034+
rbd_dev->task_wq = alloc_ordered_workqueue("%s-tasks", WQ_MEM_RECLAIM,
4035+
rbd_dev->name);
4036+
if (!rbd_dev->task_wq)
4037+
goto fail_dev_id;
40124038

4039+
/* we have a ref from do_rbd_add() */
4040+
__module_get(THIS_MODULE);
4041+
4042+
dout("%s rbd_dev %p dev_id %d\n", __func__, rbd_dev, rbd_dev->dev_id);
40134043
return rbd_dev;
4044+
4045+
fail_dev_id:
4046+
ida_simple_remove(&rbd_dev_id_ida, rbd_dev->dev_id);
4047+
fail_rbd_dev:
4048+
rbd_dev_free(rbd_dev);
4049+
return NULL;
40144050
}
40154051

40164052
static void rbd_dev_destroy(struct rbd_device *rbd_dev)
@@ -4645,46 +4681,6 @@ static int rbd_dev_header_info(struct rbd_device *rbd_dev)
46454681
return rbd_dev_v2_header_info(rbd_dev);
46464682
}
46474683

4648-
/*
4649-
* Get a unique rbd identifier for the given new rbd_dev, and add
4650-
* the rbd_dev to the global list.
4651-
*/
4652-
static int rbd_dev_id_get(struct rbd_device *rbd_dev)
4653-
{
4654-
int new_dev_id;
4655-
4656-
new_dev_id = ida_simple_get(&rbd_dev_id_ida,
4657-
0, minor_to_rbd_dev_id(1 << MINORBITS),
4658-
GFP_KERNEL);
4659-
if (new_dev_id < 0)
4660-
return new_dev_id;
4661-
4662-
rbd_dev->dev_id = new_dev_id;
4663-
4664-
spin_lock(&rbd_dev_list_lock);
4665-
list_add_tail(&rbd_dev->node, &rbd_dev_list);
4666-
spin_unlock(&rbd_dev_list_lock);
4667-
4668-
dout("rbd_dev %p given dev id %d\n", rbd_dev, rbd_dev->dev_id);
4669-
4670-
return 0;
4671-
}
4672-
4673-
/*
4674-
* Remove an rbd_dev from the global list, and record that its
4675-
* identifier is no longer in use.
4676-
*/
4677-
static void rbd_dev_id_put(struct rbd_device *rbd_dev)
4678-
{
4679-
spin_lock(&rbd_dev_list_lock);
4680-
list_del_init(&rbd_dev->node);
4681-
spin_unlock(&rbd_dev_list_lock);
4682-
4683-
ida_simple_remove(&rbd_dev_id_ida, rbd_dev->dev_id);
4684-
4685-
dout("rbd_dev %p released dev id %d\n", rbd_dev, rbd_dev->dev_id);
4686-
}
4687-
46884684
/*
46894685
* Skips over white space at *buf, and updates *buf to point to the
46904686
* first found non-space character (if any). Returns the length of
@@ -5077,8 +5073,7 @@ static int rbd_dev_probe_parent(struct rbd_device *rbd_dev, int depth)
50775073
goto out_err;
50785074
}
50795075

5080-
parent = rbd_dev_create(rbd_dev->rbd_client, rbd_dev->parent_spec,
5081-
NULL);
5076+
parent = __rbd_dev_create(rbd_dev->rbd_client, rbd_dev->parent_spec);
50825077
if (!parent) {
50835078
ret = -ENOMEM;
50845079
goto out_err;
@@ -5113,22 +5108,12 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev)
51135108
{
51145109
int ret;
51155110

5116-
/* Get an id and fill in device name. */
5117-
5118-
ret = rbd_dev_id_get(rbd_dev);
5119-
if (ret)
5120-
goto err_out_unlock;
5121-
5122-
BUILD_BUG_ON(DEV_NAME_LEN
5123-
< sizeof (RBD_DRV_NAME) + MAX_INT_FORMAT_WIDTH);
5124-
sprintf(rbd_dev->name, "%s%d", RBD_DRV_NAME, rbd_dev->dev_id);
5125-
51265111
/* Record our major and minor device numbers. */
51275112

51285113
if (!single_major) {
51295114
ret = register_blkdev(0, rbd_dev->name);
51305115
if (ret < 0)
5131-
goto err_out_id;
5116+
goto err_out_unlock;
51325117

51335118
rbd_dev->major = ret;
51345119
rbd_dev->minor = 0;
@@ -5160,6 +5145,10 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev)
51605145
set_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags);
51615146
up_write(&rbd_dev->header_rwsem);
51625147

5148+
spin_lock(&rbd_dev_list_lock);
5149+
list_add_tail(&rbd_dev->node, &rbd_dev_list);
5150+
spin_unlock(&rbd_dev_list_lock);
5151+
51635152
add_disk(rbd_dev->disk);
51645153
pr_info("%s: added with size 0x%llx\n", rbd_dev->disk->disk_name,
51655154
(unsigned long long) rbd_dev->mapping.size);
@@ -5173,8 +5162,6 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev)
51735162
err_out_blkdev:
51745163
if (!single_major)
51755164
unregister_blkdev(rbd_dev->major, rbd_dev->name);
5176-
err_out_id:
5177-
rbd_dev_id_put(rbd_dev);
51785165
err_out_unlock:
51795166
up_write(&rbd_dev->header_rwsem);
51805167
return ret;
@@ -5406,12 +5393,16 @@ static ssize_t rbd_add_single_major(struct bus_type *bus,
54065393
static void rbd_dev_device_release(struct rbd_device *rbd_dev)
54075394
{
54085395
rbd_free_disk(rbd_dev);
5396+
5397+
spin_lock(&rbd_dev_list_lock);
5398+
list_del_init(&rbd_dev->node);
5399+
spin_unlock(&rbd_dev_list_lock);
5400+
54095401
clear_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags);
54105402
device_del(&rbd_dev->dev);
54115403
rbd_dev_mapping_clear(rbd_dev);
54125404
if (!single_major)
54135405
unregister_blkdev(rbd_dev->major, rbd_dev->name);
5414-
rbd_dev_id_put(rbd_dev);
54155406
}
54165407

54175408
static void rbd_dev_remove_parent(struct rbd_device *rbd_dev)

0 commit comments

Comments
 (0)