Skip to content

Commit

Permalink
block/gluster: prevent data loss after i/o error
Browse files Browse the repository at this point in the history
Upon receiving an I/O error after an fsync, by default gluster will
dump its cache.  However, QEMU will retry the fsync, which is especially
useful when encountering errors such as ENOSPC when using the werror=stop
option.  When using caching with gluster, however, the last written data
will be lost upon encountering ENOSPC.  Using the write-behind-cache
xlator option of 'resync-failed-syncs-after-fsync' should cause gluster
to retain the cached data after a failed fsync, so that ENOSPC and other
transient errors are recoverable.

Unfortunately, we have no way of knowing if the
'resync-failed-syncs-after-fsync' xlator option is supported, so for now
close the fd and set the BDS driver to NULL upon fsync error.

Signed-off-by: Jeff Cody <[email protected]>
  • Loading branch information
codyprime committed Apr 19, 2016
1 parent 5d4343e commit d85fa9e
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 1 deletion.
53 changes: 52 additions & 1 deletion block/gluster.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,23 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
goto out;
}

#ifdef CONFIG_GLUSTERFS_XLATOR_OPT
/* Without this, if fsync fails for a recoverable reason (for instance,
* ENOSPC), gluster will dump its cache, preventing retries. This means
* almost certain data loss. Not all gluster versions support the
* 'resync-failed-syncs-after-fsync' key value, but there is no way to
* discover during runtime if it is supported (this api returns success for
* unknown key/value pairs) */
ret = glfs_set_xlator_option(s->glfs, "*-write-behind",
"resync-failed-syncs-after-fsync",
"on");
if (ret < 0) {
error_setg_errno(errp, errno, "Unable to set xlator key/value pair");
ret = -errno;
goto out;
}
#endif

qemu_gluster_parse_flags(bdrv_flags, &open_flags);

s->fd = glfs_open(s->glfs, gconf->image, open_flags);
Expand Down Expand Up @@ -366,6 +383,16 @@ static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
goto exit;
}

#ifdef CONFIG_GLUSTERFS_XLATOR_OPT
ret = glfs_set_xlator_option(reop_s->glfs, "*-write-behind",
"resync-failed-syncs-after-fsync", "on");
if (ret < 0) {
error_setg_errno(errp, errno, "Unable to set xlator key/value pair");
ret = -errno;
goto exit;
}
#endif

reop_s->fd = glfs_open(reop_s->glfs, gconf->image, open_flags);
if (reop_s->fd == NULL) {
/* reops->glfs will be cleaned up in _abort */
Expand Down Expand Up @@ -613,11 +640,35 @@ static coroutine_fn int qemu_gluster_co_flush_to_disk(BlockDriverState *bs)

ret = glfs_fsync_async(s->fd, gluster_finish_aiocb, &acb);
if (ret < 0) {
return -errno;
ret = -errno;
goto error;
}

qemu_coroutine_yield();
if (acb.ret < 0) {
ret = acb.ret;
goto error;
}

return acb.ret;

error:
/* Some versions of Gluster (3.5.6 -> 3.5.8?) will not retain its cache
* after a fsync failure, so we have no way of allowing the guest to safely
* continue. Gluster versions prior to 3.5.6 don't retain the cache
* either, but will invalidate the fd on error, so this is again our only
* option.
*
* The 'resync-failed-syncs-after-fsync' xlator option for the
* write-behind cache will cause later gluster versions to retain its
* cache after error, so long as the fd remains open. However, we
* currently have no way of knowing if this option is supported.
*
* TODO: Once gluster provides a way for us to determine if the option
* is supported, bypass the closure and setting drv to NULL. */
qemu_gluster_close(bs);
bs->drv = NULL;
return ret;
}

#ifdef CONFIG_GLUSTERFS_DISCARD
Expand Down
8 changes: 8 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ coroutine=""
coroutine_pool=""
seccomp=""
glusterfs=""
glusterfs_xlator_opt="no"
glusterfs_discard="no"
glusterfs_zerofill="no"
archipelago="no"
Expand Down Expand Up @@ -3400,6 +3401,9 @@ if test "$glusterfs" != "no" ; then
glusterfs="yes"
glusterfs_cflags=`$pkg_config --cflags glusterfs-api`
glusterfs_libs=`$pkg_config --libs glusterfs-api`
if $pkg_config --atleast-version=4 glusterfs-api; then
glusterfs_xlator_opt="yes"
fi
if $pkg_config --atleast-version=5 glusterfs-api; then
glusterfs_discard="yes"
fi
Expand Down Expand Up @@ -5342,6 +5346,10 @@ if test "$glusterfs" = "yes" ; then
echo "GLUSTERFS_LIBS=$glusterfs_libs" >> $config_host_mak
fi

if test "$glusterfs_xlator_opt" = "yes" ; then
echo "CONFIG_GLUSTERFS_XLATOR_OPT=y" >> $config_host_mak
fi

if test "$glusterfs_discard" = "yes" ; then
echo "CONFIG_GLUSTERFS_DISCARD=y" >> $config_host_mak
fi
Expand Down

0 comments on commit d85fa9e

Please sign in to comment.