aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorAlex Elder <elder@inktank.com>2013-05-08 23:50:04 -0400
committerAlex Elder <elder@inktank.com>2013-05-13 16:06:44 -0400
commita2acd00e7964dbb1668a5956c9d0a4bdeb838c4a (patch)
treec8da76d9bd9d6ee72ea5d1fdefa01f72199ef232 /drivers/block
parente93f3152357ca75284284bef8eeea7d45fe1bab1 (diff)
rbd: reference count parent requests
Keep a reference count for uses of the parent information for an rbd device. An initial reference is set in rbd_img_request_create() if the target image has a parent (with non-zero overlap). Each image request for an image with a non-zero parent overlap gets another reference when it's created, and that reference is dropped when the request is destroyed. The initial reference is dropped when the image gets torn down. Signed-off-by: Alex Elder <elder@inktank.com> Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/rbd.c104
1 files changed, 102 insertions, 2 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 1ffdfbfbf3c4..8b6091b6d5cb 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -55,6 +55,39 @@
55#define SECTOR_SHIFT 9 55#define SECTOR_SHIFT 9
56#define SECTOR_SIZE (1ULL << SECTOR_SHIFT) 56#define SECTOR_SIZE (1ULL << SECTOR_SHIFT)
57 57
58/*
59 * Increment the given counter and return its updated value.
60 * If the counter is already 0 it will not be incremented.
61 * If the counter is already at its maximum value returns
62 * -EINVAL without updating it.
63 */
64static int atomic_inc_return_safe(atomic_t *v)
65{
66 unsigned int counter;
67
68 counter = (unsigned int)__atomic_add_unless(v, 1, 0);
69 if (counter <= (unsigned int)INT_MAX)
70 return (int)counter;
71
72 atomic_dec(v);
73
74 return -EINVAL;
75}
76
77/* Decrement the counter. Return the resulting value, or -EINVAL */
78static int atomic_dec_return_safe(atomic_t *v)
79{
80 int counter;
81
82 counter = atomic_dec_return(v);
83 if (counter >= 0)
84 return counter;
85
86 atomic_inc(v);
87
88 return -EINVAL;
89}
90
58#define RBD_DRV_NAME "rbd" 91#define RBD_DRV_NAME "rbd"
59#define RBD_DRV_NAME_LONG "rbd (rados block device)" 92#define RBD_DRV_NAME_LONG "rbd (rados block device)"
60 93
@@ -312,6 +345,7 @@ struct rbd_device {
312 345
313 struct rbd_spec *parent_spec; 346 struct rbd_spec *parent_spec;
314 u64 parent_overlap; 347 u64 parent_overlap;
348 atomic_t parent_ref;
315 struct rbd_device *parent; 349 struct rbd_device *parent;
316 350
317 /* protects updating the header */ 351 /* protects updating the header */
@@ -361,6 +395,7 @@ static ssize_t rbd_add(struct bus_type *bus, const char *buf,
361static ssize_t rbd_remove(struct bus_type *bus, const char *buf, 395static ssize_t rbd_remove(struct bus_type *bus, const char *buf,
362 size_t count); 396 size_t count);
363static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping); 397static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping);
398static void rbd_spec_put(struct rbd_spec *spec);
364 399
365static struct bus_attribute rbd_bus_attrs[] = { 400static struct bus_attribute rbd_bus_attrs[] = {
366 __ATTR(add, S_IWUSR, NULL, rbd_add), 401 __ATTR(add, S_IWUSR, NULL, rbd_add),
@@ -1505,6 +1540,12 @@ static void img_request_layered_set(struct rbd_img_request *img_request)
1505 smp_mb(); 1540 smp_mb();
1506} 1541}
1507 1542
1543static void img_request_layered_clear(struct rbd_img_request *img_request)
1544{
1545 clear_bit(IMG_REQ_LAYERED, &img_request->flags);
1546 smp_mb();
1547}
1548
1508static bool img_request_layered_test(struct rbd_img_request *img_request) 1549static bool img_request_layered_test(struct rbd_img_request *img_request)
1509{ 1550{
1510 smp_mb(); 1551 smp_mb();
@@ -1860,6 +1901,58 @@ static void rbd_dev_unparent(struct rbd_device *rbd_dev)
1860} 1901}
1861 1902
1862/* 1903/*
1904 * Parent image reference counting is used to determine when an
1905 * image's parent fields can be safely torn down--after there are no
1906 * more in-flight requests to the parent image. When the last
1907 * reference is dropped, cleaning them up is safe.
1908 */
1909static void rbd_dev_parent_put(struct rbd_device *rbd_dev)
1910{
1911 int counter;
1912
1913 if (!rbd_dev->parent_spec)
1914 return;
1915
1916 counter = atomic_dec_return_safe(&rbd_dev->parent_ref);
1917 if (counter > 0)
1918 return;
1919
1920 /* Last reference; clean up parent data structures */
1921
1922 if (!counter)
1923 rbd_dev_unparent(rbd_dev);
1924 else
1925 rbd_warn(rbd_dev, "parent reference underflow\n");
1926}
1927
1928/*
1929 * If an image has a non-zero parent overlap, get a reference to its
1930 * parent.
1931 *
1932 * Returns true if the rbd device has a parent with a non-zero
1933 * overlap and a reference for it was successfully taken, or
1934 * false otherwise.
1935 */
1936static bool rbd_dev_parent_get(struct rbd_device *rbd_dev)
1937{
1938 int counter;
1939
1940 if (!rbd_dev->parent_spec)
1941 return false;
1942
1943 counter = atomic_inc_return_safe(&rbd_dev->parent_ref);
1944 if (counter > 0 && rbd_dev->parent_overlap)
1945 return true;
1946
1947 /* Image was flattened, but parent is not yet torn down */
1948
1949 if (counter < 0)
1950 rbd_warn(rbd_dev, "parent reference overflow\n");
1951
1952 return false;
1953}
1954
1955/*
1863 * Caller is responsible for filling in the list of object requests 1956 * Caller is responsible for filling in the list of object requests
1864 * that comprises the image request, and the Linux request pointer 1957 * that comprises the image request, and the Linux request pointer
1865 * (if there is one). 1958 * (if there is one).
@@ -1892,7 +1985,7 @@ static struct rbd_img_request *rbd_img_request_create(
1892 } else { 1985 } else {
1893 img_request->snap_id = rbd_dev->spec->snap_id; 1986 img_request->snap_id = rbd_dev->spec->snap_id;
1894 } 1987 }
1895 if (rbd_dev->parent_overlap) 1988 if (rbd_dev_parent_get(rbd_dev))
1896 img_request_layered_set(img_request); 1989 img_request_layered_set(img_request);
1897 spin_lock_init(&img_request->completion_lock); 1990 spin_lock_init(&img_request->completion_lock);
1898 img_request->next_completion = 0; 1991 img_request->next_completion = 0;
@@ -1923,6 +2016,11 @@ static void rbd_img_request_destroy(struct kref *kref)
1923 rbd_img_obj_request_del(img_request, obj_request); 2016 rbd_img_obj_request_del(img_request, obj_request);
1924 rbd_assert(img_request->obj_request_count == 0); 2017 rbd_assert(img_request->obj_request_count == 0);
1925 2018
2019 if (img_request_layered_test(img_request)) {
2020 img_request_layered_clear(img_request);
2021 rbd_dev_parent_put(img_request->rbd_dev);
2022 }
2023
1926 if (img_request_write_test(img_request)) 2024 if (img_request_write_test(img_request))
1927 ceph_put_snap_context(img_request->snapc); 2025 ceph_put_snap_context(img_request->snapc);
1928 2026
@@ -3502,6 +3600,7 @@ static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc,
3502 3600
3503 spin_lock_init(&rbd_dev->lock); 3601 spin_lock_init(&rbd_dev->lock);
3504 rbd_dev->flags = 0; 3602 rbd_dev->flags = 0;
3603 atomic_set(&rbd_dev->parent_ref, 0);
3505 INIT_LIST_HEAD(&rbd_dev->node); 3604 INIT_LIST_HEAD(&rbd_dev->node);
3506 init_rwsem(&rbd_dev->header_rwsem); 3605 init_rwsem(&rbd_dev->header_rwsem);
3507 3606
@@ -4534,7 +4633,7 @@ static void rbd_dev_unprobe(struct rbd_device *rbd_dev)
4534{ 4633{
4535 struct rbd_image_header *header; 4634 struct rbd_image_header *header;
4536 4635
4537 rbd_dev_unparent(rbd_dev); 4636 rbd_dev_parent_put(rbd_dev);
4538 4637
4539 /* Free dynamic fields from the header, then zero it out */ 4638 /* Free dynamic fields from the header, then zero it out */
4540 4639
@@ -4606,6 +4705,7 @@ static int rbd_dev_probe_parent(struct rbd_device *rbd_dev)
4606 if (ret < 0) 4705 if (ret < 0)
4607 goto out_err; 4706 goto out_err;
4608 rbd_dev->parent = parent; 4707 rbd_dev->parent = parent;
4708 atomic_set(&rbd_dev->parent_ref, 1);
4609 4709
4610 return 0; 4710 return 0;
4611out_err: 4711out_err: