diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-bus-rbd | 22 | ||||
-rw-r--r-- | drivers/block/rbd.c | 132 |
2 files changed, 134 insertions, 20 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-rbd b/Documentation/ABI/testing/sysfs-bus-rbd index 17b119c692da..501adc2a9ec7 100644 --- a/Documentation/ABI/testing/sysfs-bus-rbd +++ b/Documentation/ABI/testing/sysfs-bus-rbd | |||
@@ -18,6 +18,28 @@ Removal of a device: | |||
18 | 18 | ||
19 | $ echo <dev-id> > /sys/bus/rbd/remove | 19 | $ echo <dev-id> > /sys/bus/rbd/remove |
20 | 20 | ||
21 | What: /sys/bus/rbd/add_single_major | ||
22 | Date: December 2013 | ||
23 | KernelVersion: 3.14 | ||
24 | Contact: Sage Weil <sage@inktank.com> | ||
25 | Description: Available only if rbd module is inserted with single_major | ||
26 | parameter set to true. | ||
27 | Usage is the same as for /sys/bus/rbd/add. If present, | ||
28 | should be used instead of the latter: any attempts to use | ||
29 | /sys/bus/rbd/add if /sys/bus/rbd/add_single_major is | ||
30 | available will fail for backwards compatibility reasons. | ||
31 | |||
32 | What: /sys/bus/rbd/remove_single_major | ||
33 | Date: December 2013 | ||
34 | KernelVersion: 3.14 | ||
35 | Contact: Sage Weil <sage@inktank.com> | ||
36 | Description: Available only if rbd module is inserted with single_major | ||
37 | parameter set to true. | ||
38 | Usage is the same as for /sys/bus/rbd/remove. If present, | ||
39 | should be used instead of the latter: any attempts to use | ||
40 | /sys/bus/rbd/remove if /sys/bus/rbd/remove_single_major is | ||
41 | available will fail for backwards compatibility reasons. | ||
42 | |||
21 | Entries under /sys/bus/rbd/devices/<dev-id>/ | 43 | Entries under /sys/bus/rbd/devices/<dev-id>/ |
22 | -------------------------------------------- | 44 | -------------------------------------------- |
23 | 45 | ||
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 3fa18b0c5e4d..e5ddcb58e9a2 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c | |||
@@ -91,7 +91,7 @@ static int atomic_dec_return_safe(atomic_t *v) | |||
91 | 91 | ||
92 | #define RBD_DRV_NAME "rbd" | 92 | #define RBD_DRV_NAME "rbd" |
93 | 93 | ||
94 | #define RBD_MINORS_PER_MAJOR 256 /* max minors per blkdev */ | 94 | #define RBD_PART_SHIFT 8 |
95 | 95 | ||
96 | #define RBD_SNAP_DEV_NAME_PREFIX "snap_" | 96 | #define RBD_SNAP_DEV_NAME_PREFIX "snap_" |
97 | #define RBD_MAX_SNAP_NAME_LEN \ | 97 | #define RBD_MAX_SNAP_NAME_LEN \ |
@@ -387,8 +387,17 @@ static struct kmem_cache *rbd_img_request_cache; | |||
387 | static struct kmem_cache *rbd_obj_request_cache; | 387 | static struct kmem_cache *rbd_obj_request_cache; |
388 | static struct kmem_cache *rbd_segment_name_cache; | 388 | static struct kmem_cache *rbd_segment_name_cache; |
389 | 389 | ||
390 | static int rbd_major; | ||
390 | static DEFINE_IDA(rbd_dev_id_ida); | 391 | static DEFINE_IDA(rbd_dev_id_ida); |
391 | 392 | ||
393 | /* | ||
394 | * Default to false for now, as single-major requires >= 0.75 version of | ||
395 | * userspace rbd utility. | ||
396 | */ | ||
397 | static bool single_major = false; | ||
398 | module_param(single_major, bool, S_IRUGO); | ||
399 | MODULE_PARM_DESC(single_major, "Use a single major number for all rbd devices (default: false)"); | ||
400 | |||
392 | static int rbd_img_request_submit(struct rbd_img_request *img_request); | 401 | static int rbd_img_request_submit(struct rbd_img_request *img_request); |
393 | 402 | ||
394 | static void rbd_dev_device_release(struct device *dev); | 403 | static void rbd_dev_device_release(struct device *dev); |
@@ -397,21 +406,44 @@ static ssize_t rbd_add(struct bus_type *bus, const char *buf, | |||
397 | size_t count); | 406 | size_t count); |
398 | static ssize_t rbd_remove(struct bus_type *bus, const char *buf, | 407 | static ssize_t rbd_remove(struct bus_type *bus, const char *buf, |
399 | size_t count); | 408 | size_t count); |
409 | static ssize_t rbd_add_single_major(struct bus_type *bus, const char *buf, | ||
410 | size_t count); | ||
411 | static ssize_t rbd_remove_single_major(struct bus_type *bus, const char *buf, | ||
412 | size_t count); | ||
400 | static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping); | 413 | static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping); |
401 | static void rbd_spec_put(struct rbd_spec *spec); | 414 | static void rbd_spec_put(struct rbd_spec *spec); |
402 | 415 | ||
416 | static int rbd_dev_id_to_minor(int dev_id) | ||
417 | { | ||
418 | return dev_id << RBD_PART_SHIFT; | ||
419 | } | ||
420 | |||
421 | static int minor_to_rbd_dev_id(int minor) | ||
422 | { | ||
423 | return minor >> RBD_PART_SHIFT; | ||
424 | } | ||
425 | |||
403 | static BUS_ATTR(add, S_IWUSR, NULL, rbd_add); | 426 | static BUS_ATTR(add, S_IWUSR, NULL, rbd_add); |
404 | static BUS_ATTR(remove, S_IWUSR, NULL, rbd_remove); | 427 | static BUS_ATTR(remove, S_IWUSR, NULL, rbd_remove); |
428 | static BUS_ATTR(add_single_major, S_IWUSR, NULL, rbd_add_single_major); | ||
429 | static BUS_ATTR(remove_single_major, S_IWUSR, NULL, rbd_remove_single_major); | ||
405 | 430 | ||
406 | static struct attribute *rbd_bus_attrs[] = { | 431 | static struct attribute *rbd_bus_attrs[] = { |
407 | &bus_attr_add.attr, | 432 | &bus_attr_add.attr, |
408 | &bus_attr_remove.attr, | 433 | &bus_attr_remove.attr, |
434 | &bus_attr_add_single_major.attr, | ||
435 | &bus_attr_remove_single_major.attr, | ||
409 | NULL, | 436 | NULL, |
410 | }; | 437 | }; |
411 | 438 | ||
412 | static umode_t rbd_bus_is_visible(struct kobject *kobj, | 439 | static umode_t rbd_bus_is_visible(struct kobject *kobj, |
413 | struct attribute *attr, int index) | 440 | struct attribute *attr, int index) |
414 | { | 441 | { |
442 | if (!single_major && | ||
443 | (attr == &bus_attr_add_single_major.attr || | ||
444 | attr == &bus_attr_remove_single_major.attr)) | ||
445 | return 0; | ||
446 | |||
415 | return attr->mode; | 447 | return attr->mode; |
416 | } | 448 | } |
417 | 449 | ||
@@ -3402,7 +3434,7 @@ static int rbd_init_disk(struct rbd_device *rbd_dev) | |||
3402 | u64 segment_size; | 3434 | u64 segment_size; |
3403 | 3435 | ||
3404 | /* create gendisk info */ | 3436 | /* create gendisk info */ |
3405 | disk = alloc_disk(RBD_MINORS_PER_MAJOR); | 3437 | disk = alloc_disk(1 << RBD_PART_SHIFT); |
3406 | if (!disk) | 3438 | if (!disk) |
3407 | return -ENOMEM; | 3439 | return -ENOMEM; |
3408 | 3440 | ||
@@ -4403,7 +4435,9 @@ static int rbd_dev_id_get(struct rbd_device *rbd_dev) | |||
4403 | { | 4435 | { |
4404 | int new_dev_id; | 4436 | int new_dev_id; |
4405 | 4437 | ||
4406 | new_dev_id = ida_simple_get(&rbd_dev_id_ida, 0, 0, GFP_KERNEL); | 4438 | new_dev_id = ida_simple_get(&rbd_dev_id_ida, |
4439 | 0, minor_to_rbd_dev_id(1 << MINORBITS), | ||
4440 | GFP_KERNEL); | ||
4407 | if (new_dev_id < 0) | 4441 | if (new_dev_id < 0) |
4408 | return new_dev_id; | 4442 | return new_dev_id; |
4409 | 4443 | ||
@@ -4863,13 +4897,19 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev) | |||
4863 | < sizeof (RBD_DRV_NAME) + MAX_INT_FORMAT_WIDTH); | 4897 | < sizeof (RBD_DRV_NAME) + MAX_INT_FORMAT_WIDTH); |
4864 | sprintf(rbd_dev->name, "%s%d", RBD_DRV_NAME, rbd_dev->dev_id); | 4898 | sprintf(rbd_dev->name, "%s%d", RBD_DRV_NAME, rbd_dev->dev_id); |
4865 | 4899 | ||
4866 | /* Get our block major device number. */ | 4900 | /* Record our major and minor device numbers. */ |
4867 | 4901 | ||
4868 | ret = register_blkdev(0, rbd_dev->name); | 4902 | if (!single_major) { |
4869 | if (ret < 0) | 4903 | ret = register_blkdev(0, rbd_dev->name); |
4870 | goto err_out_id; | 4904 | if (ret < 0) |
4871 | rbd_dev->major = ret; | 4905 | goto err_out_id; |
4872 | rbd_dev->minor = 0; | 4906 | |
4907 | rbd_dev->major = ret; | ||
4908 | rbd_dev->minor = 0; | ||
4909 | } else { | ||
4910 | rbd_dev->major = rbd_major; | ||
4911 | rbd_dev->minor = rbd_dev_id_to_minor(rbd_dev->dev_id); | ||
4912 | } | ||
4873 | 4913 | ||
4874 | /* Set up the blkdev mapping. */ | 4914 | /* Set up the blkdev mapping. */ |
4875 | 4915 | ||
@@ -4901,7 +4941,8 @@ err_out_mapping: | |||
4901 | err_out_disk: | 4941 | err_out_disk: |
4902 | rbd_free_disk(rbd_dev); | 4942 | rbd_free_disk(rbd_dev); |
4903 | err_out_blkdev: | 4943 | err_out_blkdev: |
4904 | unregister_blkdev(rbd_dev->major, rbd_dev->name); | 4944 | if (!single_major) |
4945 | unregister_blkdev(rbd_dev->major, rbd_dev->name); | ||
4905 | err_out_id: | 4946 | err_out_id: |
4906 | rbd_dev_id_put(rbd_dev); | 4947 | rbd_dev_id_put(rbd_dev); |
4907 | rbd_dev_mapping_clear(rbd_dev); | 4948 | rbd_dev_mapping_clear(rbd_dev); |
@@ -5022,9 +5063,9 @@ err_out_format: | |||
5022 | return ret; | 5063 | return ret; |
5023 | } | 5064 | } |
5024 | 5065 | ||
5025 | static ssize_t rbd_add(struct bus_type *bus, | 5066 | static ssize_t do_rbd_add(struct bus_type *bus, |
5026 | const char *buf, | 5067 | const char *buf, |
5027 | size_t count) | 5068 | size_t count) |
5028 | { | 5069 | { |
5029 | struct rbd_device *rbd_dev = NULL; | 5070 | struct rbd_device *rbd_dev = NULL; |
5030 | struct ceph_options *ceph_opts = NULL; | 5071 | struct ceph_options *ceph_opts = NULL; |
@@ -5106,6 +5147,23 @@ err_out_module: | |||
5106 | return (ssize_t)rc; | 5147 | return (ssize_t)rc; |
5107 | } | 5148 | } |
5108 | 5149 | ||
5150 | static ssize_t rbd_add(struct bus_type *bus, | ||
5151 | const char *buf, | ||
5152 | size_t count) | ||
5153 | { | ||
5154 | if (single_major) | ||
5155 | return -EINVAL; | ||
5156 | |||
5157 | return do_rbd_add(bus, buf, count); | ||
5158 | } | ||
5159 | |||
5160 | static ssize_t rbd_add_single_major(struct bus_type *bus, | ||
5161 | const char *buf, | ||
5162 | size_t count) | ||
5163 | { | ||
5164 | return do_rbd_add(bus, buf, count); | ||
5165 | } | ||
5166 | |||
5109 | static void rbd_dev_device_release(struct device *dev) | 5167 | static void rbd_dev_device_release(struct device *dev) |
5110 | { | 5168 | { |
5111 | struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); | 5169 | struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); |
@@ -5113,8 +5171,8 @@ static void rbd_dev_device_release(struct device *dev) | |||
5113 | rbd_free_disk(rbd_dev); | 5171 | rbd_free_disk(rbd_dev); |
5114 | clear_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags); | 5172 | clear_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags); |
5115 | rbd_dev_mapping_clear(rbd_dev); | 5173 | rbd_dev_mapping_clear(rbd_dev); |
5116 | unregister_blkdev(rbd_dev->major, rbd_dev->name); | 5174 | if (!single_major) |
5117 | rbd_dev->major = 0; | 5175 | unregister_blkdev(rbd_dev->major, rbd_dev->name); |
5118 | rbd_dev_id_put(rbd_dev); | 5176 | rbd_dev_id_put(rbd_dev); |
5119 | rbd_dev_mapping_clear(rbd_dev); | 5177 | rbd_dev_mapping_clear(rbd_dev); |
5120 | } | 5178 | } |
@@ -5145,9 +5203,9 @@ static void rbd_dev_remove_parent(struct rbd_device *rbd_dev) | |||
5145 | } | 5203 | } |
5146 | } | 5204 | } |
5147 | 5205 | ||
5148 | static ssize_t rbd_remove(struct bus_type *bus, | 5206 | static ssize_t do_rbd_remove(struct bus_type *bus, |
5149 | const char *buf, | 5207 | const char *buf, |
5150 | size_t count) | 5208 | size_t count) |
5151 | { | 5209 | { |
5152 | struct rbd_device *rbd_dev = NULL; | 5210 | struct rbd_device *rbd_dev = NULL; |
5153 | struct list_head *tmp; | 5211 | struct list_head *tmp; |
@@ -5210,6 +5268,23 @@ static ssize_t rbd_remove(struct bus_type *bus, | |||
5210 | return count; | 5268 | return count; |
5211 | } | 5269 | } |
5212 | 5270 | ||
5271 | static ssize_t rbd_remove(struct bus_type *bus, | ||
5272 | const char *buf, | ||
5273 | size_t count) | ||
5274 | { | ||
5275 | if (single_major) | ||
5276 | return -EINVAL; | ||
5277 | |||
5278 | return do_rbd_remove(bus, buf, count); | ||
5279 | } | ||
5280 | |||
5281 | static ssize_t rbd_remove_single_major(struct bus_type *bus, | ||
5282 | const char *buf, | ||
5283 | size_t count) | ||
5284 | { | ||
5285 | return do_rbd_remove(bus, buf, count); | ||
5286 | } | ||
5287 | |||
5213 | /* | 5288 | /* |
5214 | * create control files in sysfs | 5289 | * create control files in sysfs |
5215 | * /sys/bus/rbd/... | 5290 | * /sys/bus/rbd/... |
@@ -5298,13 +5373,28 @@ static int __init rbd_init(void) | |||
5298 | if (rc) | 5373 | if (rc) |
5299 | return rc; | 5374 | return rc; |
5300 | 5375 | ||
5376 | if (single_major) { | ||
5377 | rbd_major = register_blkdev(0, RBD_DRV_NAME); | ||
5378 | if (rbd_major < 0) { | ||
5379 | rc = rbd_major; | ||
5380 | goto err_out_slab; | ||
5381 | } | ||
5382 | } | ||
5383 | |||
5301 | rc = rbd_sysfs_init(); | 5384 | rc = rbd_sysfs_init(); |
5302 | if (rc) | 5385 | if (rc) |
5303 | goto err_out_slab; | 5386 | goto err_out_blkdev; |
5387 | |||
5388 | if (single_major) | ||
5389 | pr_info("loaded (major %d)\n", rbd_major); | ||
5390 | else | ||
5391 | pr_info("loaded\n"); | ||
5304 | 5392 | ||
5305 | pr_info("loaded\n"); | ||
5306 | return 0; | 5393 | return 0; |
5307 | 5394 | ||
5395 | err_out_blkdev: | ||
5396 | if (single_major) | ||
5397 | unregister_blkdev(rbd_major, RBD_DRV_NAME); | ||
5308 | err_out_slab: | 5398 | err_out_slab: |
5309 | rbd_slab_exit(); | 5399 | rbd_slab_exit(); |
5310 | return rc; | 5400 | return rc; |
@@ -5313,6 +5403,8 @@ err_out_slab: | |||
5313 | static void __exit rbd_exit(void) | 5403 | static void __exit rbd_exit(void) |
5314 | { | 5404 | { |
5315 | rbd_sysfs_cleanup(); | 5405 | rbd_sysfs_cleanup(); |
5406 | if (single_major) | ||
5407 | unregister_blkdev(rbd_major, RBD_DRV_NAME); | ||
5316 | rbd_slab_exit(); | 5408 | rbd_slab_exit(); |
5317 | } | 5409 | } |
5318 | 5410 | ||