diff options
| -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", |
