diff options
Diffstat (limited to 'xlators')
-rw-r--r-- | xlators/features/qemu-block/src/bdrv-xlator.c | 43 | ||||
-rw-r--r-- | xlators/features/qemu-block/src/qb-coroutines.c | 64 | ||||
-rw-r--r-- | xlators/features/qemu-block/src/qemu-block.c | 75 | ||||
-rw-r--r-- | xlators/features/qemu-block/src/qemu-block.h | 7 |
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 145f7c79d5e..106c5977535 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 9e64fecaf5c..d29117eb5d4 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 416ae44383c..0edb7b9493d 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 a91adb1ed51..55e7c23ac58 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); |