aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/rbd.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index b8b8271bd9e2..b673a8dc161d 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -62,6 +62,7 @@
62#define RBD_MINORS_PER_MAJOR 256 /* max minors per blkdev */ 62#define RBD_MINORS_PER_MAJOR 256 /* max minors per blkdev */
63 63
64#define RBD_MAX_SNAP_NAME_LEN 32 64#define RBD_MAX_SNAP_NAME_LEN 32
65#define RBD_MAX_SNAP_COUNT 510 /* allows max snapc to fit in 4KB */
65#define RBD_MAX_OPT_LEN 1024 66#define RBD_MAX_OPT_LEN 1024
66 67
67#define RBD_SNAP_HEAD_NAME "-" 68#define RBD_SNAP_HEAD_NAME "-"
@@ -2240,6 +2241,84 @@ static int rbd_dev_v2_features(struct rbd_device *rbd_dev)
2240 &rbd_dev->header.features); 2241 &rbd_dev->header.features);
2241} 2242}
2242 2243
2244static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev)
2245{
2246 size_t size;
2247 int ret;
2248 void *reply_buf;
2249 void *p;
2250 void *end;
2251 u64 seq;
2252 u32 snap_count;
2253 struct ceph_snap_context *snapc;
2254 u32 i;
2255
2256 /*
2257 * We'll need room for the seq value (maximum snapshot id),
2258 * snapshot count, and array of that many snapshot ids.
2259 * For now we have a fixed upper limit on the number we're
2260 * prepared to receive.
2261 */
2262 size = sizeof (__le64) + sizeof (__le32) +
2263 RBD_MAX_SNAP_COUNT * sizeof (__le64);
2264 reply_buf = kzalloc(size, GFP_KERNEL);
2265 if (!reply_buf)
2266 return -ENOMEM;
2267
2268 ret = rbd_req_sync_exec(rbd_dev, rbd_dev->header_name,
2269 "rbd", "get_snapcontext",
2270 NULL, 0,
2271 reply_buf, size,
2272 CEPH_OSD_FLAG_READ, NULL);
2273 dout("%s: rbd_req_sync_exec returned %d\n", __func__, ret);
2274 if (ret < 0)
2275 goto out;
2276
2277 ret = -ERANGE;
2278 p = reply_buf;
2279 end = (char *) reply_buf + size;
2280 ceph_decode_64_safe(&p, end, seq, out);
2281 ceph_decode_32_safe(&p, end, snap_count, out);
2282
2283 /*
2284 * Make sure the reported number of snapshot ids wouldn't go
2285 * beyond the end of our buffer. But before checking that,
2286 * make sure the computed size of the snapshot context we
2287 * allocate is representable in a size_t.
2288 */
2289 if (snap_count > (SIZE_MAX - sizeof (struct ceph_snap_context))
2290 / sizeof (u64)) {
2291 ret = -EINVAL;
2292 goto out;
2293 }
2294 if (!ceph_has_room(&p, end, snap_count * sizeof (__le64)))
2295 goto out;
2296
2297 size = sizeof (struct ceph_snap_context) +
2298 snap_count * sizeof (snapc->snaps[0]);
2299 snapc = kmalloc(size, GFP_KERNEL);
2300 if (!snapc) {
2301 ret = -ENOMEM;
2302 goto out;
2303 }
2304
2305 atomic_set(&snapc->nref, 1);
2306 snapc->seq = seq;
2307 snapc->num_snaps = snap_count;
2308 for (i = 0; i < snap_count; i++)
2309 snapc->snaps[i] = ceph_decode_64(&p);
2310
2311 rbd_dev->header.snapc = snapc;
2312
2313 dout(" snap context seq = %llu, snap_count = %u\n",
2314 (unsigned long long) seq, (unsigned int) snap_count);
2315
2316out:
2317 kfree(reply_buf);
2318
2319 return 0;
2320}
2321
2243/* 2322/*
2244 * Scan the rbd device's current snapshot list and compare it to the 2323 * Scan the rbd device's current snapshot list and compare it to the
2245 * newly-received snapshot context. Remove any existing snapshots 2324 * newly-received snapshot context. Remove any existing snapshots
@@ -2779,6 +2858,12 @@ static int rbd_dev_v2_probe(struct rbd_device *rbd_dev)
2779 ret = rbd_dev_v2_features(rbd_dev); 2858 ret = rbd_dev_v2_features(rbd_dev);
2780 if (ret < 0) 2859 if (ret < 0)
2781 goto out_err; 2860 goto out_err;
2861
2862 /* Get the snapshot context */
2863
2864 ret = rbd_dev_v2_snap_context(rbd_dev);
2865 if (ret)
2866 goto out_err;
2782 rbd_dev->image_format = 2; 2867 rbd_dev->image_format = 2;
2783 2868
2784 dout("discovered version 2 image, header name is %s\n", 2869 dout("discovered version 2 image, header name is %s\n",