qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/18] block: Allow exporting BDSs via FUSE
@ 2019-12-19 14:38 Max Reitz
  2019-12-19 14:38 ` [PATCH 01/18] configure: Detect libfuse Max Reitz
                   ` (19 more replies)
  0 siblings, 20 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-19 14:38 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-devel, Max Reitz

Preamble: This series is based on a combination of my (current) block
branch and “iotests: Minor fixes”.  I’ve pushed it here:

  https://git.xanclic.moe/XanClic/qemu fuse-exports-v1

(The base is on fuse-exports-v1-base.)


Hi,

Ever since I found out that you can mount FUSE filesystems on regular
files (not just directories), I had the idea of adding FUSE block
exports to qemu where you can export block nodes as raw images.  The
best thing is that you’d be able to mount an image on itself, so
whatever format it may be in, qemu lets it appear as a raw image (and
you can then use regular tools like dd on it).

I started with some concept of a qemu-blkfuse daemon (similar to
qemu-nbd), but never sent patches, for two reasons: (1) Performance was
not good, (2) it didn’t seem right, for some reason.

Now Kevin is proposing a storage daemon for multiple export types like
NBD, and he also mentioned FUSE (while knowing of my previous attempts).
Now it does seem right to add FUSE exports to qemu, but only in the form
of some module with a proper QAPI/QMP binding.

Performance is still quite bad, but who cares.  We can always improve
it, if the need arises.


This series does the following:

First, add the FUSE export module (block/fuse.c) that implements the
basic file access functions.  (Note that you need libfuse 3.8.0 or later
for SEEK_HOLE/SEEK_DATA.)

Second, it allows using FUSE exports as a protocol in the iotests and
makes many iotests work with it.  (The file node is exported by a
background qemu instance to $SOCK_DIR.)
Note that I only ran raw and qcow2 on it; I’m sure other formats
currently have some failing tests.

This gives us a lot of coverage for, well, not free (it does take ten
patches), but for cheap; but there are still some more specialized
things we want to test, so third and last, this series adds an iotest
dedicated to FUSE exports.


Final rather important notice: I didn’t really run the iotests with this
yet.  I wanted to, but they appear rather broken on current master,
actually.  I’m not yet sure whether that’s because something in my setup
broke in the last two weeks, or because there’s quite something broken
in master (it does look like there are a couple things broken in master
currently).


Max Reitz (18):
  configure: Detect libfuse
  fuse: Allow exporting BDSs via FUSE
  fuse: Implement standard FUSE operations
  fuse: Add fuse-export-remove
  fuse: Allow growable exports
  fuse: (Partially) implement fallocate()
  fuse: Implement hole detection through lseek
  iotests: Do not needlessly filter _make_test_img
  iotests: Do not pipe _make_test_img
  iotests: Use convert -n in some cases
  iotests: Avoid renaming images
  iotests: Derive image names from $TEST_IMG
  iotests/091: Use _cleanup_qemu instad of "wait"
  iotests: Restrict some Python tests to file
  iotests: Let _make_test_img guess $TEST_IMG_FILE
  iotests: Allow testing FUSE exports
  iotests: Enable fuse for many tests
  iotests/281: Add test for FUSE exports

 block.c                          |   4 +
 block/Makefile.objs              |   3 +
 block/fuse.c                     | 668 +++++++++++++++++++++++++++++++
 configure                        |  68 ++++
 include/block/fuse.h             |  24 ++
 qapi/block.json                  |  42 ++
 tests/qemu-iotests/013           |   9 +-
 tests/qemu-iotests/013.out       |   3 +-
 tests/qemu-iotests/018           |   5 +-
 tests/qemu-iotests/018.out       |   1 +
 tests/qemu-iotests/020           |   2 +-
 tests/qemu-iotests/025           |   2 +-
 tests/qemu-iotests/026           |   2 +-
 tests/qemu-iotests/028           |  16 +-
 tests/qemu-iotests/028.out       |   3 +
 tests/qemu-iotests/031           |   2 +-
 tests/qemu-iotests/034           |   2 +-
 tests/qemu-iotests/036           |   2 +-
 tests/qemu-iotests/037           |   2 +-
 tests/qemu-iotests/038           |   2 +-
 tests/qemu-iotests/039           |   2 +-
 tests/qemu-iotests/046           |   7 +-
 tests/qemu-iotests/046.out       |   2 +-
 tests/qemu-iotests/050           |   2 +-
 tests/qemu-iotests/054           |   2 +-
 tests/qemu-iotests/060           |   2 +-
 tests/qemu-iotests/071           |  21 +-
 tests/qemu-iotests/072           |   5 +-
 tests/qemu-iotests/072.out       |   1 +
 tests/qemu-iotests/079           |   2 +-
 tests/qemu-iotests/080           |   2 +-
 tests/qemu-iotests/089           |   5 +-
 tests/qemu-iotests/089.out       |   1 +
 tests/qemu-iotests/090           |   2 +-
 tests/qemu-iotests/091           |   5 +-
 tests/qemu-iotests/095           |   2 +-
 tests/qemu-iotests/097           |   2 +-
 tests/qemu-iotests/098           |   2 +-
 tests/qemu-iotests/102           |   2 +-
 tests/qemu-iotests/103           |   2 +-
 tests/qemu-iotests/106           |   2 +-
 tests/qemu-iotests/107           |   2 +-
 tests/qemu-iotests/108           |   2 +-
 tests/qemu-iotests/111           |   2 +-
 tests/qemu-iotests/112           |   2 +-
 tests/qemu-iotests/115           |   2 +-
 tests/qemu-iotests/117           |   2 +-
 tests/qemu-iotests/120           |   2 +-
 tests/qemu-iotests/121           |   2 +-
 tests/qemu-iotests/127           |   2 +-
 tests/qemu-iotests/133           |   2 +-
 tests/qemu-iotests/137           |   2 +-
 tests/qemu-iotests/138           |   2 +-
 tests/qemu-iotests/140           |   2 +-
 tests/qemu-iotests/154           |   2 +-
 tests/qemu-iotests/161           |  14 +-
 tests/qemu-iotests/171           |   2 +-
 tests/qemu-iotests/174           |  10 +-
 tests/qemu-iotests/175           |   8 +-
 tests/qemu-iotests/176           |   2 +-
 tests/qemu-iotests/177           |   2 +-
 tests/qemu-iotests/179           |   2 +-
 tests/qemu-iotests/183           |   2 +-
 tests/qemu-iotests/186           |   2 +-
 tests/qemu-iotests/187           |   2 +-
 tests/qemu-iotests/191           |   2 +-
 tests/qemu-iotests/195           |   2 +-
 tests/qemu-iotests/200           |   5 +-
 tests/qemu-iotests/200.out       |   4 +-
 tests/qemu-iotests/204           |   2 +-
 tests/qemu-iotests/206           |   1 +
 tests/qemu-iotests/214           |   2 +-
 tests/qemu-iotests/217           |   2 +-
 tests/qemu-iotests/220           |   2 +-
 tests/qemu-iotests/221           |   2 +-
 tests/qemu-iotests/229           |   5 +-
 tests/qemu-iotests/229.out       |   6 +-
 tests/qemu-iotests/242           |   1 +
 tests/qemu-iotests/247           |   2 +-
 tests/qemu-iotests/249           |   8 +-
 tests/qemu-iotests/250           |   2 +-
 tests/qemu-iotests/252           |   2 +-
 tests/qemu-iotests/265           |   2 +-
 tests/qemu-iotests/268           |   2 +-
 tests/qemu-iotests/272           |   2 +-
 tests/qemu-iotests/273           |   2 +-
 tests/qemu-iotests/279           |   2 +-
 tests/qemu-iotests/281           | 328 +++++++++++++++
 tests/qemu-iotests/281.out       |  92 +++++
 tests/qemu-iotests/check         |   6 +
 tests/qemu-iotests/common.filter |   5 +-
 tests/qemu-iotests/common.rc     | 190 ++++++++-
 tests/qemu-iotests/group         |   1 +
 93 files changed, 1571 insertions(+), 120 deletions(-)
 create mode 100644 block/fuse.c
 create mode 100644 include/block/fuse.h
 create mode 100755 tests/qemu-iotests/281
 create mode 100644 tests/qemu-iotests/281.out

-- 
2.23.0



^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 01/18] configure: Detect libfuse
  2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
@ 2019-12-19 14:38 ` Max Reitz
  2019-12-19 14:38 ` [PATCH 02/18] fuse: Allow exporting BDSs via FUSE Max Reitz
                   ` (18 subsequent siblings)
  19 siblings, 0 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-19 14:38 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-devel, Max Reitz

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 configure | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/configure b/configure
index 84b413dbfc..ff7d760a0a 100755
--- a/configure
+++ b/configure
@@ -503,6 +503,7 @@ debug_mutex="no"
 libpmem=""
 default_devices="yes"
 plugins="no"
+fuse=""
 
 supported_cpu="no"
 supported_os="no"
@@ -1534,6 +1535,10 @@ for opt do
   ;;
   --disable-plugins) plugins="no"
   ;;
+  --enable-fuse) fuse=yes
+  ;;
+  --disable-fuse) fuse=no
+  ;;
   *)
       echo "ERROR: unknown option $opt"
       echo "Try '$0 --help' for more information"
@@ -1819,6 +1824,7 @@ disabled with --disable-FEATURE, default is enabled if available:
   debug-mutex     mutex debugging support
   libpmem         libpmem support
   xkbcommon       xkbcommon support
+  fuse            fuse block device export
 
 NOTE: The object files are built at the place where configure is launched
 EOF
@@ -6042,6 +6048,28 @@ case "$slirp" in
     ;;
 esac
 
+##########################################
+# FUSE support
+
+if test "$fuse" != "no"; then
+  cat > $TMPC <<EOF
+#define FUSE_USE_VERSION 31
+#include <fuse.h>
+#include <fuse_lowlevel.h>
+int main(void) { return 0; }
+EOF
+  fuse_cflags=$(pkg-config --cflags fuse3)
+  fuse_libs=$(pkg-config --libs fuse3)
+  if compile_prog "$fuse_cflags" "$fuse_libs"; then
+    fuse=yes
+  else
+    if test "$fuse" = "yes"; then
+      feature_not_found "fuse"
+    fi
+    fuse=no
+  fi
+fi
+
 
 ##########################################
 # End of CC checks
@@ -6556,6 +6584,7 @@ echo "libpmem support   $libpmem"
 echo "libudev           $libudev"
 echo "default devices   $default_devices"
 echo "plugin support    $plugins"
+echo "fuse exports      $fuse"
 
 if test "$supported_cpu" = "no"; then
     echo
@@ -7410,6 +7439,12 @@ if test "$plugins" = "yes" ; then
     fi
 fi
 
+if test "$fuse" = "yes"; then
+  echo "CONFIG_FUSE=y" >> $config_host_mak
+  echo "FUSE_CFLAGS=$fuse_cflags" >> $config_host_mak
+  echo "FUSE_LIBS=$fuse_libs" >> $config_host_mak
+fi
+
 if test "$tcg_interpreter" = "yes"; then
   QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/tci $QEMU_INCLUDES"
 elif test "$ARCH" = "sparc64" ; then
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 02/18] fuse: Allow exporting BDSs via FUSE
  2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
  2019-12-19 14:38 ` [PATCH 01/18] configure: Detect libfuse Max Reitz
@ 2019-12-19 14:38 ` Max Reitz
  2019-12-20 10:26   ` Kevin Wolf
  2019-12-20 21:15   ` Eric Blake
  2019-12-19 14:38 ` [PATCH 03/18] fuse: Implement standard FUSE operations Max Reitz
                   ` (17 subsequent siblings)
  19 siblings, 2 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-19 14:38 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-devel, Max Reitz

fuse-export-add allows mounting block graph nodes via FUSE on some
existing regular file.  That file should then appears like a raw disk
image, and accesses to it result in accesses to the exported BDS.

Right now, we only set up the mount point and tear all mount points down
in bdrv_close_all().  We do not implement any access functions, so
accessing the mount point only results in errors.  This will be
addressed by a followup patch.

The set of exported nodes is kept in a hash table so we can later add a
fuse-export-remove that allows unmounting.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 block.c              |   4 +
 block/Makefile.objs  |   3 +
 block/fuse.c         | 260 +++++++++++++++++++++++++++++++++++++++++++
 include/block/fuse.h |  24 ++++
 qapi/block.json      |  23 ++++
 5 files changed, 314 insertions(+)
 create mode 100644 block/fuse.c
 create mode 100644 include/block/fuse.h

diff --git a/block.c b/block.c
index c390ec6461..887c0b105e 100644
--- a/block.c
+++ b/block.c
@@ -26,6 +26,7 @@
 #include "block/trace.h"
 #include "block/block_int.h"
 #include "block/blockjob.h"
+#include "block/fuse.h"
 #include "block/nbd.h"
 #include "block/qdict.h"
 #include "qemu/error-report.h"
@@ -4077,6 +4078,9 @@ void bdrv_close_all(void)
 {
     assert(job_next(NULL) == NULL);
     nbd_export_close_all();
+#ifdef CONFIG_FUSE
+    fuse_export_close_all();
+#endif
 
     /* Drop references from requests still in flight, such as canceled block
      * jobs whose AIO context has not been polled yet */
diff --git a/block/Makefile.objs b/block/Makefile.objs
index e394fe0b6c..b02846a6e7 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -43,6 +43,7 @@ block-obj-y += crypto.o
 
 block-obj-y += aio_task.o
 block-obj-y += backup-top.o
+block-obj-$(CONFIG_FUSE) += fuse.o
 
 common-obj-y += stream.o
 
@@ -67,3 +68,5 @@ qcow.o-libs        := -lz
 linux-aio.o-libs   := -laio
 parallels.o-cflags := $(LIBXML2_CFLAGS)
 parallels.o-libs   := $(LIBXML2_LIBS)
+fuse.o-cflags      := $(FUSE_CFLAGS)
+fuse.o-libs        := $(FUSE_LIBS)
diff --git a/block/fuse.c b/block/fuse.c
new file mode 100644
index 0000000000..3a22579dca
--- /dev/null
+++ b/block/fuse.c
@@ -0,0 +1,260 @@
+/*
+ * Present a block device as a raw image through FUSE
+ *
+ * Copyright (c) 2019 Max Reitz <mreitz@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; under version 2 or later of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define FUSE_USE_VERSION 31
+
+#include "qemu/osdep.h"
+#include "block/aio.h"
+#include "block/block.h"
+#include "block/fuse.h"
+#include "block/qapi.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-block.h"
+#include "sysemu/block-backend.h"
+
+#include <fuse.h>
+#include <fuse_lowlevel.h>
+
+
+typedef struct BdrvFuseSession {
+    struct fuse_session *fuse_session;
+    struct fuse_buf fuse_buf;
+    BlockBackend *blk;
+    uint64_t perm, shared_perm;
+    bool mounted, fd_handler_set_up;
+    bool writable;
+} BdrvFuseSession;
+
+static GHashTable *sessions;
+static const struct fuse_lowlevel_ops fuse_ops;
+
+static void init_fuse(void);
+static int setup_fuse_session(BdrvFuseSession *session, const char *mountpoint,
+                              Error **errp);
+static void read_from_fuse_session(void *opaque);
+static void close_fuse_session(BdrvFuseSession *session);
+static void drop_fuse_session_from_hash_table(gpointer value);
+
+static bool is_regular_file(const char *path, Error **errp);
+
+
+void qmp_fuse_export_add(const char *node_name, const char *mountpoint,
+                         bool has_writable, bool writable,
+                         Error **errp)
+{
+    BlockDriverState *bs;
+    BdrvFuseSession *session = NULL;
+
+    if (!has_writable) {
+        writable = false;
+    }
+
+    init_fuse();
+
+    /*
+     * It is important to do this check before calling is_regular_file() --
+     * that function will do a stat(), which we would have to handle if we
+     * already exported something on @mountpoint.  But we cannot, because
+     * we are currently caught up here.
+     */
+    if (g_hash_table_contains(sessions, mountpoint)) {
+        error_setg(errp, "There already is a FUSE export on '%s'", mountpoint);
+        goto fail;
+    }
+
+    if (!is_regular_file(mountpoint, errp)) {
+        goto fail;
+    }
+
+    bs = bdrv_find_node(node_name);
+    if (!bs) {
+        error_setg(errp, "Node '%s' not found", node_name);
+        goto fail;
+    }
+
+    session = g_new(BdrvFuseSession, 1);
+    *session = (BdrvFuseSession){
+        .fuse_buf = {
+            .mem = NULL,
+        },
+
+        .writable = writable,
+    };
+
+    session->perm = BLK_PERM_CONSISTENT_READ;
+    if (writable) {
+        session->perm |= BLK_PERM_WRITE;
+    }
+    session->shared_perm = BLK_PERM_ALL;
+
+    session->blk = blk_new(bdrv_get_aio_context(bs),
+                           session->perm, session->shared_perm);
+    if (blk_insert_bs(session->blk, bs, errp) < 0) {
+        goto fail;
+    }
+
+    if (setup_fuse_session(session, mountpoint, errp) < 0) {
+        goto fail;
+    }
+
+    g_hash_table_insert(sessions, g_strdup(mountpoint), session);
+    return;
+
+fail:
+    close_fuse_session(session);
+}
+
+/**
+ * Drop all FUSE exports.
+ */
+void fuse_export_close_all(void)
+{
+    if (sessions) {
+        g_hash_table_destroy(sessions);
+    }
+}
+
+
+/**
+ * Ensure that the global FUSE context is set up.
+ */
+static void init_fuse(void)
+{
+    if (sessions) {
+        return;
+    }
+
+    sessions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+                                     drop_fuse_session_from_hash_table);
+}
+
+/**
+ * Create session->fuse_session and mount it.
+ */
+static int setup_fuse_session(BdrvFuseSession *session, const char *mountpoint,
+                              Error **errp)
+{
+    const char *fuse_argv[2];
+    struct fuse_args fuse_args;
+    int ret;
+
+    fuse_argv[0] = ""; /* Dummy program name */
+    fuse_argv[1] = NULL;
+    fuse_args = (struct fuse_args)FUSE_ARGS_INIT(1, (char **)fuse_argv);
+
+    session->fuse_session = fuse_session_new(&fuse_args, &fuse_ops,
+                                             sizeof(fuse_ops), session);
+    if (!session->fuse_session) {
+        error_setg(errp, "Failed to set up FUSE session");
+        return -EIO;
+    }
+
+    ret = fuse_session_mount(session->fuse_session, mountpoint);
+    if (ret < 0) {
+        error_setg(errp, "Failed to mount FUSE session to export");
+        return -EIO;
+    }
+    session->mounted = true;
+
+    aio_set_fd_handler(blk_get_aio_context(session->blk),
+                       fuse_session_fd(session->fuse_session), true,
+                       read_from_fuse_session, NULL, NULL, session);
+    session->fd_handler_set_up = true;
+
+    return 0;
+}
+
+/**
+ * Callback to be invoked when the FUSE session FD can be read from.
+ * (This is basically the FUSE event loop.)
+ */
+static void read_from_fuse_session(void *opaque)
+{
+    BdrvFuseSession *session = opaque;
+    int ret;
+
+    ret = fuse_session_receive_buf(session->fuse_session, &session->fuse_buf);
+    if (ret < 0) {
+        return;
+    }
+
+    fuse_session_process_buf(session->fuse_session, &session->fuse_buf);
+}
+
+/**
+ * Drop a FUSE session (unmount it and free all associated resources).
+ * It is not removed from the @sessions hash table.
+ */
+static void close_fuse_session(BdrvFuseSession *session)
+{
+    if (!session) {
+        return;
+    }
+
+    if (session->fuse_session) {
+        if (session->mounted) {
+            fuse_session_unmount(session->fuse_session);
+        }
+        if (session->fd_handler_set_up) {
+            aio_set_fd_handler(blk_get_aio_context(session->blk),
+                               fuse_session_fd(session->fuse_session), true,
+                               NULL, NULL, NULL, NULL);
+        }
+        fuse_session_destroy(session->fuse_session);
+    }
+    blk_unref(session->blk);
+
+    g_free(session);
+}
+
+/**
+ * Wrapper around close_fuse_session() for use with
+ * g_hash_table_new_full().  This allows dropping sessions by removing
+ * them from the @sessions hash table.
+ */
+static void drop_fuse_session_from_hash_table(gpointer value)
+{
+    return close_fuse_session(value);
+}
+
+
+/**
+ * Check whether @path points to a regular file.  If not, put an
+ * appropriate message into *errp.
+ */
+static bool is_regular_file(const char *path, Error **errp)
+{
+    struct stat statbuf;
+    int ret;
+
+    ret = stat(path, &statbuf);
+    if (ret < 0) {
+        error_setg_errno(errp, errno, "Failed to stat '%s'", path);
+        return false;
+    }
+
+    if (!S_ISREG(statbuf.st_mode)) {
+        error_setg(errp, "'%s' is not a regular file", path);
+        return false;
+    }
+
+    return true;
+}
+
+static const struct fuse_lowlevel_ops fuse_ops = {
+};
diff --git a/include/block/fuse.h b/include/block/fuse.h
new file mode 100644
index 0000000000..1d24dded50
--- /dev/null
+++ b/include/block/fuse.h
@@ -0,0 +1,24 @@
+/*
+ * Present a block device as a raw image through FUSE
+ *
+ * Copyright (c) 2019 Max Reitz <mreitz@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; under version 2 or later of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef BLOCK_FUSE_H
+#define BLOCK_FUSE_H
+
+void fuse_export_close_all(void);
+
+#endif
diff --git a/qapi/block.json b/qapi/block.json
index 145c268bb6..03f8d1b537 100644
--- a/qapi/block.json
+++ b/qapi/block.json
@@ -317,6 +317,29 @@
 ##
 { 'command': 'nbd-server-stop' }
 
+##
+# @fuse-export-add:
+#
+# Exports a block graph node on some (file) mountpoint as a raw image.
+#
+# @node-name: Node to be exported
+#
+# @mountpoint: Path on which to export the block device via FUSE.
+#              This must point to an existing regular file.
+#
+# @writable: Whether clients should be able to write to the block
+#            device via the FUSE export. (default: false)
+#
+# Since: 5.0
+##
+{ 'command': 'fuse-export-add',
+  'data': {
+      'node-name': 'str',
+      'mountpoint': 'str',
+      '*writable': 'bool'
+  },
+  'if': 'defined(CONFIG_FUSE)' }
+
 ##
 # @DEVICE_TRAY_MOVED:
 #
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 03/18] fuse: Implement standard FUSE operations
  2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
  2019-12-19 14:38 ` [PATCH 01/18] configure: Detect libfuse Max Reitz
  2019-12-19 14:38 ` [PATCH 02/18] fuse: Allow exporting BDSs via FUSE Max Reitz
@ 2019-12-19 14:38 ` Max Reitz
  2019-12-19 14:38 ` [PATCH 04/18] fuse: Add fuse-export-remove Max Reitz
                   ` (16 subsequent siblings)
  19 siblings, 0 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-19 14:38 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-devel, Max Reitz

This makes the export actually useful instead of only producing errors
whenever it is accessed.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 block/fuse.c | 222 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 222 insertions(+)

diff --git a/block/fuse.c b/block/fuse.c
index 3a22579dca..f18e8e7591 100644
--- a/block/fuse.c
+++ b/block/fuse.c
@@ -31,6 +31,10 @@
 #include <fuse_lowlevel.h>
 
 
+/* Prevent overly long bounce buffer allocations */
+#define FUSE_MAX_BOUNCE_BYTES (MIN(BDRV_REQUEST_MAX_BYTES, 64 * 1024 * 1024))
+
+
 typedef struct BdrvFuseSession {
     struct fuse_session *fuse_session;
     struct fuse_buf fuse_buf;
@@ -256,5 +260,223 @@ static bool is_regular_file(const char *path, Error **errp)
     return true;
 }
 
+
+/**
+ * Let clients look up files.  Always return ENOENT because we only
+ * care about the mountpoint itself.
+ */
+static void fuse_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
+{
+    fuse_reply_err(req, ENOENT);
+}
+
+/**
+ * Let clients get file attributes (i.e., stat() the file).
+ */
+static void fuse_getattr(fuse_req_t req, fuse_ino_t inode,
+                         struct fuse_file_info *fi)
+{
+    struct stat statbuf;
+    int64_t length, allocated_blocks;
+    time_t now = time(NULL);
+    ImageInfo *info;
+    BdrvFuseSession *session = fuse_req_userdata(req);
+    mode_t mode;
+    Error *local_error = NULL;
+
+    length = blk_getlength(session->blk);
+    if (length < 0) {
+        fuse_reply_err(req, -length);
+        return;
+    }
+
+    bdrv_query_image_info(blk_bs(session->blk), &info, &local_error);
+    if (local_error) {
+        error_free(local_error);
+        allocated_blocks = DIV_ROUND_UP(length, 512);
+    } else {
+        allocated_blocks = DIV_ROUND_UP(info->actual_size, 512);
+        qapi_free_ImageInfo(info);
+    }
+
+    mode = S_IFREG | 0400;
+    if (session->writable) {
+        mode |= 0200;
+    }
+
+    statbuf = (struct stat) {
+        .st_ino     = inode,
+        .st_mode    = mode,
+        .st_nlink   = 1,
+        .st_uid     = getuid(),
+        .st_gid     = getgid(),
+        .st_size    = length,
+        .st_blksize = blk_bs(session->blk)->bl.request_alignment,
+        .st_blocks  = allocated_blocks,
+        .st_atime   = now,
+        .st_mtime   = now,
+        .st_ctime   = now,
+    };
+
+    fuse_reply_attr(req, &statbuf, 1.);
+}
+
+static int fuse_do_truncate(const BdrvFuseSession *session, int64_t size,
+                            PreallocMode prealloc)
+{
+    int ret;
+
+    ret = blk_set_perm(session->blk, session->perm | BLK_PERM_RESIZE,
+                       session->shared_perm, NULL);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = blk_truncate(session->blk, size, true, prealloc, NULL);
+
+    /* Must succeed, because we are only giving up the RESIZE permission */
+    blk_set_perm(session->blk, session->perm, session->shared_perm,
+                 &error_abort);
+
+    return ret;
+}
+
+/**
+ * Let clients set file attributes.  Only resizing is supported.
+ */
+static void fuse_setattr(fuse_req_t req, fuse_ino_t inode, struct stat *statbuf,
+                         int to_set, struct fuse_file_info *fi)
+{
+    BdrvFuseSession *session = fuse_req_userdata(req);
+    int ret;
+
+    if (!session->writable) {
+        fuse_reply_err(req, EACCES);
+        return;
+    }
+
+    if (to_set & ~FUSE_SET_ATTR_SIZE) {
+        fuse_reply_err(req, ENOTSUP);
+        return;
+    }
+
+    ret = fuse_do_truncate(session, statbuf->st_size, PREALLOC_MODE_OFF);
+    if (ret < 0) {
+        fuse_reply_err(req, -ret);
+        return;
+    }
+
+    fuse_getattr(req, inode, fi);
+}
+
+/**
+ * Let clients open a file (i.e., the exported image).
+ */
+static void fuse_open(fuse_req_t req, fuse_ino_t inode,
+                      struct fuse_file_info *fi)
+{
+    fuse_reply_open(req, fi);
+}
+
+/**
+ * Handle client reads from the exported image.
+ */
+static void fuse_read(fuse_req_t req, fuse_ino_t inode,
+                      size_t size, off_t offset, struct fuse_file_info *fi)
+{
+    BdrvFuseSession *session = fuse_req_userdata(req);
+    int64_t length;
+    void *buf;
+    int ret;
+
+    /**
+     * Clients will expect short reads at EOF, so we have to limit
+     * offset+size to the image length.
+     */
+    length = blk_getlength(session->blk);
+    if (length < 0) {
+        fuse_reply_err(req, -length);
+        return;
+    }
+
+    size = MIN(size, FUSE_MAX_BOUNCE_BYTES);
+    if (offset + size > length) {
+        size = length - offset;
+    }
+
+    buf = qemu_try_blockalign(blk_bs(session->blk), size);
+    if (!buf) {
+        fuse_reply_err(req, ENOMEM);
+        return;
+    }
+
+    ret = blk_pread(session->blk, offset, buf, size);
+    if (ret >= 0) {
+        fuse_reply_buf(req, buf, size);
+    } else {
+        fuse_reply_err(req, -ret);
+    }
+
+    qemu_vfree(buf);
+}
+
+/**
+ * Handle client writes to the exported image.
+ */
+static void fuse_write(fuse_req_t req, fuse_ino_t inode, const char *buf,
+                       size_t size, off_t offset, struct fuse_file_info *fi)
+{
+    BdrvFuseSession *session = fuse_req_userdata(req);
+    int64_t length;
+    int ret;
+
+    if (!session->writable) {
+        fuse_reply_err(req, EACCES);
+        return;
+    }
+
+    /**
+     * Clients will expect short writes at EOF, so we have to limit
+     * offset+size to the image length.
+     */
+    length = blk_getlength(session->blk);
+    if (length < 0) {
+        fuse_reply_err(req, -length);
+        return;
+    }
+
+    size = MIN(size, BDRV_REQUEST_MAX_BYTES);
+    if (offset + size > length) {
+        size = length - offset;
+    }
+
+    ret = blk_pwrite(session->blk, offset, buf, size, 0);
+    if (ret >= 0) {
+        fuse_reply_write(req, size);
+    } else {
+        fuse_reply_err(req, -ret);
+    }
+}
+
+/**
+ * Let clients flush the exported image.
+ */
+static void fuse_flush(fuse_req_t req, fuse_ino_t inode,
+                       struct fuse_file_info *fi)
+{
+    BdrvFuseSession *session = fuse_req_userdata(req);
+    int ret;
+
+    ret = blk_flush(session->blk);
+    fuse_reply_err(req, ret < 0 ? -ret : 0);
+}
+
 static const struct fuse_lowlevel_ops fuse_ops = {
+    .lookup     = fuse_lookup,
+    .getattr    = fuse_getattr,
+    .setattr    = fuse_setattr,
+    .open       = fuse_open,
+    .read       = fuse_read,
+    .write      = fuse_write,
+    .flush      = fuse_flush,
 };
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 04/18] fuse: Add fuse-export-remove
  2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
                   ` (2 preceding siblings ...)
  2019-12-19 14:38 ` [PATCH 03/18] fuse: Implement standard FUSE operations Max Reitz
@ 2019-12-19 14:38 ` Max Reitz
  2019-12-19 14:38 ` [PATCH 05/18] fuse: Allow growable exports Max Reitz
                   ` (15 subsequent siblings)
  19 siblings, 0 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-19 14:38 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-devel, Max Reitz

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 block/fuse.c    | 16 ++++++++++++++++
 qapi/block.json | 15 +++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/block/fuse.c b/block/fuse.c
index f18e8e7591..4e662e6dfb 100644
--- a/block/fuse.c
+++ b/block/fuse.c
@@ -123,6 +123,22 @@ fail:
     close_fuse_session(session);
 }
 
+void qmp_fuse_export_remove(const char *mountpoint, Error **errp)
+{
+    BdrvFuseSession *session = NULL;
+
+    if (sessions) {
+        session = g_hash_table_lookup(sessions, mountpoint);
+    }
+
+    if (!session) {
+        error_setg(errp, "No export found on '%s'", mountpoint);
+        return;
+    }
+
+    g_hash_table_remove(sessions, mountpoint);
+}
+
 /**
  * Drop all FUSE exports.
  */
diff --git a/qapi/block.json b/qapi/block.json
index 03f8d1b537..26768dc8ef 100644
--- a/qapi/block.json
+++ b/qapi/block.json
@@ -340,6 +340,21 @@
   },
   'if': 'defined(CONFIG_FUSE)' }
 
+##
+# @fuse-export-remove:
+#
+# Unmount an exported block graph node.
+#
+# @mountpoint: The export path given to fuse-export-add
+#
+# Since: 5.0
+##
+{ 'command': 'fuse-export-remove',
+  'data': {
+      'mountpoint': 'str'
+  },
+  'if': 'defined(CONFIG_FUSE)' }
+
 ##
 # @DEVICE_TRAY_MOVED:
 #
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 05/18] fuse: Allow growable exports
  2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
                   ` (3 preceding siblings ...)
  2019-12-19 14:38 ` [PATCH 04/18] fuse: Add fuse-export-remove Max Reitz
@ 2019-12-19 14:38 ` Max Reitz
  2019-12-19 14:38 ` [PATCH 06/18] fuse: (Partially) implement fallocate() Max Reitz
                   ` (14 subsequent siblings)
  19 siblings, 0 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-19 14:38 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-devel, Max Reitz

These will behave more like normal files in that writes beyond the EOF
will automatically grow the export size.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 block/fuse.c    | 16 +++++++++++++++-
 qapi/block.json |  6 +++++-
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/block/fuse.c b/block/fuse.c
index 4e662e6dfb..d7c7824815 100644
--- a/block/fuse.c
+++ b/block/fuse.c
@@ -42,6 +42,7 @@ typedef struct BdrvFuseSession {
     uint64_t perm, shared_perm;
     bool mounted, fd_handler_set_up;
     bool writable;
+    bool growable;
 } BdrvFuseSession;
 
 static GHashTable *sessions;
@@ -59,6 +60,7 @@ static bool is_regular_file(const char *path, Error **errp);
 
 void qmp_fuse_export_add(const char *node_name, const char *mountpoint,
                          bool has_writable, bool writable,
+                         bool has_growable, bool growable,
                          Error **errp)
 {
     BlockDriverState *bs;
@@ -67,6 +69,9 @@ void qmp_fuse_export_add(const char *node_name, const char *mountpoint,
     if (!has_writable) {
         writable = false;
     }
+    if (!has_growable) {
+        growable = false;
+    }
 
     init_fuse();
 
@@ -98,6 +103,7 @@ void qmp_fuse_export_add(const char *node_name, const char *mountpoint,
         },
 
         .writable = writable,
+        .growable = growable,
     };
 
     session->perm = BLK_PERM_CONSISTENT_READ;
@@ -463,7 +469,15 @@ static void fuse_write(fuse_req_t req, fuse_ino_t inode, const char *buf,
 
     size = MIN(size, BDRV_REQUEST_MAX_BYTES);
     if (offset + size > length) {
-        size = length - offset;
+        if (session->growable) {
+            ret = fuse_do_truncate(session, offset + size, PREALLOC_MODE_OFF);
+            if (ret < 0) {
+                fuse_reply_err(req, -ret);
+                return;
+            }
+        } else {
+            size = length - offset;
+        }
     }
 
     ret = blk_pwrite(session->blk, offset, buf, size, 0);
diff --git a/qapi/block.json b/qapi/block.json
index 26768dc8ef..039cbc6773 100644
--- a/qapi/block.json
+++ b/qapi/block.json
@@ -330,13 +330,17 @@
 # @writable: Whether clients should be able to write to the block
 #            device via the FUSE export. (default: false)
 #
+# @growable: Whether writes beyond the EOF should grow the block node
+#            fit. (default: false)
+#
 # Since: 5.0
 ##
 { 'command': 'fuse-export-add',
   'data': {
       'node-name': 'str',
       'mountpoint': 'str',
-      '*writable': 'bool'
+      '*writable': 'bool',
+      '*growable': 'bool'
   },
   'if': 'defined(CONFIG_FUSE)' }
 
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 06/18] fuse: (Partially) implement fallocate()
  2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
                   ` (4 preceding siblings ...)
  2019-12-19 14:38 ` [PATCH 05/18] fuse: Allow growable exports Max Reitz
@ 2019-12-19 14:38 ` Max Reitz
  2019-12-19 14:38 ` [PATCH 07/18] fuse: Implement hole detection through lseek Max Reitz
                   ` (13 subsequent siblings)
  19 siblings, 0 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-19 14:38 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-devel, Max Reitz

This allows allocating areas after the EOF, writing zeroes, and
discarding.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 block/fuse.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/block/fuse.c b/block/fuse.c
index d7c7824815..018afee6cd 100644
--- a/block/fuse.c
+++ b/block/fuse.c
@@ -488,6 +488,84 @@ static void fuse_write(fuse_req_t req, fuse_ino_t inode, const char *buf,
     }
 }
 
+/**
+ * Let clients perform various fallocate() operations.
+ */
+static void fuse_fallocate(fuse_req_t req, fuse_ino_t inode, int mode,
+                           off_t offset, off_t length,
+                           struct fuse_file_info *fi)
+{
+    BdrvFuseSession *session = fuse_req_userdata(req);
+    int64_t blk_len;
+    int ret;
+
+    if (!session->writable) {
+        fuse_reply_err(req, EACCES);
+        return;
+    }
+
+    blk_len = blk_getlength(session->blk);
+    if (blk_len < 0) {
+        fuse_reply_err(req, -blk_len);
+        return;
+    }
+
+    if (mode & FALLOC_FL_KEEP_SIZE) {
+        length = MIN(length, blk_len - offset);
+    }
+
+    if (mode & FALLOC_FL_PUNCH_HOLE) {
+        if (!(mode & FALLOC_FL_KEEP_SIZE)) {
+            fuse_reply_err(req, EINVAL);
+            return;
+        }
+
+        do {
+            int size = MIN(length, BDRV_REQUEST_MAX_BYTES);
+
+            ret = blk_pdiscard(session->blk, offset, size);
+            length -= size;
+        } while (ret == 0 && length > 0);
+    } else if (mode & FALLOC_FL_ZERO_RANGE) {
+        if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + length > blk_len) {
+            ret = fuse_do_truncate(session, offset + length, PREALLOC_MODE_OFF);
+            if (ret < 0) {
+                fuse_reply_err(req, -ret);
+                return;
+            }
+        }
+
+        do {
+            int size = MIN(length, BDRV_REQUEST_MAX_BYTES);
+
+            ret = blk_pwrite_zeroes(session->blk,
+                                    offset, size, 0);
+            length -= size;
+        } while (ret == 0 && length > 0);
+    } else if (!mode) {
+        /* We can only fallocate at the EOF with a truncate */
+        if (offset < blk_len) {
+            fuse_reply_err(req, EOPNOTSUPP);
+            return;
+        }
+
+        if (offset > blk_len) {
+            /* No preallocation needed here */
+            ret = fuse_do_truncate(session, offset, PREALLOC_MODE_OFF);
+            if (ret < 0) {
+                fuse_reply_err(req, -ret);
+                return;
+            }
+        }
+
+        ret = fuse_do_truncate(session, offset + length, PREALLOC_MODE_FALLOC);
+    } else {
+        ret = -EOPNOTSUPP;
+    }
+
+    fuse_reply_err(req, ret < 0 ? -ret : 0);
+}
+
 /**
  * Let clients flush the exported image.
  */
@@ -508,5 +586,6 @@ static const struct fuse_lowlevel_ops fuse_ops = {
     .open       = fuse_open,
     .read       = fuse_read,
     .write      = fuse_write,
+    .fallocate  = fuse_fallocate,
     .flush      = fuse_flush,
 };
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 07/18] fuse: Implement hole detection through lseek
  2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
                   ` (5 preceding siblings ...)
  2019-12-19 14:38 ` [PATCH 06/18] fuse: (Partially) implement fallocate() Max Reitz
@ 2019-12-19 14:38 ` Max Reitz
  2019-12-19 14:38 ` [PATCH 08/18] iotests: Do not needlessly filter _make_test_img Max Reitz
                   ` (12 subsequent siblings)
  19 siblings, 0 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-19 14:38 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-devel, Max Reitz

This is a relatively new feature in libfuse (available since 3.8.0,
which was released in November 2019), so we have to let configure check
whether it is available before making use of it.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 block/fuse.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 configure    | 33 ++++++++++++++++++++++
 2 files changed, 110 insertions(+)

diff --git a/block/fuse.c b/block/fuse.c
index 018afee6cd..6b693b05b7 100644
--- a/block/fuse.c
+++ b/block/fuse.c
@@ -579,6 +579,80 @@ static void fuse_flush(fuse_req_t req, fuse_ino_t inode,
     fuse_reply_err(req, ret < 0 ? -ret : 0);
 }
 
+#ifdef CONFIG_FUSE_LSEEK
+/**
+ * Let clients inquire allocation status.
+ */
+static void fuse_lseek(fuse_req_t req, fuse_ino_t inode, off_t offset,
+                       int whence, struct fuse_file_info *fi)
+{
+    BdrvFuseSession *session = fuse_req_userdata(req);
+
+    if (whence != SEEK_HOLE && whence != SEEK_DATA) {
+        fuse_reply_err(req, EINVAL);
+        return;
+    }
+
+    while (true) {
+        int64_t pnum;
+        int ret;
+
+        ret = bdrv_block_status_above(blk_bs(session->blk), NULL,
+                                      offset, INT64_MAX, &pnum, NULL, NULL);
+        if (ret < 0) {
+            fuse_reply_err(req, -ret);
+            return;
+        }
+
+        if (!pnum && (ret & BDRV_BLOCK_EOF)) {
+            int64_t blk_len;
+
+            /*
+             * If blk_getlength() rounds (e.g. by sectors), then the
+             * export length will be rounded, too.  However,
+             * bdrv_block_status_above() may return EOF at unaligned
+             * offsets.  We must not let this become visible and thus
+             * always simulate a hole between @offset (the real EOF)
+             * and @blk_len (the client-visible EOF).
+             */
+
+            blk_len = blk_getlength(session->blk);
+            if (blk_len < 0) {
+                fuse_reply_err(req, -blk_len);
+                return;
+            }
+
+            if (offset > blk_len || whence == SEEK_DATA) {
+                fuse_reply_err(req, ENXIO);
+            } else {
+                fuse_reply_lseek(req, offset);
+            }
+            return;
+        }
+
+        if (ret & BDRV_BLOCK_DATA) {
+            if (whence == SEEK_DATA) {
+                fuse_reply_lseek(req, offset);
+                return;
+            }
+        } else {
+            if (whence == SEEK_HOLE) {
+                fuse_reply_lseek(req, offset);
+                return;
+            }
+        }
+
+        /* Safety check against infinite loops */
+        if (!pnum) {
+            fuse_reply_err(req, ENXIO);
+            return;
+        }
+
+        offset += pnum;
+    }
+}
+#endif
+
 static const struct fuse_lowlevel_ops fuse_ops = {
     .lookup     = fuse_lookup,
     .getattr    = fuse_getattr,
@@ -588,4 +662,7 @@ static const struct fuse_lowlevel_ops fuse_ops = {
     .write      = fuse_write,
     .fallocate  = fuse_fallocate,
     .flush      = fuse_flush,
+#ifdef CONFIG_FUSE_LSEEK
+    .lseek      = fuse_lseek,
+#endif
 };
diff --git a/configure b/configure
index ff7d760a0a..18c38f111b 100755
--- a/configure
+++ b/configure
@@ -6062,11 +6062,39 @@ EOF
   fuse_libs=$(pkg-config --libs fuse3)
   if compile_prog "$fuse_cflags" "$fuse_libs"; then
     fuse=yes
+
+    cat > $TMPC <<EOF
+#define FUSE_USE_VERSION 31
+#include <fuse.h>
+#include <fuse_lowlevel.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+static void fuse_lseek(fuse_req_t req, fuse_ino_t inode, off_t offset,
+                       int whence, struct fuse_file_info *fi)
+{
+    if (whence == SEEK_DATA || whence == SEEK_HOLE) {
+        fuse_reply_lseek(req, offset);
+    } else {
+        fuse_reply_err(req, EINVAL);
+    }
+}
+const struct fuse_lowlevel_ops fuse_ops = {
+    .lseek = fuse_lseek,
+};
+int main(void) { return 0; }
+EOF
+    if compile_prog "$fuse_cflags" "$fuse_libs"; then
+      fuse_lseek=yes
+    else
+      fuse_lseek=no
+    fi
   else
     if test "$fuse" = "yes"; then
       feature_not_found "fuse"
     fi
     fuse=no
+    fuse_lseek=no
   fi
 fi
 
@@ -6585,6 +6613,7 @@ echo "libudev           $libudev"
 echo "default devices   $default_devices"
 echo "plugin support    $plugins"
 echo "fuse exports      $fuse"
+echo "fuse lseek        $fuse_lseek"
 
 if test "$supported_cpu" = "no"; then
     echo
@@ -7443,6 +7472,10 @@ if test "$fuse" = "yes"; then
   echo "CONFIG_FUSE=y" >> $config_host_mak
   echo "FUSE_CFLAGS=$fuse_cflags" >> $config_host_mak
   echo "FUSE_LIBS=$fuse_libs" >> $config_host_mak
+
+  if test "$fuse_lseek" = "yes"; then
+    echo "CONFIG_FUSE_LSEEK=y" >> $config_host_mak
+  fi
 fi
 
 if test "$tcg_interpreter" = "yes"; then
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 08/18] iotests: Do not needlessly filter _make_test_img
  2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
                   ` (6 preceding siblings ...)
  2019-12-19 14:38 ` [PATCH 07/18] fuse: Implement hole detection through lseek Max Reitz
@ 2019-12-19 14:38 ` Max Reitz
  2019-12-19 14:38 ` [PATCH 09/18] iotests: Do not pipe _make_test_img Max Reitz
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-19 14:38 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-devel, Max Reitz

In most cases, _make_test_img does not need a _filter_imgfmt on top.  It
does that by itself.

(The exception is when IMGFMT has been overwritten but TEST_IMG has not.
In such cases, we do need a _filter_imgfmt on top to filter the test's
original IMGFMT from TEST_IMG.)

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/161 | 12 ++++++------
 tests/qemu-iotests/175 |  6 +++---
 tests/qemu-iotests/249 |  6 +++---
 3 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/tests/qemu-iotests/161 b/tests/qemu-iotests/161
index f572a19af2..f9b44e52cf 100755
--- a/tests/qemu-iotests/161
+++ b/tests/qemu-iotests/161
@@ -48,9 +48,9 @@ _supported_os Linux
 IMG_SIZE=1M
 
 # Create the images
-TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE | _filter_imgfmt
-TEST_IMG="$TEST_IMG.int" _make_test_img -b "$TEST_IMG.base" | _filter_imgfmt
-_make_test_img -b "$TEST_IMG.int" | _filter_imgfmt
+TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE
+TEST_IMG="$TEST_IMG.int" _make_test_img -b "$TEST_IMG.base"
+_make_test_img -b "$TEST_IMG.int"
 
 # First test: reopen $TEST.IMG changing the detect-zeroes option on
 # its backing file ($TEST_IMG.int).
@@ -105,9 +105,9 @@ echo
 echo "*** Commit and then change an option on the backing file"
 echo
 # Create the images again
-TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE | _filter_imgfmt
-TEST_IMG="$TEST_IMG.int" _make_test_img -b "$TEST_IMG.base" | _filter_imgfmt
-_make_test_img -b "$TEST_IMG.int" | _filter_imgfmt
+TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE
+TEST_IMG="$TEST_IMG.int" _make_test_img -b "$TEST_IMG.base"
+_make_test_img -b "$TEST_IMG.int"
 
 _launch_qemu -drive if=none,file="${TEST_IMG}"
 _send_qemu_cmd $QEMU_HANDLE \
diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175
index 020ed8e61f..2d164b6b5d 100755
--- a/tests/qemu-iotests/175
+++ b/tests/qemu-iotests/175
@@ -89,20 +89,20 @@ min_blocks=$(stat -c '%b' "$TEST_DIR/empty")
 
 echo
 echo "== creating image with default preallocation =="
-_make_test_img $size | _filter_imgfmt
+_make_test_img $size
 stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size
 
 for mode in off full falloc; do
     echo
     echo "== creating image with preallocation $mode =="
-    _make_test_img -o preallocation=$mode $size | _filter_imgfmt
+    _make_test_img -o preallocation=$mode $size
     stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size
 done
 
 for new_size in 4096 1048576; do
     echo
     echo "== resize empty image with block_resize =="
-    _make_test_img 0 | _filter_imgfmt
+    _make_test_img 0
     _block_resize $TEST_IMG $new_size >/dev/null
     stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $new_size
 done
diff --git a/tests/qemu-iotests/249 b/tests/qemu-iotests/249
index 2b99c9789e..4b0f810795 100755
--- a/tests/qemu-iotests/249
+++ b/tests/qemu-iotests/249
@@ -48,9 +48,9 @@ _supported_os Linux
 IMG_SIZE=1M
 
 # Create the images: base <- int <- active
-TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE | _filter_imgfmt
-TEST_IMG="$TEST_IMG.int" _make_test_img -b "$TEST_IMG.base" | _filter_imgfmt
-_make_test_img -b "$TEST_IMG.int" | _filter_imgfmt
+TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE
+TEST_IMG="$TEST_IMG.int" _make_test_img -b "$TEST_IMG.base"
+_make_test_img -b "$TEST_IMG.int"
 
 # Launch QEMU with these two drives:
 # none0: base (read-only)
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 09/18] iotests: Do not pipe _make_test_img
  2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
                   ` (7 preceding siblings ...)
  2019-12-19 14:38 ` [PATCH 08/18] iotests: Do not needlessly filter _make_test_img Max Reitz
@ 2019-12-19 14:38 ` Max Reitz
  2019-12-19 14:38 ` [PATCH 10/18] iotests: Use convert -n in some cases Max Reitz
                   ` (10 subsequent siblings)
  19 siblings, 0 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-19 14:38 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-devel, Max Reitz

Executing _make_test_img as part of a pipe will undo all variable
changes it has done.  As such, this could not work with FUSE (because
we want to remember all of our exports and their qemu instances).

Replace the pipe by a temporary file in 071 and 174 (the two tests that
can run on FUSE).

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/071 | 19 +++++++++++++++----
 tests/qemu-iotests/174 | 10 +++++++++-
 2 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071
index 88faebcc1d..18fe9054b0 100755
--- a/tests/qemu-iotests/071
+++ b/tests/qemu-iotests/071
@@ -61,8 +61,17 @@ echo
 echo "=== Testing blkverify through filename ==="
 echo
 
-TEST_IMG="$TEST_IMG.base" IMGFMT="raw" _make_test_img --no-opts $IMG_SIZE |\
-    _filter_imgfmt
+# _make_test_img may set variables that we need to retain.  Everything
+# in a pipe is executed in a subshell, so doing so would throw away
+# all changes.  Therefore, we have to store the output in some temp
+# file and filter that.
+scratch_out="$TEST_DIR/img-create.out"
+
+TEST_IMG="$TEST_IMG.base" IMGFMT="raw" _make_test_img --no-opts $IMG_SIZE \
+    >"$scratch_out"
+_filter_imgfmt <"$scratch_out"
+rm -f "$scratch_out"
+
 _make_test_img $IMG_SIZE
 $QEMU_IO -c "open -o driver=raw,file.driver=blkverify,file.raw.filename=$TEST_IMG.base $TEST_IMG" \
          -c 'read 0 512' -c 'write -P 42 0x38000 512' -c 'read -P 42 0x38000 512' | _filter_qemu_io
@@ -76,8 +85,10 @@ echo
 echo "=== Testing blkverify through file blockref ==="
 echo
 
-TEST_IMG="$TEST_IMG.base" IMGFMT="raw" _make_test_img --no-opts $IMG_SIZE |\
-    _filter_imgfmt
+TEST_IMG="$TEST_IMG.base" IMGFMT="raw" _make_test_img --no-opts $IMG_SIZE \
+    >"$scratch_out"
+_filter_imgfmt <"$scratch_out"
+
 _make_test_img $IMG_SIZE
 $QEMU_IO -c "open -o driver=raw,file.driver=blkverify,file.raw.filename=$TEST_IMG.base,file.test.driver=$IMGFMT,file.test.file.filename=$TEST_IMG" \
          -c 'read 0 512' -c 'write -P 42 0x38000 512' -c 'read -P 42 0x38000 512' | _filter_qemu_io
diff --git a/tests/qemu-iotests/174 b/tests/qemu-iotests/174
index e2f14a38c6..1b0dd2e8b7 100755
--- a/tests/qemu-iotests/174
+++ b/tests/qemu-iotests/174
@@ -40,7 +40,15 @@ _unsupported_fmt raw
 
 
 size=256K
-IMGFMT=raw IMGKEYSECRET= _make_test_img --no-opts $size | _filter_imgfmt
+
+# _make_test_img may set variables that we need to retain.  Everything
+# in a pipe is executed in a subshell, so doing so would throw away
+# all changes.  Therefore, we have to store the output in some temp
+# file and filter that.
+scratch_out="$TEST_DIR/img-create.out"
+IMGFMT=raw IMGKEYSECRET= _make_test_img --no-opts $size >"$scratch_out"
+_filter_imgfmt <"$scratch_out"
+rm -f "$scratch_out"
 
 echo
 echo "== reading wrong format should fail =="
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 10/18] iotests: Use convert -n in some cases
  2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
                   ` (8 preceding siblings ...)
  2019-12-19 14:38 ` [PATCH 09/18] iotests: Do not pipe _make_test_img Max Reitz
@ 2019-12-19 14:38 ` Max Reitz
  2019-12-19 14:38 ` [PATCH 11/18] iotests: Avoid renaming images Max Reitz
                   ` (9 subsequent siblings)
  19 siblings, 0 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-19 14:38 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-devel, Max Reitz

qemu-img convert (without -n) can often be replaced by a combination of
_make_test_img + qemu-img convert -n.  Doing so allows converting to
protocols that do not allow direct file creation, such as FUSE exports.

So do it for some iotests, so they can run on FUSE exports.

Note that doing this allows us to remove a 9-line comment from 028 that
used to explain why we cannot safely filter drive-backup's image
creation output.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/013     |  3 ++-
 tests/qemu-iotests/013.out |  1 +
 tests/qemu-iotests/018     |  3 ++-
 tests/qemu-iotests/018.out |  1 +
 tests/qemu-iotests/028     | 14 ++++----------
 tests/qemu-iotests/028.out |  3 +++
 tests/qemu-iotests/072     |  3 ++-
 tests/qemu-iotests/072.out |  1 +
 tests/qemu-iotests/089     |  3 ++-
 tests/qemu-iotests/089.out |  1 +
 10 files changed, 19 insertions(+), 14 deletions(-)

diff --git a/tests/qemu-iotests/013 b/tests/qemu-iotests/013
index 5cb9032f16..b977290480 100755
--- a/tests/qemu-iotests/013
+++ b/tests/qemu-iotests/013
@@ -64,7 +64,8 @@ echo "Compressing image"
 echo
 
 mv "$TEST_IMG" "$TEST_IMG.orig"
-$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -c "$TEST_IMG.orig" "$TEST_IMG"
+_make_test_img 6G
+$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -c -n "$TEST_IMG.orig" "$TEST_IMG"
 
 echo "Testing compressed image"
 echo
diff --git a/tests/qemu-iotests/013.out b/tests/qemu-iotests/013.out
index 317cdf4b48..07323a742b 100644
--- a/tests/qemu-iotests/013.out
+++ b/tests/qemu-iotests/013.out
@@ -17592,6 +17592,7 @@ read 12288/12288 bytes at offset 4315947008
 No errors were found on the image.
 Compressing image
 
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944
 Testing compressed image
 
 With offset 0:
diff --git a/tests/qemu-iotests/018 b/tests/qemu-iotests/018
index c69ce09209..04e0a76cf3 100755
--- a/tests/qemu-iotests/018
+++ b/tests/qemu-iotests/018
@@ -81,7 +81,8 @@ done
 _check_test_img
 
 TEST_IMG="$TEST_IMG_SAVE"
-$QEMU_IMG convert -f $IMGFMT -O $IMGFMT "$TEST_IMG.orig" "$TEST_IMG"
+_make_test_img 6G
+$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n "$TEST_IMG.orig" "$TEST_IMG"
 
 echo "Reading"
 echo
diff --git a/tests/qemu-iotests/018.out b/tests/qemu-iotests/018.out
index 5df966727f..834900a1ab 100644
--- a/tests/qemu-iotests/018.out
+++ b/tests/qemu-iotests/018.out
@@ -537,6 +537,7 @@ wrote 512/512 bytes at offset 4295032320
 wrote 65536/65536 bytes at offset 4295098368
 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 No errors were found on the image.
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944
 Reading
 
 === IO: pattern 0
diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028
index e2556d8e57..8b0ce4e96a 100755
--- a/tests/qemu-iotests/028
+++ b/tests/qemu-iotests/028
@@ -116,16 +116,10 @@ else
     QEMU_COMM_TIMEOUT=1
 fi
 
-# Silence output since it contains the disk image path and QEMU's readline
-# character echoing makes it very hard to filter the output. Plus, there
-# is no telling how many times the command will repeat before succeeding.
-# (Note that creating the image results in a "Formatting..." message over
-# stdout, which is the same channel the monitor uses.  We cannot reliably
-# wait for it because the monitor output may interact with it in such a
-# way that _timed_wait_for cannot read it.  However, once the block job is
-# done, we know that the "Formatting..." message must have appeared
-# already, so the output is still deterministic.)
-silent=y _send_qemu_cmd $h "drive_backup disk ${TEST_IMG}.copy" "(qemu)"
+TEST_IMG="$TEST_IMG.copy" _make_test_img $image_size
+_send_qemu_cmd $h "drive_backup -n disk ${TEST_IMG}.copy" "(qemu)" \
+    | _filter_imgfmt
+
 silent=y qemu_cmd_repeat=20 _send_qemu_cmd $h "info block-jobs" "No active jobs"
 _send_qemu_cmd $h "info block-jobs" "No active jobs"
 _send_qemu_cmd $h 'quit' ""
diff --git a/tests/qemu-iotests/028.out b/tests/qemu-iotests/028.out
index 37aed84436..2bbdabc18f 100644
--- a/tests/qemu-iotests/028.out
+++ b/tests/qemu-iotests/028.out
@@ -468,6 +468,9 @@ No errors were found on the image.
 
 block-backup
 
+Formatting 'TEST_DIR/t.IMGFMT.copy', fmt=IMGFMT size=4294968832
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) drive_backup -n disk TEST_DIR/t.IMGFMT.copy
 (qemu) info block-jobs
 No active jobs
 === IO: pattern 195
diff --git a/tests/qemu-iotests/072 b/tests/qemu-iotests/072
index f0b73e7e65..3a9861bf24 100755
--- a/tests/qemu-iotests/072
+++ b/tests/qemu-iotests/072
@@ -51,7 +51,8 @@ TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE
 $QEMU_IO -c 'write -P 42 0 512' -c 'write -P 23 512 512' \
          -c 'write -P 66 1024 512' "$TEST_IMG.base" | _filter_qemu_io
 
-$QEMU_IMG convert -f raw -O $IMGFMT "$TEST_IMG.base" "$TEST_IMG"
+_make_test_img $IMG_SIZE
+$QEMU_IMG convert -f raw -O $IMGFMT -n "$TEST_IMG.base" "$TEST_IMG"
 
 $QEMU_IO -c "open -o driver=$IMGFMT,file.driver=$IMGFMT,file.file.filename=$TEST_IMG" \
          -c 'read -P 42 0 512' -c 'read -P 23 512 512' \
diff --git a/tests/qemu-iotests/072.out b/tests/qemu-iotests/072.out
index fe949d4781..46d24ade16 100644
--- a/tests/qemu-iotests/072.out
+++ b/tests/qemu-iotests/072.out
@@ -9,6 +9,7 @@ wrote 512/512 bytes at offset 512
 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 wrote 512/512 bytes at offset 1024
 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
 read 512/512 bytes at offset 0
 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 read 512/512 bytes at offset 512
diff --git a/tests/qemu-iotests/089 b/tests/qemu-iotests/089
index ad029f1f09..82c1d19680 100755
--- a/tests/qemu-iotests/089
+++ b/tests/qemu-iotests/089
@@ -62,7 +62,8 @@ TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE
 $QEMU_IO -c 'write -P 42 0 512' -c 'write -P 23 512 512' \
          -c 'write -P 66 1024 512' "$TEST_IMG.base" | _filter_qemu_io
 
-$QEMU_IMG convert -f raw -O $IMGFMT "$TEST_IMG.base" "$TEST_IMG"
+_make_test_img $IMG_SIZE
+$QEMU_IMG convert -f raw -O $IMGFMT -n "$TEST_IMG.base" "$TEST_IMG"
 
 $QEMU_IO_PROG --cache $CACHEMODE \
          -c 'read -P 42 0 512' -c 'read -P 23 512 512' \
diff --git a/tests/qemu-iotests/089.out b/tests/qemu-iotests/089.out
index 20c8ce8f0e..8ed5884f68 100644
--- a/tests/qemu-iotests/089.out
+++ b/tests/qemu-iotests/089.out
@@ -9,6 +9,7 @@ wrote 512/512 bytes at offset 512
 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 wrote 512/512 bytes at offset 1024
 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
 read 512/512 bytes at offset 0
 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 read 512/512 bytes at offset 512
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 11/18] iotests: Avoid renaming images
  2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
                   ` (9 preceding siblings ...)
  2019-12-19 14:38 ` [PATCH 10/18] iotests: Use convert -n in some cases Max Reitz
@ 2019-12-19 14:38 ` Max Reitz
  2019-12-19 14:38 ` [PATCH 12/18] iotests: Derive image names from $TEST_IMG Max Reitz
                   ` (8 subsequent siblings)
  19 siblings, 0 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-19 14:38 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-devel, Max Reitz

This generally does not work on non-file protocols.  It is better to
create the image with the final name from the start, and most tests do
this already.  Let 013 and 046 follow suit.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/013     | 4 +++-
 tests/qemu-iotests/013.out | 2 +-
 tests/qemu-iotests/046     | 5 +++--
 tests/qemu-iotests/046.out | 2 +-
 4 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/tests/qemu-iotests/013 b/tests/qemu-iotests/013
index b977290480..a2c748c55e 100755
--- a/tests/qemu-iotests/013
+++ b/tests/qemu-iotests/013
@@ -46,6 +46,8 @@ TEST_OFFSETS="0 4294967296"
 TEST_OPS="writev read write readv"
 CLUSTER_SIZE=4096
 
+TEST_IMG_SAVE=$TEST_IMG
+TEST_IMG="$TEST_IMG.orig"
 _make_test_img 6G
 
 echo "Testing empty image"
@@ -63,7 +65,7 @@ done
 echo "Compressing image"
 echo
 
-mv "$TEST_IMG" "$TEST_IMG.orig"
+TEST_IMG=$TEST_IMG_SAVE
 _make_test_img 6G
 $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -c -n "$TEST_IMG.orig" "$TEST_IMG"
 
diff --git a/tests/qemu-iotests/013.out b/tests/qemu-iotests/013.out
index 07323a742b..23e3160b49 100644
--- a/tests/qemu-iotests/013.out
+++ b/tests/qemu-iotests/013.out
@@ -1,5 +1,5 @@
 QA output created by 013
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944
+Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=6442450944
 Testing empty image
 
 At offset 0:
diff --git a/tests/qemu-iotests/046 b/tests/qemu-iotests/046
index a066eec605..1dca1f4f30 100755
--- a/tests/qemu-iotests/046
+++ b/tests/qemu-iotests/046
@@ -47,6 +47,8 @@ size=128M
 echo
 echo "== creating backing file for COW tests =="
 
+TEST_IMG_SAVE=$TEST_IMG
+TEST_IMG="$TEST_IMG.base"
 _make_test_img $size
 
 backing_io()
@@ -67,8 +69,7 @@ backing_io()
 
 backing_io 0 32 write | $QEMU_IO "$TEST_IMG" | _filter_qemu_io
 
-mv "$TEST_IMG" "$TEST_IMG.base"
-
+TEST_IMG=$TEST_IMG_SAVE
 _make_test_img -b "$TEST_IMG.base" 6G
 
 echo
diff --git a/tests/qemu-iotests/046.out b/tests/qemu-iotests/046.out
index ca2c7404a9..15d9ebd232 100644
--- a/tests/qemu-iotests/046.out
+++ b/tests/qemu-iotests/046.out
@@ -1,7 +1,7 @@
 QA output created by 046
 
 == creating backing file for COW tests ==
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
 wrote 65536/65536 bytes at offset 0
 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 wrote 65536/65536 bytes at offset 65536
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 12/18] iotests: Derive image names from $TEST_IMG
  2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
                   ` (10 preceding siblings ...)
  2019-12-19 14:38 ` [PATCH 11/18] iotests: Avoid renaming images Max Reitz
@ 2019-12-19 14:38 ` Max Reitz
  2019-12-19 14:38 ` [PATCH 13/18] iotests/091: Use _cleanup_qemu instad of "wait" Max Reitz
                   ` (7 subsequent siblings)
  19 siblings, 0 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-19 14:38 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-devel, Max Reitz

Avoid creating images with custom filenames in $TEST_DIR, because
non-file protocols may want to keep $TEST_IMG (and all other test
images) in some other directory.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/200     | 3 +--
 tests/qemu-iotests/200.out | 4 ++--
 tests/qemu-iotests/229     | 3 +--
 tests/qemu-iotests/229.out | 6 +++---
 4 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/tests/qemu-iotests/200 b/tests/qemu-iotests/200
index a2cdd7f83d..616b632a86 100755
--- a/tests/qemu-iotests/200
+++ b/tests/qemu-iotests/200
@@ -44,8 +44,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 _supported_fmt qcow2 qed
 _supported_proto file
 
-BACKING_IMG="${TEST_DIR}/backing.img"
-TEST_IMG="${TEST_DIR}/test.img"
+BACKING_IMG="$TEST_IMG.base"
 
 TEST_IMG="$BACKING_IMG" _make_test_img 512M
 _make_test_img -F $IMGFMT -b "$BACKING_IMG" 512M
diff --git a/tests/qemu-iotests/200.out b/tests/qemu-iotests/200.out
index a6776070e4..5883f16ac3 100644
--- a/tests/qemu-iotests/200.out
+++ b/tests/qemu-iotests/200.out
@@ -1,6 +1,6 @@
 QA output created by 200
-Formatting 'TEST_DIR/backing.img', fmt=IMGFMT size=536870912
-Formatting 'TEST_DIR/test.img', fmt=IMGFMT size=536870912 backing_file=TEST_DIR/backing.img backing_fmt=IMGFMT
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=536870912
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=536870912 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
 wrote 314572800/314572800 bytes at offset 512
 300 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 
diff --git a/tests/qemu-iotests/229 b/tests/qemu-iotests/229
index 866168b236..abc88f881f 100755
--- a/tests/qemu-iotests/229
+++ b/tests/qemu-iotests/229
@@ -47,8 +47,7 @@ _supported_proto file
 _supported_os Linux
 
 
-DEST_IMG="$TEST_DIR/d.$IMGFMT"
-TEST_IMG="$TEST_DIR/b.$IMGFMT"
+DEST_IMG="$TEST_IMG.dest"
 
 _make_test_img 2M
 
diff --git a/tests/qemu-iotests/229.out b/tests/qemu-iotests/229.out
index 22350d75d7..ef96b85062 100644
--- a/tests/qemu-iotests/229.out
+++ b/tests/qemu-iotests/229.out
@@ -1,6 +1,6 @@
 QA output created by 229
-Formatting 'TEST_DIR/b.IMGFMT', fmt=IMGFMT size=2097152
-Formatting 'TEST_DIR/d.IMGFMT', fmt=IMGFMT size=1048576
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2097152
+Formatting 'TEST_DIR/t.IMGFMT.dest', fmt=IMGFMT size=1048576
 wrote 2097152/2097152 bytes at offset 0
 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 {'execute': 'qmp_capabilities'}
@@ -8,7 +8,7 @@ wrote 2097152/2097152 bytes at offset 0
 
 === Starting drive-mirror, causing error & stop  ===
 
-{'execute': 'drive-mirror', 'arguments': {'device': 'testdisk', 'format': 'IMGFMT', 'target': 'TEST_DIR/d.IMGFMT', 'sync': 'full', 'mode': 'existing', 'on-source-error': 'stop', 'on-target-error': 'stop' }}
+{'execute': 'drive-mirror', 'arguments': {'device': 'testdisk', 'format': 'IMGFMT', 'target': 'TEST_DIR/t.IMGFMT.dest', 'sync': 'full', 'mode': 'existing', 'on-source-error': 'stop', 'on-target-error': 'stop' }}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "testdisk"}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "testdisk"}}
 {"return": {}}
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 13/18] iotests/091: Use _cleanup_qemu instad of "wait"
  2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
                   ` (11 preceding siblings ...)
  2019-12-19 14:38 ` [PATCH 12/18] iotests: Derive image names from $TEST_IMG Max Reitz
@ 2019-12-19 14:38 ` Max Reitz
  2019-12-19 14:38 ` [PATCH 14/18] iotests: Restrict some Python tests to file Max Reitz
                   ` (6 subsequent siblings)
  19 siblings, 0 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-19 14:38 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-devel, Max Reitz

If the test environment has some other child processes running (like a
storage daemon that provides a FUSE export), then "wait" will never
finish.  Use wait=yes _cleanup_qemu instead.

(We need to discard the output so there is no change to the reference
output.)

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/091 | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091
index 0874fa84c8..7d23a6862b 100755
--- a/tests/qemu-iotests/091
+++ b/tests/qemu-iotests/091
@@ -96,7 +96,8 @@ _send_qemu_cmd $h2 'qemu-io disk flush' "(qemu)"
 _send_qemu_cmd $h2 'quit' ""
 _send_qemu_cmd $h1 'quit' ""
 
-wait
+wait=yes _cleanup_qemu >/dev/null
+
 echo "Check image pattern"
 ${QEMU_IO} -c "read -P 0x22 0 4M" "${TEST_IMG}" | _filter_testdir | _filter_qemu_io
 
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 14/18] iotests: Restrict some Python tests to file
  2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
                   ` (12 preceding siblings ...)
  2019-12-19 14:38 ` [PATCH 13/18] iotests/091: Use _cleanup_qemu instad of "wait" Max Reitz
@ 2019-12-19 14:38 ` Max Reitz
  2019-12-19 14:38 ` [PATCH 15/18] iotests: Let _make_test_img guess $TEST_IMG_FILE Max Reitz
                   ` (5 subsequent siblings)
  19 siblings, 0 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-19 14:38 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-devel, Max Reitz

Most Python tests are restricted to the file protocol (without
explicitly saying so), but these are the ones that would break
./check -fuse -qcow2.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/206 | 1 +
 tests/qemu-iotests/242 | 1 +
 2 files changed, 2 insertions(+)

diff --git a/tests/qemu-iotests/206 b/tests/qemu-iotests/206
index 5bb738bf23..b3e8c5bb96 100755
--- a/tests/qemu-iotests/206
+++ b/tests/qemu-iotests/206
@@ -24,6 +24,7 @@ import iotests
 from iotests import imgfmt
 
 iotests.verify_image_format(supported_fmts=['qcow2'])
+iotests.verify_protocol(supported=['file'])
 
 def blockdev_create(vm, options):
     result = vm.qmp_log('blockdev-create',
diff --git a/tests/qemu-iotests/242 b/tests/qemu-iotests/242
index c176e92da6..452fbb7b80 100755
--- a/tests/qemu-iotests/242
+++ b/tests/qemu-iotests/242
@@ -25,6 +25,7 @@ from iotests import qemu_img_create, qemu_io, qemu_img_pipe, \
     file_path, img_info_log, log, filter_qemu_io
 
 iotests.verify_image_format(supported_fmts=['qcow2'])
+iotests.verify_protocol(supported=['file'])
 
 disk = file_path('disk')
 chunk = 256 * 1024
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 15/18] iotests: Let _make_test_img guess $TEST_IMG_FILE
  2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
                   ` (13 preceding siblings ...)
  2019-12-19 14:38 ` [PATCH 14/18] iotests: Restrict some Python tests to file Max Reitz
@ 2019-12-19 14:38 ` Max Reitz
  2019-12-19 14:38 ` [PATCH 16/18] iotests: Allow testing FUSE exports Max Reitz
                   ` (4 subsequent siblings)
  19 siblings, 0 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-19 14:38 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-devel, Max Reitz

When most iotests want to create a test image that is named differently
from the default $TEST_IMG, they do something like this:

    TEST_IMG="$TEST_IMG.base" _make_test_img $options

This works fine with the "file" protocol, but not so much for anything
else: _make_test_img tries to create an image under $TEST_IMG_FILE
first, and only under $TEST_IMG if the former is not set; and on
everything but "file", $TEST_IMG_FILE is set.

There are two ways we can fix this: First, we could make all tests
adjust not only TEST_IMG, but also TEST_IMG_FILE if that is present
(e.g. with something like _set_test_img_suffix $suffix that would affect
not only TEST_IMG but also TEST_IMG_FILE, if necessary).  This is a
pretty clean solution, and this is maybe what we should have done from
the start.

But it would also require changes to most existing bash tests.  So the
alternative is this: Let _make_test_img see whether $TEST_IMG_FILE still
points to the original value.  If so, it is possible that the caller has
adjusted $TEST_IMG but not $TEST_IMG_FILE.  In such a case, we can (for
most protocols) derive the corresponding $TEST_IMG_FILE value from
$TEST_IMG value and thus work around what technically is the caller
misbehaving.

This second solution is less clean, but it is robust against people
keeping their old habit of adjusting TEST_IMG only, and requires much
less changes.  So this patch implements it.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/common.rc | 42 +++++++++++++++++++++++++++++++++---
 1 file changed, 39 insertions(+), 3 deletions(-)

diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index d088392ab6..192c988401 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -250,6 +250,7 @@ else
         TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT
     fi
 fi
+ORIG_TEST_IMG_FILE=$TEST_IMG_FILE
 ORIG_TEST_IMG="$TEST_IMG"
 
 if [ -z "$TEST_DIR" ]; then
@@ -312,6 +313,33 @@ _get_data_file()
                     | sed -e "s#\\\$TEST_IMG#$1#"
 }
 
+# Translate a $TEST_IMG to its corresponding $TEST_IMG_FILE for
+# different protocols
+_test_img_to_test_img_file()
+{
+    case "$IMGPROTO" in
+        file)
+            echo "$1"
+            ;;
+
+        nfs)
+            echo "$1" | sed -e "s#nfs://127.0.0.1##"
+            ;;
+
+        ssh)
+            echo "$1" | sed -e "s#ssh://127.0.0.1##"
+            ;;
+
+        vxhs)
+            echo "$1" | sed -e "s#vxhs://127.0.0.1:9999#$TEST_DIR#"
+            ;;
+
+        *)
+            return 1
+            ;;
+    esac
+}
+
 _make_test_img()
 {
     # extra qemu-img options can be added by tests
@@ -325,10 +353,18 @@ _make_test_img()
     local opts_param=false
     local misc_params=()
 
-    if [ -n "$TEST_IMG_FILE" ]; then
-        img_name=$TEST_IMG_FILE
-    else
+    if [ -z "$TEST_IMG_FILE" ]; then
         img_name=$TEST_IMG
+    elif [ "$TEST_IMG_FILE" = "$ORIG_TEST_IMG_FILE" ]; then
+        # Handle cases of tests only updating TEST_IMG, but not TEST_IMG_FILE
+        img_name=$(_test_img_to_test_img_file "$TEST_IMG")
+        if [ "$?" != 0 ]; then
+            img_name=$TEST_IMG_FILE
+        fi
+    else
+        # $TEST_IMG_FILE is not the default value, so it definitely has been
+        # modified by the test
+        img_name=$TEST_IMG_FILE
     fi
 
     if [ -n "$IMGOPTS" ]; then
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 16/18] iotests: Allow testing FUSE exports
  2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
                   ` (14 preceding siblings ...)
  2019-12-19 14:38 ` [PATCH 15/18] iotests: Let _make_test_img guess $TEST_IMG_FILE Max Reitz
@ 2019-12-19 14:38 ` Max Reitz
  2019-12-19 14:38 ` [PATCH 17/18] iotests: Enable fuse for many tests Max Reitz
                   ` (3 subsequent siblings)
  19 siblings, 0 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-19 14:38 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-devel, Max Reitz

This pretends FUSE exports are a kind of protocol.  As such, they are
always tested under the format node.  This is probably the best way to
test them, actually, because this will generate more I/O load and more
varied patterns.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/check         |   6 ++
 tests/qemu-iotests/common.filter |   5 +-
 tests/qemu-iotests/common.rc     | 148 +++++++++++++++++++++++++++++++
 3 files changed, 158 insertions(+), 1 deletion(-)

diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
index 90970b0549..dcb725e4eb 100755
--- a/tests/qemu-iotests/check
+++ b/tests/qemu-iotests/check
@@ -263,6 +263,7 @@ image protocol options
     -rbd                test rbd
     -sheepdog           test sheepdog
     -nbd                test nbd
+    -fuse               test fuse
     -ssh                test ssh
     -nfs                test nfs
     -vxhs               test vxhs
@@ -375,6 +376,11 @@ testlist options
             xpand=false
             ;;
 
+        -fuse)
+            IMGPROTO=fuse
+            xpand=false
+            ;;
+
         -vxhs)
             IMGPROTO=vxhs
             xpand=false
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index 3f8ee3e5f7..5f48351cae 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -44,7 +44,8 @@ _filter_qom_path()
 _filter_testdir()
 {
     $SED -e "s#$TEST_DIR/#TEST_DIR/#g" \
-         -e "s#$SOCK_DIR/#SOCK_DIR/#g"
+         -e "s#$SOCK_DIR/#SOCK_DIR/#g" \
+         -e "s#SOCK_DIR/fuse-#TEST_DIR/#g"
 }
 
 # replace occurrences of the actual IMGFMT value with IMGFMT
@@ -135,6 +136,7 @@ _filter_img_create()
         -e "s#$IMGFMT#IMGFMT#g" \
         -e 's#nbd:127.0.0.1:[0-9]\\+#TEST_DIR/t.IMGFMT#g' \
         -e 's#nbd+unix:///\??socket=SOCK_DIR/nbd#TEST_DIR/t.IMGFMT#g' \
+        -e 's#SOCK_DIR/fuse-#TEST_DIR/#g' \
         -e "s# encryption=off##g" \
         -e "s# cluster_size=[0-9]\\+##g" \
         -e "s# table_size=[0-9]\\+##g" \
@@ -173,6 +175,7 @@ _filter_img_info()
         -e "s#$IMGFMT#IMGFMT#g" \
         -e 's#nbd://127.0.0.1:[0-9]\\+$#TEST_DIR/t.IMGFMT#g' \
         -e 's#nbd+unix:///\??socket=SOCK_DIR/nbd#TEST_DIR/t.IMGFMT#g' \
+        -e 's#SOCK_DIR/fuse-#TEST_DIR/#g' \
         -e 's#json.*vdisk-id.*vxhs"}}#TEST_DIR/t.IMGFMT#' \
         -e "/encrypted: yes/d" \
         -e "/cluster_size: [0-9]\\+/d" \
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index 192c988401..fbd8fb7309 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -219,6 +219,9 @@ if [ "$IMGOPTSSYNTAX" = "true" ]; then
         TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
         TEST_IMG="$DRIVER,file.driver=nbd,file.type=unix"
         TEST_IMG="$TEST_IMG,file.path=$SOCK_DIR/nbd"
+    elif [ "$IMGPROTO" = "fuse" ]; then
+        TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
+        TEST_IMG="$DRIVER,file.filename=$SOCK_DIR/fuse-t.$IMGFMT"
     elif [ "$IMGPROTO" = "ssh" ]; then
         TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
         TEST_IMG="$DRIVER,file.driver=ssh,file.host=127.0.0.1,file.path=$TEST_IMG_FILE"
@@ -235,6 +238,9 @@ else
     elif [ "$IMGPROTO" = "nbd" ]; then
         TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
         TEST_IMG="nbd+unix:///?socket=$SOCK_DIR/nbd"
+    elif [ "$IMGPROTO" = "fuse" ]; then
+        TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
+        TEST_IMG="$SOCK_DIR/fuse-t.$IMGFMT"
     elif [ "$IMGPROTO" = "ssh" ]; then
         TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
         REMOTE_TEST_DIR="ssh://\\($USER@\\)\\?127.0.0.1\\(:[0-9]\\+\\)\\?$TEST_DIR"
@@ -253,6 +259,9 @@ fi
 ORIG_TEST_IMG_FILE=$TEST_IMG_FILE
 ORIG_TEST_IMG="$TEST_IMG"
 
+FUSE_PIDS=()
+FUSE_EXPORTS=()
+
 if [ -z "$TEST_DIR" ]; then
         TEST_DIR=$PWD/scratch
 fi
@@ -322,6 +331,10 @@ _test_img_to_test_img_file()
             echo "$1"
             ;;
 
+        fuse)
+            echo "$1" | sed -e "s#$SOCK_DIR/fuse-#$TEST_DIR/#"
+            ;;
+
         nfs)
             echo "$1" | sed -e "s#nfs://127.0.0.1##"
             ;;
@@ -353,6 +366,11 @@ _make_test_img()
     local opts_param=false
     local misc_params=()
 
+    if [[ $IMGPROTO == fuse && $TEST_IMG == $SOCK_DIR/fuse-* ]]; then
+        # The caller may be trying to overwrite an existing image
+        _rm_test_img "$TEST_IMG"
+    fi
+
     if [ -z "$TEST_IMG_FILE" ]; then
         img_name=$TEST_IMG
     elif [ "$TEST_IMG_FILE" = "$ORIG_TEST_IMG_FILE" ]; then
@@ -437,6 +455,68 @@ _make_test_img()
         sleep 1 # FIXME: qemu-nbd needs to be listening before we continue
     fi
 
+    if [ $IMGPROTO = "fuse" -a -f "$img_name" ]; then
+        local export_mp
+        local pid
+        local pidfile
+        local timeout
+
+        export_mp=$(echo "$img_name" | sed -e "s#$TEST_DIR/#$SOCK_DIR/fuse-#")
+        if ! echo "$export_mp" | grep -q "^$SOCK_DIR"; then
+            echo 'Cannot use FUSE exports with images outside of TEST_DIR' >&2
+            return 1
+        fi
+
+        touch "$export_mp"
+        rm -f "$SOCK_DIR/fuse-output"
+
+        # Usually, users would export formatted nodes.  But we present fuse as a
+        # protocol-level driver here, so we have to leave the format to the
+        # client.
+        echo "{'execute': 'qmp_capabilities'}
+              {'execute': 'fuse-export-add',
+               'arguments': { 'node-name': 'export-node',
+                              'mountpoint': '$export_mp',
+                              'writable': true,
+                              'growable': true }}" | \
+        QEMU_NEED_PID=y _QEMU_HANDLE=fuse $QEMU -qmp stdio \
+              -M none,accel=qtest -qtest null \
+              -blockdev file,node-name=export-node,filename=$img_name,discard=unmap \
+              >$SOCK_DIR/fuse-output &
+
+        pidfile="$QEMU_TEST_DIR/qemu-fuse.pid"
+
+        # Wait for the PID file
+        while [ ! -f "$pidfile" ]; do
+            sleep 0.5
+        done
+
+        pid=$(cat "$pidfile")
+        rm -f "$pidfile"
+
+        # Wait until the node is exported (i.e., both QMP commands
+        # have been completed)
+        timeout=10 # *0.5 s
+        while [ "$(grep -c return "$SOCK_DIR/fuse-output" 2>/dev/null)" != 2 ]; do
+            sleep 0.5
+
+            timeout=$((timeout - 1))
+            if [ "$timeout" = 0 ]; then
+                kill -SIGTERM $pid
+                echo 'Failed to set up FUSE export:' >&2
+                cat "$SOCK_DIR/fuse-output" >&2
+                rm -f "$export_mp"
+                break
+            fi
+        done
+        rm -f "$SOCK_DIR/fuse-output"
+
+        if [ "$timeout" -gt 0 ]; then
+            FUSE_PIDS+=($pid)
+            FUSE_EXPORTS+=("$export_mp")
+        fi
+    fi
+
     # Start QNIO server on image directory for vxhs protocol
     if [ $IMGPROTO = "vxhs" ]; then
         eval "$QEMU_VXHS -d  $TEST_DIR > /dev/null &"
@@ -447,6 +527,63 @@ _make_test_img()
 _rm_test_img()
 {
     local img=$1
+
+    if [[ $IMGPROTO == fuse && $img == $SOCK_DIR/fuse-* ]]; then
+        # Drop a FUSE export
+        local df_output
+        local i
+        local image_file
+        local index=''
+        local timeout
+
+        for i in "${!FUSE_EXPORTS[@]}"; do
+            if [ "${FUSE_EXPORTS[i]}" = "$img" ]; then
+                index=$i
+                break
+            fi
+        done
+
+        if [ -z "$index" ]; then
+            # Probably gone already
+            return 0
+        fi
+
+        kill "${FUSE_PIDS[index]}"
+
+        # Wait until the mount is gone
+        timeout=10 # *0.5 s
+        while true; do
+            # Will show the mount point; if the mount is still there,
+            # it will be $img.
+            df_output=$(df -T "$img" 2>/dev/null)
+
+            # But df may also show an error ("Transpoint endpoint not
+            # connected"), so retry in such cases
+            if [ -n "$df_output" ]; then
+                if ! echo "$df_output" | grep -q "$img"; then
+                    break
+                fi
+            fi
+
+            sleep 0.5
+
+            timeout=$((timeout - 1))
+            if [ "$timeout" = 0 ]; then
+                echo 'Failed to take down FUSE export' >&2
+                return 1
+            fi
+        done
+
+        rm -f "$img"
+
+        unset "FUSE_PIDS[$index]"
+        unset "FUSE_EXPORTS[$index]"
+
+        image_file=$(echo "$img" | sed -e "s#$SOCK_DIR/fuse-#$TEST_DIR/#")
+        _rm_test_img "$image_file"
+        return
+    fi
+
     if [ "$IMGFMT" = "vmdk" ]; then
         # Remove all the extents for vmdk
         "$QEMU_IMG" info "$img" 2>/dev/null | grep 'filename:' | cut -f 2 -d: \
@@ -468,6 +605,16 @@ _cleanup_test_img()
             _stop_nbd_server
             rm -f "$TEST_IMG_FILE"
             ;;
+        fuse)
+            local mp
+
+            for mp in "${FUSE_EXPORTS[@]}"; do
+                _rm_test_img "$mp"
+            done
+
+            FUSE_PIDS=()
+            FUSE_EXPORTS=()
+            ;;
         vxhs)
             if [ -f "${TEST_DIR}/qemu-vxhs.pid" ]; then
                 local QEMU_VXHS_PID
@@ -544,6 +691,7 @@ _img_info()
         sed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \
             -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
             -e "s#$TEST_DIR#TEST_DIR#g" \
+            -e "s#$SOCK_DIR/fuse-#TEST_DIR/#g" \
             -e "s#$IMGFMT#IMGFMT#g" \
             -e "/^disk size:/ D" \
             -e "/actual-size/ D" | \
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 17/18] iotests: Enable fuse for many tests
  2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
                   ` (15 preceding siblings ...)
  2019-12-19 14:38 ` [PATCH 16/18] iotests: Allow testing FUSE exports Max Reitz
@ 2019-12-19 14:38 ` Max Reitz
  2019-12-19 14:38 ` [PATCH 18/18] iotests/281: Add test for FUSE exports Max Reitz
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-19 14:38 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-devel, Max Reitz

Many tests (that do not support generic protocols) can run just fine
with FUSE-exported images, so allow them to.

Note that 221 and 250 only pass when .lseek is correctly implemented,
which is only possible with a libfuse that is 3.8 or newer.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/013 | 2 +-
 tests/qemu-iotests/018 | 2 +-
 tests/qemu-iotests/020 | 2 +-
 tests/qemu-iotests/025 | 2 +-
 tests/qemu-iotests/026 | 2 +-
 tests/qemu-iotests/028 | 2 +-
 tests/qemu-iotests/031 | 2 +-
 tests/qemu-iotests/034 | 2 +-
 tests/qemu-iotests/036 | 2 +-
 tests/qemu-iotests/037 | 2 +-
 tests/qemu-iotests/038 | 2 +-
 tests/qemu-iotests/039 | 2 +-
 tests/qemu-iotests/046 | 2 +-
 tests/qemu-iotests/050 | 2 +-
 tests/qemu-iotests/054 | 2 +-
 tests/qemu-iotests/060 | 2 +-
 tests/qemu-iotests/071 | 2 +-
 tests/qemu-iotests/072 | 2 +-
 tests/qemu-iotests/079 | 2 +-
 tests/qemu-iotests/080 | 2 +-
 tests/qemu-iotests/089 | 2 +-
 tests/qemu-iotests/090 | 2 +-
 tests/qemu-iotests/091 | 2 +-
 tests/qemu-iotests/095 | 2 +-
 tests/qemu-iotests/097 | 2 +-
 tests/qemu-iotests/098 | 2 +-
 tests/qemu-iotests/102 | 2 +-
 tests/qemu-iotests/103 | 2 +-
 tests/qemu-iotests/106 | 2 +-
 tests/qemu-iotests/107 | 2 +-
 tests/qemu-iotests/108 | 2 +-
 tests/qemu-iotests/111 | 2 +-
 tests/qemu-iotests/112 | 2 +-
 tests/qemu-iotests/115 | 2 +-
 tests/qemu-iotests/117 | 2 +-
 tests/qemu-iotests/120 | 2 +-
 tests/qemu-iotests/121 | 2 +-
 tests/qemu-iotests/127 | 2 +-
 tests/qemu-iotests/133 | 2 +-
 tests/qemu-iotests/137 | 2 +-
 tests/qemu-iotests/138 | 2 +-
 tests/qemu-iotests/140 | 2 +-
 tests/qemu-iotests/154 | 2 +-
 tests/qemu-iotests/161 | 2 +-
 tests/qemu-iotests/171 | 2 +-
 tests/qemu-iotests/175 | 2 +-
 tests/qemu-iotests/176 | 2 +-
 tests/qemu-iotests/177 | 2 +-
 tests/qemu-iotests/179 | 2 +-
 tests/qemu-iotests/183 | 2 +-
 tests/qemu-iotests/186 | 2 +-
 tests/qemu-iotests/187 | 2 +-
 tests/qemu-iotests/191 | 2 +-
 tests/qemu-iotests/195 | 2 +-
 tests/qemu-iotests/200 | 2 +-
 tests/qemu-iotests/204 | 2 +-
 tests/qemu-iotests/214 | 2 +-
 tests/qemu-iotests/217 | 2 +-
 tests/qemu-iotests/220 | 2 +-
 tests/qemu-iotests/221 | 2 +-
 tests/qemu-iotests/229 | 2 +-
 tests/qemu-iotests/247 | 2 +-
 tests/qemu-iotests/249 | 2 +-
 tests/qemu-iotests/250 | 2 +-
 tests/qemu-iotests/252 | 2 +-
 tests/qemu-iotests/265 | 2 +-
 tests/qemu-iotests/268 | 2 +-
 tests/qemu-iotests/272 | 2 +-
 tests/qemu-iotests/273 | 2 +-
 tests/qemu-iotests/279 | 2 +-
 70 files changed, 70 insertions(+), 70 deletions(-)

diff --git a/tests/qemu-iotests/013 b/tests/qemu-iotests/013
index a2c748c55e..8e17a43cf0 100755
--- a/tests/qemu-iotests/013
+++ b/tests/qemu-iotests/013
@@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # much of this could be generic for any format supporting compression.
 _supported_fmt qcow qcow2
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 
 TEST_OFFSETS="0 4294967296"
diff --git a/tests/qemu-iotests/018 b/tests/qemu-iotests/018
index 04e0a76cf3..bc7797ffe5 100755
--- a/tests/qemu-iotests/018
+++ b/tests/qemu-iotests/018
@@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # Any format supporting backing files
 _supported_fmt qcow qcow2 vmdk qed
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 _unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \
                      "streamOptimized"
diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020
index 20f8f185d0..fef5cdf429 100755
--- a/tests/qemu-iotests/020
+++ b/tests/qemu-iotests/020
@@ -41,7 +41,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # Any format supporting backing files
 _supported_fmt qcow qcow2 vmdk qed
-_supported_proto file
+_supported_proto file fuse
 _unsupported_imgopts "subformat=monolithicFlat" \
                      "subformat=twoGbMaxExtentFlat" \
                      "subformat=twoGbMaxExtentSparse" \
diff --git a/tests/qemu-iotests/025 b/tests/qemu-iotests/025
index e05d833452..1569d912f4 100755
--- a/tests/qemu-iotests/025
+++ b/tests/qemu-iotests/025
@@ -38,7 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.pattern
 
 _supported_fmt raw qcow2 qed luks
-_supported_proto file sheepdog rbd nfs
+_supported_proto file sheepdog rbd nfs fuse
 
 echo "=== Creating image"
 echo
diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026
index a4aa74764f..9623e54998 100755
--- a/tests/qemu-iotests/026
+++ b/tests/qemu-iotests/026
@@ -40,7 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # Currently only qcow2 supports rebasing
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 _default_cache_mode writethrough
 _supported_cache_modes writethrough none
 # The refcount table tests expect a certain minimum width for refcount entries
diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028
index 8b0ce4e96a..3c975f3e6f 100755
--- a/tests/qemu-iotests/028
+++ b/tests/qemu-iotests/028
@@ -46,7 +46,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # Any format supporting backing files except vmdk and qcow which do not support
 # smaller backing files.
 _supported_fmt qcow2 qed
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 
 # Choose a size that is not necessarily a cluster size multiple for image
diff --git a/tests/qemu-iotests/031 b/tests/qemu-iotests/031
index 646ecd593f..2bcbc5886e 100755
--- a/tests/qemu-iotests/031
+++ b/tests/qemu-iotests/031
@@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # This tests qcow2-specific low-level functionality
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 # We want to test compat=0.10, which does not support external data
 # files or refcount widths other than 16
 _unsupported_imgopts data_file 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
diff --git a/tests/qemu-iotests/034 b/tests/qemu-iotests/034
index da4cea1571..6f283177ef 100755
--- a/tests/qemu-iotests/034
+++ b/tests/qemu-iotests/034
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow qcow2 vmdk qed
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 _unsupported_imgopts "subformat=monolithicFlat" \
                      "subformat=twoGbMaxExtentFlat" \
diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036
index 512598421c..626f295935 100755
--- a/tests/qemu-iotests/036
+++ b/tests/qemu-iotests/036
@@ -42,7 +42,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # This tests qcow2-specific low-level functionality
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 # Only qcow2v3 and later supports feature bits;
 # qcow2.py does not support external data files
 _unsupported_imgopts 'compat=0.10' data_file
diff --git a/tests/qemu-iotests/037 b/tests/qemu-iotests/037
index e6517acbd4..9bf5bbd6a0 100755
--- a/tests/qemu-iotests/037
+++ b/tests/qemu-iotests/037
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow qcow2 vmdk qed
-_supported_proto file
+_supported_proto file fuse
 _unsupported_imgopts "subformat=monolithicFlat" \
                      "subformat=twoGbMaxExtentFlat" \
                      "subformat=twoGbMaxExtentSparse" \
diff --git a/tests/qemu-iotests/038 b/tests/qemu-iotests/038
index 707e2d72e9..9367b91d23 100755
--- a/tests/qemu-iotests/038
+++ b/tests/qemu-iotests/038
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2 qed
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 
 CLUSTER_SIZE=2M
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
index ddce48ab47..329896307f 100755
--- a/tests/qemu-iotests/039
+++ b/tests/qemu-iotests/039
@@ -40,7 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 _default_cache_mode writethrough
 _supported_cache_modes writethrough
diff --git a/tests/qemu-iotests/046 b/tests/qemu-iotests/046
index 1dca1f4f30..8d0c338a42 100755
--- a/tests/qemu-iotests/046
+++ b/tests/qemu-iotests/046
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 # data_file does not support compressed clusters
 _unsupported_imgopts data_file
 
diff --git a/tests/qemu-iotests/050 b/tests/qemu-iotests/050
index cdc5356541..75b8fd6f6e 100755
--- a/tests/qemu-iotests/050
+++ b/tests/qemu-iotests/050
@@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2 qed
-_supported_proto file
+_supported_proto file fuse
 
 echo
 echo "== Creating images =="
diff --git a/tests/qemu-iotests/054 b/tests/qemu-iotests/054
index a8905b60d0..40922db2b1 100755
--- a/tests/qemu-iotests/054
+++ b/tests/qemu-iotests/054
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 
 echo
 echo "creating too large image (1 EB)"
diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060
index 043f12904a..c8f7d2523f 100755
--- a/tests/qemu-iotests/060
+++ b/tests/qemu-iotests/060
@@ -46,7 +46,7 @@ _filter_io_error()
 
 # This tests qcow2-specific low-level functionality
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 # These tests only work for compat=1.1 images without an external
 # data file with refcount_bits=16
diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071
index 18fe9054b0..49faae6684 100755
--- a/tests/qemu-iotests/071
+++ b/tests/qemu-iotests/071
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 _require_drivers blkdebug blkverify
 # blkdebug can only inject errors on bs->file, not on the data_file,
 # so thie test does not work with external data files
diff --git a/tests/qemu-iotests/072 b/tests/qemu-iotests/072
index 3a9861bf24..7ee52dca42 100755
--- a/tests/qemu-iotests/072
+++ b/tests/qemu-iotests/072
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt vpc vmdk vhdx vdi qed qcow2 qcow
-_supported_proto file
+_supported_proto file fuse
 _unsupported_imgopts "subformat=streamOptimized"
 
 IMG_SIZE=64M
diff --git a/tests/qemu-iotests/079 b/tests/qemu-iotests/079
index 3642b51feb..0f0d94a2ac 100755
--- a/tests/qemu-iotests/079
+++ b/tests/qemu-iotests/079
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file nfs
+_supported_proto file nfs fuse
 
 # Some containers (e.g. non-x86 on Travis) do not allow large files
 _require_large_file 4G
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
index a3d13c414e..906e82bd19 100755
--- a/tests/qemu-iotests/080
+++ b/tests/qemu-iotests/080
@@ -38,7 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 # - Internal snapshots are (currently) impossible with refcount_bits=1,
 #   and generally impossible with external data files
diff --git a/tests/qemu-iotests/089 b/tests/qemu-iotests/089
index 82c1d19680..298dc60b6f 100755
--- a/tests/qemu-iotests/089
+++ b/tests/qemu-iotests/089
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 # Because anything other than 16 would change the output of qemu_io -c info
 _unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
 
diff --git a/tests/qemu-iotests/090 b/tests/qemu-iotests/090
index 1246e4f910..87e872ebf4 100755
--- a/tests/qemu-iotests/090
+++ b/tests/qemu-iotests/090
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file nfs
+_supported_proto file nfs fuse
 # External data files do not support compressed clusters
 _unsupported_imgopts data_file
 
diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091
index 7d23a6862b..838af79f86 100755
--- a/tests/qemu-iotests/091
+++ b/tests/qemu-iotests/091
@@ -44,7 +44,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.qemu
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 _default_cache_mode none
 _supported_cache_modes writethrough none writeback
diff --git a/tests/qemu-iotests/095 b/tests/qemu-iotests/095
index 155ae86aa7..98ae0ce015 100755
--- a/tests/qemu-iotests/095
+++ b/tests/qemu-iotests/095
@@ -44,7 +44,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.qemu
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 
 size_smaller=5M
 size_larger=100M
diff --git a/tests/qemu-iotests/097 b/tests/qemu-iotests/097
index 690f3d3ce1..aa7b431c93 100755
--- a/tests/qemu-iotests/097
+++ b/tests/qemu-iotests/097
@@ -41,7 +41,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # Any format supporting backing files and bdrv_make_empty
 _supported_fmt qcow qcow2
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 
 
diff --git a/tests/qemu-iotests/098 b/tests/qemu-iotests/098
index 1e29d96b3d..3a9361ea3e 100755
--- a/tests/qemu-iotests/098
+++ b/tests/qemu-iotests/098
@@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.pattern
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 # The code path we want to test here only works for compat=1.1 images;
 # blkdebug can only inject errors on bs->file, so external data files
 # do not work with this test
diff --git a/tests/qemu-iotests/102 b/tests/qemu-iotests/102
index b898df436f..2cc3efd1ed 100755
--- a/tests/qemu-iotests/102
+++ b/tests/qemu-iotests/102
@@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.qemu
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 
 IMG_SIZE=64K
 
diff --git a/tests/qemu-iotests/103 b/tests/qemu-iotests/103
index 8c1ebe0443..220481db4c 100755
--- a/tests/qemu-iotests/103
+++ b/tests/qemu-iotests/103
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file nfs
+_supported_proto file nfs fuse
 # Internal snapshots are (currently) impossible with refcount_bits=1,
 # and generally impossible with external data files
 _unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
diff --git a/tests/qemu-iotests/106 b/tests/qemu-iotests/106
index b5d1ec4078..b4fa6669e1 100755
--- a/tests/qemu-iotests/106
+++ b/tests/qemu-iotests/106
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt raw
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 
 # in kB
diff --git a/tests/qemu-iotests/107 b/tests/qemu-iotests/107
index 268ba27688..d24829ccf9 100755
--- a/tests/qemu-iotests/107
+++ b/tests/qemu-iotests/107
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file nfs
+_supported_proto file nfs fuse
 
 
 IMG_SIZE=64K
diff --git a/tests/qemu-iotests/108 b/tests/qemu-iotests/108
index 5f7076fba4..ba67748bdf 100755
--- a/tests/qemu-iotests/108
+++ b/tests/qemu-iotests/108
@@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # This tests qcow2-specific low-level functionality
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 # This test directly modifies a refblock so it relies on refcount_bits being 16;
 # and the low-level modification it performs are not tuned for external data
diff --git a/tests/qemu-iotests/111 b/tests/qemu-iotests/111
index 3b43d1bd83..bd839a39f4 100755
--- a/tests/qemu-iotests/111
+++ b/tests/qemu-iotests/111
@@ -38,7 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qed qcow qcow2 vmdk
-_supported_proto file
+_supported_proto file fuse
 _unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
 
 _make_test_img -b "$TEST_IMG.inexistent"
diff --git a/tests/qemu-iotests/112 b/tests/qemu-iotests/112
index 20ff5c224a..6e413f5651 100755
--- a/tests/qemu-iotests/112
+++ b/tests/qemu-iotests/112
@@ -38,7 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # This tests qcow2-specific low-level functionality
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 # This test will set refcount_bits on its own which would conflict with the
 # manual setting; compat will be overridden as well;
 # and external data files do not work well with our refcount testing
diff --git a/tests/qemu-iotests/115 b/tests/qemu-iotests/115
index d254b18342..7f53987d1b 100755
--- a/tests/qemu-iotests/115
+++ b/tests/qemu-iotests/115
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 # This test relies on refcounts being 64 bits wide (which does not work with
 # compat=0.10)
 _unsupported_imgopts 'refcount_bits=\([^6]\|.\([^4]\|$\)\)' 'compat=0.10'
diff --git a/tests/qemu-iotests/117 b/tests/qemu-iotests/117
index f37b34f8b1..9039555ac4 100755
--- a/tests/qemu-iotests/117
+++ b/tests/qemu-iotests/117
@@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.qemu
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 
 _make_test_img 64k
 
diff --git a/tests/qemu-iotests/120 b/tests/qemu-iotests/120
index 2931a7550f..45c55c1c01 100755
--- a/tests/qemu-iotests/120
+++ b/tests/qemu-iotests/120
@@ -38,7 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt generic
-_supported_proto file
+_supported_proto file fuse
 _unsupported_fmt luks
 _require_drivers raw
 
diff --git a/tests/qemu-iotests/121 b/tests/qemu-iotests/121
index 90ea0db737..8357ce089a 100755
--- a/tests/qemu-iotests/121
+++ b/tests/qemu-iotests/121
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 # Refcount structures are used much differently with external data
 # files
diff --git a/tests/qemu-iotests/127 b/tests/qemu-iotests/127
index b64926ab31..a2d5556909 100755
--- a/tests/qemu-iotests/127
+++ b/tests/qemu-iotests/127
@@ -41,7 +41,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.qemu
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 
 IMG_SIZE=64K
 
diff --git a/tests/qemu-iotests/133 b/tests/qemu-iotests/133
index 6f7cacc091..1b88c15c0f 100755
--- a/tests/qemu-iotests/133
+++ b/tests/qemu-iotests/133
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 
 TEST_IMG="$TEST_IMG.base" _make_test_img 64M
 _make_test_img -b "$TEST_IMG.base"
diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137
index 7ae86892f7..de555a91c9 100755
--- a/tests/qemu-iotests/137
+++ b/tests/qemu-iotests/137
@@ -38,7 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.qemu
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 # We are going to use lazy-refcounts
 _unsupported_imgopts 'compat=0.10'
diff --git a/tests/qemu-iotests/138 b/tests/qemu-iotests/138
index 54b01046ad..08cd9e17bb 100755
--- a/tests/qemu-iotests/138
+++ b/tests/qemu-iotests/138
@@ -38,7 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # This tests qcow2-specific low-level functionality
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 # With an external data file, data clusters are not refcounted
 # (and so qemu-img check does not check their refcount)
diff --git a/tests/qemu-iotests/140 b/tests/qemu-iotests/140
index 8d2ce5d9e3..3125e89064 100755
--- a/tests/qemu-iotests/140
+++ b/tests/qemu-iotests/140
@@ -44,7 +44,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.qemu
 
 _supported_fmt generic
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 
 _make_test_img 64k
diff --git a/tests/qemu-iotests/154 b/tests/qemu-iotests/154
index d68f66b9e0..26664a91de 100755
--- a/tests/qemu-iotests/154
+++ b/tests/qemu-iotests/154
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 
 CLUSTER_SIZE=4k
diff --git a/tests/qemu-iotests/161 b/tests/qemu-iotests/161
index f9b44e52cf..eeb8ccf2b5 100755
--- a/tests/qemu-iotests/161
+++ b/tests/qemu-iotests/161
@@ -42,7 +42,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # Any format implementing BlockDriver.bdrv_change_backing_file
 _supported_fmt qcow2 qed
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 
 IMG_SIZE=1M
diff --git a/tests/qemu-iotests/171 b/tests/qemu-iotests/171
index 341064a1c6..f3582edb10 100755
--- a/tests/qemu-iotests/171
+++ b/tests/qemu-iotests/171
@@ -38,7 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt raw
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 
 
diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175
index 2d164b6b5d..7792fdcaca 100755
--- a/tests/qemu-iotests/175
+++ b/tests/qemu-iotests/175
@@ -71,7 +71,7 @@ EOF
 . ./common.filter
 
 _supported_fmt raw
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 
 _default_cache_mode none
diff --git a/tests/qemu-iotests/176 b/tests/qemu-iotests/176
index 117c8b6954..15b83829a6 100755
--- a/tests/qemu-iotests/176
+++ b/tests/qemu-iotests/176
@@ -45,7 +45,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # This test is specific to qcow2
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 # Persistent dirty bitmaps require compat=1.1;
 # Internal snapshots forbid using an external data file
diff --git a/tests/qemu-iotests/177 b/tests/qemu-iotests/177
index 752d29f8ad..d26bcaf45f 100755
--- a/tests/qemu-iotests/177
+++ b/tests/qemu-iotests/177
@@ -40,7 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # tests specific to compat=1.1.
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 
 CLUSTER_SIZE=1M
 size=128M
diff --git a/tests/qemu-iotests/179 b/tests/qemu-iotests/179
index 9372dc30ef..eaffac3fae 100755
--- a/tests/qemu-iotests/179
+++ b/tests/qemu-iotests/179
@@ -38,7 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 
 # v2 images can't mark clusters as zero
diff --git a/tests/qemu-iotests/183 b/tests/qemu-iotests/183
index 3f74b9f62d..218e22e282 100755
--- a/tests/qemu-iotests/183
+++ b/tests/qemu-iotests/183
@@ -43,7 +43,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.qemu
 
 _supported_fmt qcow2 raw qed quorum
-_supported_proto file
+_supported_proto file fuse
 
 size=64M
 _make_test_img $size
diff --git a/tests/qemu-iotests/186 b/tests/qemu-iotests/186
index 3ea0442d44..0db25b0e68 100755
--- a/tests/qemu-iotests/186
+++ b/tests/qemu-iotests/186
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 _require_drivers null-co
 
 if [ "$QEMU_DEFAULT_MACHINE" != "pc" ]; then
diff --git a/tests/qemu-iotests/187 b/tests/qemu-iotests/187
index c6e1dc57a0..f262d83e3a 100755
--- a/tests/qemu-iotests/187
+++ b/tests/qemu-iotests/187
@@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 
 size=64M
 _make_test_img $size
diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191
index b05db68141..b5ebea4c28 100755
--- a/tests/qemu-iotests/191
+++ b/tests/qemu-iotests/191
@@ -42,7 +42,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.qemu
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 # An external data file would change the query-named-block-nodes output
 _unsupported_imgopts data_file
 
diff --git a/tests/qemu-iotests/195 b/tests/qemu-iotests/195
index 48984b7ac1..6553fcbda9 100755
--- a/tests/qemu-iotests/195
+++ b/tests/qemu-iotests/195
@@ -38,7 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 
 do_run_qemu()
 {
diff --git a/tests/qemu-iotests/200 b/tests/qemu-iotests/200
index 616b632a86..98d95b1482 100755
--- a/tests/qemu-iotests/200
+++ b/tests/qemu-iotests/200
@@ -42,7 +42,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.qemu
 
 _supported_fmt qcow2 qed
-_supported_proto file
+_supported_proto file fuse
 
 BACKING_IMG="$TEST_IMG.base"
 
diff --git a/tests/qemu-iotests/204 b/tests/qemu-iotests/204
index abb73dc381..7d4554ea96 100755
--- a/tests/qemu-iotests/204
+++ b/tests/qemu-iotests/204
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 # This test assumes that discard leaves zero clusters; see test 177 for
 # other tests that also work in older images
 _unsupported_imgopts 'compat=0.10'
diff --git a/tests/qemu-iotests/214 b/tests/qemu-iotests/214
index 0f2e61280a..f2e0b14d55 100755
--- a/tests/qemu-iotests/214
+++ b/tests/qemu-iotests/214
@@ -35,7 +35,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 
 # Repairing the corrupted image requires qemu-img check to store a
 # refcount up to 3, which requires at least two refcount bits.
diff --git a/tests/qemu-iotests/217 b/tests/qemu-iotests/217
index d89116ccad..7385342498 100755
--- a/tests/qemu-iotests/217
+++ b/tests/qemu-iotests/217
@@ -36,7 +36,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # This test is specific to qcow2
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 
 # This test needs clusters with at least a refcount of 2 so that
 # OFLAG_COPIED is not set.  refcount_bits=1 is therefore unsupported.
diff --git a/tests/qemu-iotests/220 b/tests/qemu-iotests/220
index a9259b7127..9ba3b3fdcb 100755
--- a/tests/qemu-iotests/220
+++ b/tests/qemu-iotests/220
@@ -35,7 +35,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.pattern
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 # To use a different refcount width but 16 bits we need compat=1.1,
 # and external data files do not support compressed clusters.
diff --git a/tests/qemu-iotests/221 b/tests/qemu-iotests/221
index 0e9096fec7..ca62b3baa1 100755
--- a/tests/qemu-iotests/221
+++ b/tests/qemu-iotests/221
@@ -35,7 +35,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt raw
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 
 _default_cache_mode writeback
diff --git a/tests/qemu-iotests/229 b/tests/qemu-iotests/229
index abc88f881f..b6ca941f6b 100755
--- a/tests/qemu-iotests/229
+++ b/tests/qemu-iotests/229
@@ -43,7 +43,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # Needs backing file and backing format support
 _supported_fmt qcow2 qed
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 
 
diff --git a/tests/qemu-iotests/247 b/tests/qemu-iotests/247
index 87e37b39e2..6cf2679750 100755
--- a/tests/qemu-iotests/247
+++ b/tests/qemu-iotests/247
@@ -41,7 +41,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # Requires backing files and .bdrv_change_backing_file support
 _supported_fmt qcow2 qed
-_supported_proto file
+_supported_proto file fuse
 
 size=128M
 
diff --git a/tests/qemu-iotests/249 b/tests/qemu-iotests/249
index 4b0f810795..bf874edc73 100755
--- a/tests/qemu-iotests/249
+++ b/tests/qemu-iotests/249
@@ -42,7 +42,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # Any format implementing BlockDriver.bdrv_change_backing_file
 _supported_fmt qcow2 qed
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 
 IMG_SIZE=1M
diff --git a/tests/qemu-iotests/250 b/tests/qemu-iotests/250
index 9bb6b94d74..3df275c76b 100755
--- a/tests/qemu-iotests/250
+++ b/tests/qemu-iotests/250
@@ -37,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 # This test does not make much sense with external data files
 _unsupported_imgopts data_file
diff --git a/tests/qemu-iotests/252 b/tests/qemu-iotests/252
index 83280c1715..e0db2616de 100755
--- a/tests/qemu-iotests/252
+++ b/tests/qemu-iotests/252
@@ -42,7 +42,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # zero cluster support
 _supported_fmt qcow2
 _unsupported_imgopts 'compat=0.10'
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 
 CLUSTER_SIZE=65536
diff --git a/tests/qemu-iotests/265 b/tests/qemu-iotests/265
index 00f2ec769e..0e800fb524 100755
--- a/tests/qemu-iotests/265
+++ b/tests/qemu-iotests/265
@@ -35,7 +35,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # qcow2-specific test
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 
 echo '--- Writing to the image ---'
diff --git a/tests/qemu-iotests/268 b/tests/qemu-iotests/268
index 78c3f4db3a..ddf4312284 100755
--- a/tests/qemu-iotests/268
+++ b/tests/qemu-iotests/268
@@ -38,7 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 
 echo
 echo "== Required alignment larger than cluster size =="
diff --git a/tests/qemu-iotests/272 b/tests/qemu-iotests/272
index c2f782d47b..de475bf6f0 100755
--- a/tests/qemu-iotests/272
+++ b/tests/qemu-iotests/272
@@ -35,7 +35,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # This is a qcow2 regression test
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 
 # External data files do not support compression;
 # We need an exact cluster size (2M) and refcount width (2) so we can
diff --git a/tests/qemu-iotests/273 b/tests/qemu-iotests/273
index 00ff79bcf8..a40c55eb3b 100755
--- a/tests/qemu-iotests/273
+++ b/tests/qemu-iotests/273
@@ -35,7 +35,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # This is a qcow2 regression test
 _supported_fmt qcow2
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 # External data files would add nodes to the block graph, so it would
 # not match the reference output
diff --git a/tests/qemu-iotests/279 b/tests/qemu-iotests/279
index 6682376808..78ff039372 100755
--- a/tests/qemu-iotests/279
+++ b/tests/qemu-iotests/279
@@ -36,7 +36,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 # Backing files are required...
 _supported_fmt qcow qcow2 vmdk qed
-_supported_proto file
+_supported_proto file fuse
 _supported_os Linux
 
 TEST_IMG="$TEST_IMG.base" _make_test_img 64M
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 18/18] iotests/281: Add test for FUSE exports
  2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
                   ` (16 preceding siblings ...)
  2019-12-19 14:38 ` [PATCH 17/18] iotests: Enable fuse for many tests Max Reitz
@ 2019-12-19 14:38 ` Max Reitz
  2019-12-19 19:05 ` [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
  2019-12-20 10:08 ` Stefan Hajnoczi
  19 siblings, 0 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-19 14:38 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-devel, Max Reitz

We have good coverage of the normal I/O paths now, but what remains is a
test that tests some more special cases: Exporting an image on itself
(thus turning a formatted image into a raw one), some error cases, and
non-writable and non-growable exports.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/281     | 328 +++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/281.out |  92 +++++++++++
 tests/qemu-iotests/group   |   1 +
 3 files changed, 421 insertions(+)
 create mode 100755 tests/qemu-iotests/281
 create mode 100644 tests/qemu-iotests/281.out

diff --git a/tests/qemu-iotests/281 b/tests/qemu-iotests/281
new file mode 100755
index 0000000000..071420697c
--- /dev/null
+++ b/tests/qemu-iotests/281
@@ -0,0 +1,328 @@
+#!/usr/bin/env bash
+#
+# Test FUSE exports (in ways that are not captured by the generic
+# tests)
+#
+# Copyright (C) 2019 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+seq=$(basename "$0")
+echo "QA output created by $seq"
+
+status=1	# failure is the default!
+
+_cleanup()
+{
+    _cleanup_test_img
+    rmdir "$EXT_MP" 2>/dev/null
+    rm -f "$EXT_MP"
+    rm -f "$COPIED_IMG"
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+. ./common.qemu
+
+# Generic format, but needs a plain filename
+_supported_fmt generic
+if [ "$IMGOPTSSYNTAX" = "true" ]; then
+    _unsupported_fmt $IMGFMT
+fi
+
+_supported_proto file # We create the FUSE export manually
+_supported_os Linux # We need /dev/urandom
+
+# $1: Options (beyond the node-name)
+# $2: Expected return value (defaults to 'return')
+# $3: Node to export (defaults to 'node-format')
+fuse_export_add()
+{
+    _send_qemu_cmd $QEMU_HANDLE \
+        "{'execute': 'fuse-export-add',
+          'arguments': {
+              'node-name': '${3:-node-format}',
+              $1
+          } }" \
+        "${2:-return}" \
+        | _filter_imgfmt
+}
+
+# $1: Mountpoint
+# $2: Expected return value (defaults to 'return')
+fuse_export_remove()
+{
+    _send_qemu_cmd $QEMU_HANDLE \
+        "{'execute': 'fuse-export-remove',
+          'arguments': {
+              'mountpoint': '$1'
+          } }" \
+        "${2:-return}"
+}
+
+# Return the length of the protocol file
+# $1: Protocol node export mount point
+# $2: Original file (to compare)
+get_proto_len()
+{
+    len1=$(stat -c '%s' "$1")
+    len2=$(stat -c '%s' "$2")
+
+    if [ "$len1" != "$len2" ]; then
+        echo 'ERROR: Length of export and original differ:' >&2
+        echo "$len1 != $len2" >&2
+    else
+        echo '(OK: Lengths of export and original are the same)' >&2
+    fi
+
+    echo "$len1"
+}
+
+COPIED_IMG="$TEST_IMG.copy"
+EXT_MP="$TEST_IMG.fuse"
+
+echo '=== Set up ==='
+
+# Create image with random data
+_make_test_img 64M
+$QEMU_IO -c 'write -s /dev/urandom 0 64M' "$TEST_IMG" | _filter_qemu_io
+
+_launch_qemu
+_send_qemu_cmd $QEMU_HANDLE \
+    "{'execute': 'qmp_capabilities'}" \
+    'return'
+
+# Separate blockdev-add calls for format and protocol so we can remove
+# the format layer later on
+_send_qemu_cmd $QEMU_HANDLE \
+    "{'execute': 'blockdev-add',
+      'arguments': {
+          'driver': 'file',
+          'node-name': 'node-protocol',
+          'filename': '$TEST_IMG'
+      } }" \
+    'return'
+
+_send_qemu_cmd $QEMU_HANDLE \
+    "{'execute': 'blockdev-add',
+      'arguments': {
+          'driver': '$IMGFMT',
+          'node-name': 'node-format',
+          'file': 'node-protocol'
+      } }" \
+    'return'
+
+echo
+echo '=== Mountpoint not present ==='
+
+rmdir "$EXT_MP" 2>/dev/null
+rm -f "$EXT_MP"
+output=$(fuse_export_add "'mountpoint': '$EXT_MP'" error)
+
+if echo "$output" | grep -q 'CommandNotFound'; then
+    _notrun 'No FUSE support'
+fi
+
+echo "$output"
+
+echo
+echo '=== Mountpoint is a directory ==='
+
+mkdir "$EXT_MP"
+fuse_export_add "'mountpoint': '$EXT_MP'" error
+rmdir "$EXT_MP"
+
+echo
+echo '=== Mountpoint is a regular file ==='
+
+touch "$EXT_MP"
+fuse_export_add "'mountpoint': '$EXT_MP'"
+
+# Check that the export presents the same data as the original image
+$QEMU_IMG compare -f raw -F $IMGFMT -U "$EXT_MP" "$TEST_IMG"
+
+echo
+echo '=== Mount over existing file ==='
+
+# This is the coolest feature of FUSE exports: You can transparently
+# make images in any format appear as raw images
+fuse_export_add "'mountpoint': '$TEST_IMG'"
+
+# Accesses both exports at the same time, so we get a concurrency test
+$QEMU_IMG compare -f raw -F raw -U "$EXT_MP" "$TEST_IMG"
+
+# Just to be sure, we later want to compare the data offline.  Also,
+# this allows us to see that cp works without complaining.
+# (This is not a given, because cp will expect a short read at EOF.
+# Internally, qemu does not allow short reads, so we have to check
+# whether the FUSE export driver lets them work.)
+cp "$TEST_IMG" "$COPIED_IMG"
+
+# $TEST_IMG will be in mode 0400 because it is read-only; we are going
+# to write to the copy, so make it writable
+chmod 0600 "$COPIED_IMG"
+
+echo
+echo '=== Double export ==='
+
+# We have already seen that exporting a node twice works fine, but you
+# cannot export anything twice on the same mount point.  One reason is
+# that the MP acts as the unique identifier for the export.  The other
+# is that qemu has to stat the given mount point, and this would have
+# to be answered by the same qemu instance if it already has an export
+# there.  However, it cannot answer the stat because it is itself
+# caught up in that same stat.
+fuse_export_add "'mountpoint': '$EXT_MP'" error
+
+echo
+echo '=== Remove export ==='
+
+# Double-check that $EXT_MP appears as a non-empty file (the raw image)
+$QEMU_IMG info -f raw "$EXT_MP" | grep 'virtual size'
+
+fuse_export_remove "$EXT_MP"
+
+# See that the file appears empty again
+$QEMU_IMG info -f raw "$EXT_MP" | grep 'virtual size'
+
+echo
+echo '=== Writable export ==='
+
+fuse_export_add "'mountpoint': '$EXT_MP', 'writable': true"
+
+# Check that writing to the read-only export fails
+$QEMU_IO -f raw -c 'write -P 42 1M 64k' "$TEST_IMG" | _filter_qemu_io
+
+# But here it should work
+$QEMU_IO -f raw -c 'write -P 42 1M 64k' "$EXT_MP" | _filter_qemu_io
+
+# (Adjust the copy, too)
+$QEMU_IO -f raw -c 'write -P 42 1M 64k' "$COPIED_IMG" | _filter_qemu_io
+
+echo
+echo '=== Resizing exports ==='
+
+# Here, we need to export the protocol node -- the format layer may
+# not be growable in principle.
+
+# Remove all exports and the format node first so permissions will not
+# get in the way
+fuse_export_remove "$EXT_MP"
+fuse_export_remove "$TEST_IMG"
+
+_send_qemu_cmd $QEMU_HANDLE \
+    "{'execute': 'blockdev-del',
+      'arguments': {
+          'node-name': 'node-format'
+      } }" \
+    'return'
+
+# Now export the protocol node
+fuse_export_add \
+    "'mountpoint': '$EXT_MP', 'writable': true" \
+    'return' \
+    'node-protocol'
+
+echo
+echo '--- Try growing non-growable export ---'
+
+# Get the current size so we can write beyond the EOF
+orig_len=$(get_proto_len "$EXT_MP" "$TEST_IMG")
+orig_disk_usage=$(stat -c '%b' "$TEST_IMG")
+
+# Should fail (exports are non-growable by default)
+# (Note that qemu-io can never write beyond the EOF, so we have to use
+# dd here)
+dd if=/dev/zero of="$EXT_MP" bs=1 count=64k seek=$orig_len 2>&1 \
+    | _filter_testdir | _filter_imgfmt
+
+echo
+echo '--- Resize export ---'
+
+# But we can truncate it explicitly; even with fallocate
+fallocate -o "$orig_len" -l 64k "$EXT_MP"
+
+new_len=$(get_proto_len "$EXT_MP" "$TEST_IMG")
+if [ "$new_len" != "$((orig_len + 65536))" ]; then
+    echo 'ERROR: Unexpected post-truncate image size:'
+    echo "$new_len != $((orig_len + 65536))"
+else
+    echo 'OK: Post-truncate image size is as expected'
+fi
+
+new_disk_usage=$(stat -c '%b' "$TEST_IMG")
+if [ "$new_disk_usage" -gt "$orig_disk_usage" ]; then
+    echo 'OK: Disk usage grew with fallocate'
+else
+    echo 'ERROR: Disk usage did not grow despite fallocate:'
+    echo "$orig_disk_usage => $new_disk_usage"
+fi
+
+echo
+echo '--- Try growing growable export ---'
+
+# Now export as growable
+fuse_export_remove "$EXT_MP"
+fuse_export_add \
+    "'mountpoint': '$EXT_MP', 'writable': true, 'growable': true" \
+    'return' \
+    'node-protocol'
+
+# Now we should be able to write beyond the EOF
+dd if=/dev/zero of="$EXT_MP" bs=1 count=64k seek=$new_len 2>&1 \
+    | _filter_testdir | _filter_imgfmt
+
+new_len=$(get_proto_len "$EXT_MP" "$TEST_IMG")
+if [ "$new_len" != "$((orig_len + 131072))" ]; then
+    echo 'ERROR: Unexpected post-grow image size:'
+    echo "$new_len != $((orig_len + 131072))"
+else
+    echo 'OK: Post-grow image size is as expected'
+fi
+
+echo
+echo '--- Shrink export ---'
+
+# Now go back to the original size
+truncate -s "$orig_len" "$EXT_MP"
+
+new_len=$(get_proto_len "$EXT_MP" "$TEST_IMG")
+if [ "$new_len" != "$orig_len" ]; then
+    echo 'ERROR: Unexpected post-truncate image size:'
+    echo "$new_len != $orig_len"
+else
+    echo 'OK: Post-truncate image size is as expected'
+fi
+
+echo
+echo '=== Tear down ==='
+
+_send_qemu_cmd $QEMU_HANDLE \
+    "{'execute': 'quit'}" \
+    'return'
+
+wait=yes _cleanup_qemu
+
+echo
+echo '=== Compare copy with original ==='
+
+$QEMU_IMG compare -f raw -F $IMGFMT "$COPIED_IMG" "$TEST_IMG"
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/281.out b/tests/qemu-iotests/281.out
new file mode 100644
index 0000000000..ba41e14b2a
--- /dev/null
+++ b/tests/qemu-iotests/281.out
@@ -0,0 +1,92 @@
+QA output created by 281
+=== Set up ===
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+wrote 67108864/67108864 bytes at offset 0
+64 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+{'execute': 'qmp_capabilities'}
+{"return": {}}
+{'execute': 'blockdev-add', 'arguments': { 'driver': 'file', 'node-name': 'node-protocol', 'filename': 'TEST_DIR/t.IMGFMT' } }
+{"return": {}}
+{'execute': 'blockdev-add', 'arguments': { 'driver': 'IMGFMT', 'node-name': 'node-format', 'file': 'node-protocol' } }
+{"return": {}}
+
+=== Mountpoint not present ===
+{'execute': 'fuse-export-add', 'arguments': { 'node-name': 'node-format', 'mountpoint': 'TEST_DIR/t.IMGFMT.fuse' } }
+{"error": {"class": "GenericError", "desc": "Failed to stat 'TEST_DIR/t.IMGFMT.fuse': No such file or directory"}}
+
+=== Mountpoint is a directory ===
+{'execute': 'fuse-export-add', 'arguments': { 'node-name': 'node-format', 'mountpoint': 'TEST_DIR/t.IMGFMT.fuse' } }
+{"error": {"class": "GenericError", "desc": "'TEST_DIR/t.IMGFMT.fuse' is not a regular file"}}
+
+=== Mountpoint is a regular file ===
+{'execute': 'fuse-export-add', 'arguments': { 'node-name': 'node-format', 'mountpoint': 'TEST_DIR/t.IMGFMT.fuse' } }
+{"return": {}}
+Images are identical.
+
+=== Mount over existing file ===
+{'execute': 'fuse-export-add', 'arguments': { 'node-name': 'node-format', 'mountpoint': 'TEST_DIR/t.IMGFMT' } }
+{"return": {}}
+Images are identical.
+
+=== Double export ===
+{'execute': 'fuse-export-add', 'arguments': { 'node-name': 'node-format', 'mountpoint': 'TEST_DIR/t.IMGFMT.fuse' } }
+{"error": {"class": "GenericError", "desc": "There already is a FUSE export on 'TEST_DIR/t.IMGFMT.fuse'"}}
+
+=== Remove export ===
+virtual size: 64 MiB (67108864 bytes)
+{'execute': 'fuse-export-remove', 'arguments': { 'mountpoint': 'TEST_DIR/t.IMGFMT.fuse' } }
+{"return": {}}
+virtual size: 0 B (0 bytes)
+
+=== Writable export ===
+{'execute': 'fuse-export-add', 'arguments': { 'node-name': 'node-format', 'mountpoint': 'TEST_DIR/t.IMGFMT.fuse', 'writable': true } }
+{"return": {}}
+write failed: Permission denied
+wrote 65536/65536 bytes at offset 1048576
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 65536/65536 bytes at offset 1048576
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Resizing exports ===
+{'execute': 'fuse-export-remove', 'arguments': { 'mountpoint': 'TEST_DIR/t.IMGFMT.fuse' } }
+{"return": {}}
+{'execute': 'fuse-export-remove', 'arguments': { 'mountpoint': 'TEST_DIR/t.IMGFMT' } }
+{"return": {}}
+{'execute': 'blockdev-del', 'arguments': { 'node-name': 'node-format' } }
+{"return": {}}
+{'execute': 'fuse-export-add', 'arguments': { 'node-name': 'node-protocol', 'mountpoint': 'TEST_DIR/t.IMGFMT.fuse', 'writable': true } }
+{"return": {}}
+
+--- Try growing non-growable export ---
+(OK: Lengths of export and original are the same)
+dd: error writing 'TEST_DIR/t.IMGFMT.fuse': Input/output error
+1+0 records in
+0+0 records out
+
+--- Resize export ---
+(OK: Lengths of export and original are the same)
+OK: Post-truncate image size is as expected
+OK: Disk usage grew with fallocate
+
+--- Try growing growable export ---
+{'execute': 'fuse-export-remove', 'arguments': { 'mountpoint': 'TEST_DIR/t.IMGFMT.fuse' } }
+{"return": {}}
+{'execute': 'fuse-export-add', 'arguments': { 'node-name': 'node-protocol', 'mountpoint': 'TEST_DIR/t.IMGFMT.fuse', 'writable': true, 'growable': true } }
+{"return": {}}
+65536+0 records in
+65536+0 records out
+(OK: Lengths of export and original are the same)
+OK: Post-grow image size is as expected
+
+--- Shrink export ---
+(OK: Lengths of export and original are the same)
+OK: Post-truncate image size is as expected
+
+=== Tear down ===
+{'execute': 'quit'}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
+
+=== Compare copy with original ===
+Images are identical.
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index eb57ddc72c..6fce3f1cfd 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -287,3 +287,4 @@
 273 backing quick
 277 rw quick
 279 rw backing quick
+281 rw
-- 
2.23.0



^ permalink raw reply related	[flat|nested] 37+ messages in thread

* Re: [PATCH 00/18] block: Allow exporting BDSs via FUSE
  2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
                   ` (17 preceding siblings ...)
  2019-12-19 14:38 ` [PATCH 18/18] iotests/281: Add test for FUSE exports Max Reitz
@ 2019-12-19 19:05 ` Max Reitz
  2019-12-20 10:08 ` Stefan Hajnoczi
  19 siblings, 0 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-19 19:05 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-devel


[-- Attachment #1.1: Type: text/plain, Size: 1255 bytes --]

On 19.12.19 15:38, Max Reitz wrote:

[...]

> Final rather important notice: I didn’t really run the iotests with this
> yet.  I wanted to, but they appear rather broken on current master,
> actually.  I’m not yet sure whether that’s because something in my setup
> broke in the last two weeks, or because there’s quite something broken
> in master (it does look like there are a couple things broken in master
> currently).

Bit of both, it turns out.  The problems in this series are:

Patch 10: We can’t sprinkle -n into convert statements as generously as
I’d liked, because for some reason this gives me disk space issues with
qcow1 and vmdk.  We can still do it in 028 and 089, but I should
probably drop the rest.  (Of course, this means that this rest also has
to be dropped from patch 17.)

Patch 15: We must not guess TEST_IMG_FILE from TEST_IMG if IMGOPTSSYNTAX
is true.  Otherwise, this breaks basically all luks tests.

Patch 18: This does not work with vpc.  (Because vpc by default aligns
the image size for its CHS magic, and so the output changes when
inquiring the image size.)

These together with the fixes I’ve sent to the list are then enough to
make the iotests pass for me again.

Max


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 00/18] block: Allow exporting BDSs via FUSE
  2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
                   ` (18 preceding siblings ...)
  2019-12-19 19:05 ` [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
@ 2019-12-20 10:08 ` Stefan Hajnoczi
  2019-12-20 10:30   ` Max Reitz
  19 siblings, 1 reply; 37+ messages in thread
From: Stefan Hajnoczi @ 2019-12-20 10:08 UTC (permalink / raw)
  To: Max Reitz; +Cc: Kevin Wolf, qemu-devel, qemu-block

[-- Attachment #1: Type: text/plain, Size: 8199 bytes --]

On Thu, Dec 19, 2019 at 03:38:00PM +0100, Max Reitz wrote:
> Preamble: This series is based on a combination of my (current) block
> branch and “iotests: Minor fixes”.  I’ve pushed it here:
> 
>   https://git.xanclic.moe/XanClic/qemu fuse-exports-v1
> 
> (The base is on fuse-exports-v1-base.)
> 
> 
> Hi,
> 
> Ever since I found out that you can mount FUSE filesystems on regular
> files (not just directories), I had the idea of adding FUSE block
> exports to qemu where you can export block nodes as raw images.  The
> best thing is that you’d be able to mount an image on itself, so
> whatever format it may be in, qemu lets it appear as a raw image (and
> you can then use regular tools like dd on it).
> 
> I started with some concept of a qemu-blkfuse daemon (similar to
> qemu-nbd), but never sent patches, for two reasons: (1) Performance was
> not good, (2) it didn’t seem right, for some reason.
> 
> Now Kevin is proposing a storage daemon for multiple export types like
> NBD, and he also mentioned FUSE (while knowing of my previous attempts).
> Now it does seem right to add FUSE exports to qemu, but only in the form
> of some module with a proper QAPI/QMP binding.
> 
> Performance is still quite bad, but who cares.  We can always improve
> it, if the need arises.
> 
> 
> This series does the following:
> 
> First, add the FUSE export module (block/fuse.c) that implements the
> basic file access functions.  (Note that you need libfuse 3.8.0 or later
> for SEEK_HOLE/SEEK_DATA.)
> 
> Second, it allows using FUSE exports as a protocol in the iotests and
> makes many iotests work with it.  (The file node is exported by a
> background qemu instance to $SOCK_DIR.)
> Note that I only ran raw and qcow2 on it; I’m sure other formats
> currently have some failing tests.
> 
> This gives us a lot of coverage for, well, not free (it does take ten
> patches), but for cheap; but there are still some more specialized
> things we want to test, so third and last, this series adds an iotest
> dedicated to FUSE exports.
> 
> 
> Final rather important notice: I didn’t really run the iotests with this
> yet.  I wanted to, but they appear rather broken on current master,
> actually.  I’m not yet sure whether that’s because something in my setup
> broke in the last two weeks, or because there’s quite something broken
> in master (it does look like there are a couple things broken in master
> currently).
> 
> 
> Max Reitz (18):
>   configure: Detect libfuse
>   fuse: Allow exporting BDSs via FUSE
>   fuse: Implement standard FUSE operations
>   fuse: Add fuse-export-remove
>   fuse: Allow growable exports
>   fuse: (Partially) implement fallocate()
>   fuse: Implement hole detection through lseek
>   iotests: Do not needlessly filter _make_test_img
>   iotests: Do not pipe _make_test_img
>   iotests: Use convert -n in some cases
>   iotests: Avoid renaming images
>   iotests: Derive image names from $TEST_IMG
>   iotests/091: Use _cleanup_qemu instad of "wait"
>   iotests: Restrict some Python tests to file
>   iotests: Let _make_test_img guess $TEST_IMG_FILE
>   iotests: Allow testing FUSE exports
>   iotests: Enable fuse for many tests
>   iotests/281: Add test for FUSE exports
> 
>  block.c                          |   4 +
>  block/Makefile.objs              |   3 +
>  block/fuse.c                     | 668 +++++++++++++++++++++++++++++++
>  configure                        |  68 ++++
>  include/block/fuse.h             |  24 ++
>  qapi/block.json                  |  42 ++
>  tests/qemu-iotests/013           |   9 +-
>  tests/qemu-iotests/013.out       |   3 +-
>  tests/qemu-iotests/018           |   5 +-
>  tests/qemu-iotests/018.out       |   1 +
>  tests/qemu-iotests/020           |   2 +-
>  tests/qemu-iotests/025           |   2 +-
>  tests/qemu-iotests/026           |   2 +-
>  tests/qemu-iotests/028           |  16 +-
>  tests/qemu-iotests/028.out       |   3 +
>  tests/qemu-iotests/031           |   2 +-
>  tests/qemu-iotests/034           |   2 +-
>  tests/qemu-iotests/036           |   2 +-
>  tests/qemu-iotests/037           |   2 +-
>  tests/qemu-iotests/038           |   2 +-
>  tests/qemu-iotests/039           |   2 +-
>  tests/qemu-iotests/046           |   7 +-
>  tests/qemu-iotests/046.out       |   2 +-
>  tests/qemu-iotests/050           |   2 +-
>  tests/qemu-iotests/054           |   2 +-
>  tests/qemu-iotests/060           |   2 +-
>  tests/qemu-iotests/071           |  21 +-
>  tests/qemu-iotests/072           |   5 +-
>  tests/qemu-iotests/072.out       |   1 +
>  tests/qemu-iotests/079           |   2 +-
>  tests/qemu-iotests/080           |   2 +-
>  tests/qemu-iotests/089           |   5 +-
>  tests/qemu-iotests/089.out       |   1 +
>  tests/qemu-iotests/090           |   2 +-
>  tests/qemu-iotests/091           |   5 +-
>  tests/qemu-iotests/095           |   2 +-
>  tests/qemu-iotests/097           |   2 +-
>  tests/qemu-iotests/098           |   2 +-
>  tests/qemu-iotests/102           |   2 +-
>  tests/qemu-iotests/103           |   2 +-
>  tests/qemu-iotests/106           |   2 +-
>  tests/qemu-iotests/107           |   2 +-
>  tests/qemu-iotests/108           |   2 +-
>  tests/qemu-iotests/111           |   2 +-
>  tests/qemu-iotests/112           |   2 +-
>  tests/qemu-iotests/115           |   2 +-
>  tests/qemu-iotests/117           |   2 +-
>  tests/qemu-iotests/120           |   2 +-
>  tests/qemu-iotests/121           |   2 +-
>  tests/qemu-iotests/127           |   2 +-
>  tests/qemu-iotests/133           |   2 +-
>  tests/qemu-iotests/137           |   2 +-
>  tests/qemu-iotests/138           |   2 +-
>  tests/qemu-iotests/140           |   2 +-
>  tests/qemu-iotests/154           |   2 +-
>  tests/qemu-iotests/161           |  14 +-
>  tests/qemu-iotests/171           |   2 +-
>  tests/qemu-iotests/174           |  10 +-
>  tests/qemu-iotests/175           |   8 +-
>  tests/qemu-iotests/176           |   2 +-
>  tests/qemu-iotests/177           |   2 +-
>  tests/qemu-iotests/179           |   2 +-
>  tests/qemu-iotests/183           |   2 +-
>  tests/qemu-iotests/186           |   2 +-
>  tests/qemu-iotests/187           |   2 +-
>  tests/qemu-iotests/191           |   2 +-
>  tests/qemu-iotests/195           |   2 +-
>  tests/qemu-iotests/200           |   5 +-
>  tests/qemu-iotests/200.out       |   4 +-
>  tests/qemu-iotests/204           |   2 +-
>  tests/qemu-iotests/206           |   1 +
>  tests/qemu-iotests/214           |   2 +-
>  tests/qemu-iotests/217           |   2 +-
>  tests/qemu-iotests/220           |   2 +-
>  tests/qemu-iotests/221           |   2 +-
>  tests/qemu-iotests/229           |   5 +-
>  tests/qemu-iotests/229.out       |   6 +-
>  tests/qemu-iotests/242           |   1 +
>  tests/qemu-iotests/247           |   2 +-
>  tests/qemu-iotests/249           |   8 +-
>  tests/qemu-iotests/250           |   2 +-
>  tests/qemu-iotests/252           |   2 +-
>  tests/qemu-iotests/265           |   2 +-
>  tests/qemu-iotests/268           |   2 +-
>  tests/qemu-iotests/272           |   2 +-
>  tests/qemu-iotests/273           |   2 +-
>  tests/qemu-iotests/279           |   2 +-
>  tests/qemu-iotests/281           | 328 +++++++++++++++
>  tests/qemu-iotests/281.out       |  92 +++++
>  tests/qemu-iotests/check         |   6 +
>  tests/qemu-iotests/common.filter |   5 +-
>  tests/qemu-iotests/common.rc     | 190 ++++++++-
>  tests/qemu-iotests/group         |   1 +
>  93 files changed, 1571 insertions(+), 120 deletions(-)
>  create mode 100644 block/fuse.c
>  create mode 100644 include/block/fuse.h
>  create mode 100755 tests/qemu-iotests/281
>  create mode 100644 tests/qemu-iotests/281.out

A lot of qemu-iotests changes but the actual FUSE code is small and well
worth it for the flexibility and convenience that this feature brings.
Nice!

Please send a follow-up patch that adds a qemu(1) -blockdev
'Driver-specific options for "fuse"' documentation section.

Acked-by: Stefan Hajnoczi <stefanha@redhat.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 02/18] fuse: Allow exporting BDSs via FUSE
  2019-12-19 14:38 ` [PATCH 02/18] fuse: Allow exporting BDSs via FUSE Max Reitz
@ 2019-12-20 10:26   ` Kevin Wolf
  2019-12-20 10:48     ` Max Reitz
  2019-12-20 12:49     ` Markus Armbruster
  2019-12-20 21:15   ` Eric Blake
  1 sibling, 2 replies; 37+ messages in thread
From: Kevin Wolf @ 2019-12-20 10:26 UTC (permalink / raw)
  To: Max Reitz; +Cc: qemu-devel, qemu-block, armbru

Am 19.12.2019 um 15:38 hat Max Reitz geschrieben:
> fuse-export-add allows mounting block graph nodes via FUSE on some
> existing regular file.  That file should then appears like a raw disk
> image, and accesses to it result in accesses to the exported BDS.
> 
> Right now, we only set up the mount point and tear all mount points down
> in bdrv_close_all().  We do not implement any access functions, so
> accessing the mount point only results in errors.  This will be
> addressed by a followup patch.
> 
> The set of exported nodes is kept in a hash table so we can later add a
> fuse-export-remove that allows unmounting.
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>

> diff --git a/qapi/block.json b/qapi/block.json
> index 145c268bb6..03f8d1b537 100644
> --- a/qapi/block.json
> +++ b/qapi/block.json
> @@ -317,6 +317,29 @@
>  ##
>  { 'command': 'nbd-server-stop' }
>  
> +##
> +# @fuse-export-add:
> +#
> +# Exports a block graph node on some (file) mountpoint as a raw image.
> +#
> +# @node-name: Node to be exported
> +#
> +# @mountpoint: Path on which to export the block device via FUSE.
> +#              This must point to an existing regular file.
> +#
> +# @writable: Whether clients should be able to write to the block
> +#            device via the FUSE export. (default: false)
> +#
> +# Since: 5.0
> +##
> +{ 'command': 'fuse-export-add',
> +  'data': {
> +      'node-name': 'str',
> +      'mountpoint': 'str',
> +      '*writable': 'bool'
> +  },
> +  'if': 'defined(CONFIG_FUSE)' }

Can this use a BlockExport union from the start like I'm introducing in
the storage daemon series, together with a generic block-export-add?

It also looks like node-name and writable should be part of the common
base of BlockExport. Unfortunately this would mean that I can't use the
same BlockExportNbd for the existing nbd-server-add command any more. I
guess I could somehow get a shared base type for both, though.

Markus, any thoughts on these QAPI interfaces?

Kevin



^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 00/18] block: Allow exporting BDSs via FUSE
  2019-12-20 10:08 ` Stefan Hajnoczi
@ 2019-12-20 10:30   ` Max Reitz
  2019-12-20 12:50     ` Kevin Wolf
  2020-01-02 11:22     ` Stefan Hajnoczi
  0 siblings, 2 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-20 10:30 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: Kevin Wolf, qemu-devel, qemu-block


[-- Attachment #1.1: Type: text/plain, Size: 8895 bytes --]

On 20.12.19 11:08, Stefan Hajnoczi wrote:
> On Thu, Dec 19, 2019 at 03:38:00PM +0100, Max Reitz wrote:
>> Preamble: This series is based on a combination of my (current) block
>> branch and “iotests: Minor fixes”.  I’ve pushed it here:
>>
>>   https://git.xanclic.moe/XanClic/qemu fuse-exports-v1
>>
>> (The base is on fuse-exports-v1-base.)
>>
>>
>> Hi,
>>
>> Ever since I found out that you can mount FUSE filesystems on regular
>> files (not just directories), I had the idea of adding FUSE block
>> exports to qemu where you can export block nodes as raw images.  The
>> best thing is that you’d be able to mount an image on itself, so
>> whatever format it may be in, qemu lets it appear as a raw image (and
>> you can then use regular tools like dd on it).
>>
>> I started with some concept of a qemu-blkfuse daemon (similar to
>> qemu-nbd), but never sent patches, for two reasons: (1) Performance was
>> not good, (2) it didn’t seem right, for some reason.
>>
>> Now Kevin is proposing a storage daemon for multiple export types like
>> NBD, and he also mentioned FUSE (while knowing of my previous attempts).
>> Now it does seem right to add FUSE exports to qemu, but only in the form
>> of some module with a proper QAPI/QMP binding.
>>
>> Performance is still quite bad, but who cares.  We can always improve
>> it, if the need arises.
>>
>>
>> This series does the following:
>>
>> First, add the FUSE export module (block/fuse.c) that implements the
>> basic file access functions.  (Note that you need libfuse 3.8.0 or later
>> for SEEK_HOLE/SEEK_DATA.)
>>
>> Second, it allows using FUSE exports as a protocol in the iotests and
>> makes many iotests work with it.  (The file node is exported by a
>> background qemu instance to $SOCK_DIR.)
>> Note that I only ran raw and qcow2 on it; I’m sure other formats
>> currently have some failing tests.
>>
>> This gives us a lot of coverage for, well, not free (it does take ten
>> patches), but for cheap; but there are still some more specialized
>> things we want to test, so third and last, this series adds an iotest
>> dedicated to FUSE exports.
>>
>>
>> Final rather important notice: I didn’t really run the iotests with this
>> yet.  I wanted to, but they appear rather broken on current master,
>> actually.  I’m not yet sure whether that’s because something in my setup
>> broke in the last two weeks, or because there’s quite something broken
>> in master (it does look like there are a couple things broken in master
>> currently).
>>
>>
>> Max Reitz (18):
>>   configure: Detect libfuse
>>   fuse: Allow exporting BDSs via FUSE
>>   fuse: Implement standard FUSE operations
>>   fuse: Add fuse-export-remove
>>   fuse: Allow growable exports
>>   fuse: (Partially) implement fallocate()
>>   fuse: Implement hole detection through lseek
>>   iotests: Do not needlessly filter _make_test_img
>>   iotests: Do not pipe _make_test_img
>>   iotests: Use convert -n in some cases
>>   iotests: Avoid renaming images
>>   iotests: Derive image names from $TEST_IMG
>>   iotests/091: Use _cleanup_qemu instad of "wait"
>>   iotests: Restrict some Python tests to file
>>   iotests: Let _make_test_img guess $TEST_IMG_FILE
>>   iotests: Allow testing FUSE exports
>>   iotests: Enable fuse for many tests
>>   iotests/281: Add test for FUSE exports
>>
>>  block.c                          |   4 +
>>  block/Makefile.objs              |   3 +
>>  block/fuse.c                     | 668 +++++++++++++++++++++++++++++++
>>  configure                        |  68 ++++
>>  include/block/fuse.h             |  24 ++
>>  qapi/block.json                  |  42 ++
>>  tests/qemu-iotests/013           |   9 +-
>>  tests/qemu-iotests/013.out       |   3 +-
>>  tests/qemu-iotests/018           |   5 +-
>>  tests/qemu-iotests/018.out       |   1 +
>>  tests/qemu-iotests/020           |   2 +-
>>  tests/qemu-iotests/025           |   2 +-
>>  tests/qemu-iotests/026           |   2 +-
>>  tests/qemu-iotests/028           |  16 +-
>>  tests/qemu-iotests/028.out       |   3 +
>>  tests/qemu-iotests/031           |   2 +-
>>  tests/qemu-iotests/034           |   2 +-
>>  tests/qemu-iotests/036           |   2 +-
>>  tests/qemu-iotests/037           |   2 +-
>>  tests/qemu-iotests/038           |   2 +-
>>  tests/qemu-iotests/039           |   2 +-
>>  tests/qemu-iotests/046           |   7 +-
>>  tests/qemu-iotests/046.out       |   2 +-
>>  tests/qemu-iotests/050           |   2 +-
>>  tests/qemu-iotests/054           |   2 +-
>>  tests/qemu-iotests/060           |   2 +-
>>  tests/qemu-iotests/071           |  21 +-
>>  tests/qemu-iotests/072           |   5 +-
>>  tests/qemu-iotests/072.out       |   1 +
>>  tests/qemu-iotests/079           |   2 +-
>>  tests/qemu-iotests/080           |   2 +-
>>  tests/qemu-iotests/089           |   5 +-
>>  tests/qemu-iotests/089.out       |   1 +
>>  tests/qemu-iotests/090           |   2 +-
>>  tests/qemu-iotests/091           |   5 +-
>>  tests/qemu-iotests/095           |   2 +-
>>  tests/qemu-iotests/097           |   2 +-
>>  tests/qemu-iotests/098           |   2 +-
>>  tests/qemu-iotests/102           |   2 +-
>>  tests/qemu-iotests/103           |   2 +-
>>  tests/qemu-iotests/106           |   2 +-
>>  tests/qemu-iotests/107           |   2 +-
>>  tests/qemu-iotests/108           |   2 +-
>>  tests/qemu-iotests/111           |   2 +-
>>  tests/qemu-iotests/112           |   2 +-
>>  tests/qemu-iotests/115           |   2 +-
>>  tests/qemu-iotests/117           |   2 +-
>>  tests/qemu-iotests/120           |   2 +-
>>  tests/qemu-iotests/121           |   2 +-
>>  tests/qemu-iotests/127           |   2 +-
>>  tests/qemu-iotests/133           |   2 +-
>>  tests/qemu-iotests/137           |   2 +-
>>  tests/qemu-iotests/138           |   2 +-
>>  tests/qemu-iotests/140           |   2 +-
>>  tests/qemu-iotests/154           |   2 +-
>>  tests/qemu-iotests/161           |  14 +-
>>  tests/qemu-iotests/171           |   2 +-
>>  tests/qemu-iotests/174           |  10 +-
>>  tests/qemu-iotests/175           |   8 +-
>>  tests/qemu-iotests/176           |   2 +-
>>  tests/qemu-iotests/177           |   2 +-
>>  tests/qemu-iotests/179           |   2 +-
>>  tests/qemu-iotests/183           |   2 +-
>>  tests/qemu-iotests/186           |   2 +-
>>  tests/qemu-iotests/187           |   2 +-
>>  tests/qemu-iotests/191           |   2 +-
>>  tests/qemu-iotests/195           |   2 +-
>>  tests/qemu-iotests/200           |   5 +-
>>  tests/qemu-iotests/200.out       |   4 +-
>>  tests/qemu-iotests/204           |   2 +-
>>  tests/qemu-iotests/206           |   1 +
>>  tests/qemu-iotests/214           |   2 +-
>>  tests/qemu-iotests/217           |   2 +-
>>  tests/qemu-iotests/220           |   2 +-
>>  tests/qemu-iotests/221           |   2 +-
>>  tests/qemu-iotests/229           |   5 +-
>>  tests/qemu-iotests/229.out       |   6 +-
>>  tests/qemu-iotests/242           |   1 +
>>  tests/qemu-iotests/247           |   2 +-
>>  tests/qemu-iotests/249           |   8 +-
>>  tests/qemu-iotests/250           |   2 +-
>>  tests/qemu-iotests/252           |   2 +-
>>  tests/qemu-iotests/265           |   2 +-
>>  tests/qemu-iotests/268           |   2 +-
>>  tests/qemu-iotests/272           |   2 +-
>>  tests/qemu-iotests/273           |   2 +-
>>  tests/qemu-iotests/279           |   2 +-
>>  tests/qemu-iotests/281           | 328 +++++++++++++++
>>  tests/qemu-iotests/281.out       |  92 +++++
>>  tests/qemu-iotests/check         |   6 +
>>  tests/qemu-iotests/common.filter |   5 +-
>>  tests/qemu-iotests/common.rc     | 190 ++++++++-
>>  tests/qemu-iotests/group         |   1 +
>>  93 files changed, 1571 insertions(+), 120 deletions(-)
>>  create mode 100644 block/fuse.c
>>  create mode 100644 include/block/fuse.h
>>  create mode 100755 tests/qemu-iotests/281
>>  create mode 100644 tests/qemu-iotests/281.out
> 
> A lot of qemu-iotests changes but the actual FUSE code is small and well
> worth it for the flexibility and convenience that this feature brings.
> Nice!

Good that you like it! :-)

> Please send a follow-up patch that adds a qemu(1) -blockdev
> 'Driver-specific options for "fuse"' documentation section.

What exactly do you mean?  This is not a block driver, so it doesn’t
work as part of -blockdev.  Currently, it can only be used through QMP
(fuse-export-add/fuse-export-remove).

I placed it into block/ because that just seemed like the least bad
place to me (apart from creating a new top-level directory like nbd has)
– and also because we already have quite some few non-driver files in
block/ (io.c, the jobs (where some got drivers only rather recently),
accounting.c, ...).

Max


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 02/18] fuse: Allow exporting BDSs via FUSE
  2019-12-20 10:26   ` Kevin Wolf
@ 2019-12-20 10:48     ` Max Reitz
  2019-12-20 11:24       ` Kevin Wolf
  2019-12-20 12:49     ` Markus Armbruster
  1 sibling, 1 reply; 37+ messages in thread
From: Max Reitz @ 2019-12-20 10:48 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel, qemu-block, armbru


[-- Attachment #1.1: Type: text/plain, Size: 3350 bytes --]

On 20.12.19 11:26, Kevin Wolf wrote:
> Am 19.12.2019 um 15:38 hat Max Reitz geschrieben:
>> fuse-export-add allows mounting block graph nodes via FUSE on some
>> existing regular file.  That file should then appears like a raw disk
>> image, and accesses to it result in accesses to the exported BDS.
>>
>> Right now, we only set up the mount point and tear all mount points down
>> in bdrv_close_all().  We do not implement any access functions, so
>> accessing the mount point only results in errors.  This will be
>> addressed by a followup patch.
>>
>> The set of exported nodes is kept in a hash table so we can later add a
>> fuse-export-remove that allows unmounting.
>>
>> Signed-off-by: Max Reitz <mreitz@redhat.com>
> 
>> diff --git a/qapi/block.json b/qapi/block.json
>> index 145c268bb6..03f8d1b537 100644
>> --- a/qapi/block.json
>> +++ b/qapi/block.json
>> @@ -317,6 +317,29 @@
>>  ##
>>  { 'command': 'nbd-server-stop' }
>>  
>> +##
>> +# @fuse-export-add:
>> +#
>> +# Exports a block graph node on some (file) mountpoint as a raw image.
>> +#
>> +# @node-name: Node to be exported
>> +#
>> +# @mountpoint: Path on which to export the block device via FUSE.
>> +#              This must point to an existing regular file.
>> +#
>> +# @writable: Whether clients should be able to write to the block
>> +#            device via the FUSE export. (default: false)
>> +#
>> +# Since: 5.0
>> +##
>> +{ 'command': 'fuse-export-add',
>> +  'data': {
>> +      'node-name': 'str',
>> +      'mountpoint': 'str',
>> +      '*writable': 'bool'
>> +  },
>> +  'if': 'defined(CONFIG_FUSE)' }
> 
> Can this use a BlockExport union from the start like I'm introducing in
> the storage daemon series, together with a generic block-export-add?

Hm, you mean still adding a FuseExport structure that would be part of
BlockExport and then dropping fuse-export-add in favor of a
block-export-add that we want anyway?

> It also looks like node-name and writable should be part of the common
> base of BlockExport.

node-name definitely, I’m not so sure about writable.  Or, to be more
precise, I think that if we want writable to be in the base, we also
want growable to be there: Both are primarily options for the
BlockBackend that the exports use.

But both of course also need to be supported by the export
implementation.  nbd can make its BB growable all it wants, but that
doesn’t make it work.

So if we kept writable and growable in the common base, then the schema
would give no information about what exports actually support them.

On one hand, I don’t know whether it’s important to have this
information in a static form, or whether it’s sufficient to learn at
runtime.

On the other, I don’t know whether it’s important to have those fields
in the base or not.  Would it make a difference on the wire?

> Unfortunately this would mean that I can't use the
> same BlockExportNbd for the existing nbd-server-add command any more. I
> guess I could somehow get a shared base type for both, though.

Hm.  This sounds like you want to make it your problem.  Can I take that
to mean that you want to implement block-export-add and I can wait with
v2 until that’s done? :-)

Max

> Markus, any thoughts on these QAPI interfaces?
> 
> Kevin


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 02/18] fuse: Allow exporting BDSs via FUSE
  2019-12-20 10:48     ` Max Reitz
@ 2019-12-20 11:24       ` Kevin Wolf
  2019-12-20 12:09         ` Max Reitz
  2019-12-20 12:48         ` Markus Armbruster
  0 siblings, 2 replies; 37+ messages in thread
From: Kevin Wolf @ 2019-12-20 11:24 UTC (permalink / raw)
  To: Max Reitz; +Cc: qemu-devel, qemu-block, armbru

[-- Attachment #1: Type: text/plain, Size: 4348 bytes --]

Am 20.12.2019 um 11:48 hat Max Reitz geschrieben:
> On 20.12.19 11:26, Kevin Wolf wrote:
> > Am 19.12.2019 um 15:38 hat Max Reitz geschrieben:
> >> fuse-export-add allows mounting block graph nodes via FUSE on some
> >> existing regular file.  That file should then appears like a raw disk
> >> image, and accesses to it result in accesses to the exported BDS.
> >>
> >> Right now, we only set up the mount point and tear all mount points down
> >> in bdrv_close_all().  We do not implement any access functions, so
> >> accessing the mount point only results in errors.  This will be
> >> addressed by a followup patch.
> >>
> >> The set of exported nodes is kept in a hash table so we can later add a
> >> fuse-export-remove that allows unmounting.
> >>
> >> Signed-off-by: Max Reitz <mreitz@redhat.com>
> > 
> >> diff --git a/qapi/block.json b/qapi/block.json
> >> index 145c268bb6..03f8d1b537 100644
> >> --- a/qapi/block.json
> >> +++ b/qapi/block.json
> >> @@ -317,6 +317,29 @@
> >>  ##
> >>  { 'command': 'nbd-server-stop' }
> >>  
> >> +##
> >> +# @fuse-export-add:
> >> +#
> >> +# Exports a block graph node on some (file) mountpoint as a raw image.
> >> +#
> >> +# @node-name: Node to be exported
> >> +#
> >> +# @mountpoint: Path on which to export the block device via FUSE.
> >> +#              This must point to an existing regular file.
> >> +#
> >> +# @writable: Whether clients should be able to write to the block
> >> +#            device via the FUSE export. (default: false)
> >> +#
> >> +# Since: 5.0
> >> +##
> >> +{ 'command': 'fuse-export-add',
> >> +  'data': {
> >> +      'node-name': 'str',
> >> +      'mountpoint': 'str',
> >> +      '*writable': 'bool'
> >> +  },
> >> +  'if': 'defined(CONFIG_FUSE)' }
> > 
> > Can this use a BlockExport union from the start like I'm introducing in
> > the storage daemon series, together with a generic block-export-add?
> 
> Hm, you mean still adding a FuseExport structure that would be part of
> BlockExport and then dropping fuse-export-add in favor of a
> block-export-add that we want anyway?

Yes.

> > It also looks like node-name and writable should be part of the common
> > base of BlockExport.
> 
> node-name definitely, I’m not so sure about writable.  Or, to be more
> precise, I think that if we want writable to be in the base, we also
> want growable to be there: Both are primarily options for the
> BlockBackend that the exports use.
> 
> But both of course also need to be supported by the export
> implementation.  nbd can make its BB growable all it wants, but that
> doesn’t make it work.

Right. Pragmatically, I think exports are very like to support writable,
but probably rather unlikely to support growable. So I do think there
would be a point for making writable part of the common base, but not
growable.

> So if we kept writable and growable in the common base, then the schema
> would give no information about what exports actually support them.
> 
> On one hand, I don’t know whether it’s important to have this
> information in a static form, or whether it’s sufficient to learn at
> runtime.
> 
> On the other, I don’t know whether it’s important to have those fields
> in the base or not.  Would it make a difference on the wire?

Not for the command itself, so I think we're free to change it later. It
might make a difference for introspection, though, not sure. Markus?

Having it in the base might allow us to remove some duplication in the
code. Probably not much, though, so not too important.

> > Unfortunately this would mean that I can't use the
> > same BlockExportNbd for the existing nbd-server-add command any more. I
> > guess I could somehow get a shared base type for both, though.
> 
> Hm.  This sounds like you want to make it your problem.  Can I take that
> to mean that you want to implement block-export-add and I can wait with
> v2 until that’s done? :-)

The NBD integration, yes. I already added the BlockExport type to my
patches, too, but I expect you would beat me to it. I'm not currently
planning to write a block-export-add because it doesn't add anything new
for the storage daemon, so FuseExport and the command this is your part.
The type currently only exists for --export.

Kevin


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 02/18] fuse: Allow exporting BDSs via FUSE
  2019-12-20 11:24       ` Kevin Wolf
@ 2019-12-20 12:09         ` Max Reitz
  2019-12-20 12:48         ` Markus Armbruster
  1 sibling, 0 replies; 37+ messages in thread
From: Max Reitz @ 2019-12-20 12:09 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel, qemu-block, armbru


[-- Attachment #1.1: Type: text/plain, Size: 7023 bytes --]

On 20.12.19 12:24, Kevin Wolf wrote:
> Am 20.12.2019 um 11:48 hat Max Reitz geschrieben:
>> On 20.12.19 11:26, Kevin Wolf wrote:
>>> Am 19.12.2019 um 15:38 hat Max Reitz geschrieben:
>>>> fuse-export-add allows mounting block graph nodes via FUSE on some
>>>> existing regular file.  That file should then appears like a raw disk
>>>> image, and accesses to it result in accesses to the exported BDS.
>>>>
>>>> Right now, we only set up the mount point and tear all mount points down
>>>> in bdrv_close_all().  We do not implement any access functions, so
>>>> accessing the mount point only results in errors.  This will be
>>>> addressed by a followup patch.
>>>>
>>>> The set of exported nodes is kept in a hash table so we can later add a
>>>> fuse-export-remove that allows unmounting.
>>>>
>>>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>>>
>>>> diff --git a/qapi/block.json b/qapi/block.json
>>>> index 145c268bb6..03f8d1b537 100644
>>>> --- a/qapi/block.json
>>>> +++ b/qapi/block.json
>>>> @@ -317,6 +317,29 @@
>>>>  ##
>>>>  { 'command': 'nbd-server-stop' }
>>>>  
>>>> +##
>>>> +# @fuse-export-add:
>>>> +#
>>>> +# Exports a block graph node on some (file) mountpoint as a raw image.
>>>> +#
>>>> +# @node-name: Node to be exported
>>>> +#
>>>> +# @mountpoint: Path on which to export the block device via FUSE.
>>>> +#              This must point to an existing regular file.
>>>> +#
>>>> +# @writable: Whether clients should be able to write to the block
>>>> +#            device via the FUSE export. (default: false)
>>>> +#
>>>> +# Since: 5.0
>>>> +##
>>>> +{ 'command': 'fuse-export-add',
>>>> +  'data': {
>>>> +      'node-name': 'str',
>>>> +      'mountpoint': 'str',
>>>> +      '*writable': 'bool'
>>>> +  },
>>>> +  'if': 'defined(CONFIG_FUSE)' }
>>>
>>> Can this use a BlockExport union from the start like I'm introducing in
>>> the storage daemon series, together with a generic block-export-add?
>>
>> Hm, you mean still adding a FuseExport structure that would be part of
>> BlockExport and then dropping fuse-export-add in favor of a
>> block-export-add that we want anyway?
> 
> Yes.
> 
>>> It also looks like node-name and writable should be part of the common
>>> base of BlockExport.
>>
>> node-name definitely, I’m not so sure about writable.  Or, to be more
>> precise, I think that if we want writable to be in the base, we also
>> want growable to be there: Both are primarily options for the
>> BlockBackend that the exports use.
>>
>> But both of course also need to be supported by the export
>> implementation.  nbd can make its BB growable all it wants, but that
>> doesn’t make it work.
> 
> Right. Pragmatically, I think exports are very like to support writable,
> but probably rather unlikely to support growable. So I do think there
> would be a point for making writable part of the common base, but not
> growable.

True.

But there’s nothing that inherently binds it to FUSE, so I think both
from an implementation’s POV and from a user’s POV, it looks just as
generic as “writable”.  But that’s theory.  I agree that in practice, it
won’t be as generic.

(I realize this doesn’t help much in finding out what we should do.)

>> So if we kept writable and growable in the common base, then the schema
>> would give no information about what exports actually support them.
>>
>> On one hand, I don’t know whether it’s important to have this
>> information in a static form, or whether it’s sufficient to learn at
>> runtime.
>>
>> On the other, I don’t know whether it’s important to have those fields
>> in the base or not.  Would it make a difference on the wire?
> 
> Not for the command itself, so I think we're free to change it later. It
> might make a difference for introspection, though, not sure. Markus?

Yes, I asked because I’m wondering whether it would be more cumbersome
to users if we didn’t keep it in the base structure.

The duplication depends on how we want to design the command.  Should
the export implementations receive a ready-to-use BB?  Or just a
node-name?  In the latter case, we wouldn’t get rid of duplicated code
by having writable/growable in the base.  For the former, it could, but
then again, just taking the WRITE permission and making the BB growable
isn’t that bad to duplicate.

Something to consider is that of course the current NBD code wants a
node-name and not a BB.  So if we decided to generally give export
implementations a BB, then the initial implementation of
qmp_block_export_add() would look a bit freaky: It would first branch
off to qmp_nbd_server_add(), and then open the BB for the “common” case,
but this common case only exists for FUSE (right now).

OTOH, right now we’re free to decide whether we open the BB in
qmp_block_export_add() or fuse.c, and so we might as well just do it in
the former.  If we later find out that this was a stupid idea, we can
always move it into fuse.c.


Now I don’t quite know where I’m trying to get with this.

I suppose it means that we should start with qmp_block_export_add()
creating the BB and handing it over to the export implementation.

Then it makes sense to me that the BB should be ready to go, i.e. have
all the necessary flags and permissions set.  If so, writable and
growable should be part of the base, so the WRITE permission can be
taken and allow_write_beyond_eof can be set.

But there’s a catch: The common code actually cannot pass on a
ready-to-go BB, because it depends on the export type what kinds of
permissions can be shared.  FUSE exports are fine with sharing the
RESIZE permission, but NBD can’t do that.  And, well, if we require the
export implementation to adjust the permissions anyway, we might as well
require it to take WRITE if necessary.  And then the argument for
avoiding duplication is gone.

> Having it in the base might allow us to remove some duplication in the
> code. Probably not much, though, so not too important.
> 
>>> Unfortunately this would mean that I can't use the
>>> same BlockExportNbd for the existing nbd-server-add command any more. I
>>> guess I could somehow get a shared base type for both, though.
>>
>> Hm.  This sounds like you want to make it your problem.  Can I take that
>> to mean that you want to implement block-export-add and I can wait with
>> v2 until that’s done? :-)
> 
> The NBD integration, yes. I already added the BlockExport type to my
> patches, too, but I expect you would beat me to it. I'm not currently
> planning to write a block-export-add because it doesn't add anything new
> for the storage daemon, so FuseExport and the command this is your part.
> The type currently only exists for --export.

That’s too bad. ;-)

I was mostly asking because I imagine it would actually make more sense
to add block-export-add in a seperate (prerequisite) series.

Max


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 02/18] fuse: Allow exporting BDSs via FUSE
  2019-12-20 11:24       ` Kevin Wolf
  2019-12-20 12:09         ` Max Reitz
@ 2019-12-20 12:48         ` Markus Armbruster
  2019-12-20 12:58           ` Kevin Wolf
  1 sibling, 1 reply; 37+ messages in thread
From: Markus Armbruster @ 2019-12-20 12:48 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel, qemu-block, Max Reitz

Kevin Wolf <kwolf@redhat.com> writes:

> Am 20.12.2019 um 11:48 hat Max Reitz geschrieben:
>> On 20.12.19 11:26, Kevin Wolf wrote:
>> > Am 19.12.2019 um 15:38 hat Max Reitz geschrieben:
>> >> fuse-export-add allows mounting block graph nodes via FUSE on some
>> >> existing regular file.  That file should then appears like a raw disk
>> >> image, and accesses to it result in accesses to the exported BDS.
>> >>
>> >> Right now, we only set up the mount point and tear all mount points down
>> >> in bdrv_close_all().  We do not implement any access functions, so
>> >> accessing the mount point only results in errors.  This will be
>> >> addressed by a followup patch.
>> >>
>> >> The set of exported nodes is kept in a hash table so we can later add a
>> >> fuse-export-remove that allows unmounting.
>> >>
>> >> Signed-off-by: Max Reitz <mreitz@redhat.com>
>> > 
>> >> diff --git a/qapi/block.json b/qapi/block.json
>> >> index 145c268bb6..03f8d1b537 100644
>> >> --- a/qapi/block.json
>> >> +++ b/qapi/block.json
>> >> @@ -317,6 +317,29 @@
>> >>  ##
>> >>  { 'command': 'nbd-server-stop' }
>> >>  
>> >> +##
>> >> +# @fuse-export-add:
>> >> +#
>> >> +# Exports a block graph node on some (file) mountpoint as a raw image.
>> >> +#
>> >> +# @node-name: Node to be exported
>> >> +#
>> >> +# @mountpoint: Path on which to export the block device via FUSE.
>> >> +#              This must point to an existing regular file.
>> >> +#
>> >> +# @writable: Whether clients should be able to write to the block
>> >> +#            device via the FUSE export. (default: false)
>> >> +#
>> >> +# Since: 5.0
>> >> +##
>> >> +{ 'command': 'fuse-export-add',
>> >> +  'data': {
>> >> +      'node-name': 'str',
>> >> +      'mountpoint': 'str',
>> >> +      '*writable': 'bool'
>> >> +  },
>> >> +  'if': 'defined(CONFIG_FUSE)' }
>> > 
>> > Can this use a BlockExport union from the start like I'm introducing in
>> > the storage daemon series, together with a generic block-export-add?
>> 
>> Hm, you mean still adding a FuseExport structure that would be part of
>> BlockExport and then dropping fuse-export-add in favor of a
>> block-export-add that we want anyway?
>
> Yes.
>
>> > It also looks like node-name and writable should be part of the common
>> > base of BlockExport.
>> 
>> node-name definitely, I’m not so sure about writable.  Or, to be more
>> precise, I think that if we want writable to be in the base, we also
>> want growable to be there: Both are primarily options for the
>> BlockBackend that the exports use.
>> 
>> But both of course also need to be supported by the export
>> implementation.  nbd can make its BB growable all it wants, but that
>> doesn’t make it work.
>
> Right. Pragmatically, I think exports are very like to support writable,
> but probably rather unlikely to support growable. So I do think there
> would be a point for making writable part of the common base, but not
> growable.
>
>> So if we kept writable and growable in the common base, then the schema
>> would give no information about what exports actually support them.
>> 
>> On one hand, I don’t know whether it’s important to have this
>> information in a static form, or whether it’s sufficient to learn at
>> runtime.
>> 
>> On the other, I don’t know whether it’s important to have those fields
>> in the base or not.  Would it make a difference on the wire?
>
> Not for the command itself, so I think we're free to change it later. It
> might make a difference for introspection, though, not sure. Markus?

QAPI schema introspection is designed to hide the difference between
local members and base members.  You can move members to or from a base
type freely without affecting introspection.  Even if that creates or
deletes the base type.

Example: DriveBackup

    { 'struct': 'DriveBackup',
      'base': 'BackupCommon',
      'data': { 'target': 'str',
                '*format': 'str',
                '*mode': 'NewImageMode' } }

where BackupCommon is

    { 'struct': 'BackupCommon',
      'data': { '*job-id': 'str', 'device': 'str',
                'sync': 'MirrorSyncMode', '*speed': 'int',
                '*bitmap': 'str', '*bitmap-mode': 'BitmapSyncMode',
                '*compress': 'bool',
                '*on-source-error': 'BlockdevOnError',
                '*on-target-error': 'BlockdevOnError',
                '*auto-finalize': 'bool', '*auto-dismiss': 'bool',
                '*filter-node-name': 'str' } }

query-qmp-schema describes DriveBackup like this:

    {"name": "30",
     "members": [
         {"name": "job-id", "default": null, "type": "str"},
         {"name": "device", "type": "str"},
         {"name": "sync", "type": "235"},
         {"name": "speed", "default": null, "type": "int"},
         {"name": "bitmap", "default": null, "type": "str"},
         {"name": "bitmap-mode", "default": null, "type": "236"},
         {"name": "compress", "default": null, "type": "bool"},
         {"name": "on-source-error", "default": null, "type": "237"},
         {"name": "on-target-error", "default": null, "type": "237"},
         {"name": "auto-finalize", "default": null, "type": "bool"},
         {"name": "auto-dismiss", "default": null, "type": "bool"},
         {"name": "filter-node-name", "default": null, "type": "str"},
         {"name": "target", "type": "str"},
         {"name": "format", "default": null, "type": "str"},
         {"name": "mode", "default": null, "type": "234"}],
     "meta-type": "object"}

[...]



^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 02/18] fuse: Allow exporting BDSs via FUSE
  2019-12-20 10:26   ` Kevin Wolf
  2019-12-20 10:48     ` Max Reitz
@ 2019-12-20 12:49     ` Markus Armbruster
  2019-12-20 13:02       ` Kevin Wolf
  1 sibling, 1 reply; 37+ messages in thread
From: Markus Armbruster @ 2019-12-20 12:49 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel, qemu-block, Max Reitz

Kevin Wolf <kwolf@redhat.com> writes:

> Am 19.12.2019 um 15:38 hat Max Reitz geschrieben:
>> fuse-export-add allows mounting block graph nodes via FUSE on some
>> existing regular file.  That file should then appears like a raw disk
>> image, and accesses to it result in accesses to the exported BDS.
>> 
>> Right now, we only set up the mount point and tear all mount points down
>> in bdrv_close_all().  We do not implement any access functions, so
>> accessing the mount point only results in errors.  This will be
>> addressed by a followup patch.
>> 
>> The set of exported nodes is kept in a hash table so we can later add a
>> fuse-export-remove that allows unmounting.
>> 
>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>
>> diff --git a/qapi/block.json b/qapi/block.json
>> index 145c268bb6..03f8d1b537 100644
>> --- a/qapi/block.json
>> +++ b/qapi/block.json
>> @@ -317,6 +317,29 @@
>>  ##
>>  { 'command': 'nbd-server-stop' }
>>  
>> +##
>> +# @fuse-export-add:
>> +#
>> +# Exports a block graph node on some (file) mountpoint as a raw image.
>> +#
>> +# @node-name: Node to be exported
>> +#
>> +# @mountpoint: Path on which to export the block device via FUSE.
>> +#              This must point to an existing regular file.
>> +#
>> +# @writable: Whether clients should be able to write to the block
>> +#            device via the FUSE export. (default: false)
>> +#
>> +# Since: 5.0
>> +##
>> +{ 'command': 'fuse-export-add',
>> +  'data': {
>> +      'node-name': 'str',
>> +      'mountpoint': 'str',
>> +      '*writable': 'bool'
>> +  },
>> +  'if': 'defined(CONFIG_FUSE)' }
>
> Can this use a BlockExport union from the start like I'm introducing in
> the storage daemon series, together with a generic block-export-add?
>
> It also looks like node-name and writable should be part of the common
> base of BlockExport. Unfortunately this would mean that I can't use the
> same BlockExportNbd for the existing nbd-server-add command any more. I
> guess I could somehow get a shared base type for both, though.
>
> Markus, any thoughts on these QAPI interfaces?

Context?  How far back should I read?



^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 00/18] block: Allow exporting BDSs via FUSE
  2019-12-20 10:30   ` Max Reitz
@ 2019-12-20 12:50     ` Kevin Wolf
  2019-12-20 21:20       ` Eric Blake
  2020-01-02 11:22     ` Stefan Hajnoczi
  1 sibling, 1 reply; 37+ messages in thread
From: Kevin Wolf @ 2019-12-20 12:50 UTC (permalink / raw)
  To: Max Reitz; +Cc: Stefan Hajnoczi, qemu-devel, qemu-block

[-- Attachment #1: Type: text/plain, Size: 462 bytes --]

Am 20.12.2019 um 11:30 hat Max Reitz geschrieben:
> I placed it into block/ because that just seemed like the least bad
> place to me (apart from creating a new top-level directory like nbd has)
> – and also because we already have quite some few non-driver files in
> block/ (io.c, the jobs (where some got drivers only rather recently),
> accounting.c, ...).

We could consider block/exports/ and eventually also move the NBD server
there.

Kevin

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 02/18] fuse: Allow exporting BDSs via FUSE
  2019-12-20 12:48         ` Markus Armbruster
@ 2019-12-20 12:58           ` Kevin Wolf
  2019-12-20 13:25             ` Markus Armbruster
  0 siblings, 1 reply; 37+ messages in thread
From: Kevin Wolf @ 2019-12-20 12:58 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, qemu-block, Max Reitz

Am 20.12.2019 um 13:48 hat Markus Armbruster geschrieben:
> Kevin Wolf <kwolf@redhat.com> writes:
> 
> > Am 20.12.2019 um 11:48 hat Max Reitz geschrieben:
> >> So if we kept writable and growable in the common base, then the schema
> >> would give no information about what exports actually support them.
> >> 
> >> On one hand, I don’t know whether it’s important to have this
> >> information in a static form, or whether it’s sufficient to learn at
> >> runtime.
> >> 
> >> On the other, I don’t know whether it’s important to have those fields
> >> in the base or not.  Would it make a difference on the wire?
> >
> > Not for the command itself, so I think we're free to change it later. It
> > might make a difference for introspection, though, not sure. Markus?
> 
> QAPI schema introspection is designed to hide the difference between
> local members and base members.  You can move members to or from a base
> type freely without affecting introspection.  Even if that creates or
> deletes the base type.

Good, that's helpful. So I can split the nbd-server-add argument type
into a base that is reused as a union branch and the rest without
potentially breaking anything.

I suppose moving a field between a union base and all variants does
still result in different introspection even though the accepted inputs
are the same. Is this kind of movement still allowed unconditionally or
should we be more careful with something like this?

Kevin



^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 02/18] fuse: Allow exporting BDSs via FUSE
  2019-12-20 12:49     ` Markus Armbruster
@ 2019-12-20 13:02       ` Kevin Wolf
  0 siblings, 0 replies; 37+ messages in thread
From: Kevin Wolf @ 2019-12-20 13:02 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, qemu-block, Max Reitz

Am 20.12.2019 um 13:49 hat Markus Armbruster geschrieben:
> Kevin Wolf <kwolf@redhat.com> writes:
> 
> > Am 19.12.2019 um 15:38 hat Max Reitz geschrieben:
> >> fuse-export-add allows mounting block graph nodes via FUSE on some
> >> existing regular file.  That file should then appears like a raw disk
> >> image, and accesses to it result in accesses to the exported BDS.
> >> 
> >> Right now, we only set up the mount point and tear all mount points down
> >> in bdrv_close_all().  We do not implement any access functions, so
> >> accessing the mount point only results in errors.  This will be
> >> addressed by a followup patch.
> >> 
> >> The set of exported nodes is kept in a hash table so we can later add a
> >> fuse-export-remove that allows unmounting.
> >> 
> >> Signed-off-by: Max Reitz <mreitz@redhat.com>
> >
> >> diff --git a/qapi/block.json b/qapi/block.json
> >> index 145c268bb6..03f8d1b537 100644
> >> --- a/qapi/block.json
> >> +++ b/qapi/block.json
> >> @@ -317,6 +317,29 @@
> >>  ##
> >>  { 'command': 'nbd-server-stop' }
> >>  
> >> +##
> >> +# @fuse-export-add:
> >> +#
> >> +# Exports a block graph node on some (file) mountpoint as a raw image.
> >> +#
> >> +# @node-name: Node to be exported
> >> +#
> >> +# @mountpoint: Path on which to export the block device via FUSE.
> >> +#              This must point to an existing regular file.
> >> +#
> >> +# @writable: Whether clients should be able to write to the block
> >> +#            device via the FUSE export. (default: false)
> >> +#
> >> +# Since: 5.0
> >> +##
> >> +{ 'command': 'fuse-export-add',
> >> +  'data': {
> >> +      'node-name': 'str',
> >> +      'mountpoint': 'str',
> >> +      '*writable': 'bool'
> >> +  },
> >> +  'if': 'defined(CONFIG_FUSE)' }
> >
> > Can this use a BlockExport union from the start like I'm introducing in
> > the storage daemon series, together with a generic block-export-add?
> >
> > It also looks like node-name and writable should be part of the common
> > base of BlockExport. Unfortunately this would mean that I can't use the
> > same BlockExportNbd for the existing nbd-server-add command any more. I
> > guess I could somehow get a shared base type for both, though.
> >
> > Markus, any thoughts on these QAPI interfaces?
> 
> Context?  How far back should I read?

Basically just the hunk quoted above and the QAPI portion of the
following storage daemon patch:

    [RFC PATCH 08/18] qemu-storage-daemon: Add --export option

Maybe the cover letter, too, if you need a more high-level introduction.

Kevin



^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 02/18] fuse: Allow exporting BDSs via FUSE
  2019-12-20 12:58           ` Kevin Wolf
@ 2019-12-20 13:25             ` Markus Armbruster
  2019-12-20 21:18               ` Eric Blake
  0 siblings, 1 reply; 37+ messages in thread
From: Markus Armbruster @ 2019-12-20 13:25 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel, qemu-block, Max Reitz

Kevin Wolf <kwolf@redhat.com> writes:

> Am 20.12.2019 um 13:48 hat Markus Armbruster geschrieben:
>> Kevin Wolf <kwolf@redhat.com> writes:
>> 
>> > Am 20.12.2019 um 11:48 hat Max Reitz geschrieben:
>> >> So if we kept writable and growable in the common base, then the schema
>> >> would give no information about what exports actually support them.
>> >> 
>> >> On one hand, I don’t know whether it’s important to have this
>> >> information in a static form, or whether it’s sufficient to learn at
>> >> runtime.
>> >> 
>> >> On the other, I don’t know whether it’s important to have those fields
>> >> in the base or not.  Would it make a difference on the wire?
>> >
>> > Not for the command itself, so I think we're free to change it later. It
>> > might make a difference for introspection, though, not sure. Markus?
>> 
>> QAPI schema introspection is designed to hide the difference between
>> local members and base members.  You can move members to or from a base
>> type freely without affecting introspection.  Even if that creates or
>> deletes the base type.
>
> Good, that's helpful. So I can split the nbd-server-add argument type
> into a base that is reused as a union branch and the rest without
> potentially breaking anything.
>
> I suppose moving a field between a union base and all variants does
> still result in different introspection even though the accepted inputs
> are the same.

Correct.  A common member (whether it's local or from the base) is in
SchemaInfoObject.members[].  Moving it to all the variants moves it to
the variant types' .members[].

>               Is this kind of movement still allowed unconditionally or
> should we be more careful with something like this?

QMP's backward compatibility promise does not include "introspection
value won't change".  Still, such changes can conceivably confuse
clients.  Care is advisable.  But it's not a hard "no".



^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 02/18] fuse: Allow exporting BDSs via FUSE
  2019-12-19 14:38 ` [PATCH 02/18] fuse: Allow exporting BDSs via FUSE Max Reitz
  2019-12-20 10:26   ` Kevin Wolf
@ 2019-12-20 21:15   ` Eric Blake
  2020-01-06 12:00     ` Max Reitz
  1 sibling, 1 reply; 37+ messages in thread
From: Eric Blake @ 2019-12-20 21:15 UTC (permalink / raw)
  To: Max Reitz, qemu-block; +Cc: Kevin Wolf, qemu-devel, Richard W.M. Jones

On 12/19/19 8:38 AM, Max Reitz wrote:
> fuse-export-add allows mounting block graph nodes via FUSE on some
> existing regular file.  That file should then appears like a raw disk
> image, and accesses to it result in accesses to the exported BDS.
> 
> Right now, we only set up the mount point and tear all mount points down
> in bdrv_close_all().  We do not implement any access functions, so
> accessing the mount point only results in errors.  This will be
> addressed by a followup patch.
> 
> The set of exported nodes is kept in a hash table so we can later add a
> fuse-export-remove that allows unmounting.

Before I review this, a quick question:

How does this compare to the recently added nbdfuse?
https://www.redhat.com/archives/libguestfs/2019-October/msg00080.html

Or put another way, maybe we get the same effect by combining qemu-nbd 
with nbdfuse, but this new utility would cut out a middleman for more 
efficiency, right?


> +++ b/block/fuse.c
> @@ -0,0 +1,260 @@
> +/*
> + * Present a block device as a raw image through FUSE
> + *
> + * Copyright (c) 2019 Max Reitz <mreitz@redhat.com>


-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org



^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 02/18] fuse: Allow exporting BDSs via FUSE
  2019-12-20 13:25             ` Markus Armbruster
@ 2019-12-20 21:18               ` Eric Blake
  0 siblings, 0 replies; 37+ messages in thread
From: Eric Blake @ 2019-12-20 21:18 UTC (permalink / raw)
  To: Markus Armbruster, Kevin Wolf; +Cc: qemu-devel, qemu-block, Max Reitz

On 12/20/19 7:25 AM, Markus Armbruster wrote:

>>
>> I suppose moving a field between a union base and all variants does
>> still result in different introspection even though the accepted inputs
>> are the same.
> 
> Correct.  A common member (whether it's local or from the base) is in
> SchemaInfoObject.members[].  Moving it to all the variants moves it to
> the variant types' .members[].
> 
>>                Is this kind of movement still allowed unconditionally or
>> should we be more careful with something like this?
> 
> QMP's backward compatibility promise does not include "introspection
> value won't change".  Still, such changes can conceivably confuse
> clients.  Care is advisable.  But it's not a hard "no".

And libvirt already correctly handles movements like this (so there are 
existing clients aware of the potential confusion).

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org



^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 00/18] block: Allow exporting BDSs via FUSE
  2019-12-20 12:50     ` Kevin Wolf
@ 2019-12-20 21:20       ` Eric Blake
  0 siblings, 0 replies; 37+ messages in thread
From: Eric Blake @ 2019-12-20 21:20 UTC (permalink / raw)
  To: Kevin Wolf, Max Reitz; +Cc: qemu-devel, qemu-block

On 12/20/19 6:50 AM, Kevin Wolf wrote:
> Am 20.12.2019 um 11:30 hat Max Reitz geschrieben:
>> I placed it into block/ because that just seemed like the least bad
>> place to me (apart from creating a new top-level directory like nbd has)
>> – and also because we already have quite some few non-driver files in
>> block/ (io.c, the jobs (where some got drivers only rather recently),
>> accounting.c, ...).
> 
> We could consider block/exports/ and eventually also move the NBD server
> there.

We already had another thread considering the motion of qemu-nbd.c to 
tools/, and I don't mind moving top-level nbd/ into block/exports/ if 
that makes things easier to reason about.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org



^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 00/18] block: Allow exporting BDSs via FUSE
  2019-12-20 10:30   ` Max Reitz
  2019-12-20 12:50     ` Kevin Wolf
@ 2020-01-02 11:22     ` Stefan Hajnoczi
  1 sibling, 0 replies; 37+ messages in thread
From: Stefan Hajnoczi @ 2020-01-02 11:22 UTC (permalink / raw)
  To: Max Reitz; +Cc: Kevin Wolf, qemu-devel, qemu-block

[-- Attachment #1: Type: text/plain, Size: 542 bytes --]

On Fri, Dec 20, 2019 at 11:30:33AM +0100, Max Reitz wrote:
> On 20.12.19 11:08, Stefan Hajnoczi wrote:
> > On Thu, Dec 19, 2019 at 03:38:00PM +0100, Max Reitz wrote:
> > Please send a follow-up patch that adds a qemu(1) -blockdev
> > 'Driver-specific options for "fuse"' documentation section.
> 
> What exactly do you mean?  This is not a block driver, so it doesn’t
> work as part of -blockdev.  Currently, it can only be used through QMP
> (fuse-export-add/fuse-export-remove).

I don't know what I was thinking :).

Stefan

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 02/18] fuse: Allow exporting BDSs via FUSE
  2019-12-20 21:15   ` Eric Blake
@ 2020-01-06 12:00     ` Max Reitz
  0 siblings, 0 replies; 37+ messages in thread
From: Max Reitz @ 2020-01-06 12:00 UTC (permalink / raw)
  To: Eric Blake, qemu-block; +Cc: Kevin Wolf, qemu-devel, Richard W.M. Jones


[-- Attachment #1.1: Type: text/plain, Size: 1761 bytes --]

On 20.12.19 22:15, Eric Blake wrote:
> On 12/19/19 8:38 AM, Max Reitz wrote:
>> fuse-export-add allows mounting block graph nodes via FUSE on some
>> existing regular file.  That file should then appears like a raw disk
>> image, and accesses to it result in accesses to the exported BDS.
>>
>> Right now, we only set up the mount point and tear all mount points down
>> in bdrv_close_all().  We do not implement any access functions, so
>> accessing the mount point only results in errors.  This will be
>> addressed by a followup patch.
>>
>> The set of exported nodes is kept in a hash table so we can later add a
>> fuse-export-remove that allows unmounting.
> 
> Before I review this, a quick question:
> 
> How does this compare to the recently added nbdfuse?
> https://www.redhat.com/archives/libguestfs/2019-October/msg00080.html

Hm.  Well, one thing is that it uses a file mount point instead of a
cumbersome directory + "ramdisk" file. O:-)  (Which, again, is fun
because this allows you to mount a qcow2 file on itself so it appears
like a raw image.)

Then we get all native block layer things without needing NBD support,
like resize (also growing on post-EOF writes).

(It also has features the nbdfuse patch mentions are not supported there
yet, i.e. fallocate() (zero writes and discards).  And I don’t suppose
nbdfuse supports lseek() yet either.  I suppose those features could be
added to nbdfuse, but, well, they are here now.)

> Or put another way, maybe we get the same effect by combining qemu-nbd
> with nbdfuse, but this new utility would cut out a middleman for more
> efficiency, right?

I would assume it has better efficiency, yes.  But the performance is
not very good anyway.

Max


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 484 bytes --]

^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2020-01-06 12:01 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-19 14:38 [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
2019-12-19 14:38 ` [PATCH 01/18] configure: Detect libfuse Max Reitz
2019-12-19 14:38 ` [PATCH 02/18] fuse: Allow exporting BDSs via FUSE Max Reitz
2019-12-20 10:26   ` Kevin Wolf
2019-12-20 10:48     ` Max Reitz
2019-12-20 11:24       ` Kevin Wolf
2019-12-20 12:09         ` Max Reitz
2019-12-20 12:48         ` Markus Armbruster
2019-12-20 12:58           ` Kevin Wolf
2019-12-20 13:25             ` Markus Armbruster
2019-12-20 21:18               ` Eric Blake
2019-12-20 12:49     ` Markus Armbruster
2019-12-20 13:02       ` Kevin Wolf
2019-12-20 21:15   ` Eric Blake
2020-01-06 12:00     ` Max Reitz
2019-12-19 14:38 ` [PATCH 03/18] fuse: Implement standard FUSE operations Max Reitz
2019-12-19 14:38 ` [PATCH 04/18] fuse: Add fuse-export-remove Max Reitz
2019-12-19 14:38 ` [PATCH 05/18] fuse: Allow growable exports Max Reitz
2019-12-19 14:38 ` [PATCH 06/18] fuse: (Partially) implement fallocate() Max Reitz
2019-12-19 14:38 ` [PATCH 07/18] fuse: Implement hole detection through lseek Max Reitz
2019-12-19 14:38 ` [PATCH 08/18] iotests: Do not needlessly filter _make_test_img Max Reitz
2019-12-19 14:38 ` [PATCH 09/18] iotests: Do not pipe _make_test_img Max Reitz
2019-12-19 14:38 ` [PATCH 10/18] iotests: Use convert -n in some cases Max Reitz
2019-12-19 14:38 ` [PATCH 11/18] iotests: Avoid renaming images Max Reitz
2019-12-19 14:38 ` [PATCH 12/18] iotests: Derive image names from $TEST_IMG Max Reitz
2019-12-19 14:38 ` [PATCH 13/18] iotests/091: Use _cleanup_qemu instad of "wait" Max Reitz
2019-12-19 14:38 ` [PATCH 14/18] iotests: Restrict some Python tests to file Max Reitz
2019-12-19 14:38 ` [PATCH 15/18] iotests: Let _make_test_img guess $TEST_IMG_FILE Max Reitz
2019-12-19 14:38 ` [PATCH 16/18] iotests: Allow testing FUSE exports Max Reitz
2019-12-19 14:38 ` [PATCH 17/18] iotests: Enable fuse for many tests Max Reitz
2019-12-19 14:38 ` [PATCH 18/18] iotests/281: Add test for FUSE exports Max Reitz
2019-12-19 19:05 ` [PATCH 00/18] block: Allow exporting BDSs via FUSE Max Reitz
2019-12-20 10:08 ` Stefan Hajnoczi
2019-12-20 10:30   ` Max Reitz
2019-12-20 12:50     ` Kevin Wolf
2019-12-20 21:20       ` Eric Blake
2020-01-02 11:22     ` Stefan Hajnoczi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).