summaryrefslogtreecommitdiff
path: root/drivers/block/rbd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/block/rbd.c')
-rw-r--r--drivers/block/rbd.c82
1 files changed, 44 insertions, 38 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index b6024a2d7b8..c80fc1a3a60 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -4702,11 +4702,49 @@ out_err:
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 */