diff options
author | Alex Elder <elder@inktank.com> | 2013-05-31 18:40:45 -0400 |
---|---|---|
committer | Sage Weil <sage@inktank.com> | 2013-07-03 18:32:43 -0400 |
commit | cfbf6377b696d88461eef6966bef9e6184111183 (patch) | |
tree | 6da8c0cfcd4aeb02a738a6c552f9a5f429139164 | |
parent | 1ba0f1e7975ad07557f7a931522bdcd813ae35f6 (diff) |
rbd: use rwsem to protect header updates
Updating an image header needs to be protected to ensure it's
done consistently. However distinct headers can be updated
concurrently without a problem. Instead of using the global
control lock to serialize headder updates, just rely on the header
semaphore. (It's already used, this just moves it out to cover
a broader section of the code.)
That leaves the control mutex protecting only the creation of rbd
clients, so rename it.
This resolves:
http://tracker.ceph.com/issues/5222
Signed-off-by: Alex Elder <elder@inktank.com>
Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
-rw-r--r-- | drivers/block/rbd.c | 26 |
1 files changed, 10 insertions, 16 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index d735eb13847d..44c44c6071ed 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c | |||
@@ -372,7 +372,7 @@ enum rbd_dev_flags { | |||
372 | RBD_DEV_FLAG_REMOVING, /* this mapping is being removed */ | 372 | RBD_DEV_FLAG_REMOVING, /* this mapping is being removed */ |
373 | }; | 373 | }; |
374 | 374 | ||
375 | static DEFINE_MUTEX(ctl_mutex); /* Serialize open/close/setup/teardown */ | 375 | static DEFINE_MUTEX(client_mutex); /* Serialize client creation */ |
376 | 376 | ||
377 | static LIST_HEAD(rbd_dev_list); /* devices */ | 377 | static LIST_HEAD(rbd_dev_list); /* devices */ |
378 | static DEFINE_SPINLOCK(rbd_dev_list_lock); | 378 | static DEFINE_SPINLOCK(rbd_dev_list_lock); |
@@ -516,7 +516,7 @@ static const struct block_device_operations rbd_bd_ops = { | |||
516 | 516 | ||
517 | /* | 517 | /* |
518 | * Initialize an rbd client instance. Success or not, this function | 518 | * Initialize an rbd client instance. Success or not, this function |
519 | * consumes ceph_opts. Caller holds ctl_mutex. | 519 | * consumes ceph_opts. Caller holds client_mutex. |
520 | */ | 520 | */ |
521 | static struct rbd_client *rbd_client_create(struct ceph_options *ceph_opts) | 521 | static struct rbd_client *rbd_client_create(struct ceph_options *ceph_opts) |
522 | { | 522 | { |
@@ -673,13 +673,13 @@ static struct rbd_client *rbd_get_client(struct ceph_options *ceph_opts) | |||
673 | { | 673 | { |
674 | struct rbd_client *rbdc; | 674 | struct rbd_client *rbdc; |
675 | 675 | ||
676 | mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); | 676 | mutex_lock_nested(&client_mutex, SINGLE_DEPTH_NESTING); |
677 | rbdc = rbd_client_find(ceph_opts); | 677 | rbdc = rbd_client_find(ceph_opts); |
678 | if (rbdc) /* using an existing client */ | 678 | if (rbdc) /* using an existing client */ |
679 | ceph_destroy_options(ceph_opts); | 679 | ceph_destroy_options(ceph_opts); |
680 | else | 680 | else |
681 | rbdc = rbd_client_create(ceph_opts); | 681 | rbdc = rbd_client_create(ceph_opts); |
682 | mutex_unlock(&ctl_mutex); | 682 | mutex_unlock(&client_mutex); |
683 | 683 | ||
684 | return rbdc; | 684 | return rbdc; |
685 | } | 685 | } |
@@ -833,7 +833,6 @@ static int rbd_header_from_disk(struct rbd_device *rbd_dev, | |||
833 | 833 | ||
834 | /* We won't fail any more, fill in the header */ | 834 | /* We won't fail any more, fill in the header */ |
835 | 835 | ||
836 | down_write(&rbd_dev->header_rwsem); | ||
837 | if (first_time) { | 836 | if (first_time) { |
838 | header->object_prefix = object_prefix; | 837 | header->object_prefix = object_prefix; |
839 | header->obj_order = ondisk->options.order; | 838 | header->obj_order = ondisk->options.order; |
@@ -862,8 +861,6 @@ static int rbd_header_from_disk(struct rbd_device *rbd_dev, | |||
862 | if (rbd_dev->mapping.size != header->image_size) | 861 | if (rbd_dev->mapping.size != header->image_size) |
863 | rbd_dev->mapping.size = header->image_size; | 862 | rbd_dev->mapping.size = header->image_size; |
864 | 863 | ||
865 | up_write(&rbd_dev->header_rwsem); | ||
866 | |||
867 | return 0; | 864 | return 0; |
868 | out_2big: | 865 | out_2big: |
869 | ret = -EIO; | 866 | ret = -EIO; |
@@ -3333,7 +3330,7 @@ static int rbd_dev_refresh(struct rbd_device *rbd_dev) | |||
3333 | int ret; | 3330 | int ret; |
3334 | 3331 | ||
3335 | rbd_assert(rbd_image_format_valid(rbd_dev->image_format)); | 3332 | rbd_assert(rbd_image_format_valid(rbd_dev->image_format)); |
3336 | mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); | 3333 | down_write(&rbd_dev->header_rwsem); |
3337 | mapping_size = rbd_dev->mapping.size; | 3334 | mapping_size = rbd_dev->mapping.size; |
3338 | if (rbd_dev->image_format == 1) | 3335 | if (rbd_dev->image_format == 1) |
3339 | ret = rbd_dev_v1_header_info(rbd_dev); | 3336 | ret = rbd_dev_v1_header_info(rbd_dev); |
@@ -3343,7 +3340,8 @@ static int rbd_dev_refresh(struct rbd_device *rbd_dev) | |||
3343 | /* If it's a mapped snapshot, validate its EXISTS flag */ | 3340 | /* If it's a mapped snapshot, validate its EXISTS flag */ |
3344 | 3341 | ||
3345 | rbd_exists_validate(rbd_dev); | 3342 | rbd_exists_validate(rbd_dev); |
3346 | mutex_unlock(&ctl_mutex); | 3343 | up_write(&rbd_dev->header_rwsem); |
3344 | |||
3347 | if (mapping_size != rbd_dev->mapping.size) { | 3345 | if (mapping_size != rbd_dev->mapping.size) { |
3348 | sector_t size; | 3346 | sector_t size; |
3349 | 3347 | ||
@@ -4272,16 +4270,14 @@ static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev) | |||
4272 | bool first_time = rbd_dev->header.object_prefix == NULL; | 4270 | bool first_time = rbd_dev->header.object_prefix == NULL; |
4273 | int ret; | 4271 | int ret; |
4274 | 4272 | ||
4275 | down_write(&rbd_dev->header_rwsem); | ||
4276 | |||
4277 | ret = rbd_dev_v2_image_size(rbd_dev); | 4273 | ret = rbd_dev_v2_image_size(rbd_dev); |
4278 | if (ret) | 4274 | if (ret) |
4279 | goto out; | 4275 | return ret; |
4280 | 4276 | ||
4281 | if (first_time) { | 4277 | if (first_time) { |
4282 | ret = rbd_dev_v2_header_onetime(rbd_dev); | 4278 | ret = rbd_dev_v2_header_onetime(rbd_dev); |
4283 | if (ret) | 4279 | if (ret) |
4284 | goto out; | 4280 | return ret; |
4285 | } | 4281 | } |
4286 | 4282 | ||
4287 | /* | 4283 | /* |
@@ -4296,7 +4292,7 @@ static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev) | |||
4296 | 4292 | ||
4297 | ret = rbd_dev_v2_parent_info(rbd_dev); | 4293 | ret = rbd_dev_v2_parent_info(rbd_dev); |
4298 | if (ret) | 4294 | if (ret) |
4299 | goto out; | 4295 | return ret; |
4300 | 4296 | ||
4301 | /* | 4297 | /* |
4302 | * Print a warning if this is the initial probe and | 4298 | * Print a warning if this is the initial probe and |
@@ -4317,8 +4313,6 @@ static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev) | |||
4317 | 4313 | ||
4318 | ret = rbd_dev_v2_snap_context(rbd_dev); | 4314 | ret = rbd_dev_v2_snap_context(rbd_dev); |
4319 | dout("rbd_dev_v2_snap_context returned %d\n", ret); | 4315 | dout("rbd_dev_v2_snap_context returned %d\n", ret); |
4320 | out: | ||
4321 | up_write(&rbd_dev->header_rwsem); | ||
4322 | 4316 | ||
4323 | return ret; | 4317 | return ret; |
4324 | } | 4318 | } |