diff options
author | Alex Elder <elder@inktank.com> | 2013-01-17 13:25:27 -0500 |
---|---|---|
committer | Sage Weil <sage@inktank.com> | 2013-02-13 21:29:08 -0500 |
commit | 788e2df3b92e30f1fff74139bb53e68ec13fe2a5 (patch) | |
tree | e0386e011b2dd488bb55e1b2baef4677b11ad6b2 /drivers/block | |
parent | 7d250b949a33c8a658a2ad4ab390d8394b842224 (diff) |
rbd: implement sync object read with new code
Reimplement the synchronous read operation used for reading a
version 1 header using the new request tracking code. Name the
resulting function rbd_obj_read_sync() to better reflect that
it's a full object operation, not an object request. To do this,
implement a new OBJ_REQUEST_PAGES object request type.
This implements a new mechanism to allow the caller to wait for
completion for an rbd_obj_request by calling rbd_obj_request_wait().
This partially resolves:
http://tracker.newdream.net/issues/3755
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.c | 96 |
1 files changed, 92 insertions, 4 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index c1bb649b4ad1..3f5eaea444a0 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c | |||
@@ -170,7 +170,7 @@ typedef void (*rbd_img_callback_t)(struct rbd_img_request *); | |||
170 | struct rbd_obj_request; | 170 | struct rbd_obj_request; |
171 | typedef void (*rbd_obj_callback_t)(struct rbd_obj_request *); | 171 | typedef void (*rbd_obj_callback_t)(struct rbd_obj_request *); |
172 | 172 | ||
173 | enum obj_request_type { OBJ_REQUEST_BIO }; /* More types to come */ | 173 | enum obj_request_type { OBJ_REQUEST_BIO, OBJ_REQUEST_PAGES }; |
174 | 174 | ||
175 | struct rbd_obj_request { | 175 | struct rbd_obj_request { |
176 | const char *object_name; | 176 | const char *object_name; |
@@ -182,7 +182,13 @@ struct rbd_obj_request { | |||
182 | u32 which; /* posn image request list */ | 182 | u32 which; /* posn image request list */ |
183 | 183 | ||
184 | enum obj_request_type type; | 184 | enum obj_request_type type; |
185 | struct bio *bio_list; | 185 | union { |
186 | struct bio *bio_list; | ||
187 | struct { | ||
188 | struct page **pages; | ||
189 | u32 page_count; | ||
190 | }; | ||
191 | }; | ||
186 | 192 | ||
187 | struct ceph_osd_request *osd_req; | 193 | struct ceph_osd_request *osd_req; |
188 | 194 | ||
@@ -192,6 +198,7 @@ struct rbd_obj_request { | |||
192 | atomic_t done; | 198 | atomic_t done; |
193 | 199 | ||
194 | rbd_obj_callback_t callback; | 200 | rbd_obj_callback_t callback; |
201 | struct completion completion; | ||
195 | 202 | ||
196 | struct kref kref; | 203 | struct kref kref; |
197 | }; | 204 | }; |
@@ -1077,6 +1084,7 @@ static bool obj_request_type_valid(enum obj_request_type type) | |||
1077 | { | 1084 | { |
1078 | switch (type) { | 1085 | switch (type) { |
1079 | case OBJ_REQUEST_BIO: | 1086 | case OBJ_REQUEST_BIO: |
1087 | case OBJ_REQUEST_PAGES: | ||
1080 | return true; | 1088 | return true; |
1081 | default: | 1089 | default: |
1082 | return false; | 1090 | return false; |
@@ -1291,14 +1299,23 @@ static void rbd_img_request_complete(struct rbd_img_request *img_request) | |||
1291 | rbd_img_request_put(img_request); | 1299 | rbd_img_request_put(img_request); |
1292 | } | 1300 | } |
1293 | 1301 | ||
1302 | /* Caller is responsible for rbd_obj_request_destroy(obj_request) */ | ||
1303 | |||
1304 | static int rbd_obj_request_wait(struct rbd_obj_request *obj_request) | ||
1305 | { | ||
1306 | return wait_for_completion_interruptible(&obj_request->completion); | ||
1307 | } | ||
1308 | |||
1294 | static void rbd_obj_request_complete(struct rbd_obj_request *obj_request) | 1309 | static void rbd_obj_request_complete(struct rbd_obj_request *obj_request) |
1295 | { | 1310 | { |
1296 | if (obj_request->callback) | 1311 | if (obj_request->callback) |
1297 | obj_request->callback(obj_request); | 1312 | obj_request->callback(obj_request); |
1313 | else | ||
1314 | complete_all(&obj_request->completion); | ||
1298 | } | 1315 | } |
1299 | 1316 | ||
1300 | /* | 1317 | /* |
1301 | * Request sync osd read | 1318 | * Synchronously read a range from an object into a provided buffer |
1302 | */ | 1319 | */ |
1303 | static int rbd_req_sync_read(struct rbd_device *rbd_dev, | 1320 | static int rbd_req_sync_read(struct rbd_device *rbd_dev, |
1304 | const char *object_name, | 1321 | const char *object_name, |
@@ -1556,6 +1573,11 @@ static struct ceph_osd_request *rbd_osd_req_create( | |||
1556 | /* osd client requires "num pages" even for bio */ | 1573 | /* osd client requires "num pages" even for bio */ |
1557 | osd_req->r_num_pages = calc_pages_for(offset, length); | 1574 | osd_req->r_num_pages = calc_pages_for(offset, length); |
1558 | break; | 1575 | break; |
1576 | case OBJ_REQUEST_PAGES: | ||
1577 | osd_req->r_pages = obj_request->pages; | ||
1578 | osd_req->r_num_pages = obj_request->page_count; | ||
1579 | osd_req->r_page_alignment = offset & ~PAGE_MASK; | ||
1580 | break; | ||
1559 | } | 1581 | } |
1560 | 1582 | ||
1561 | if (write_request) { | 1583 | if (write_request) { |
@@ -1616,6 +1638,7 @@ static struct rbd_obj_request *rbd_obj_request_create(const char *object_name, | |||
1616 | obj_request->type = type; | 1638 | obj_request->type = type; |
1617 | INIT_LIST_HEAD(&obj_request->links); | 1639 | INIT_LIST_HEAD(&obj_request->links); |
1618 | atomic_set(&obj_request->done, 0); | 1640 | atomic_set(&obj_request->done, 0); |
1641 | init_completion(&obj_request->completion); | ||
1619 | kref_init(&obj_request->kref); | 1642 | kref_init(&obj_request->kref); |
1620 | 1643 | ||
1621 | return obj_request; | 1644 | return obj_request; |
@@ -1639,6 +1662,11 @@ static void rbd_obj_request_destroy(struct kref *kref) | |||
1639 | if (obj_request->bio_list) | 1662 | if (obj_request->bio_list) |
1640 | bio_chain_put(obj_request->bio_list); | 1663 | bio_chain_put(obj_request->bio_list); |
1641 | break; | 1664 | break; |
1665 | case OBJ_REQUEST_PAGES: | ||
1666 | if (obj_request->pages) | ||
1667 | ceph_release_page_vector(obj_request->pages, | ||
1668 | obj_request->page_count); | ||
1669 | break; | ||
1642 | } | 1670 | } |
1643 | 1671 | ||
1644 | kfree(obj_request); | 1672 | kfree(obj_request); |
@@ -1987,6 +2015,65 @@ static void rbd_free_disk(struct rbd_device *rbd_dev) | |||
1987 | put_disk(disk); | 2015 | put_disk(disk); |
1988 | } | 2016 | } |
1989 | 2017 | ||
2018 | static int rbd_obj_read_sync(struct rbd_device *rbd_dev, | ||
2019 | const char *object_name, | ||
2020 | u64 offset, u64 length, | ||
2021 | char *buf, u64 *version) | ||
2022 | |||
2023 | { | ||
2024 | struct ceph_osd_req_op *op; | ||
2025 | struct rbd_obj_request *obj_request; | ||
2026 | struct ceph_osd_client *osdc; | ||
2027 | struct page **pages = NULL; | ||
2028 | u32 page_count; | ||
2029 | int ret; | ||
2030 | |||
2031 | page_count = (u32) calc_pages_for(offset, length); | ||
2032 | pages = ceph_alloc_page_vector(page_count, GFP_KERNEL); | ||
2033 | if (IS_ERR(pages)) | ||
2034 | ret = PTR_ERR(pages); | ||
2035 | |||
2036 | ret = -ENOMEM; | ||
2037 | obj_request = rbd_obj_request_create(object_name, offset, length, | ||
2038 | OBJ_REQUEST_PAGES); | ||
2039 | if (!obj_request) | ||
2040 | goto out; | ||
2041 | |||
2042 | obj_request->pages = pages; | ||
2043 | obj_request->page_count = page_count; | ||
2044 | |||
2045 | op = rbd_osd_req_op_create(CEPH_OSD_OP_READ, offset, length); | ||
2046 | if (!op) | ||
2047 | goto out; | ||
2048 | obj_request->osd_req = rbd_osd_req_create(rbd_dev, false, | ||
2049 | obj_request, op); | ||
2050 | rbd_osd_req_op_destroy(op); | ||
2051 | if (!obj_request->osd_req) | ||
2052 | goto out; | ||
2053 | |||
2054 | osdc = &rbd_dev->rbd_client->client->osdc; | ||
2055 | ret = rbd_obj_request_submit(osdc, obj_request); | ||
2056 | if (ret) | ||
2057 | goto out; | ||
2058 | ret = rbd_obj_request_wait(obj_request); | ||
2059 | if (ret) | ||
2060 | goto out; | ||
2061 | |||
2062 | ret = obj_request->result; | ||
2063 | if (ret < 0) | ||
2064 | goto out; | ||
2065 | ret = ceph_copy_from_page_vector(pages, buf, 0, obj_request->xferred); | ||
2066 | if (version) | ||
2067 | *version = obj_request->version; | ||
2068 | out: | ||
2069 | if (obj_request) | ||
2070 | rbd_obj_request_put(obj_request); | ||
2071 | else | ||
2072 | ceph_release_page_vector(pages, page_count); | ||
2073 | |||
2074 | return ret; | ||
2075 | } | ||
2076 | |||
1990 | /* | 2077 | /* |
1991 | * Read the complete header for the given rbd device. | 2078 | * Read the complete header for the given rbd device. |
1992 | * | 2079 | * |
@@ -2025,7 +2112,8 @@ rbd_dev_v1_header_read(struct rbd_device *rbd_dev, u64 *version) | |||
2025 | if (!ondisk) | 2112 | if (!ondisk) |
2026 | return ERR_PTR(-ENOMEM); | 2113 | return ERR_PTR(-ENOMEM); |
2027 | 2114 | ||
2028 | ret = rbd_req_sync_read(rbd_dev, rbd_dev->header_name, | 2115 | (void) rbd_req_sync_read; /* avoid a warning */ |
2116 | ret = rbd_obj_read_sync(rbd_dev, rbd_dev->header_name, | ||
2029 | 0, size, | 2117 | 0, size, |
2030 | (char *) ondisk, version); | 2118 | (char *) ondisk, version); |
2031 | 2119 | ||