summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--xlators/features/qemu-block/src/bdrv-xlator.c43
-rw-r--r--xlators/features/qemu-block/src/qb-coroutines.c64
-rw-r--r--xlators/features/qemu-block/src/qemu-block.c75
-rw-r--r--xlators/features/qemu-block/src/qemu-block.h7
4 files changed, 166 insertions, 23 deletions
diff --git a/xlators/features/qemu-block/src/bdrv-xlator.c b/xlators/features/qemu-block/src/bdrv-xlator.c
index 145f7c79d..106c59775 100644
--- a/xlators/features/qemu-block/src/bdrv-xlator.c
+++ b/xlators/features/qemu-block/src/bdrv-xlator.c
@@ -69,10 +69,13 @@ static int
qemu_gluster_open (BlockDriverState *bs, QDict *options, int bdrv_flags)
{
inode_t *inode = NULL;
- BDRVGlusterState *s = NULL;
+ BDRVGlusterState *s = bs->opaque;
QemuOpts *opts = NULL;
Error *local_err = NULL;
const char *filename = NULL;
+ char gfid_str[128];
+ int ret;
+ qb_conf_t *conf = THIS->private;
opts = qemu_opts_create_nofail(&runtime_opts);
qemu_opts_absorb_qdict(opts, options, &local_err);
@@ -84,12 +87,40 @@ qemu_gluster_open (BlockDriverState *bs, QDict *options, int bdrv_flags)
filename = qemu_opt_get(opts, "filename");
- inode = qb_inode_from_filename (filename);
- if (!inode)
- return -EINVAL;
+ /*
+ * gfid:<gfid> format means we're opening a backing image.
+ */
+ ret = sscanf(filename, "gluster://gfid:%s", gfid_str);
+ if (ret) {
+ loc_t loc = {0,};
+ struct iatt buf = {0,};
+ uuid_t gfid;
- s = bs->opaque;
- s->inode = inode_ref (inode);
+ uuid_parse(gfid_str, gfid);
+
+ loc.inode = inode_find(conf->root_inode->table, gfid);
+ if (!loc.inode) {
+ loc.inode = inode_new(conf->root_inode->table);
+ uuid_copy(loc.inode->gfid, gfid);
+ }
+
+ uuid_copy(loc.gfid, loc.inode->gfid);
+ ret = syncop_lookup(FIRST_CHILD(THIS), &loc, NULL, &buf, NULL,
+ NULL);
+ if (ret) {
+ loc_wipe(&loc);
+ return -errno;
+ }
+
+ s->inode = inode_ref(loc.inode);
+ loc_wipe(&loc);
+ } else {
+ inode = qb_inode_from_filename (filename);
+ if (!inode)
+ return -EINVAL;
+
+ s->inode = inode_ref(inode);
+ }
return 0;
}
diff --git a/xlators/features/qemu-block/src/qb-coroutines.c b/xlators/features/qemu-block/src/qb-coroutines.c
index 9e64fecaf..d29117eb5 100644
--- a/xlators/features/qemu-block/src/qb-coroutines.c
+++ b/xlators/features/qemu-block/src/qb-coroutines.c
@@ -35,6 +35,8 @@ qb_format_and_resume (void *opaque)
call_stub_t *stub = NULL;
inode_t *inode = NULL;
char filename[64];
+ char base_filename[128];
+ int use_base = 0;
qb_inode_t *qb_inode = NULL;
Error *local_err = NULL;
fd_t *fd = NULL;
@@ -54,8 +56,62 @@ qb_format_and_resume (void *opaque)
qb_inode = qb_inode_ctx_get (frame->this, inode);
- bdrv_img_create (filename, qb_inode->fmt, 0, 0,
- 0, qb_inode->size, 0, &local_err, true);
+ /*
+ * See if the caller specified a backing image.
+ */
+ if (!uuid_is_null(qb_inode->backing_gfid) || qb_inode->backing_fname) {
+ loc_t loc = {0,};
+ char gfid_str[64];
+ struct iatt buf;
+
+ if (!uuid_is_null(qb_inode->backing_gfid)) {
+ loc.inode = inode_find(qb_conf->root_inode->table,
+ qb_inode->backing_gfid);
+ if (!loc.inode) {
+ loc.inode = inode_new(qb_conf->root_inode->table);
+ uuid_copy(loc.inode->gfid,
+ qb_inode->backing_gfid);
+ }
+ uuid_copy(loc.gfid, loc.inode->gfid);
+ } else if (qb_inode->backing_fname) {
+ loc.inode = inode_new(qb_conf->root_inode->table);
+ loc.name = qb_inode->backing_fname;
+ loc.parent = inode_parent(inode, NULL, NULL);
+ loc_path(&loc, loc.name);
+ }
+
+ /*
+ * Lookup the backing image. Verify existence and/or get the
+ * gfid if we don't already have it.
+ */
+ ret = syncop_lookup(FIRST_CHILD(frame->this), &loc, NULL, &buf,
+ NULL, NULL);
+ GF_FREE(qb_inode->backing_fname);
+ if (ret) {
+ loc_wipe(&loc);
+ ret = errno;
+ goto err;
+ }
+
+ uuid_copy(qb_inode->backing_gfid, buf.ia_gfid);
+ loc_wipe(&loc);
+
+ /*
+ * We pass the filename of the backing image into the qemu block
+ * subsystem as the associated gfid. This is embedded into the
+ * clone image and passed along to the gluster bdrv backend when
+ * the block subsystem needs to operate on the backing image on
+ * behalf of the clone.
+ */
+ uuid_unparse(qb_inode->backing_gfid, gfid_str);
+ snprintf(base_filename, sizeof(base_filename),
+ "gluster://gfid:%s", gfid_str);
+ use_base = 1;
+ }
+
+ bdrv_img_create (filename, qb_inode->fmt,
+ use_base ? base_filename : NULL, 0, 0, qb_inode->size,
+ 0, &local_err, true);
if (error_is_set (&local_err)) {
gf_log (frame->this->name, GF_LOG_ERROR, "%s",
@@ -113,6 +169,10 @@ qb_format_and_resume (void *opaque)
QB_STUB_UNWIND (stub, 0, 0);
return 0;
+
+err:
+ QB_STUB_UNWIND(stub, -1, ret);
+ return 0;
}
diff --git a/xlators/features/qemu-block/src/qemu-block.c b/xlators/features/qemu-block/src/qemu-block.c
index 416ae4438..0edb7b949 100644
--- a/xlators/features/qemu-block/src/qemu-block.c
+++ b/xlators/features/qemu-block/src/qemu-block.c
@@ -108,42 +108,76 @@ qb_iatt_fixup (xlator_t *this, inode_t *inode, struct iatt *iatt)
int
qb_format_extract (xlator_t *this, char *format, inode_t *inode)
{
- char *s = NULL;
+ char *s, *save;
uint64_t size = 0;
char fmt[QB_XATTR_VAL_MAX+1] = {0, };
qb_inode_t *qb_inode = NULL;
+ char *formatstr = NULL;
+ uuid_t gfid = {0,};
+ char gfid_str[64] = {0,};
+ int ret;
- strncpy (fmt, format, QB_XATTR_VAL_MAX);
- s = strchr (fmt, ':');
+ strncpy(fmt, format, QB_XATTR_VAL_MAX);
+
+ s = strtok_r(fmt, ":", &save);
if (!s)
goto invalid;
- if (s == fmt)
- goto invalid;
+ formatstr = gf_strdup(s);
- *s = 0; s++;
- if (!*s || strchr (s, ':'))
+ s = strtok_r(NULL, ":", &save);
+ if (!s)
goto invalid;
-
if (gf_string2bytesize (s, &size))
goto invalid;
-
if (!size)
goto invalid;
+ s = strtok_r(NULL, "\0", &save);
+ if (s && !strncmp(s, "<gfid:", strlen("<gfid:"))) {
+ /*
+ * Check for valid gfid backing image specifier.
+ */
+ if (strlen(s) + 1 > sizeof(gfid_str))
+ goto invalid;
+ ret = sscanf(s, "<gfid:%[^>]s", gfid_str);
+ if (ret == 1) {
+ ret = uuid_parse(gfid_str, gfid);
+ if (ret < 0)
+ goto invalid;
+ }
+ }
+
qb_inode = qb_inode_ctx_get (this, inode);
if (!qb_inode)
qb_inode = GF_CALLOC (1, sizeof (*qb_inode),
gf_qb_mt_qb_inode_t);
- if (!qb_inode)
+ if (!qb_inode) {
+ GF_FREE(formatstr);
return ENOMEM;
+ }
- strncpy (qb_inode->fmt, fmt, QB_XATTR_VAL_MAX);
+ strncpy(qb_inode->fmt, formatstr, QB_XATTR_VAL_MAX);
qb_inode->size = size;
- qb_inode->size_str = s;
+
+ /*
+ * If a backing gfid was not specified, interpret any remaining bytes
+ * associated with a backing image as a filename local to the parent
+ * directory. The format processing will validate further.
+ */
+ if (!uuid_is_null(gfid))
+ uuid_copy(qb_inode->backing_gfid, gfid);
+ else if (s)
+ qb_inode->backing_fname = gf_strdup(s);
inode_ctx_set (inode, this, (void *)&qb_inode);
+
+ GF_FREE(formatstr);
+
return 0;
+
invalid:
+ GF_FREE(formatstr);
+
gf_log (this->name, GF_LOG_WARNING,
"invalid format '%s' in inode %s", format,
uuid_utoa (inode->gfid));
@@ -191,6 +225,15 @@ qb_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
if (op_ret == -1)
goto out;
+ /*
+ * Cache the root inode for dealing with backing images. The format
+ * coroutine and the gluster qemu backend driver both use the root inode
+ * table to verify and/or redirect I/O to the backing image via
+ * anonymous fd's.
+ */
+ if (!conf->root_inode && __is_root_gfid(inode->gfid))
+ conf->root_inode = inode_ref(inode);
+
if (!xdata)
goto out;
@@ -249,6 +292,7 @@ qb_setxattr_format (call_frame_t *frame, xlator_t *this, call_stub_t *stub,
int op_errno = 0;
qb_local_t *qb_local = NULL;
data_t *data = NULL;
+ qb_inode_t *qb_inode;
if (!(data = dict_get (xattr, "trusted.glusterfs.block-format"))) {
QB_STUB_RESUME (stub);
@@ -264,12 +308,15 @@ qb_setxattr_format (call_frame_t *frame, xlator_t *this, call_stub_t *stub,
QB_STUB_UNWIND (stub, -1, op_errno);
return 0;
}
+ qb_inode = qb_inode_ctx_get(this, inode);
qb_local = frame->local;
qb_local->stub = stub;
qb_local->inode = inode_ref (inode);
- strncpy (qb_local->fmt, format, QB_XATTR_VAL_MAX);
+
+ snprintf(qb_local->fmt, QB_XATTR_VAL_MAX, "%s:%lu", qb_inode->fmt,
+ qb_inode->size);
qb_coroutine (frame, qb_format_and_resume);
@@ -1041,6 +1088,8 @@ fini (xlator_t *this)
this->private = NULL;
+ if (conf->root_inode)
+ inode_unref(conf->root_inode);
GF_FREE (conf);
return;
diff --git a/xlators/features/qemu-block/src/qemu-block.h b/xlators/features/qemu-block/src/qemu-block.h
index a91adb1ed..55e7c23ac 100644
--- a/xlators/features/qemu-block/src/qemu-block.h
+++ b/xlators/features/qemu-block/src/qemu-block.h
@@ -36,15 +36,16 @@
#define QB_XATTR_KEY_MAX 64
-#define QB_XATTR_VAL_MAX 32
+#define QB_XATTR_VAL_MAX 64
typedef struct qb_inode {
char fmt[QB_XATTR_VAL_MAX]; /* this is only the format, not "format:size" */
size_t size; /* virtual size in bytes */
- char *size_str; /* pointer into fmt[] after ":" where size begins */
BlockDriverState *bs;
int refcnt;
+ uuid_t backing_gfid;
+ char *backing_fname;
} qb_inode_t;
@@ -53,6 +54,7 @@ typedef struct qb_conf {
struct syncenv *env;
char qb_xattr_key[QB_XATTR_KEY_MAX];
char *default_password;
+ inode_t *root_inode;
} qb_conf_t;
@@ -71,6 +73,7 @@ void qb_local_free (xlator_t *this, qb_local_t *local);
int qb_coroutine (call_frame_t *frame, synctask_fn_t fn);
inode_t *qb_inode_from_filename (const char *filename);
int qb_inode_to_filename (inode_t *inode, char *filename, int size);
+int qb_format_extract (xlator_t *this, char *format, inode_t *inode);
qb_inode_t *qb_inode_ctx_get (xlator_t *this, inode_t *inode);