Commit 662518b1 authored by Alex Elder's avatar Alex Elder

rbd: update in-core header directly

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: default avatarAlex Elder <elder@inktank.com>
Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
parent bb23e37a
...@@ -730,9 +730,10 @@ static bool rbd_dev_ondisk_valid(struct rbd_image_header_ondisk *ondisk) ...@@ -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 * Fill an rbd image header with information from the given format 1
* on-disk header. * 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_ondisk *ondisk)
{ {
struct rbd_image_header *header = &rbd_dev->header;
bool first_time = header->object_prefix == NULL; bool first_time = header->object_prefix == NULL;
struct ceph_snap_context *snapc; struct ceph_snap_context *snapc;
char *object_prefix = NULL; char *object_prefix = NULL;
...@@ -802,6 +803,7 @@ static int rbd_header_from_disk(struct rbd_image_header *header, ...@@ -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 */ /* We won't fail any more, fill in the header */
down_write(&rbd_dev->header_rwsem);
if (first_time) { if (first_time) {
header->object_prefix = object_prefix; header->object_prefix = object_prefix;
header->obj_order = ondisk->options.order; header->obj_order = ondisk->options.order;
...@@ -811,6 +813,10 @@ static int rbd_header_from_disk(struct rbd_image_header *header, ...@@ -811,6 +813,10 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
header->stripe_unit = 0; header->stripe_unit = 0;
header->stripe_count = 0; header->stripe_count = 0;
header->features = 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) */ /* The remaining fields always get updated (when we refresh) */
...@@ -820,6 +826,14 @@ static int rbd_header_from_disk(struct rbd_image_header *header, ...@@ -820,6 +826,14 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
header->snap_names = snap_names; header->snap_names = snap_names;
header->snap_sizes = snap_sizes; 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; return 0;
out_2big: out_2big:
ret = -EIO; ret = -EIO;
...@@ -3032,17 +3046,11 @@ static int rbd_obj_read_sync(struct rbd_device *rbd_dev, ...@@ -3032,17 +3046,11 @@ static int rbd_obj_read_sync(struct rbd_device *rbd_dev,
} }
/* /*
* Read the complete header for the given rbd device. * Read the complete header for the given rbd device. On successful
* * return, the rbd_dev->header field will contain up-to-date
* Returns a pointer to a dynamically-allocated buffer containing * information about the image.
* 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.
*/ */
static struct rbd_image_header_ondisk * static int rbd_dev_v1_header_read(struct rbd_device *rbd_dev)
rbd_dev_v1_header_read(struct rbd_device *rbd_dev)
{ {
struct rbd_image_header_ondisk *ondisk = NULL; struct rbd_image_header_ondisk *ondisk = NULL;
u32 snap_count = 0; u32 snap_count = 0;
...@@ -3067,22 +3075,22 @@ rbd_dev_v1_header_read(struct rbd_device *rbd_dev) ...@@ -3067,22 +3075,22 @@ rbd_dev_v1_header_read(struct rbd_device *rbd_dev)
size += names_size; size += names_size;
ondisk = kmalloc(size, GFP_KERNEL); ondisk = kmalloc(size, GFP_KERNEL);
if (!ondisk) if (!ondisk)
return ERR_PTR(-ENOMEM); return -ENOMEM;
ret = rbd_obj_read_sync(rbd_dev, rbd_dev->header_name, ret = rbd_obj_read_sync(rbd_dev, rbd_dev->header_name,
0, size, ondisk); 0, size, ondisk);
if (ret < 0) if (ret < 0)
goto out_err; goto out;
if ((size_t)ret < size) { if ((size_t)ret < size) {
ret = -ENXIO; ret = -ENXIO;
rbd_warn(rbd_dev, "short header read (want %zd got %d)", rbd_warn(rbd_dev, "short header read (want %zd got %d)",
size, ret); size, ret);
goto out_err; goto out;
} }
if (!rbd_dev_ondisk_valid(ondisk)) { if (!rbd_dev_ondisk_valid(ondisk)) {
ret = -ENXIO; ret = -ENXIO;
rbd_warn(rbd_dev, "invalid header"); rbd_warn(rbd_dev, "invalid header");
goto out_err; goto out;
} }
names_size = le64_to_cpu(ondisk->snap_names_len); names_size = le64_to_cpu(ondisk->snap_names_len);
...@@ -3090,27 +3098,8 @@ rbd_dev_v1_header_read(struct rbd_device *rbd_dev) ...@@ -3090,27 +3098,8 @@ rbd_dev_v1_header_read(struct rbd_device *rbd_dev)
snap_count = le32_to_cpu(ondisk->snap_count); snap_count = le32_to_cpu(ondisk->snap_count);
} while (snap_count != want_count); } while (snap_count != want_count);
return ondisk; ret = rbd_header_from_disk(rbd_dev, ondisk);
out:
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);
kfree(ondisk); kfree(ondisk);
return ret; return ret;
...@@ -3121,40 +3110,7 @@ static int rbd_read_header(struct rbd_device *rbd_dev, ...@@ -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) static int rbd_dev_v1_refresh(struct rbd_device *rbd_dev)
{ {
int ret; return rbd_dev_v1_header_read(rbd_dev);
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;
} }
/* /*
...@@ -4517,7 +4473,7 @@ static int rbd_dev_v1_probe(struct rbd_device *rbd_dev) ...@@ -4517,7 +4473,7 @@ static int rbd_dev_v1_probe(struct rbd_device *rbd_dev)
/* Populate rbd image metadata */ /* Populate rbd image metadata */
ret = rbd_read_header(rbd_dev, &rbd_dev->header); ret = rbd_dev_v1_header_read(rbd_dev);
if (ret < 0) if (ret < 0)
goto out_err; goto out_err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment