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 28052ff679c..bce1fcfb518 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); |
