diff options
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/rbd.c | 85 |
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 | ||
2244 | static 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 | |||
2316 | out: | ||
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", |