diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index b6024a2d7b86dce221b2acbce3513b93adad171c..c80fc1a3a60407387678663e8e3166e7c48110fe 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -4702,11 +4702,49 @@ static int rbd_dev_v2_probe(struct rbd_device *rbd_dev) return ret; } -static int rbd_dev_probe_finish(struct rbd_device *rbd_dev) +static int rbd_dev_probe_parent(struct rbd_device *rbd_dev) { struct rbd_device *parent = NULL; - struct rbd_spec *parent_spec = NULL; - struct rbd_client *rbdc = NULL; + struct rbd_spec *parent_spec; + struct rbd_client *rbdc; + int ret; + + if (!rbd_dev->parent_spec) + return 0; + /* + * We need to pass a reference to the client and the parent + * spec when creating the parent rbd_dev. Images related by + * parent/child relationships always share both. + */ + parent_spec = rbd_spec_get(rbd_dev->parent_spec); + rbdc = __rbd_get_client(rbd_dev->rbd_client); + + ret = -ENOMEM; + parent = rbd_dev_create(rbdc, parent_spec); + if (!parent) + goto out_err; + + ret = rbd_dev_image_probe(parent); + if (ret < 0) + goto out_err; + rbd_dev->parent = parent; + + return 0; +out_err: + if (parent) { + rbd_spec_put(rbd_dev->parent_spec); + kfree(rbd_dev->header_name); + rbd_dev_destroy(parent); + } else { + rbd_put_client(rbdc); + rbd_spec_put(parent_spec); + } + + return ret; +} + +static int rbd_dev_probe_finish(struct rbd_device *rbd_dev) +{ int ret; /* no need to lock here, as rbd_dev is not registered yet */ @@ -4747,34 +4785,9 @@ static int rbd_dev_probe_finish(struct rbd_device *rbd_dev) if (ret) goto err_out_disk; - /* - * At this point cleanup in the event of an error is the job - * of the sysfs code (initiated by rbd_bus_del_dev()). - */ - /* Probe the parent if there is one */ - - if (rbd_dev->parent_spec) { - /* - * We need to pass a reference to the client and the - * parent spec when creating the parent rbd_dev. - * Images related by parent/child relationships - * always share both. - */ - parent_spec = rbd_spec_get(rbd_dev->parent_spec); - rbdc = __rbd_get_client(rbd_dev->rbd_client); - - parent = rbd_dev_create(rbdc, parent_spec); - if (!parent) { - ret = -ENOMEM; - goto err_out_spec; - } - rbdc = NULL; /* parent now owns reference */ - parent_spec = NULL; /* parent now owns reference */ - ret = rbd_dev_image_probe(parent); - if (ret < 0) - goto err_out_parent; - rbd_dev->parent = parent; - } + ret = rbd_dev_probe_parent(rbd_dev); + if (ret) + goto err_out_bus; ret = rbd_dev_header_watch_sync(rbd_dev, 1); if (ret) @@ -4791,13 +4804,6 @@ static int rbd_dev_probe_finish(struct rbd_device *rbd_dev) return ret; -err_out_parent: - rbd_spec_put(rbd_dev->parent_spec); - kfree(rbd_dev->header_name); - rbd_dev_destroy(parent); -err_out_spec: - rbd_spec_put(parent_spec); - rbd_put_client(rbdc); err_out_bus: /* this will also clean up rest of rbd_dev stuff */