diff options
author | Alex Elder <elder@inktank.com> | 2012-10-26 00:34:42 -0400 |
---|---|---|
committer | Alex Elder <elder@inktank.com> | 2012-11-01 08:55:42 -0400 |
commit | 86b00e0da6be7bbc16412f126c5b548ac5d91d50 (patch) | |
tree | 466c0dcecd75ca707f33b18265be969e385f366c /drivers/block | |
parent | a92ffdf8a9b09f8fae9a8f418f87f30a5e459570 (diff) |
rbd: get parent spec for version 2 images
Add support for getting the the information identifying the parent
image for rbd images that have them. The child image holds a
reference to its parent image specification structure. Create a new
entry "parent" in /sys/bus/rbd/image/N/ to report the identifying
information for the parent image, if any.
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 | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 28052ff679ca..bce1fcfb5185 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c | |||
@@ -217,6 +217,9 @@ struct rbd_device { | |||
217 | struct ceph_osd_event *watch_event; | 217 | struct ceph_osd_event *watch_event; |
218 | struct ceph_osd_request *watch_request; | 218 | struct ceph_osd_request *watch_request; |
219 | 219 | ||
220 | struct rbd_spec *parent_spec; | ||
221 | u64 parent_overlap; | ||
222 | |||
220 | /* protects updating the header */ | 223 | /* protects updating the header */ |
221 | struct rw_semaphore header_rwsem; | 224 | struct rw_semaphore header_rwsem; |
222 | 225 | ||
@@ -2009,6 +2012,49 @@ static ssize_t rbd_snap_show(struct device *dev, | |||
2009 | return sprintf(buf, "%s\n", rbd_dev->spec->snap_name); | 2012 | return sprintf(buf, "%s\n", rbd_dev->spec->snap_name); |
2010 | } | 2013 | } |
2011 | 2014 | ||
2015 | /* | ||
2016 | * For an rbd v2 image, shows the pool id, image id, and snapshot id | ||
2017 | * for the parent image. If there is no parent, simply shows | ||
2018 | * "(no parent image)". | ||
2019 | */ | ||
2020 | static ssize_t rbd_parent_show(struct device *dev, | ||
2021 | struct device_attribute *attr, | ||
2022 | char *buf) | ||
2023 | { | ||
2024 | struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); | ||
2025 | struct rbd_spec *spec = rbd_dev->parent_spec; | ||
2026 | int count; | ||
2027 | char *bufp = buf; | ||
2028 | |||
2029 | if (!spec) | ||
2030 | return sprintf(buf, "(no parent image)\n"); | ||
2031 | |||
2032 | count = sprintf(bufp, "pool_id %llu\npool_name %s\n", | ||
2033 | (unsigned long long) spec->pool_id, spec->pool_name); | ||
2034 | if (count < 0) | ||
2035 | return count; | ||
2036 | bufp += count; | ||
2037 | |||
2038 | count = sprintf(bufp, "image_id %s\nimage_name %s\n", spec->image_id, | ||
2039 | spec->image_name ? spec->image_name : "(unknown)"); | ||
2040 | if (count < 0) | ||
2041 | return count; | ||
2042 | bufp += count; | ||
2043 | |||
2044 | count = sprintf(bufp, "snap_id %llu\nsnap_name %s\n", | ||
2045 | (unsigned long long) spec->snap_id, spec->snap_name); | ||
2046 | if (count < 0) | ||
2047 | return count; | ||
2048 | bufp += count; | ||
2049 | |||
2050 | count = sprintf(bufp, "overlap %llu\n", rbd_dev->parent_overlap); | ||
2051 | if (count < 0) | ||
2052 | return count; | ||
2053 | bufp += count; | ||
2054 | |||
2055 | return (ssize_t) (bufp - buf); | ||
2056 | } | ||
2057 | |||
2012 | static ssize_t rbd_image_refresh(struct device *dev, | 2058 | static ssize_t rbd_image_refresh(struct device *dev, |
2013 | struct device_attribute *attr, | 2059 | struct device_attribute *attr, |
2014 | const char *buf, | 2060 | const char *buf, |
@@ -2032,6 +2078,7 @@ static DEVICE_ATTR(name, S_IRUGO, rbd_name_show, NULL); | |||
2032 | static DEVICE_ATTR(image_id, S_IRUGO, rbd_image_id_show, NULL); | 2078 | static DEVICE_ATTR(image_id, S_IRUGO, rbd_image_id_show, NULL); |
2033 | static DEVICE_ATTR(refresh, S_IWUSR, NULL, rbd_image_refresh); | 2079 | static DEVICE_ATTR(refresh, S_IWUSR, NULL, rbd_image_refresh); |
2034 | static DEVICE_ATTR(current_snap, S_IRUGO, rbd_snap_show, NULL); | 2080 | static DEVICE_ATTR(current_snap, S_IRUGO, rbd_snap_show, NULL); |
2081 | static DEVICE_ATTR(parent, S_IRUGO, rbd_parent_show, NULL); | ||
2035 | 2082 | ||
2036 | static struct attribute *rbd_attrs[] = { | 2083 | static struct attribute *rbd_attrs[] = { |
2037 | &dev_attr_size.attr, | 2084 | &dev_attr_size.attr, |
@@ -2043,6 +2090,7 @@ static struct attribute *rbd_attrs[] = { | |||
2043 | &dev_attr_name.attr, | 2090 | &dev_attr_name.attr, |
2044 | &dev_attr_image_id.attr, | 2091 | &dev_attr_image_id.attr, |
2045 | &dev_attr_current_snap.attr, | 2092 | &dev_attr_current_snap.attr, |
2093 | &dev_attr_parent.attr, | ||
2046 | &dev_attr_refresh.attr, | 2094 | &dev_attr_refresh.attr, |
2047 | NULL | 2095 | NULL |
2048 | }; | 2096 | }; |
@@ -2192,6 +2240,7 @@ struct rbd_device *rbd_dev_create(struct rbd_client *rbdc, | |||
2192 | 2240 | ||
2193 | static void rbd_dev_destroy(struct rbd_device *rbd_dev) | 2241 | static void rbd_dev_destroy(struct rbd_device *rbd_dev) |
2194 | { | 2242 | { |
2243 | rbd_spec_put(rbd_dev->parent_spec); | ||
2195 | kfree(rbd_dev->header_name); | 2244 | kfree(rbd_dev->header_name); |
2196 | rbd_put_client(rbd_dev->rbd_client); | 2245 | rbd_put_client(rbd_dev->rbd_client); |
2197 | rbd_spec_put(rbd_dev->spec); | 2246 | rbd_spec_put(rbd_dev->spec); |
@@ -2400,6 +2449,71 @@ static int rbd_dev_v2_features(struct rbd_device *rbd_dev) | |||
2400 | &rbd_dev->header.features); | 2449 | &rbd_dev->header.features); |
2401 | } | 2450 | } |
2402 | 2451 | ||
2452 | static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev) | ||
2453 | { | ||
2454 | struct rbd_spec *parent_spec; | ||
2455 | size_t size; | ||
2456 | void *reply_buf = NULL; | ||
2457 | __le64 snapid; | ||
2458 | void *p; | ||
2459 | void *end; | ||
2460 | char *image_id; | ||
2461 | u64 overlap; | ||
2462 | size_t len = 0; | ||
2463 | int ret; | ||
2464 | |||
2465 | parent_spec = rbd_spec_alloc(); | ||
2466 | if (!parent_spec) | ||
2467 | return -ENOMEM; | ||
2468 | |||
2469 | size = sizeof (__le64) + /* pool_id */ | ||
2470 | sizeof (__le32) + RBD_IMAGE_ID_LEN_MAX + /* image_id */ | ||
2471 | sizeof (__le64) + /* snap_id */ | ||
2472 | sizeof (__le64); /* overlap */ | ||
2473 | reply_buf = kmalloc(size, GFP_KERNEL); | ||
2474 | if (!reply_buf) { | ||
2475 | ret = -ENOMEM; | ||
2476 | goto out_err; | ||
2477 | } | ||
2478 | |||
2479 | snapid = cpu_to_le64(CEPH_NOSNAP); | ||
2480 | ret = rbd_req_sync_exec(rbd_dev, rbd_dev->header_name, | ||
2481 | "rbd", "get_parent", | ||
2482 | (char *) &snapid, sizeof (snapid), | ||
2483 | (char *) reply_buf, size, | ||
2484 | CEPH_OSD_FLAG_READ, NULL); | ||
2485 | dout("%s: rbd_req_sync_exec returned %d\n", __func__, ret); | ||
2486 | if (ret < 0) | ||
2487 | goto out_err; | ||
2488 | |||
2489 | ret = -ERANGE; | ||
2490 | p = reply_buf; | ||
2491 | end = (char *) reply_buf + size; | ||
2492 | ceph_decode_64_safe(&p, end, parent_spec->pool_id, out_err); | ||
2493 | if (parent_spec->pool_id == CEPH_NOPOOL) | ||
2494 | goto out; /* No parent? No problem. */ | ||
2495 | |||
2496 | image_id = ceph_extract_encoded_string(&p, end, &len, GFP_KERNEL); | ||
2497 | if (IS_ERR(image_id)) { | ||
2498 | ret = PTR_ERR(image_id); | ||
2499 | goto out_err; | ||
2500 | } | ||
2501 | parent_spec->image_id = image_id; | ||
2502 | ceph_decode_64_safe(&p, end, parent_spec->snap_id, out_err); | ||
2503 | ceph_decode_64_safe(&p, end, overlap, out_err); | ||
2504 | |||
2505 | rbd_dev->parent_overlap = overlap; | ||
2506 | rbd_dev->parent_spec = parent_spec; | ||
2507 | parent_spec = NULL; /* rbd_dev now owns this */ | ||
2508 | out: | ||
2509 | ret = 0; | ||
2510 | out_err: | ||
2511 | kfree(reply_buf); | ||
2512 | rbd_spec_put(parent_spec); | ||
2513 | |||
2514 | return ret; | ||
2515 | } | ||
2516 | |||
2403 | static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev, u64 *ver) | 2517 | static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev, u64 *ver) |
2404 | { | 2518 | { |
2405 | size_t size; | 2519 | size_t size; |
@@ -3154,6 +3268,12 @@ static int rbd_dev_v1_probe(struct rbd_device *rbd_dev) | |||
3154 | ret = rbd_read_header(rbd_dev, &rbd_dev->header); | 3268 | ret = rbd_read_header(rbd_dev, &rbd_dev->header); |
3155 | if (ret < 0) | 3269 | if (ret < 0) |
3156 | goto out_err; | 3270 | goto out_err; |
3271 | |||
3272 | /* Version 1 images have no parent (no layering) */ | ||
3273 | |||
3274 | rbd_dev->parent_spec = NULL; | ||
3275 | rbd_dev->parent_overlap = 0; | ||
3276 | |||
3157 | rbd_dev->image_format = 1; | 3277 | rbd_dev->image_format = 1; |
3158 | 3278 | ||
3159 | dout("discovered version 1 image, header name is %s\n", | 3279 | dout("discovered version 1 image, header name is %s\n", |
@@ -3205,6 +3325,14 @@ static int rbd_dev_v2_probe(struct rbd_device *rbd_dev) | |||
3205 | if (ret < 0) | 3325 | if (ret < 0) |
3206 | goto out_err; | 3326 | goto out_err; |
3207 | 3327 | ||
3328 | /* If the image supports layering, get the parent info */ | ||
3329 | |||
3330 | if (rbd_dev->header.features & RBD_FEATURE_LAYERING) { | ||
3331 | ret = rbd_dev_v2_parent_info(rbd_dev); | ||
3332 | if (ret < 0) | ||
3333 | goto out_err; | ||
3334 | } | ||
3335 | |||
3208 | /* crypto and compression type aren't (yet) supported for v2 images */ | 3336 | /* crypto and compression type aren't (yet) supported for v2 images */ |
3209 | 3337 | ||
3210 | rbd_dev->header.crypt_type = 0; | 3338 | rbd_dev->header.crypt_type = 0; |
@@ -3224,6 +3352,9 @@ static int rbd_dev_v2_probe(struct rbd_device *rbd_dev) | |||
3224 | 3352 | ||
3225 | return 0; | 3353 | return 0; |
3226 | out_err: | 3354 | out_err: |
3355 | rbd_dev->parent_overlap = 0; | ||
3356 | rbd_spec_put(rbd_dev->parent_spec); | ||
3357 | rbd_dev->parent_spec = NULL; | ||
3227 | kfree(rbd_dev->header_name); | 3358 | kfree(rbd_dev->header_name); |
3228 | rbd_dev->header_name = NULL; | 3359 | rbd_dev->header_name = NULL; |
3229 | kfree(rbd_dev->header.object_prefix); | 3360 | kfree(rbd_dev->header.object_prefix); |