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: Alex Elder <elder@inktank.com>
Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
This commit is contained in:
Alex Elder 2013-05-06 09:51:29 -05:00
parent bb23e37acb
commit 662518b128

View 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;