Mapping an image with a long parent chain (e.g. image foo, whose parent is bar, whose parent is baz, etc) currently leads to a kernel stack overflow, due to the following recursion in the reply path: rbd_osd_req_callback() rbd_obj_request_complete() rbd_img_obj_callback() rbd_img_parent_read_callback() rbd_obj_request_complete() ... Limit the parent chain to 16 images, which is ~5K worth of stack. When the above recursion is eliminated, this limit can be lifted. Fixes: http://tracker.ceph.com/issues/12538
Unified · Split
| @@ -96,6 +96,8 @@ static int atomic_dec_return_safe(atomic_t *v) · 95 unmodified lines | ||
| 96 | 96 | #define RBD_MINORS_PER_MAJOR 256 |
| 97 | 97 | #define RBD_SINGLE_MAJOR_PART_SHIFT 4 |
| 98 | 98 | |
| 99 | +#define RBD_MAX_PARENT_CHAIN_LEN 16 | |
| 100 | + | |
| 99 | 101 | #define RBD_SNAP_DEV_NAME_PREFIX "snap_" |
| 100 | 102 | #define RBD_MAX_SNAP_NAME_LEN \ |
| 101 | 103 | (NAME_MAX - (sizeof (RBD_SNAP_DEV_NAME_PREFIX) - 1)) |
| @@ -426,7 +428,7 @@ static ssize_t rbd_add_single_major(struct bus_type *bus, const char *buf, · 324 unmodified lines | ||
| 426 | 428 | size_t count); |
| 427 | 429 | static ssize_t rbd_remove_single_major(struct bus_type *bus, const char *buf, |
| 428 | 430 | size_t count); |
| 429 | −static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping); | |
| 431 | +static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth); | |
| 430 | 432 | static void rbd_spec_put(struct rbd_spec *spec); |
| 431 | 433 | |
| 432 | 434 | static int rbd_dev_id_to_minor(int dev_id) |
| @@ -5131,7 +5133,12 @@ out_err: · 4698 unmodified lines | ||
| 5131 | 5133 | return ret; |
| 5132 | 5134 | } |
| 5133 | 5135 | |
| 5134 | −static int rbd_dev_probe_parent(struct rbd_device *rbd_dev) | |
| 5136 | +/* | |
| 5137 | + * @depth is rbd_dev_image_probe() -> rbd_dev_probe_parent() -> | |
| 5138 | + * rbd_dev_image_probe() recursion depth, which means it's also the | |
| 5139 | + * length of the already discovered part of the parent chain. | |
| 5140 | + */ | |
| 5141 | +static int rbd_dev_probe_parent(struct rbd_device *rbd_dev, int depth) | |
| 5135 | 5142 | { |
| 5136 | 5143 | struct rbd_device *parent = NULL; |
| 5137 | 5144 | int ret; |
| @@ -5139,6 +5146,12 @@ static int rbd_dev_probe_parent(struct rbd_device *rbd_dev) · 1 unmodified line | ||
| 5139 | 5146 | if (!rbd_dev->parent_spec) |
| 5140 | 5147 | return 0; |
| 5141 | 5148 | |
| 5149 | + if (++depth > RBD_MAX_PARENT_CHAIN_LEN) { | |
| 5150 | + pr_info("parent chain is too long (%d)\n", depth); | |
| 5151 | + ret = -EINVAL; | |
| 5152 | + goto out_err; | |
| 5153 | + } | |
| 5154 | + | |
| 5142 | 5155 | parent = rbd_dev_create(rbd_dev->rbd_client, rbd_dev->parent_spec, |
| 5143 | 5156 | NULL); |
| 5144 | 5157 | if (!parent) { |
| @@ -5153,7 +5166,7 @@ static int rbd_dev_probe_parent(struct rbd_device *rbd_dev) · 8 unmodified lines | ||
| 5153 | 5166 | __rbd_get_client(rbd_dev->rbd_client); |
| 5154 | 5167 | rbd_spec_get(rbd_dev->parent_spec); |
| 5155 | 5168 | |
| 5156 | − ret = rbd_dev_image_probe(parent, false); | |
| 5169 | + ret = rbd_dev_image_probe(parent, depth); | |
| 5157 | 5170 | if (ret < 0) |
| 5158 | 5171 | goto out_err; |
| 5159 | 5172 | |
| @@ -5282,7 +5295,7 @@ static void rbd_dev_image_release(struct rbd_device *rbd_dev) · 122 unmodified lines | ||
| 5282 | 5295 | * parent), initiate a watch on its header object before using that |
| 5283 | 5296 | * object to get detailed information about the rbd image. |
| 5284 | 5297 | */ |
| 5285 | −static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping) | |
| 5298 | +static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth) | |
| 5286 | 5299 | { |
| 5287 | 5300 | int ret; |
| 5288 | 5301 | |
| @@ -5300,7 +5313,7 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping) · 11 unmodified lines | ||
| 5300 | 5313 | if (ret) |
| 5301 | 5314 | goto err_out_format; |
| 5302 | 5315 | |
| 5303 | − if (mapping) { | |
| 5316 | + if (!depth) { | |
| 5304 | 5317 | ret = rbd_dev_header_watch_sync(rbd_dev); |
| 5305 | 5318 | if (ret) { |
| 5306 | 5319 | if (ret == -ENOENT) |
| @@ -5321,7 +5334,7 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping) · 14 unmodified lines | ||
| 5321 | 5334 | * Otherwise this is a parent image, identified by pool, image |
| 5322 | 5335 | * and snap ids - need to fill in names for those ids. |
| 5323 | 5336 | */ |
| 5324 | − if (mapping) | |
| 5337 | + if (!depth) | |
| 5325 | 5338 | ret = rbd_spec_fill_snap_id(rbd_dev); |
| 5326 | 5339 | else |
| 5327 | 5340 | ret = rbd_spec_fill_names(rbd_dev); |
| @@ -5343,12 +5356,12 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping) · 15 unmodified lines | ||
| 5343 | 5356 | * Need to warn users if this image is the one being |
| 5344 | 5357 | * mapped and has a parent. |
| 5345 | 5358 | */ |
| 5346 | − if (mapping && rbd_dev->parent_spec) | |
| 5359 | + if (!depth && rbd_dev->parent_spec) | |
| 5347 | 5360 | rbd_warn(rbd_dev, |
| 5348 | 5361 | "WARNING: kernel layering is EXPERIMENTAL!"); |
| 5349 | 5362 | } |
| 5350 | 5363 | |
| 5351 | − ret = rbd_dev_probe_parent(rbd_dev); | |
| 5364 | + ret = rbd_dev_probe_parent(rbd_dev, depth); | |
| 5352 | 5365 | if (ret) |
| 5353 | 5366 | goto err_out_probe; |
| 5354 | 5367 | |
| @@ -5359,7 +5372,7 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping) · 4 unmodified lines | ||
| 5359 | 5372 | err_out_probe: |
| 5360 | 5373 | rbd_dev_unprobe(rbd_dev); |
| 5361 | 5374 | err_out_watch: |
| 5362 | − if (mapping) | |
| 5375 | + if (!depth) | |
| 5363 | 5376 | rbd_dev_header_unwatch_sync(rbd_dev); |
| 5364 | 5377 | out_header_name: |
| 5365 | 5378 | kfree(rbd_dev->header_name); |
| @@ -5422,7 +5435,7 @@ static ssize_t do_rbd_add(struct bus_type *bus, · 56 unmodified lines | ||
| 5422 | 5435 | spec = NULL; /* rbd_dev now owns this */ |
| 5423 | 5436 | rbd_opts = NULL; /* rbd_dev now owns this */ |
| 5424 | 5437 | |
| 5425 | − rc = rbd_dev_image_probe(rbd_dev, true); | |
| 5438 | + rc = rbd_dev_image_probe(rbd_dev, 0); | |
| 5426 | 5439 | if (rc < 0) |
| 5427 | 5440 | goto err_out_rbd_dev; |
| 5428 | 5441 | |