Commit bb23e37a authored by Alex Elder's avatar Alex Elder

rbd: refactor rbd_header_from_disk()

This rearranges rbd_header_from_disk so that it:
    - allocates the snapshot context right away
    - keeps results in local variables, not changing the passed-in
      header until it's known we'll succeed
    - does initialization of set-once fields in a header only if
      they have not already been set

The last point is moot at the moment, because rbd_read_header()
(the only caller) always supplies a zero-filled header buffer.
Signed-off-by: default avatarAlex Elder <elder@inktank.com>
Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
parent 46578dcd
...@@ -727,86 +727,109 @@ static bool rbd_dev_ondisk_valid(struct rbd_image_header_ondisk *ondisk) ...@@ -727,86 +727,109 @@ static bool rbd_dev_ondisk_valid(struct rbd_image_header_ondisk *ondisk)
} }
/* /*
* Create a new header structure, translate header format from the on-disk * Fill an rbd image header with information from the given format 1
* header. * on-disk 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)
{ {
bool first_time = header->object_prefix == NULL;
struct ceph_snap_context *snapc;
char *object_prefix = NULL;
char *snap_names = NULL;
u64 *snap_sizes = NULL;
u32 snap_count; u32 snap_count;
size_t len;
size_t size; size_t size;
int ret = -ENOMEM;
u32 i; u32 i;
snap_count = le32_to_cpu(ondisk->snap_count); /* Allocate this now to avoid having to handle failure below */
len = strnlen(ondisk->object_prefix, sizeof (ondisk->object_prefix)); if (first_time) {
header->object_prefix = kmalloc(len + 1, GFP_KERNEL); size_t len;
if (!header->object_prefix)
return -ENOMEM;
memcpy(header->object_prefix, ondisk->object_prefix, len);
header->object_prefix[len] = '\0';
len = strnlen(ondisk->object_prefix,
sizeof (ondisk->object_prefix));
object_prefix = kmalloc(len + 1, GFP_KERNEL);
if (!object_prefix)
return -ENOMEM;
memcpy(object_prefix, ondisk->object_prefix, len);
object_prefix[len] = '\0';
}
/* Allocate the snapshot context and fill it in */
snap_count = le32_to_cpu(ondisk->snap_count);
snapc = ceph_create_snap_context(snap_count, GFP_KERNEL);
if (!snapc)
goto out_err;
snapc->seq = le64_to_cpu(ondisk->snap_seq);
if (snap_count) { if (snap_count) {
struct rbd_image_snap_ondisk *snaps;
u64 snap_names_len = le64_to_cpu(ondisk->snap_names_len); u64 snap_names_len = le64_to_cpu(ondisk->snap_names_len);
/* Save a copy of the snapshot names */ /* We'll keep a copy of the snapshot names... */
if (snap_names_len > (u64) SIZE_MAX) if (snap_names_len > (u64)SIZE_MAX)
return -EIO; goto out_2big;
header->snap_names = kmalloc(snap_names_len, GFP_KERNEL); snap_names = kmalloc(snap_names_len, GFP_KERNEL);
if (!header->snap_names) if (!snap_names)
goto out_err; goto out_err;
/*
* Note that rbd_dev_v1_header_read() guarantees
* the ondisk buffer we're working with has
* snap_names_len bytes beyond the end of the
* snapshot id array, this memcpy() is safe.
*/
memcpy(header->snap_names, &ondisk->snaps[snap_count],
snap_names_len);
/* Record each snapshot's size */ /* ...as well as the array of their sizes. */
size = snap_count * sizeof (*header->snap_sizes); size = snap_count * sizeof (*header->snap_sizes);
header->snap_sizes = kmalloc(size, GFP_KERNEL); snap_sizes = kmalloc(size, GFP_KERNEL);
if (!header->snap_sizes) if (!snap_sizes)
goto out_err; goto out_err;
for (i = 0; i < snap_count; i++)
header->snap_sizes[i] = /*
le64_to_cpu(ondisk->snaps[i].image_size); * Copy the names, and fill in each snapshot's id
} else { * and size.
header->snap_names = NULL; *
header->snap_sizes = NULL; * Note that rbd_dev_v1_header_read() guarantees the
* ondisk buffer we're working with has
* snap_names_len bytes beyond the end of the
* snapshot id array, this memcpy() is safe.
*/
memcpy(snap_names, &ondisk->snaps[snap_count], snap_names_len);
snaps = ondisk->snaps;
for (i = 0; i < snap_count; i++) {
snapc->snaps[i] = le64_to_cpu(snaps[i].id);
snap_sizes[i] = le64_to_cpu(snaps[i].image_size);
}
} }
header->features = 0; /* No features support in v1 images */ /* We won't fail any more, fill in the header */
header->obj_order = ondisk->options.order;
header->crypt_type = ondisk->options.crypt_type; if (first_time) {
header->comp_type = ondisk->options.comp_type; header->object_prefix = object_prefix;
header->obj_order = ondisk->options.order;
header->crypt_type = ondisk->options.crypt_type;
header->comp_type = ondisk->options.comp_type;
/* The rest aren't used for format 1 images */
header->stripe_unit = 0;
header->stripe_count = 0;
header->features = 0;
}
/* Allocate and fill in the snapshot context */ /* The remaining fields always get updated (when we refresh) */
header->image_size = le64_to_cpu(ondisk->image_size); header->image_size = le64_to_cpu(ondisk->image_size);
header->snapc = snapc;
header->snapc = ceph_create_snap_context(snap_count, GFP_KERNEL); header->snap_names = snap_names;
if (!header->snapc) header->snap_sizes = snap_sizes;
goto out_err;
header->snapc->seq = le64_to_cpu(ondisk->snap_seq);
for (i = 0; i < snap_count; i++)
header->snapc->snaps[i] = le64_to_cpu(ondisk->snaps[i].id);
return 0; return 0;
out_2big:
ret = -EIO;
out_err: out_err:
kfree(header->snap_sizes); kfree(snap_sizes);
header->snap_sizes = NULL; kfree(snap_names);
kfree(header->snap_names); ceph_put_snap_context(snapc);
header->snap_names = NULL; kfree(object_prefix);
kfree(header->object_prefix);
header->object_prefix = NULL;
return -ENOMEM; return ret;
} }
static const char *_rbd_dev_v1_snap_name(struct rbd_device *rbd_dev, u32 which) static const char *_rbd_dev_v1_snap_name(struct rbd_device *rbd_dev, u32 which)
......
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