rbd: lay out header probe infrastructure
authorAlex Elder <elder@inktank.com>
Wed, 11 Jul 2012 01:30:11 +0000 (20:30 -0500)
committerAlex Elder <elder@inktank.com>
Mon, 1 Oct 2012 19:30:53 +0000 (14:30 -0500)
This defines a new function rbd_dev_probe() as a top-level
function for populating detailed information about an rbd device.

It first checks for the existence of a format 2 rbd image id object.
If it exists, the image is assumed to be a format 2 rbd image, and
another function rbd_dev_v2() is called to finish populating
header data for that image.  If it does not exist, it is assumed to
be an old (format 1) rbd image, and calls a similar function
rbd_dev_v1() to populate its header information.

A new field, rbd_dev->format, is defined to record which version
of the rbd image format the device represents.  For a valid mapped
rbd device it will have one of two values, 1 or 2.

So far, the format 2 images are not really supported; this is
laying out the infrastructure for fleshing out that support.

Signed-off-by: Alex Elder <elder@inktank.com>
Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
drivers/block/rbd.c

index 366a3a1f2aac6c58e01d309c561bdf1e5ca606bf..3b284d53a56644ab55876b0b2e60046ac2bad650 100644 (file)
@@ -170,6 +170,7 @@ struct rbd_device {
        int                     major;          /* blkdev assigned major */
        struct gendisk          *disk;          /* blkdev's gendisk and rq */
 
+       u32                     image_format;   /* Either 1 or 2 */
        struct rbd_options      rbd_opts;
        struct rbd_client       *rbd_client;
 
@@ -507,6 +508,11 @@ static void rbd_coll_release(struct kref *kref)
        kfree(coll);
 }
 
+static bool rbd_image_format_valid(u32 image_format)
+{
+       return image_format == 1 || image_format == 2;
+}
+
 static bool rbd_dev_ondisk_valid(struct rbd_image_header_ondisk *ondisk)
 {
        size_t size;
@@ -2584,6 +2590,96 @@ out:
        return ret;
 }
 
+static int rbd_dev_v1_probe(struct rbd_device *rbd_dev)
+{
+       int ret;
+       size_t size;
+
+       /* Version 1 images have no id; empty string is used */
+
+       rbd_dev->image_id = kstrdup("", GFP_KERNEL);
+       if (!rbd_dev->image_id)
+               return -ENOMEM;
+       rbd_dev->image_id_len = 0;
+
+       /* Record the header object name for this rbd image. */
+
+       size = rbd_dev->image_name_len + sizeof (RBD_SUFFIX);
+       rbd_dev->header_name = kmalloc(size, GFP_KERNEL);
+       if (!rbd_dev->header_name) {
+               ret = -ENOMEM;
+               goto out_err;
+       }
+       sprintf(rbd_dev->header_name, "%s%s", rbd_dev->image_name, RBD_SUFFIX);
+
+       /* Populate rbd image metadata */
+
+       ret = rbd_read_header(rbd_dev, &rbd_dev->header);
+       if (ret < 0)
+               goto out_err;
+       rbd_dev->image_format = 1;
+
+       dout("discovered version 1 image, header name is %s\n",
+               rbd_dev->header_name);
+
+       return 0;
+
+out_err:
+       kfree(rbd_dev->header_name);
+       rbd_dev->header_name = NULL;
+       kfree(rbd_dev->image_id);
+       rbd_dev->image_id = NULL;
+
+       return ret;
+}
+
+static int rbd_dev_v2_probe(struct rbd_device *rbd_dev)
+{
+       size_t size;
+
+       /*
+        * Image id was filled in by the caller.  Record the header
+        * object name for this rbd image.
+        */
+       size = sizeof (RBD_HEADER_PREFIX) + rbd_dev->image_id_len;
+       rbd_dev->header_name = kmalloc(size, GFP_KERNEL);
+       if (!rbd_dev->header_name)
+               return -ENOMEM;
+       sprintf(rbd_dev->header_name, "%s%s",
+                       RBD_HEADER_PREFIX, rbd_dev->image_id);
+       rbd_dev->image_format = 2;
+
+       dout("discovered version 2 image, header name is %s\n",
+               rbd_dev->header_name);
+
+       return -ENOTSUPP;
+}
+
+/*
+ * Probe for the existence of the header object for the given rbd
+ * device.  For format 2 images this includes determining the image
+ * id.
+ */
+static int rbd_dev_probe(struct rbd_device *rbd_dev)
+{
+       int ret;
+
+       /*
+        * Get the id from the image id object.  If it's not a
+        * format 2 image, we'll get ENOENT back, and we'll assume
+        * it's a format 1 image.
+        */
+       ret = rbd_dev_image_id(rbd_dev);
+       if (ret)
+               ret = rbd_dev_v1_probe(rbd_dev);
+       else
+               ret = rbd_dev_v2_probe(rbd_dev);
+       if (ret)
+               dout("probe failed, returning %d\n", ret);
+
+       return ret;
+}
+
 static ssize_t rbd_add(struct bus_type *bus,
                       const char *buf,
                       size_t count)
@@ -2631,35 +2727,10 @@ static ssize_t rbd_add(struct bus_type *bus,
                goto err_out_client;
        rbd_dev->pool_id = rc;
 
-       rc = rbd_dev_image_id(rbd_dev);
-       if (!rc) {
-               rc = -ENOTSUPP; /* Not actually supporting format 2 yet */
-               goto err_out_client;
-       }
-
-       /* Version 1 images have no id; empty string is used */
-
-       rbd_dev->image_id = kstrdup("", GFP_KERNEL);
-       if (!rbd_dev->image_id) {
-               rc = -ENOMEM;
-               goto err_out_client;
-       }
-       rbd_dev->image_id_len = 0;
-
-       /* Create the name of the header object */
-
-       rbd_dev->header_name = kmalloc(rbd_dev->image_name_len
-                                               + sizeof (RBD_SUFFIX),
-                                       GFP_KERNEL);
-       if (!rbd_dev->header_name)
-               goto err_out_client;
-       sprintf(rbd_dev->header_name, "%s%s", rbd_dev->image_name, RBD_SUFFIX);
-
-       /* Get information about the image being mapped */
-
-       rc = rbd_read_header(rbd_dev, &rbd_dev->header);
-       if (rc)
+       rc = rbd_dev_probe(rbd_dev);
+       if (rc < 0)
                goto err_out_client;
+       rbd_assert(rbd_image_format_valid(rbd_dev->image_format));
 
        /* no need to lock here, as rbd_dev is not registered yet */
        rc = rbd_dev_snaps_update(rbd_dev);