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:
parent
0d60175bd6
commit
53e98f11d1
30
configure.ac
30
configure.ac
@ -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
|
||||
|
12
contrib/qemu/nop-symbols.c
Normal file
12
contrib/qemu/nop-symbols.c
Normal 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
55
tests/basic/file-snapshot.t
Executable 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;
|
@ -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 =
|
||||
|
1
xlators/features/qemu-block/Makefile.am
Normal file
1
xlators/features/qemu-block/Makefile.am
Normal file
@ -0,0 +1 @@
|
||||
SUBDIRS = src
|
147
xlators/features/qemu-block/src/Makefile.am
Normal file
147
xlators/features/qemu-block/src/Makefile.am
Normal 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
|
366
xlators/features/qemu-block/src/bdrv-xlator.c
Normal file
366
xlators/features/qemu-block/src/bdrv-xlator.c
Normal 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);
|
48
xlators/features/qemu-block/src/bh-syncop.c
Normal file
48
xlators/features/qemu-block/src/bh-syncop.c
Normal 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;
|
||||
}
|
60
xlators/features/qemu-block/src/clock-timer.c
Normal file
60
xlators/features/qemu-block/src/clock-timer.c
Normal 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;
|
||||
}
|
213
xlators/features/qemu-block/src/coroutine-synctask.c
Normal file
213
xlators/features/qemu-block/src/coroutine-synctask.c
Normal 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);
|
||||
}
|
51
xlators/features/qemu-block/src/coroutine-synctask.h
Normal file
51
xlators/features/qemu-block/src/coroutine-synctask.h
Normal 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 */
|
50
xlators/features/qemu-block/src/monitor-logging.c
Normal file
50
xlators/features/qemu-block/src/monitor-logging.c
Normal 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);
|
||||
}
|
629
xlators/features/qemu-block/src/qb-coroutines.c
Normal file
629
xlators/features/qemu-block/src/qb-coroutines.c
Normal 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;
|
||||
}
|
31
xlators/features/qemu-block/src/qb-coroutines.h
Normal file
31
xlators/features/qemu-block/src/qb-coroutines.h
Normal 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 */
|
25
xlators/features/qemu-block/src/qemu-block-memory-types.h
Normal file
25
xlators/features/qemu-block/src/qemu-block-memory-types.h
Normal 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
|
||||
|
1028
xlators/features/qemu-block/src/qemu-block.c
Normal file
1028
xlators/features/qemu-block/src/qemu-block.c
Normal file
File diff suppressed because it is too large
Load Diff
107
xlators/features/qemu-block/src/qemu-block.h
Normal file
107
xlators/features/qemu-block/src/qemu-block.h
Normal 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 */
|
@ -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");
|
||||
|
@ -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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user