rbd: update in-core header directly
authorAlex Elder <elder@inktank.com>
Mon, 6 May 2013 14:51:29 +0000 (09:51 -0500)
committerAlex Elder <elder@inktank.com>
Wed, 8 May 2013 22:00:37 +0000 (17:00 -0500)
Now that rbd_header_from_disk() only fills in one-time fields once,
we can extend it slightly so it releases the other fields before
replacing their values.  This way there's no need to pass a
temporary buffer and then copy all the results in.  Just use the rbd
device header structure in rbd_header_from_disk() so its values get
updated directly.

Note that this means we need to take the header semaphore at the
point we update things.  So pass the rbd_dev rather than the address
of its header as its first argument to rbd_header_from_disk(), and
have it return an error code.

As a result, rbd_dev_v1_header_read() does all the work,
rbd_read_header() becomes unnecessary, and rbd_dev_v1_refresh()
becomes a very simple wrapper.

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

index a3b6bf5..e4586f2 100644 (file)
@@ -730,9 +730,10 @@ static bool rbd_dev_ondisk_valid(struct rbd_image_header_ondisk *ondisk)
  * Fill an rbd image header with information from the given format 1
  * on-disk header.
  */
-static int rbd_header_from_disk(struct rbd_image_header *header,
+static int rbd_header_from_disk(struct rbd_device *rbd_dev,
                                 struct rbd_image_header_ondisk *ondisk)
 {
+       struct rbd_image_header *header = &rbd_dev->header;
        bool first_time = header->object_prefix == NULL;
        struct ceph_snap_context *snapc;
        char *object_prefix = NULL;
@@ -802,6 +803,7 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
 
        /* We won't fail any more, fill in the header */
 
+       down_write(&rbd_dev->header_rwsem);
        if (first_time) {
                header->object_prefix = object_prefix;
                header->obj_order = ondisk->options.order;
@@ -811,6 +813,10 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
                header->stripe_unit = 0;
                header->stripe_count = 0;
                header->features = 0;
+       } else {
+               ceph_put_snap_context(header->snapc);
+               kfree(header->snap_names);
+               kfree(header->snap_sizes);
        }
 
        /* The remaining fields always get updated (when we refresh) */
@@ -820,6 +826,14 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
        header->snap_names = snap_names;
        header->snap_sizes = snap_sizes;
 
+       /* Make sure mapping size is consistent with header info */
+
+       if (rbd_dev->spec->snap_id == CEPH_NOSNAP || first_time)
+               if (rbd_dev->mapping.size != header->image_size)
+                       rbd_dev->mapping.size = header->image_size;
+
+       up_write(&rbd_dev->header_rwsem);
+
        return 0;
 out_2big:
        ret = -EIO;
@@ -3032,17 +3046,11 @@ out:
 }
 
 /*
- * Read the complete header for the given rbd device.
- *
- * Returns a pointer to a dynamically-allocated buffer containing
- * the complete and validated header.  Caller can pass the address
- * of a variable that will be filled in with the version of the
- * header object at the time it was read.
- *
- * Returns a pointer-coded errno if a failure occurs.
+ * Read the complete header for the given rbd device.  On successful
+ * return, the rbd_dev->header field will contain up-to-date
+ * information about the image.
  */
-static struct rbd_image_header_ondisk *
-rbd_dev_v1_header_read(struct rbd_device *rbd_dev)
+static int rbd_dev_v1_header_read(struct rbd_device *rbd_dev)
 {
        struct rbd_image_header_ondisk *ondisk = NULL;
        u32 snap_count = 0;
@@ -3067,22 +3075,22 @@ rbd_dev_v1_header_read(struct rbd_device *rbd_dev)
                size += names_size;
                ondisk = kmalloc(size, GFP_KERNEL);
                if (!ondisk)
-                       return ERR_PTR(-ENOMEM);
+                       return -ENOMEM;
 
                ret = rbd_obj_read_sync(rbd_dev, rbd_dev->header_name,
                                       0, size, ondisk);
                if (ret < 0)
-                       goto out_err;
+                       goto out;
                if ((size_t)ret < size) {
                        ret = -ENXIO;
                        rbd_warn(rbd_dev, "short header read (want %zd got %d)",
                                size, ret);
-                       goto out_err;
+                       goto out;
                }
                if (!rbd_dev_ondisk_valid(ondisk)) {
                        ret = -ENXIO;
                        rbd_warn(rbd_dev, "invalid header");
-                       goto out_err;
+                       goto out;
                }
 
                names_size = le64_to_cpu(ondisk->snap_names_len);
@@ -3090,27 +3098,8 @@ rbd_dev_v1_header_read(struct rbd_device *rbd_dev)
                snap_count = le32_to_cpu(ondisk->snap_count);
        } while (snap_count != want_count);
 
-       return ondisk;
-
-out_err:
-       kfree(ondisk);
-
-       return ERR_PTR(ret);
-}
-
-/*
- * reload the ondisk the header
- */
-static int rbd_read_header(struct rbd_device *rbd_dev,
-                          struct rbd_image_header *header)
-{
-       struct rbd_image_header_ondisk *ondisk;
-       int ret;
-
-       ondisk = rbd_dev_v1_header_read(rbd_dev);
-       if (IS_ERR(ondisk))
-               return PTR_ERR(ondisk);
-       ret = rbd_header_from_disk(header, ondisk);
+       ret = rbd_header_from_disk(rbd_dev, ondisk);
+out:
        kfree(ondisk);
 
        return ret;
@@ -3121,40 +3110,7 @@ static int rbd_read_header(struct rbd_device *rbd_dev,
  */
 static int rbd_dev_v1_refresh(struct rbd_device *rbd_dev)
 {
-       int ret;
-       struct rbd_image_header h;
-
-       memset(&h, 0, sizeof (h));
-       ret = rbd_read_header(rbd_dev, &h);
-       if (ret < 0)
-               return ret;
-
-       down_write(&rbd_dev->header_rwsem);
-
-       /* Update image size, and check for resize of mapped image */
-       rbd_dev->header.image_size = h.image_size;
-       if (rbd_dev->spec->snap_id == CEPH_NOSNAP)
-               if (rbd_dev->mapping.size != rbd_dev->header.image_size)
-                       rbd_dev->mapping.size = rbd_dev->header.image_size;
-
-       /* rbd_dev->header.object_prefix shouldn't change */
-       kfree(rbd_dev->header.snap_sizes);
-       kfree(rbd_dev->header.snap_names);
-       /* osd requests may still refer to snapc */
-       ceph_put_snap_context(rbd_dev->header.snapc);
-
-       rbd_dev->header.image_size = h.image_size;
-       rbd_dev->header.snapc = h.snapc;
-       rbd_dev->header.snap_names = h.snap_names;
-       rbd_dev->header.snap_sizes = h.snap_sizes;
-       /* Free the extra copy of the object prefix */
-       if (strcmp(rbd_dev->header.object_prefix, h.object_prefix))
-               rbd_warn(rbd_dev, "object prefix changed (ignoring)");
-       kfree(h.object_prefix);
-
-       up_write(&rbd_dev->header_rwsem);
-
-       return ret;
+       return rbd_dev_v1_header_read(rbd_dev);
 }
 
 /*
@@ -4517,7 +4473,7 @@ static int rbd_dev_v1_probe(struct rbd_device *rbd_dev)
 
        /* Populate rbd image metadata */
 
-       ret = rbd_read_header(rbd_dev, &rbd_dev->header);
+       ret = rbd_dev_v1_header_read(rbd_dev);
        if (ret < 0)
                goto out_err;