features/qemu-block: support for QCOW2 and QED formats

This patch adds support for internals snapshots using QCOW2 and
general framework for external snapshots (next patch) with
QCOW2 and QED.

For internal snapshots, the file must be "initialized" or
"formatted" into QCOW2 format, and specify a file size.

Snapshots can be created, deleted, and applied ("goto").

e.g:

 // Format and Initialize

sh# setfattr -n trusted.glusterfs.block-format -v qcow2:10GB /mnt/imgfile
sh# ls -l /mnt/imgfile
-rw-r--r-- 1 root root 10G Jul 18 21:20 imgfile

 // Create a snapshot

sh# setfattr -n trusted.glusterfs.block-snapshot-create -v name1 imgfile

 // Apply a snapshot

sh# setfattr -n trusted.gluterfs.block-snapshot-goto -v name1 imgfile

Change-Id: If993e057a9455967ba3fa9dcabb7f74b8b2cf4c3
BUG: 986775
Signed-off-by: Anand Avati <avati@redhat.com>
Reviewed-on: http://review.gluster.org/5367
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
This commit is contained in:
Anand Avati 2013-03-05 14:48:28 -08:00
parent 0d60175bd6
commit 53e98f11d1
19 changed files with 2878 additions and 1 deletions

View File

@ -127,6 +127,8 @@ AC_CONFIG_FILES([Makefile
xlators/encryption/Makefile
xlators/encryption/rot-13/Makefile
xlators/encryption/rot-13/src/Makefile
xlators/features/qemu-block/Makefile
xlators/features/qemu-block/src/Makefile
xlators/system/Makefile
xlators/system/posix-acl/Makefile
xlators/system/posix-acl/src/Makefile
@ -353,6 +355,33 @@ fi
AC_SUBST(FUSERMOUNT_SUBDIR)
#end FUSERMOUNT section
# QEMU_BLOCK section
AC_ARG_ENABLE([qemu-block],
AC_HELP_STRING([--enable-qemu-block],
[Build QEMU Block formats translator]))
if test "x$enable_qemu_block" != "xno"; then
PKG_CHECK_MODULES([GLIB], [glib-2.0],
[HAVE_GLIB_2="yes"],
[HAVE_GLIB_2="no"])
fi
if test "x$enable_qemu_block" = "xyes" -a "x$HAVE_GLIB_2" = "xno"; then
echo "QEMU Block formats translator requires libglib-2.0, but missing."
exit 1
fi
BUILD_QEMU_BLOCK=no
if test "x${enable_qemu_block}" != "xno" -a "x${HAVE_GLIB_2}" = "xyes"; then
BUILD_QEMU_BLOCK=yes
AC_DEFINE(HAVE_QEMU_BLOCK, 1, [define if libglib-2.0 library found and QEMU
Block translator enabled])
fi
AM_CONDITIONAL([ENABLE_QEMU_BLOCK], [test x$BUILD_QEMU_BLOCK = xyes])
# end QEMU_BLOCK section
# EPOLL section
AC_ARG_ENABLE([epoll],
@ -816,4 +845,5 @@ echo "Block Device backend : $BUILD_BD_XLATOR"
echo "glupy : $BUILD_GLUPY"
echo "Use syslog : $USE_SYSLOG"
echo "XML output : $BUILD_XML_OUTPUT"
echo "QEMU Block formats : $BUILD_QEMU_BLOCK"
echo

View File

@ -0,0 +1,12 @@
int notifier_with_return_list_init () { return 0; }
int notifier_with_return_list_notify () { return 0; }
int notifier_with_return_list_add () { return 0; }
int notifier_list_init () { return 0; }
int notifier_list_notify () { return 0; }
int notifier_list_add () { return 0; }
int monitor_protocol_event () { return 0; }
int block_job_cancel_sync () { return 0; }
int block_job_iostatus_reset () { return 0; }
int vm_stop () { return 0; }
int qemu_get_aio_context () { return 0; }

55
tests/basic/file-snapshot.t Executable file
View File

@ -0,0 +1,55 @@
#!/bin/bash
. $(dirname $0)/../include.rc
. $(dirname $0)/../volume.rc
cleanup;
TEST glusterd
TEST pidof glusterd
TEST $CLI volume info;
TEST $CLI volume create $V0 $H0:$B0/$V0;
EXPECT "$V0" volinfo_field $V0 'Volume Name';
EXPECT 'Created' volinfo_field $V0 'Status';
TEST $CLI volume start $V0;
EXPECT 'Started' volinfo_field $V0 'Status';
TEST $CLI volume set $V0 features.file-snapshot on;
TEST $CLI volume set $V0 performance.quick-read off;
TEST $CLI volume set $V0 performance.io-cache off;
TEST glusterfs -s $H0 --volfile-id $V0 $M0 --attribute-timeout=0;
TEST touch $M0/big-file;
TEST setfattr -n trusted.glusterfs.block-format -v qcow2:10GB $M0/big-file;
TEST [ `stat -c '%s' $M0/big-file` = 10737418240 ]
echo 'ABCDEFGHIJ' > $M0/data-file1
TEST dd if=$M0/data-file1 of=$M0/big-file conv=notrunc;
TEST setfattr -n trusted.glusterfs.block-snapshot-create -v image1 $M0/big-file;
echo '1234567890' > $M0/data-file2
TEST dd if=$M0/data-file2 of=$M0/big-file conv=notrunc;
TEST setfattr -n trusted.glusterfs.block-snapshot-create -v image2 $M0/big-file;
TEST setfattr -n trusted.glusterfs.block-snapshot-goto -v image1 $M0/big-file;
TEST dd if=$M0/big-file of=$M0/out-file1 bs=11 count=1;
TEST setfattr -n trusted.glusterfs.block-snapshot-goto -v image2 $M0/big-file;
TEST dd if=$M0/big-file of=$M0/out-file2 bs=11 count=1;
TEST cmp $M0/data-file1 $M0/out-file1;
TEST cmp $M0/data-file2 $M0/out-file2;
TEST $CLI volume stop $V0;
EXPECT 'Stopped' volinfo_field $V0 'Status';
TEST $CLI volume delete $V0;
TEST ! $CLI volume info $V0;
cleanup;

View File

@ -1,4 +1,4 @@
SUBDIRS = locks quota read-only mac-compat quiesce marker index \
protect changelog gfid-access $(GLUPY_SUBDIR) # trash path-converter # filter
protect changelog gfid-access $(GLUPY_SUBDIR) qemu-block # trash path-converter # filter
CLEANFILES =

View File

@ -0,0 +1 @@
SUBDIRS = src

View File

@ -0,0 +1,147 @@
if ENABLE_QEMU_BLOCK
xlator_LTLIBRARIES = qemu-block.la
xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/features
qemu_block_la_LDFLAGS = -module -avoid-version
qemu_block_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la $(GLIB_LIBS) -lz -lrt
qemu_block_la_SOURCES_qemu = \
$(CONTRIBDIR)/qemu/qemu-coroutine.c \
$(CONTRIBDIR)/qemu/qemu-coroutine-lock.c \
$(CONTRIBDIR)/qemu/qemu-coroutine-sleep.c \
$(CONTRIBDIR)/qemu/block.c \
$(CONTRIBDIR)/qemu/nop-symbols.c
qemu_block_la_SOURCES_qemu_util = \
$(CONTRIBDIR)/qemu/util/aes.c \
$(CONTRIBDIR)/qemu/util/bitmap.c \
$(CONTRIBDIR)/qemu/util/bitops.c \
$(CONTRIBDIR)/qemu/util/cutils.c \
$(CONTRIBDIR)/qemu/util/error.c \
$(CONTRIBDIR)/qemu/util/hbitmap.c \
$(CONTRIBDIR)/qemu/util/iov.c \
$(CONTRIBDIR)/qemu/util/module.c \
$(CONTRIBDIR)/qemu/util/oslib-posix.c \
$(CONTRIBDIR)/qemu/util/qemu-option.c \
$(CONTRIBDIR)/qemu/util/qemu-error.c \
$(CONTRIBDIR)/qemu/util/qemu-thread-posix.c \
$(CONTRIBDIR)/qemu/util/unicode.c \
$(CONTRIBDIR)/qemu/util/hexdump.c
qemu_block_la_SOURCES_qemu_block = \
$(CONTRIBDIR)/qemu/block/snapshot.c \
$(CONTRIBDIR)/qemu/block/qcow2-cache.c \
$(CONTRIBDIR)/qemu/block/qcow2-cluster.c \
$(CONTRIBDIR)/qemu/block/qcow2-refcount.c \
$(CONTRIBDIR)/qemu/block/qcow2-snapshot.c \
$(CONTRIBDIR)/qemu/block/qcow2.c \
$(CONTRIBDIR)/qemu/block/qed-check.c \
$(CONTRIBDIR)/qemu/block/qed-cluster.c \
$(CONTRIBDIR)/qemu/block/qed-gencb.c \
$(CONTRIBDIR)/qemu/block/qed-l2-cache.c \
$(CONTRIBDIR)/qemu/block/qed-table.c \
$(CONTRIBDIR)/qemu/block/qed.c
qemu_block_la_SOURCES_qemu_qobject = \
$(CONTRIBDIR)/qemu/qobject/json-lexer.c \
$(CONTRIBDIR)/qemu/qobject/json-parser.c \
$(CONTRIBDIR)/qemu/qobject/json-streamer.c \
$(CONTRIBDIR)/qemu/qobject/qbool.c \
$(CONTRIBDIR)/qemu/qobject/qdict.c \
$(CONTRIBDIR)/qemu/qobject/qerror.c \
$(CONTRIBDIR)/qemu/qobject/qfloat.c \
$(CONTRIBDIR)/qemu/qobject/qint.c \
$(CONTRIBDIR)/qemu/qobject/qjson.c \
$(CONTRIBDIR)/qemu/qobject/qlist.c \
$(CONTRIBDIR)/qemu/qobject/qstring.c
qemu_block_la_SOURCES = \
$(qemu_block_la_SOURCES_qemu) \
$(qemu_block_la_SOURCES_qemu_util) \
$(qemu_block_la_SOURCES_qemu_block) \
$(qemu_block_la_SOURCES_qemu_qobject) \
bdrv-xlator.c \
coroutine-synctask.c \
bh-syncop.c \
monitor-logging.c \
clock-timer.c \
qemu-block.c \
qb-coroutines.c
noinst_HEADERS_qemu = \
$(CONTRIBDIR)/qemu/config-host.h \
$(CONTRIBDIR)/qemu/qapi-types.h \
$(CONTRIBDIR)/qemu/qmp-commands.h \
$(CONTRIBDIR)/qemu/trace/generated-tracers.h \
$(CONTRIBDIR)/qemu/include/config.h \
$(CONTRIBDIR)/qemu/include/qemu-common.h \
$(CONTRIBDIR)/qemu/include/trace.h \
$(CONTRIBDIR)/qemu/include/block/coroutine.h \
$(CONTRIBDIR)/qemu/include/block/aio.h \
$(CONTRIBDIR)/qemu/include/block/block.h \
$(CONTRIBDIR)/qemu/include/block/block_int.h \
$(CONTRIBDIR)/qemu/include/block/blockjob.h \
$(CONTRIBDIR)/qemu/include/block/coroutine.h \
$(CONTRIBDIR)/qemu/include/block/coroutine_int.h \
$(CONTRIBDIR)/qemu/include/fpu/softfloat.h \
$(CONTRIBDIR)/qemu/include/migration/migration.h \
$(CONTRIBDIR)/qemu/include/migration/vmstate.h \
$(CONTRIBDIR)/qemu/include/monitor/monitor.h \
$(CONTRIBDIR)/qemu/include/monitor/readline.h \
$(CONTRIBDIR)/qemu/include/qapi/error.h \
$(CONTRIBDIR)/qemu/include/qapi/qmp/json-lexer.h \
$(CONTRIBDIR)/qemu/include/qapi/qmp/json-parser.h \
$(CONTRIBDIR)/qemu/include/qapi/qmp/json-streamer.h \
$(CONTRIBDIR)/qemu/include/qapi/qmp/qbool.h \
$(CONTRIBDIR)/qemu/include/qapi/qmp/qdict.h \
$(CONTRIBDIR)/qemu/include/qapi/qmp/qerror.h \
$(CONTRIBDIR)/qemu/include/qapi/qmp/qfloat.h \
$(CONTRIBDIR)/qemu/include/qapi/qmp/qint.h \
$(CONTRIBDIR)/qemu/include/qapi/qmp/qlist.h \
$(CONTRIBDIR)/qemu/include/qapi/qmp/qobject.h \
$(CONTRIBDIR)/qemu/include/qapi/qmp/qstring.h \
$(CONTRIBDIR)/qemu/include/qapi/qmp/types.h \
$(CONTRIBDIR)/qemu/include/qemu/aes.h \
$(CONTRIBDIR)/qemu/include/qemu/atomic.h \
$(CONTRIBDIR)/qemu/include/qemu/bitmap.h \
$(CONTRIBDIR)/qemu/include/qemu/bitops.h \
$(CONTRIBDIR)/qemu/include/qemu/bswap.h \
$(CONTRIBDIR)/qemu/include/qemu/compiler.h \
$(CONTRIBDIR)/qemu/include/qemu/error-report.h \
$(CONTRIBDIR)/qemu/include/qemu/event_notifier.h \
$(CONTRIBDIR)/qemu/include/qemu/hbitmap.h \
$(CONTRIBDIR)/qemu/include/qemu/host-utils.h \
$(CONTRIBDIR)/qemu/include/qemu/iov.h \
$(CONTRIBDIR)/qemu/include/qemu/main-loop.h \
$(CONTRIBDIR)/qemu/include/qemu/module.h \
$(CONTRIBDIR)/qemu/include/qemu/notify.h \
$(CONTRIBDIR)/qemu/include/qemu/option.h \
$(CONTRIBDIR)/qemu/include/qemu/option_int.h \
$(CONTRIBDIR)/qemu/include/qemu/queue.h \
$(CONTRIBDIR)/qemu/include/qemu/sockets.h \
$(CONTRIBDIR)/qemu/include/qemu/thread-posix.h \
$(CONTRIBDIR)/qemu/include/qemu/thread.h \
$(CONTRIBDIR)/qemu/include/qemu/timer.h \
$(CONTRIBDIR)/qemu/include/qemu/typedefs.h \
$(CONTRIBDIR)/qemu/include/sysemu/sysemu.h \
$(CONTRIBDIR)/qemu/include/sysemu/os-posix.h \
$(CONTRIBDIR)/qemu/block/qcow2.h \
$(CONTRIBDIR)/qemu/block/qed.h
noinst_HEADERS = \
$(noinst_HEADERS_qemu) \
qemu-block.h \
qemu-block-memory-types.h \
coroutine-synctask.h \
qb-coroutines.h
AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src \
-I$(CONTRIBDIR)/qemu \
-I$(CONTRIBDIR)/qemu/include \
-DGLUSTER_XLATOR
AM_CFLAGS = -fno-strict-aliasing -Wall $(GF_CFLAGS) $(GLIB_CFLAGS)
CLEANFILES =
endif

View File

@ -0,0 +1,366 @@
/*
Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
This file is part of GlusterFS.
This file is licensed to you under your choice of the GNU Lesser
General Public License, version 3 or any later version (LGPLv3 or
later), or the GNU General Public License, version 2 (GPLv2), in all
cases as published by the Free Software Foundation.
*/
#ifndef _CONFIG_H
#define _CONFIG_H
#include "config.h"
#endif
#include "inode.h"
#include "syncop.h"
#include "qemu-block.h"
#include "block/block_int.h"
typedef struct BDRVGlusterState {
inode_t *inode;
} BDRVGlusterState;
static QemuOptsList runtime_opts = {
.name = "gluster",
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
.desc = {
{
.name = "filename",
.type = QEMU_OPT_STRING,
.help = "GFID of file",
},
{ /* end of list */ }
},
};
inode_t *
qb_inode_from_filename (const char *filename)
{
const char *iptr = NULL;
inode_t *inode = NULL;
iptr = filename + 17;
sscanf (iptr, "%p", &inode);
return inode;
}
int
qb_inode_to_filename (inode_t *inode, char *filename, int size)
{
return snprintf (filename, size, "gluster://inodep:%p", inode);
}
static fd_t *
fd_from_bs (BlockDriverState *bs)
{
BDRVGlusterState *s = bs->opaque;
return fd_anonymous (s->inode);
}
static int
qemu_gluster_open (BlockDriverState *bs, QDict *options, int bdrv_flags)
{
inode_t *inode = NULL;
BDRVGlusterState *s = NULL;
QemuOpts *opts = NULL;
Error *local_err = NULL;
const char *filename = NULL;
opts = qemu_opts_create_nofail(&runtime_opts);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (error_is_set(&local_err)) {
qerror_report_err(local_err);
error_free(local_err);
return -EINVAL;
}
filename = qemu_opt_get(opts, "filename");
inode = qb_inode_from_filename (filename);
if (!inode)
return -EINVAL;
s = bs->opaque;
s->inode = inode_ref (inode);
return 0;
}
static int
qemu_gluster_create (const char *filename, QEMUOptionParameter *options)
{
uint64_t total_size = 0;
inode_t *inode = NULL;
fd_t *fd = NULL;
struct iatt stat = {0, };
int ret = 0;
inode = qb_inode_from_filename (filename);
if (!inode)
return -EINVAL;
while (options && options->name) {
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
total_size = options->value.n / BDRV_SECTOR_SIZE;
}
options++;
}
fd = fd_anonymous (inode);
if (!fd)
return -ENOMEM;
ret = syncop_fstat (FIRST_CHILD(THIS), fd, &stat);
if (ret) {
fd_unref (fd);
return -errno;
}
if (stat.ia_size) {
/* format ONLY if the filesize is 0 bytes */
fd_unref (fd);
return -EFBIG;
}
if (total_size) {
ret = syncop_ftruncate (FIRST_CHILD(THIS), fd, total_size);
if (ret) {
fd_unref (fd);
return -errno;
}
}
fd_unref (fd);
return 0;
}
static int
qemu_gluster_co_readv (BlockDriverState *bs, int64_t sector_num, int nb_sectors,
QEMUIOVector *qiov)
{
fd_t *fd = NULL;
off_t offset = 0;
size_t size = 0;
struct iovec *iov = NULL;
int count = 0;
struct iobref *iobref = NULL;
int ret = 0;
fd = fd_from_bs (bs);
if (!fd)
return -EIO;
offset = sector_num * BDRV_SECTOR_SIZE;
size = nb_sectors * BDRV_SECTOR_SIZE;
ret = syncop_readv (FIRST_CHILD(THIS), fd, size, offset, 0,
&iov, &count, &iobref);
if (ret < 0) {
ret = -errno;
goto out;
}
iov_copy (qiov->iov, qiov->niov, iov, count); /* *choke!* */
out:
GF_FREE (iov);
if (iobref)
iobref_unref (iobref);
fd_unref (fd);
return ret;
}
static int
qemu_gluster_co_writev (BlockDriverState *bs, int64_t sector_num, int nb_sectors,
QEMUIOVector *qiov)
{
fd_t *fd = NULL;
off_t offset = 0;
size_t size = 0;
struct iobref *iobref = NULL;
struct iobuf *iobuf = NULL;
struct iovec iov = {0, };
int ret = -ENOMEM;
fd = fd_from_bs (bs);
if (!fd)
return -EIO;
offset = sector_num * BDRV_SECTOR_SIZE;
size = nb_sectors * BDRV_SECTOR_SIZE;
iobuf = iobuf_get2 (THIS->ctx->iobuf_pool, size);
if (!iobuf)
goto out;
iobref = iobref_new ();
if (!iobref) {
iobuf_unref (iobuf);
goto out;
}
iobref_add (iobref, iobuf);
iov_unload (iobuf_ptr (iobuf), qiov->iov, qiov->niov); /* *choke!* */
iov.iov_base = iobuf_ptr (iobuf);
iov.iov_len = size;
ret = syncop_writev (FIRST_CHILD(THIS), fd, &iov, 1, offset, iobref, 0);
if (ret < 0)
ret = -errno;
out:
if (iobuf)
iobuf_unref (iobuf);
if (iobref)
iobref_unref (iobref);
fd_unref (fd);
return ret;
}
static int
qemu_gluster_co_flush (BlockDriverState *bs)
{
fd_t *fd = NULL;
int ret = 0;
fd = fd_from_bs (bs);
ret = syncop_flush (FIRST_CHILD(THIS), fd);
fd_unref (fd);
return ret;
}
static int
qemu_gluster_co_fsync (BlockDriverState *bs)
{
fd_t *fd = NULL;
int ret = 0;
fd = fd_from_bs (bs);
ret = syncop_fsync (FIRST_CHILD(THIS), fd, 0);
fd_unref (fd);
return ret;
}
static int
qemu_gluster_truncate (BlockDriverState *bs, int64_t offset)
{
fd_t *fd = NULL;
int ret = 0;
fd = fd_from_bs (bs);
ret = syncop_ftruncate (FIRST_CHILD(THIS), fd, offset);
fd_unref (fd);
if (ret < 0)
return ret;
return ret;
}
static int64_t
qemu_gluster_getlength (BlockDriverState *bs)
{
fd_t *fd = NULL;
int ret = 0;
struct iatt iatt = {0, };
fd = fd_from_bs (bs);
ret = syncop_fstat (FIRST_CHILD(THIS), fd, &iatt);
if (ret < 0)
return -1;
return iatt.ia_size;
}
static int64_t
qemu_gluster_allocated_file_size (BlockDriverState *bs)
{
fd_t *fd = NULL;
int ret = 0;
struct iatt iatt = {0, };
fd = fd_from_bs (bs);
ret = syncop_fstat (FIRST_CHILD(THIS), fd, &iatt);
if (ret < 0)
return -1;
return iatt.ia_blocks * 512;
}
static void
qemu_gluster_close (BlockDriverState *bs)
{
BDRVGlusterState *s = NULL;
s = bs->opaque;
inode_unref (s->inode);
return;
}
static QEMUOptionParameter qemu_gluster_create_options[] = {
{
.name = BLOCK_OPT_SIZE,
.type = OPT_SIZE,
.help = "Virtual disk size"
},
{ NULL }
};
static BlockDriver bdrv_gluster = {
.format_name = "gluster",
.protocol_name = "gluster",
.instance_size = sizeof(BDRVGlusterState),
.bdrv_file_open = qemu_gluster_open,
.bdrv_close = qemu_gluster_close,
.bdrv_create = qemu_gluster_create,
.bdrv_getlength = qemu_gluster_getlength,
.bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
.bdrv_co_readv = qemu_gluster_co_readv,
.bdrv_co_writev = qemu_gluster_co_writev,
.bdrv_co_flush_to_os = qemu_gluster_co_flush,
.bdrv_co_flush_to_disk = qemu_gluster_co_fsync,
.bdrv_truncate = qemu_gluster_truncate,
.create_options = qemu_gluster_create_options,
};
static void bdrv_gluster_init(void)
{
bdrv_register(&bdrv_gluster);
}
block_init(bdrv_gluster_init);

View File

@ -0,0 +1,48 @@
/*
Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
This file is part of GlusterFS.
This file is licensed to you under your choice of the GNU Lesser
General Public License, version 3 or any later version (LGPLv3 or
later), or the GNU General Public License, version 2 (GPLv2), in all
cases as published by the Free Software Foundation.
*/
#ifndef _CONFIG_H
#define _CONFIG_H
#include "config.h"
#endif
#include "glusterfs.h"
#include "logging.h"
#include "dict.h"
#include "xlator.h"
#include "syncop.h"
#include "qemu-block-memory-types.h"
#include "block/aio.h"
void
qemu_bh_schedule (QEMUBH *bh)
{
return;
}
void
qemu_bh_cancel (QEMUBH *bh)
{
return;
}
void
qemu_bh_delete (QEMUBH *bh)
{
}
QEMUBH *
qemu_bh_new (QEMUBHFunc *cb, void *opaque)
{
return NULL;
}

View File

@ -0,0 +1,60 @@
/*
Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
This file is part of GlusterFS.
This file is licensed to you under your choice of the GNU Lesser
General Public License, version 3 or any later version (LGPLv3 or
later), or the GNU General Public License, version 2 (GPLv2), in all
cases as published by the Free Software Foundation.
*/
#ifndef _CONFIG_H
#define _CONFIG_H
#include "config.h"
#endif
#include "glusterfs.h"
#include "logging.h"
#include "dict.h"
#include "xlator.h"
#include "syncop.h"
#include "qemu-block-memory-types.h"
#include "qemu/timer.h"
QEMUClock *vm_clock;
int use_rt_clock = 0;
QEMUTimer *qemu_new_timer (QEMUClock *clock, int scale,
QEMUTimerCB *cb, void *opaque)
{
return NULL;
}
int64_t qemu_get_clock_ns (QEMUClock *clock)
{
return 0;
}
void qemu_mod_timer (QEMUTimer *ts, int64_t expire_time)
{
return;
}
void qemu_free_timer (QEMUTimer *ts)
{
}
void qemu_del_timer (QEMUTimer *ts)
{
}
bool qemu_aio_wait()
{
synctask_wake (synctask_get());
synctask_yield (synctask_get());
return 0;
}

View File

@ -0,0 +1,213 @@
/*
Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
This file is part of GlusterFS.
This file is licensed to you under your choice of the GNU Lesser
General Public License, version 3 or any later version (LGPLv3 or
later), or the GNU General Public License, version 2 (GPLv2), in all
cases as published by the Free Software Foundation.
*/
#ifndef _CONFIG_H
#define _CONFIG_H
#include "config.h"
#endif
#include "glusterfs.h"
#include "logging.h"
#include "dict.h"
#include "xlator.h"
#include "syncop.h"
#include "qemu-block-memory-types.h"
#include "qemu-block.h"
#include "coroutine-synctask.h"
void
qemu_coroutine_delete (Coroutine *co_)
{
struct synctask *synctask = NULL;
CoroutineSynctask *cs = NULL;
cs = DO_UPCAST(CoroutineSynctask, base, co_);
synctask = cs->synctask;
cs->die = 1;
synctask_wake (synctask);
/* Do not free either @cs or @synctask here.
@synctask is naturally destroyed when
cs_proc() returns (after "break"ing out of
the loop because of setting cs->die=1 above.
We free @cs too just before returning from
cs_proc()
*/
return;
}
CoroutineAction
qemu_coroutine_switch (Coroutine *from_, Coroutine *to_, CoroutineAction action)
{
struct synctask *to = NULL;
struct synctask *from = NULL;
CoroutineSynctask *csto = NULL;
CoroutineSynctask *csfrom = NULL;
csto = DO_UPCAST(CoroutineSynctask, base, to_);
csfrom = DO_UPCAST(CoroutineSynctask, base, from_);
to = csto->synctask;
from = csfrom->synctask;
/* TODO: need mutex/cond guarding when making syncenv
multithreaded
*/
csfrom->run = false;
csto->run = true;
/* the next three lines must be in this specific order only */
csfrom->action = action;
synctask_wake (to);
synctask_yield (from);
/* the yielder set @action value in @csfrom, but for the
resumer it is @csto
*/
return csto->action;
}
int
cs_fin (int ret, call_frame_t *frame, void *opaque)
{
/* nop */
return 0;
}
static int
cs_proc (void *opaque)
{
CoroutineSynctask *cs = opaque;
struct synctask *synctask = NULL;
synctask = synctask_get (); /* == cs->synctask */
for (;;) {
while (!cs->run && !cs->die)
/* entry function (i.e cs->base.entry) will
not be set just yet first time. Wait for
caller to set it and call switch()
*/
synctask_yield (synctask);
if (cs->die)
break;
cs->base.entry (cs->base.entry_arg);
qemu_coroutine_switch (&cs->base, cs->base.caller,
COROUTINE_TERMINATE);
}
GF_FREE (cs);
return 0;
}
Coroutine *
qemu_coroutine_new()
{
qb_conf_t *conf = NULL;
CoroutineSynctask *cs = NULL;
struct synctask *task = NULL;
conf = THIS->private;
cs = GF_CALLOC (1, sizeof (*cs), gf_qb_mt_coroutinesynctask_t);
if (!cs)
return NULL;
task = synctask_get ();
/* Inherit the frame from the parent synctask, as this will
carry forward things like uid, gid, pid, lkowner etc. of the
caller properly.
*/
cs->synctask = synctask_create (conf->env, cs_proc, cs_fin,
task ? task->frame : NULL, cs);
if (!cs->synctask)
return NULL;
return &cs->base;
}
Coroutine *
qemu_coroutine_self()
{
struct synctask *synctask = NULL;
CoroutineSynctask *cs = NULL;
synctask = synctask_get();
cs = synctask->opaque;
return &cs->base;
}
bool
qemu_in_coroutine ()
{
Coroutine *co = NULL;
co = qemu_coroutine_self ();
return co && co->caller;
}
/* These are calls for the "top" xlator to invoke/submit
coroutines
*/
static int
synctask_nop_cbk (int ret, call_frame_t *frame, void *opaque)
{
return 0;
}
int
qb_synctask_wrap (void *opaque)
{
struct synctask *task = NULL;
CoroutineSynctask *cs = NULL;
qb_local_t *qb_local = NULL;
task = synctask_get ();
cs = opaque;
cs->synctask = task;
qb_local = DO_UPCAST (qb_local_t, cs, cs);
return qb_local->synctask_fn (opaque);
}
int
qb_coroutine (call_frame_t *frame, synctask_fn_t fn)
{
qb_local_t *qb_local = NULL;
qb_conf_t *qb_conf = NULL;
qb_local = frame->local;
qb_local->synctask_fn = fn;
qb_conf = frame->this->private;
return synctask_new (qb_conf->env, qb_synctask_wrap, synctask_nop_cbk,
frame, &qb_local->cs);
}

View File

@ -0,0 +1,51 @@
/*
Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
This file is part of GlusterFS.
This file is licensed to you under your choice of the GNU Lesser
General Public License, version 3 or any later version (LGPLv3 or
later), or the GNU General Public License, version 2 (GPLv2), in all
cases as published by the Free Software Foundation.
*/
#ifndef __COROUTINE_SYNCTASK_H
#define __COROUTINE_SYNCTASK_H
#include "syncop.h"
#include "block/coroutine_int.h"
#include "qemu-common.h"
#include "block/coroutine_int.h"
/*
Three entities:
synctask - glusterfs implementation of xlator friendly lightweight threads
Coroutine - qemu coroutine API for its block drivers
CoroutineSynctask - implementation of Coroutine using synctasks
Coroutine is an "embedded" structure inside CoroutineSynctask, called "base".
E.g:
Coroutine *co;
CoroutineSynctask *cs;
struct synctask *synctask;
cs == synctask->opaque;
co == &(cs->base);
cs = DO_UPCAST(CoroutineSynctask, base, co);
synctask == cs->synctask;
*/
typedef struct {
Coroutine base;
struct synctask *synctask;
CoroutineAction action;
bool run;
bool die;
} CoroutineSynctask;
#endif /* !__COROUTINE_SYNCTASK_H */

View File

@ -0,0 +1,50 @@
/*
Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
This file is part of GlusterFS.
This file is licensed to you under your choice of the GNU Lesser
General Public License, version 3 or any later version (LGPLv3 or
later), or the GNU General Public License, version 2 (GPLv2), in all
cases as published by the Free Software Foundation.
*/
#ifndef _CONFIG_H
#define _CONFIG_H
#include "config.h"
#endif
#include "glusterfs.h"
#include "logging.h"
#include "dict.h"
#include "xlator.h"
#include "qemu-block-memory-types.h"
#include "block/block_int.h"
Monitor *cur_mon;
int
monitor_cur_is_qmp()
{
/* No QMP support here */
return 0;
}
void
monitor_set_error (Monitor *mon, QError *qerror)
{
/* NOP here */
return;
}
void
monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
{
char buf[4096];
vsnprintf(buf, sizeof(buf), fmt, ap);
gf_log (THIS->name, GF_LOG_ERROR, "%s", buf);
}

View File

@ -0,0 +1,629 @@
/*
Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
This file is part of GlusterFS.
This file is licensed to you under your choice of the GNU Lesser
General Public License, version 3 or any later version (LGPLv3 or
later), or the GNU General Public License, version 2 (GPLv2), in all
cases as published by the Free Software Foundation.
*/
#ifndef _CONFIG_H
#define _CONFIG_H
#include "config.h"
#endif
#include "glusterfs.h"
#include "logging.h"
#include "dict.h"
#include "xlator.h"
#include "inode.h"
#include "call-stub.h"
#include "defaults.h"
#include "qemu-block-memory-types.h"
#include "qemu-block.h"
#include "qb-coroutines.h"
int
qb_format_and_resume (void *opaque)
{
CoroutineSynctask *cs = NULL;
qb_local_t *local = NULL;
call_frame_t *frame = NULL;
call_stub_t *stub = NULL;
inode_t *inode = NULL;
char filename[64];
qb_inode_t *qb_inode = NULL;
Error *local_err = NULL;
fd_t *fd = NULL;
dict_t *xattr = NULL;
qb_conf_t *qb_conf = NULL;
int ret = -1;
cs = opaque;
local = DO_UPCAST(qb_local_t, cs, cs);
frame = local->frame;
stub = local->stub;
inode = local->inode;
qb_conf = frame->this->private;
qb_inode_to_filename (inode, filename, 64);
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);
if (error_is_set (&local_err)) {
gf_log (frame->this->name, GF_LOG_ERROR, "%s",
error_get_pretty (local_err));
error_free (local_err);
QB_STUB_UNWIND (stub, -1, EIO);
return 0;
}
fd = fd_anonymous (inode);
if (!fd) {
gf_log (frame->this->name, GF_LOG_ERROR,
"could not create anonymous fd for %s",
uuid_utoa (inode->gfid));
QB_STUB_UNWIND (stub, -1, ENOMEM);
return 0;
}
xattr = dict_new ();
if (!xattr) {
gf_log (frame->this->name, GF_LOG_ERROR,
"could not allocate xattr dict for %s",
uuid_utoa (inode->gfid));
QB_STUB_UNWIND (stub, -1, ENOMEM);
fd_unref (fd);
return 0;
}
ret = dict_set_str (xattr, qb_conf->qb_xattr_key, local->fmt);
if (ret) {
gf_log (frame->this->name, GF_LOG_ERROR,
"could not dict_set for %s",
uuid_utoa (inode->gfid));
QB_STUB_UNWIND (stub, -1, ENOMEM);
fd_unref (fd);
dict_unref (xattr);
return 0;
}
ret = syncop_fsetxattr (FIRST_CHILD(THIS), fd, xattr, 0);
if (ret) {
ret = errno;
gf_log (frame->this->name, GF_LOG_ERROR,
"failed to setxattr for %s",
uuid_utoa (inode->gfid));
QB_STUB_UNWIND (stub, -1, ret);
fd_unref (fd);
dict_unref (xattr);
return 0;
}
fd_unref (fd);
dict_unref (xattr);
QB_STUB_UNWIND (stub, 0, 0);
return 0;
}
static BlockDriverState *
qb_bs_create (inode_t *inode, const char *fmt)
{
char filename[64];
BlockDriverState *bs = NULL;
BlockDriver *drv = NULL;
int op_errno = 0;
int ret = 0;
bs = bdrv_new (uuid_utoa (inode->gfid));
if (!bs) {
op_errno = ENOMEM;
gf_log (THIS->name, GF_LOG_ERROR,
"could not allocate @bdrv for gfid:%s",
uuid_utoa (inode->gfid));
goto err;
}
drv = bdrv_find_format (fmt);
if (!drv) {
op_errno = EINVAL;
gf_log (THIS->name, GF_LOG_ERROR,
"Unknown file format: %s for gfid:%s",
fmt, uuid_utoa (inode->gfid));
goto err;
}
qb_inode_to_filename (inode, filename, 64);
ret = bdrv_open (bs, filename, NULL, BDRV_O_RDWR, drv);
if (ret < 0) {
op_errno = -ret;
gf_log (THIS->name, GF_LOG_ERROR,
"Unable to bdrv_open() gfid:%s (%s)",
uuid_utoa (inode->gfid), strerror (op_errno));
goto err;
}
return bs;
err:
errno = op_errno;
return NULL;
}
int
qb_co_open (void *opaque)
{
CoroutineSynctask *cs = NULL;
qb_local_t *local = NULL;
call_frame_t *frame = NULL;
call_stub_t *stub = NULL;
inode_t *inode = NULL;
qb_inode_t *qb_inode = NULL;
cs = opaque;
local = DO_UPCAST(qb_local_t, cs, cs);
frame = local->frame;
stub = local->stub;
inode = local->inode;
qb_inode = qb_inode_ctx_get (frame->this, inode);
if (!qb_inode->bs) {
/* FIXME: we need locks around this when
enabling multithreaded syncop/coroutine
for qemu-block
*/
qb_inode->bs = qb_bs_create (inode, qb_inode->fmt);
if (!qb_inode->bs) {
QB_STUB_UNWIND (stub, -1, errno);
return 0;
}
}
qb_inode->refcnt++;
QB_STUB_RESUME (stub);
return 0;
}
int
qb_co_writev (void *opaque)
{
CoroutineSynctask *cs = NULL;
qb_local_t *local = NULL;
call_frame_t *frame = NULL;
call_stub_t *stub = NULL;
inode_t *inode = NULL;
qb_inode_t *qb_inode = NULL;
QEMUIOVector qiov = {0, };
int ret = 0;
cs = opaque;
local = DO_UPCAST(qb_local_t, cs, cs);
frame = local->frame;
stub = local->stub;
inode = local->inode;
qb_inode = qb_inode_ctx_get (frame->this, inode);
if (!qb_inode->bs) {
/* FIXME: we need locks around this when
enabling multithreaded syncop/coroutine
for qemu-block
*/
qb_inode->bs = qb_bs_create (inode, qb_inode->fmt);
if (!qb_inode->bs) {
QB_STUB_UNWIND (stub, -1, errno);
return 0;
}
}
qemu_iovec_init_external (&qiov, stub->args.vector, stub->args.count);
ret = bdrv_pwritev (qb_inode->bs, stub->args.offset, &qiov);
if (ret < 0) {
QB_STUB_UNWIND (stub, -1, -ret);
} else {
QB_STUB_UNWIND (stub, ret, 0);
}
return 0;
}
int
qb_co_readv (void *opaque)
{
CoroutineSynctask *cs = NULL;
qb_local_t *local = NULL;
call_frame_t *frame = NULL;
call_stub_t *stub = NULL;
inode_t *inode = NULL;
qb_inode_t *qb_inode = NULL;
struct iobuf *iobuf = NULL;
struct iobref *iobref = NULL;
struct iovec iov = {0, };
int ret = 0;
cs = opaque;
local = DO_UPCAST(qb_local_t, cs, cs);
frame = local->frame;
stub = local->stub;
inode = local->inode;
qb_inode = qb_inode_ctx_get (frame->this, inode);
if (!qb_inode->bs) {
/* FIXME: we need locks around this when
enabling multithreaded syncop/coroutine
for qemu-block
*/
qb_inode->bs = qb_bs_create (inode, qb_inode->fmt);
if (!qb_inode->bs) {
QB_STUB_UNWIND (stub, -1, errno);
return 0;
}
}
if (stub->args.offset >= qb_inode->size) {
QB_STUB_UNWIND (stub, 0, 0);
return 0;
}
iobuf = iobuf_get2 (frame->this->ctx->iobuf_pool, stub->args.size);
if (!iobuf) {
QB_STUB_UNWIND (stub, -1, ENOMEM);
return 0;
}
iobref = iobref_new ();
if (!iobref) {
QB_STUB_UNWIND (stub, -1, ENOMEM);
iobuf_unref (iobuf);
return 0;
}
if (iobref_add (iobref, iobuf) < 0) {
iobuf_unref (iobuf);
iobref_unref (iobref);
QB_STUB_UNWIND (stub, -1, ENOMEM);
return 0;
}
ret = bdrv_pread (qb_inode->bs, stub->args.offset, iobuf_ptr (iobuf),
stub->args.size);
if (ret < 0) {
QB_STUB_UNWIND (stub, -1, -ret);
iobref_unref (iobref);
return 0;
}
iov.iov_base = iobuf_ptr (iobuf);
iov.iov_len = ret;
stub->args_cbk.vector = iov_dup (&iov, 1);
stub->args_cbk.count = 1;
stub->args_cbk.iobref = iobref;
QB_STUB_UNWIND (stub, ret, 0);
return 0;
}
int
qb_co_fsync (void *opaque)
{
CoroutineSynctask *cs = NULL;
qb_local_t *local = NULL;
call_frame_t *frame = NULL;
call_stub_t *stub = NULL;
inode_t *inode = NULL;
qb_inode_t *qb_inode = NULL;
int ret = 0;
cs = opaque;
local = DO_UPCAST(qb_local_t, cs, cs);
frame = local->frame;
stub = local->stub;
inode = local->inode;
qb_inode = qb_inode_ctx_get (frame->this, inode);
if (!qb_inode->bs) {
/* FIXME: we need locks around this when
enabling multithreaded syncop/coroutine
for qemu-block
*/
qb_inode->bs = qb_bs_create (inode, qb_inode->fmt);
if (!qb_inode->bs) {
QB_STUB_UNWIND (stub, -1, errno);
return 0;
}
}
ret = bdrv_flush (qb_inode->bs);
if (ret < 0) {
QB_STUB_UNWIND (stub, -1, -ret);
} else {
QB_STUB_UNWIND (stub, ret, 0);
}
return 0;
}
static void
qb_update_size_xattr (xlator_t *this, fd_t *fd, const char *fmt, off_t offset)
{
char val[QB_XATTR_VAL_MAX];
qb_conf_t *qb_conf = NULL;
dict_t *xattr = NULL;
qb_conf = this->private;
snprintf (val, QB_XATTR_VAL_MAX, "%s:%llu",
fmt, (long long unsigned) offset);
xattr = dict_new ();
if (!xattr)
return;
if (dict_set_str (xattr, qb_conf->qb_xattr_key, val) != 0) {
dict_unref (xattr);
return;
}
syncop_fsetxattr (FIRST_CHILD(this), fd, xattr, 0);
dict_unref (xattr);
}
int
qb_co_truncate (void *opaque)
{
CoroutineSynctask *cs = NULL;
qb_local_t *local = NULL;
call_frame_t *frame = NULL;
call_stub_t *stub = NULL;
inode_t *inode = NULL;
qb_inode_t *qb_inode = NULL;
int ret = 0;
off_t offset = 0;
xlator_t *this = NULL;
this = THIS;
cs = opaque;
local = DO_UPCAST(qb_local_t, cs, cs);
frame = local->frame;
stub = local->stub;
inode = local->inode;
qb_inode = qb_inode_ctx_get (frame->this, inode);
if (!qb_inode->bs) {
/* FIXME: we need locks around this when
enabling multithreaded syncop/coroutine
for qemu-block
*/
qb_inode->bs = qb_bs_create (inode, qb_inode->fmt);
if (!qb_inode->bs) {
QB_STUB_UNWIND (stub, -1, errno);
return 0;
}
}
syncop_fstat (FIRST_CHILD(this), local->fd, &stub->args_cbk.prestat);
stub->args_cbk.prestat.ia_size = qb_inode->size;
ret = bdrv_truncate (qb_inode->bs, stub->args.offset);
if (ret < 0)
goto out;
offset = bdrv_getlength (qb_inode->bs);
qb_inode->size = offset;
syncop_fstat (FIRST_CHILD(this), local->fd, &stub->args_cbk.poststat);
stub->args_cbk.poststat.ia_size = qb_inode->size;
qb_update_size_xattr (this, local->fd, qb_inode->fmt, qb_inode->size);
out:
if (ret < 0) {
QB_STUB_UNWIND (stub, -1, -ret);
} else {
QB_STUB_UNWIND (stub, ret, 0);
}
return 0;
}
int
qb_co_close (void *opaque)
{
CoroutineSynctask *cs = NULL;
qb_local_t *local = NULL;
call_frame_t *frame = NULL;
inode_t *inode = NULL;
qb_inode_t *qb_inode = NULL;
BlockDriverState *bs = NULL;
local = DO_UPCAST(qb_local_t, cs, cs);
inode = local->inode;
qb_inode = qb_inode_ctx_get (THIS, inode);
if (!--qb_inode->refcnt) {
bs = qb_inode->bs;
qb_inode->bs = NULL;
bdrv_delete (bs);
}
frame = local->frame;
frame->local = NULL;
qb_local_free (THIS, local);
STACK_DESTROY (frame->root);
return 0;
}
int
qb_snapshot_create (void *opaque)
{
CoroutineSynctask *cs = NULL;
qb_local_t *local = NULL;
call_frame_t *frame = NULL;
call_stub_t *stub = NULL;
inode_t *inode = NULL;
qb_inode_t *qb_inode = NULL;
QEMUSnapshotInfo sn;
struct timeval tv = {0, };
int ret = 0;
cs = opaque;
local = DO_UPCAST(qb_local_t, cs, cs);
frame = local->frame;
stub = local->stub;
inode = local->inode;
qb_inode = qb_inode_ctx_get (frame->this, inode);
if (!qb_inode->bs) {
/* FIXME: we need locks around this when
enabling multithreaded syncop/coroutine
for qemu-block
*/
qb_inode->bs = qb_bs_create (inode, qb_inode->fmt);
if (!qb_inode->bs) {
QB_STUB_UNWIND (stub, -1, errno);
return 0;
}
}
memset (&sn, 0, sizeof (sn));
pstrcpy (sn.name, sizeof(sn.name), local->name);
gettimeofday (&tv, NULL);
sn.date_sec = tv.tv_sec;
sn.date_nsec = tv.tv_usec * 1000;
ret = bdrv_snapshot_create (qb_inode->bs, &sn);
if (ret < 0) {
QB_STUB_UNWIND (stub, -1, -ret);
} else {
QB_STUB_UNWIND (stub, ret, 0);
}
return 0;
}
int
qb_snapshot_delete (void *opaque)
{
CoroutineSynctask *cs = NULL;
qb_local_t *local = NULL;
call_frame_t *frame = NULL;
call_stub_t *stub = NULL;
inode_t *inode = NULL;
qb_inode_t *qb_inode = NULL;
int ret = 0;
cs = opaque;
local = DO_UPCAST(qb_local_t, cs, cs);
frame = local->frame;
stub = local->stub;
inode = local->inode;
qb_inode = qb_inode_ctx_get (frame->this, inode);
if (!qb_inode->bs) {
/* FIXME: we need locks around this when
enabling multithreaded syncop/coroutine
for qemu-block
*/
qb_inode->bs = qb_bs_create (inode, qb_inode->fmt);
if (!qb_inode->bs) {
QB_STUB_UNWIND (stub, -1, errno);
return 0;
}
}
ret = bdrv_snapshot_delete (qb_inode->bs, local->name);
if (ret < 0) {
QB_STUB_UNWIND (stub, -1, -ret);
} else {
QB_STUB_UNWIND (stub, ret, 0);
}
return 0;
}
int
qb_snapshot_goto (void *opaque)
{
CoroutineSynctask *cs = NULL;
qb_local_t *local = NULL;
call_frame_t *frame = NULL;
call_stub_t *stub = NULL;
inode_t *inode = NULL;
qb_inode_t *qb_inode = NULL;
int ret = 0;
cs = opaque;
local = DO_UPCAST(qb_local_t, cs, cs);
frame = local->frame;
stub = local->stub;
inode = local->inode;
qb_inode = qb_inode_ctx_get (frame->this, inode);
if (!qb_inode->bs) {
/* FIXME: we need locks around this when
enabling multithreaded syncop/coroutine
for qemu-block
*/
qb_inode->bs = qb_bs_create (inode, qb_inode->fmt);
if (!qb_inode->bs) {
QB_STUB_UNWIND (stub, -1, errno);
return 0;
}
}
ret = bdrv_snapshot_goto (qb_inode->bs, local->name);
if (ret < 0) {
QB_STUB_UNWIND (stub, -1, -ret);
} else {
QB_STUB_UNWIND (stub, ret, 0);
}
return 0;
}

View File

@ -0,0 +1,31 @@
/*
Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
This file is part of GlusterFS.
This file is licensed to you under your choice of the GNU Lesser
General Public License, version 3 or any later version (LGPLv3 or
later), or the GNU General Public License, version 2 (GPLv2), in all
cases as published by the Free Software Foundation.
*/
#ifndef __QB_COROUTINES_H
#define __QB_COROUTINES_H
#include "syncop.h"
#include "call-stub.h"
#include "block/block_int.h"
#include "monitor/monitor.h"
#include "coroutine-synctask.h"
int qb_format_and_resume (void *opaque);
int qb_snapshot_create (void *opaque);
int qb_snapshot_delete (void *opaque);
int qb_snapshot_goto (void *opaque);
int qb_co_open (void *opaque);
int qb_co_close (void *opaque);
int qb_co_writev (void *opaque);
int qb_co_readv (void *opaque);
int qb_co_fsync (void *opaque);
int qb_co_truncate (void *opaque);
#endif /* __QB_COROUTINES_H */

View File

@ -0,0 +1,25 @@
/*
Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
This file is part of GlusterFS.
This file is licensed to you under your choice of the GNU Lesser
General Public License, version 3 or any later version (LGPLv3 or
later), or the GNU General Public License, version 2 (GPLv2), in all
cases as published by the Free Software Foundation.
*/
#ifndef __QB_MEM_TYPES_H__
#define __QB_MEM_TYPES_H__
#include "mem-types.h"
enum gf_qb_mem_types_ {
gf_qb_mt_qb_conf_t = gf_common_mt_end + 1,
gf_qb_mt_qb_inode_t,
gf_qb_mt_qb_local_t,
gf_qb_mt_coroutinesynctask_t,
gf_qb_mt_end
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,107 @@
/*
Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
This file is part of GlusterFS.
This file is licensed to you under your choice of the GNU Lesser
General Public License, version 3 or any later version (LGPLv3 or
later), or the GNU General Public License, version 2 (GPLv2), in all
cases as published by the Free Software Foundation.
*/
#ifndef __QEMU_BLOCK_H
#define __QEMU_BLOCK_H
#include "syncop.h"
#include "call-stub.h"
#include "block/block_int.h"
#include "monitor/monitor.h"
#include "coroutine-synctask.h"
/* QB_XATTR_KEY_FMT is the on-disk xattr stored in the inode which
indicates that the file must be "interpreted" by the block format
logic. The value of the key is of the pattern:
"format:virtual_size"
e.g
"qcow2:20GB" or "qed:100GB"
The format and virtual size are colon separated. The format is
a case sensitive string which qemu recognizes. virtual_size is
specified as a size which glusterfs recognizes as size (i.e.,
value accepted by gf_string2bytesize())
*/
#define QB_XATTR_KEY_FMT "trusted.glusterfs.%s.format"
#define QB_XATTR_KEY_MAX 64
#define QB_XATTR_VAL_MAX 32
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;
} qb_inode_t;
typedef struct qb_conf {
Monitor *mon;
struct syncenv *env;
char qb_xattr_key[QB_XATTR_KEY_MAX];
char *default_password;
} qb_conf_t;
typedef struct qb_local {
CoroutineSynctask cs;
call_frame_t *frame; /* backpointer */
call_stub_t *stub;
inode_t *inode;
fd_t *fd;
char fmt[QB_XATTR_VAL_MAX+1];
char name[256];
synctask_fn_t synctask_fn;
} qb_local_t;
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);
qb_inode_t *qb_inode_ctx_get (xlator_t *this, inode_t *inode);
#define QB_STACK_UNWIND(typ, frame, args ...) do { \
qb_local_t *__local = frame->local; \
xlator_t *__this = frame->this; \
\
frame->local = NULL; \
STACK_UNWIND_STRICT (typ, frame, args); \
if (__local) \
qb_local_free (__this, __local); \
} while (0)
#define QB_STUB_UNWIND(stub, op_ret, op_errno) do { \
qb_local_t *__local = stub->frame->local; \
xlator_t *__this = stub->frame->this; \
\
stub->frame->local = NULL; \
call_unwind_error (stub, op_ret, op_errno); \
if (__local) \
qb_local_free (__this, __local); \
} while (0)
#define QB_STUB_RESUME(stub_errno) do { \
qb_local_t *__local = stub->frame->local; \
xlator_t *__this = stub->frame->this; \
\
stub->frame->local = NULL; \
call_resume (stub); \
if (__local) \
qb_local_free (__this, __local); \
} while (0)
#endif /* !__QEMU_BLOCK_H */

View File

@ -2474,6 +2474,19 @@ client_graph_builder (volgen_graph_t *graph, glusterd_volinfo_t *volinfo,
}
}
ret = glusterd_volinfo_get_boolean (volinfo, "features.file-snapshot");
if (ret == -1)
goto out;
if (ret) {
xl = volgen_graph_add (graph, "features/qemu-block", volname);
if (!xl) {
ret = -1;
goto out;
}
}
/* Logic to make sure NFS doesn't have performance translators by
default for a volume */
tmp_data = dict_get (set_dict, "nfs-volume-file");

View File

@ -944,6 +944,17 @@ struct volopt_map_entry glusterd_volopt_map[] = {
.flags = OPT_FLAG_CLIENT_OPT
},
/* Feature translators */
{ .key = "features.file-snapshot",
.voltype = "features/qemu-block",
.option = "!feat",
.value = "off",
.op_version = 3,
.description = "enable/disable file-snapshot feature in the "
"volume.",
.flags = OPT_FLAG_CLIENT_OPT | OPT_FLAG_XLATOR_OPT
},
/* Quota xlator options */
{ .key = VKEY_FEATURES_LIMIT_USAGE,
.voltype = "features/quota",