Commit 4156d998 authored by Alex Elder's avatar Alex Elder

rbd: separate reading header from decoding it

Right now rbd_read_header() both reads the header object for an rbd
image and decodes its contents.  It does this repeatedly if needed,
in order to ensure a complete and intact header is obtained.

Separate this process into two steps--reading of the raw header
data (in new function, rbd_dev_v1_header_read()) and separately
decoding its contents (in rbd_header_from_disk()).  As a result,
the latter function no longer requires its allocated_snaps argument.
Signed-off-by: default avatarAlex Elder <elder@inktank.com>
Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
parent 103a150f
...@@ -513,15 +513,11 @@ static bool rbd_dev_ondisk_valid(struct rbd_image_header_ondisk *ondisk) ...@@ -513,15 +513,11 @@ static bool rbd_dev_ondisk_valid(struct rbd_image_header_ondisk *ondisk)
* header. * header.
*/ */
static int rbd_header_from_disk(struct rbd_image_header *header, static int rbd_header_from_disk(struct rbd_image_header *header,
struct rbd_image_header_ondisk *ondisk, struct rbd_image_header_ondisk *ondisk)
u32 allocated_snaps)
{ {
u32 snap_count; u32 snap_count;
size_t size; size_t size;
if (!rbd_dev_ondisk_valid(ondisk))
return -ENXIO;
memset(header, 0, sizeof (*header)); memset(header, 0, sizeof (*header));
snap_count = le32_to_cpu(ondisk->snap_count); snap_count = le32_to_cpu(ondisk->snap_count);
...@@ -558,15 +554,6 @@ static int rbd_header_from_disk(struct rbd_image_header *header, ...@@ -558,15 +554,6 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
header->comp_type = ondisk->options.comp_type; header->comp_type = ondisk->options.comp_type;
header->total_snaps = snap_count; header->total_snaps = snap_count;
/*
* If the number of snapshot ids provided by the caller
* doesn't match the number in the entire context there's
* no point in going further. Caller will try again after
* getting an updated snapshot context from the server.
*/
if (allocated_snaps != snap_count)
return 0;
size = sizeof (struct ceph_snap_context); size = sizeof (struct ceph_snap_context);
size += snap_count * sizeof (header->snapc->snaps[0]); size += snap_count * sizeof (header->snapc->snaps[0]);
header->snapc = kzalloc(size, GFP_KERNEL); header->snapc = kzalloc(size, GFP_KERNEL);
...@@ -1629,61 +1616,96 @@ static void rbd_free_disk(struct rbd_device *rbd_dev) ...@@ -1629,61 +1616,96 @@ static void rbd_free_disk(struct rbd_device *rbd_dev)
} }
/* /*
* reload the ondisk the header * 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.
*/ */
static int rbd_read_header(struct rbd_device *rbd_dev, static struct rbd_image_header_ondisk *
struct rbd_image_header *header) rbd_dev_v1_header_read(struct rbd_device *rbd_dev, u64 *version)
{ {
ssize_t rc; struct rbd_image_header_ondisk *ondisk = NULL;
struct rbd_image_header_ondisk *dh;
u32 snap_count = 0; u32 snap_count = 0;
u64 ver; u64 names_size = 0;
size_t len; u32 want_count;
int ret;
/* /*
* First reads the fixed-size header to determine the number * The complete header will include an array of its 64-bit
* of snapshots, then re-reads it, along with all snapshot * snapshot ids, followed by the names of those snapshots as
* records as well as their stored names. * a contiguous block of NUL-terminated strings. Note that
* the number of snapshots could change by the time we read
* it in, in which case we re-read it.
*/ */
len = sizeof (*dh); do {
while (1) { size_t size;
dh = kmalloc(len, GFP_KERNEL);
if (!dh) kfree(ondisk);
return -ENOMEM;
size = sizeof (*ondisk);
rc = rbd_req_sync_read(rbd_dev, size += snap_count * sizeof (struct rbd_image_snap_ondisk);
CEPH_NOSNAP, size += names_size;
ondisk = kmalloc(size, GFP_KERNEL);
if (!ondisk)
return ERR_PTR(-ENOMEM);
ret = rbd_req_sync_read(rbd_dev, CEPH_NOSNAP,
rbd_dev->header_name, rbd_dev->header_name,
0, len, 0, size,
(char *)dh, &ver); (char *) ondisk, version);
if (rc < 0)
goto out_dh; if (ret < 0)
goto out_err;
rc = rbd_header_from_disk(header, dh, snap_count); if (WARN_ON((size_t) ret < size)) {
if (rc < 0) { ret = -ENXIO;
if (rc == -ENXIO) pr_warning("short header read for image %s"
pr_warning("unrecognized header format" " (want %zd got %d)\n",
" for image %s\n", rbd_dev->image_name, size, ret);
rbd_dev->image_name); goto out_err;
goto out_dh; }
if (!rbd_dev_ondisk_valid(ondisk)) {
ret = -ENXIO;
pr_warning("invalid header for image %s\n",
rbd_dev->image_name);
goto out_err;
} }
if (snap_count == header->total_snaps) names_size = le64_to_cpu(ondisk->snap_names_len);
break; want_count = snap_count;
snap_count = le32_to_cpu(ondisk->snap_count);
} while (snap_count != want_count);
snap_count = header->total_snaps; return ondisk;
len = sizeof (*dh) +
snap_count * sizeof(struct rbd_image_snap_ondisk) +
header->snap_names_len;
rbd_header_free(header); out_err:
kfree(dh); kfree(ondisk);
}
header->obj_version = ver;
out_dh: return ERR_PTR(ret);
kfree(dh); }
return rc;
/*
* 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;
u64 ver = 0;
int ret;
ondisk = rbd_dev_v1_header_read(rbd_dev, &ver);
if (IS_ERR(ondisk))
return PTR_ERR(ondisk);
ret = rbd_header_from_disk(header, ondisk);
if (ret >= 0)
header->obj_version = ver;
kfree(ondisk);
return ret;
} }
/* /*
......
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