diff --git a/0001-riscv-sifive_u-fix-a-memory-leak-in-soc_realize.patch b/0001-riscv-sifive_u-fix-a-memory-leak-in-soc_realize.patch
deleted file mode 100644
index 3f0e784..0000000
--- a/0001-riscv-sifive_u-fix-a-memory-leak-in-soc_realize.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From bb8136df698bd565ee4f6c18d26c50dee320bfe4 Mon Sep 17 00:00:00 2001
-From: Pan Nengyuan <pannengyuan@huawei.com>
-Date: Tue, 10 Dec 2019 15:14:37 +0800
-Subject: [PATCH 1/5] riscv/sifive_u: fix a memory leak in soc_realize()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Fix a minor memory leak in riscv_sifive_u_soc_realize()
-
-Reported-by: Euler Robot <euler.robot@huawei.com>
-Signed-off-by: Pan Nengyuan <pannengyuan@huawei.com>
-Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
-Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
-Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
----
- hw/riscv/sifive_u.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
-index 0140e95732..0e12b3ccef 100644
---- a/hw/riscv/sifive_u.c
-+++ b/hw/riscv/sifive_u.c
-@@ -542,6 +542,7 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp)
-         SIFIVE_U_PLIC_CONTEXT_BASE,
-         SIFIVE_U_PLIC_CONTEXT_STRIDE,
-         memmap[SIFIVE_U_PLIC].size);
-+    g_free(plic_hart_config);
-     sifive_uart_create(system_memory, memmap[SIFIVE_U_UART0].base,
-         serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ));
-     sifive_uart_create(system_memory, memmap[SIFIVE_U_UART1].base,
--- 
-2.24.1
-
diff --git a/0001-tests-fix-modules-test-duplicate-test-case-error.patch b/0001-tests-fix-modules-test-duplicate-test-case-error.patch
index 7c8f385..2848e42 100644
--- a/0001-tests-fix-modules-test-duplicate-test-case-error.patch
+++ b/0001-tests-fix-modules-test-duplicate-test-case-error.patch
@@ -1,5 +1,3 @@
-From d64c9aa098cc6e5c0b638438c4959eddfa7e24e2 Mon Sep 17 00:00:00 2001
-Message-Id: <d64c9aa098cc6e5c0b638438c4959eddfa7e24e2.1573679311.git.crobinso@redhat.com>
 From: Cole Robinson <crobinso@redhat.com>
 Date: Wed, 13 Nov 2019 16:05:11 -0500
 Subject: [PATCH] tests: fix modules-test 'duplicate test case' error
@@ -35,6 +33,3 @@ index d1a6ace218..88217686e1 100644
          qtest_add_data_func(testname, modules + i, test_modules_load);
          g_free(testname);
      }
--- 
-2.23.0
-
diff --git a/0002-riscv-Set-xPIE-to-1-after-xRET.patch b/0002-riscv-Set-xPIE-to-1-after-xRET.patch
deleted file mode 100644
index 4bd340a..0000000
--- a/0002-riscv-Set-xPIE-to-1-after-xRET.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From a37f21c27d3e2342c2080aafd4cfe7e949612428 Mon Sep 17 00:00:00 2001
-From: Yiting Wang <yiting.wang@windriver.com>
-Date: Fri, 3 Jan 2020 11:53:42 +0800
-Subject: [PATCH 2/5] riscv: Set xPIE to 1 after xRET
-
-When executing an xRET instruction, supposing xPP holds the
-value y, xIE is set to xPIE; the privilege mode is changed to y;
-xPIE is set to 1. But QEMU sets xPIE to 0 incorrectly.
-
-Signed-off-by: Yiting Wang <yiting.wang@windriver.com>
-Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
-Tested-by: Bin Meng <bmeng.cn@gmail.com>
-Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
-Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
----
- target/riscv/op_helper.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
-index 331cc36232..e87c9115bc 100644
---- a/target/riscv/op_helper.c
-+++ b/target/riscv/op_helper.c
-@@ -93,7 +93,7 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
-         env->priv_ver >= PRIV_VERSION_1_10_0 ?
-         MSTATUS_SIE : MSTATUS_UIE << prev_priv,
-         get_field(mstatus, MSTATUS_SPIE));
--    mstatus = set_field(mstatus, MSTATUS_SPIE, 0);
-+    mstatus = set_field(mstatus, MSTATUS_SPIE, 1);
-     mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
-     riscv_cpu_set_mode(env, prev_priv);
-     env->mstatus = mstatus;
-@@ -118,7 +118,7 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
-         env->priv_ver >= PRIV_VERSION_1_10_0 ?
-         MSTATUS_MIE : MSTATUS_UIE << prev_priv,
-         get_field(mstatus, MSTATUS_MPIE));
--    mstatus = set_field(mstatus, MSTATUS_MPIE, 0);
-+    mstatus = set_field(mstatus, MSTATUS_MPIE, 1);
-     mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
-     riscv_cpu_set_mode(env, prev_priv);
-     env->mstatus = mstatus;
--- 
-2.24.1
-
diff --git a/0002-riscv-sifive_u-fix-a-memory-leak-in-soc_realize.patch b/0002-riscv-sifive_u-fix-a-memory-leak-in-soc_realize.patch
new file mode 100644
index 0000000..70d4fb1
--- /dev/null
+++ b/0002-riscv-sifive_u-fix-a-memory-leak-in-soc_realize.patch
@@ -0,0 +1,30 @@
+From: Pan Nengyuan <pannengyuan@huawei.com>
+Date: Tue, 10 Dec 2019 15:14:37 +0800
+Subject: [PATCH] riscv/sifive_u: fix a memory leak in soc_realize()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Fix a minor memory leak in riscv_sifive_u_soc_realize()
+
+Reported-by: Euler Robot <euler.robot@huawei.com>
+Signed-off-by: Pan Nengyuan <pannengyuan@huawei.com>
+Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
+Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
+---
+ hw/riscv/sifive_u.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
+index 0140e95732..0e12b3ccef 100644
+--- a/hw/riscv/sifive_u.c
++++ b/hw/riscv/sifive_u.c
+@@ -542,6 +542,7 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp)
+         SIFIVE_U_PLIC_CONTEXT_BASE,
+         SIFIVE_U_PLIC_CONTEXT_STRIDE,
+         memmap[SIFIVE_U_PLIC].size);
++    g_free(plic_hart_config);
+     sifive_uart_create(system_memory, memmap[SIFIVE_U_UART0].base,
+         serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ));
+     sifive_uart_create(system_memory, memmap[SIFIVE_U_UART1].base,
diff --git a/0003-riscv-Set-xPIE-to-1-after-xRET.patch b/0003-riscv-Set-xPIE-to-1-after-xRET.patch
new file mode 100644
index 0000000..25a5123
--- /dev/null
+++ b/0003-riscv-Set-xPIE-to-1-after-xRET.patch
@@ -0,0 +1,39 @@
+From: Yiting Wang <yiting.wang@windriver.com>
+Date: Fri, 3 Jan 2020 11:53:42 +0800
+Subject: [PATCH] riscv: Set xPIE to 1 after xRET
+
+When executing an xRET instruction, supposing xPP holds the
+value y, xIE is set to xPIE; the privilege mode is changed to y;
+xPIE is set to 1. But QEMU sets xPIE to 0 incorrectly.
+
+Signed-off-by: Yiting Wang <yiting.wang@windriver.com>
+Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
+Tested-by: Bin Meng <bmeng.cn@gmail.com>
+Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
+Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
+---
+ target/riscv/op_helper.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
+index 331cc36232..e87c9115bc 100644
+--- a/target/riscv/op_helper.c
++++ b/target/riscv/op_helper.c
+@@ -93,7 +93,7 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
+         env->priv_ver >= PRIV_VERSION_1_10_0 ?
+         MSTATUS_SIE : MSTATUS_UIE << prev_priv,
+         get_field(mstatus, MSTATUS_SPIE));
+-    mstatus = set_field(mstatus, MSTATUS_SPIE, 0);
++    mstatus = set_field(mstatus, MSTATUS_SPIE, 1);
+     mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
+     riscv_cpu_set_mode(env, prev_priv);
+     env->mstatus = mstatus;
+@@ -118,7 +118,7 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
+         env->priv_ver >= PRIV_VERSION_1_10_0 ?
+         MSTATUS_MIE : MSTATUS_UIE << prev_priv,
+         get_field(mstatus, MSTATUS_MPIE));
+-    mstatus = set_field(mstatus, MSTATUS_MPIE, 0);
++    mstatus = set_field(mstatus, MSTATUS_MPIE, 1);
+     mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
+     riscv_cpu_set_mode(env, prev_priv);
+     env->mstatus = mstatus;
diff --git a/0003-target-riscv-Fix-tb-flags-FS-status.patch b/0003-target-riscv-Fix-tb-flags-FS-status.patch
deleted file mode 100644
index 93e5287..0000000
--- a/0003-target-riscv-Fix-tb-flags-FS-status.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-From 613fa160e19abe8e1fe44423fcfa8ec73d3d48e5 Mon Sep 17 00:00:00 2001
-From: ShihPo Hung <shihpo.hung@sifive.com>
-Date: Tue, 14 Jan 2020 22:17:31 -0800
-Subject: [PATCH 3/5] target/riscv: Fix tb->flags FS status
-
-It was found that running libquantum on riscv-linux qemu produced an
-incorrect result. After investigation, FP registers are not saved
-during context switch due to incorrect mstatus.FS.
-
-In current implementation tb->flags merges all non-disabled state to
-dirty. This means the code in mark_fs_dirty in translate.c that
-handles initial and clean states is unreachable.
-
-This patch fixes it and is successfully tested with:
-  libquantum
-
-Thanks to Richard for pointing out the actual bug.
-
-v3: remove the redundant condition
-v2: root cause FS problem
-
-Suggested-by: Richard Henderson <richard.henderson@linaro.org>
-Signed-off-by: ShihPo Hung <shihpo.hung@sifive.com>
-Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
-Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
----
- target/riscv/cpu.h | 5 +----
- 1 file changed, 1 insertion(+), 4 deletions(-)
-
-diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
-index e59343e13c..de0a8d893a 100644
---- a/target/riscv/cpu.h
-+++ b/target/riscv/cpu.h
-@@ -293,10 +293,7 @@ static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
- #ifdef CONFIG_USER_ONLY
-     *flags = TB_FLAGS_MSTATUS_FS;
- #else
--    *flags = cpu_mmu_index(env, 0);
--    if (riscv_cpu_fp_enabled(env)) {
--        *flags |= TB_FLAGS_MSTATUS_FS;
--    }
-+    *flags = cpu_mmu_index(env, 0) | (env->mstatus & MSTATUS_FS);
- #endif
- }
- 
--- 
-2.24.1
-
diff --git a/0004-target-riscv-Fix-tb-flags-FS-status.patch b/0004-target-riscv-Fix-tb-flags-FS-status.patch
new file mode 100644
index 0000000..d0fc7b5
--- /dev/null
+++ b/0004-target-riscv-Fix-tb-flags-FS-status.patch
@@ -0,0 +1,44 @@
+From: ShihPo Hung <shihpo.hung@sifive.com>
+Date: Tue, 14 Jan 2020 22:17:31 -0800
+Subject: [PATCH] target/riscv: Fix tb->flags FS status
+
+It was found that running libquantum on riscv-linux qemu produced an
+incorrect result. After investigation, FP registers are not saved
+during context switch due to incorrect mstatus.FS.
+
+In current implementation tb->flags merges all non-disabled state to
+dirty. This means the code in mark_fs_dirty in translate.c that
+handles initial and clean states is unreachable.
+
+This patch fixes it and is successfully tested with:
+  libquantum
+
+Thanks to Richard for pointing out the actual bug.
+
+v3: remove the redundant condition
+v2: root cause FS problem
+
+Suggested-by: Richard Henderson <richard.henderson@linaro.org>
+Signed-off-by: ShihPo Hung <shihpo.hung@sifive.com>
+Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
+Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
+---
+ target/riscv/cpu.h | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
+index e59343e13c..de0a8d893a 100644
+--- a/target/riscv/cpu.h
++++ b/target/riscv/cpu.h
+@@ -293,10 +293,7 @@ static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
+ #ifdef CONFIG_USER_ONLY
+     *flags = TB_FLAGS_MSTATUS_FS;
+ #else
+-    *flags = cpu_mmu_index(env, 0);
+-    if (riscv_cpu_fp_enabled(env)) {
+-        *flags |= TB_FLAGS_MSTATUS_FS;
+-    }
++    *flags = cpu_mmu_index(env, 0) | (env->mstatus & MSTATUS_FS);
+ #endif
+ }
+ 
diff --git a/0004-target-riscv-fsd-fsw-doesn-t-dirty-FP-state.patch b/0004-target-riscv-fsd-fsw-doesn-t-dirty-FP-state.patch
deleted file mode 100644
index 6b5a896..0000000
--- a/0004-target-riscv-fsd-fsw-doesn-t-dirty-FP-state.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From a59796eb6d59bbd74ce28ddbddb1b83e60674e96 Mon Sep 17 00:00:00 2001
-From: ShihPo Hung <shihpo.hung@sifive.com>
-Date: Tue, 14 Jan 2020 22:17:32 -0800
-Subject: [PATCH 4/5] target/riscv: fsd/fsw doesn't dirty FP state
-
-Signed-off-by: ShihPo Hung <shihpo.hung@sifive.com>
-Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
-Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
-Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
----
- target/riscv/insn_trans/trans_rvd.inc.c | 1 -
- target/riscv/insn_trans/trans_rvf.inc.c | 1 -
- 2 files changed, 2 deletions(-)
-
-diff --git a/target/riscv/insn_trans/trans_rvd.inc.c b/target/riscv/insn_trans/trans_rvd.inc.c
-index 393fa0248c..ea1044f13b 100644
---- a/target/riscv/insn_trans/trans_rvd.inc.c
-+++ b/target/riscv/insn_trans/trans_rvd.inc.c
-@@ -43,7 +43,6 @@ static bool trans_fsd(DisasContext *ctx, arg_fsd *a)
- 
-     tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], t0, ctx->mem_idx, MO_TEQ);
- 
--    mark_fs_dirty(ctx);
-     tcg_temp_free(t0);
-     return true;
- }
-diff --git a/target/riscv/insn_trans/trans_rvf.inc.c b/target/riscv/insn_trans/trans_rvf.inc.c
-index 172dbfa919..e23cd639a6 100644
---- a/target/riscv/insn_trans/trans_rvf.inc.c
-+++ b/target/riscv/insn_trans/trans_rvf.inc.c
-@@ -52,7 +52,6 @@ static bool trans_fsw(DisasContext *ctx, arg_fsw *a)
-     tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], t0, ctx->mem_idx, MO_TEUL);
- 
-     tcg_temp_free(t0);
--    mark_fs_dirty(ctx);
-     return true;
- }
- 
--- 
-2.24.1
-
diff --git a/0005-target-riscv-fsd-fsw-doesn-t-dirty-FP-state.patch b/0005-target-riscv-fsd-fsw-doesn-t-dirty-FP-state.patch
new file mode 100644
index 0000000..1ca5360
--- /dev/null
+++ b/0005-target-riscv-fsd-fsw-doesn-t-dirty-FP-state.patch
@@ -0,0 +1,37 @@
+From: ShihPo Hung <shihpo.hung@sifive.com>
+Date: Tue, 14 Jan 2020 22:17:32 -0800
+Subject: [PATCH] target/riscv: fsd/fsw doesn't dirty FP state
+
+Signed-off-by: ShihPo Hung <shihpo.hung@sifive.com>
+Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
+Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
+Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
+---
+ target/riscv/insn_trans/trans_rvd.inc.c | 1 -
+ target/riscv/insn_trans/trans_rvf.inc.c | 1 -
+ 2 files changed, 2 deletions(-)
+
+diff --git a/target/riscv/insn_trans/trans_rvd.inc.c b/target/riscv/insn_trans/trans_rvd.inc.c
+index 393fa0248c..ea1044f13b 100644
+--- a/target/riscv/insn_trans/trans_rvd.inc.c
++++ b/target/riscv/insn_trans/trans_rvd.inc.c
+@@ -43,7 +43,6 @@ static bool trans_fsd(DisasContext *ctx, arg_fsd *a)
+ 
+     tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], t0, ctx->mem_idx, MO_TEQ);
+ 
+-    mark_fs_dirty(ctx);
+     tcg_temp_free(t0);
+     return true;
+ }
+diff --git a/target/riscv/insn_trans/trans_rvf.inc.c b/target/riscv/insn_trans/trans_rvf.inc.c
+index 172dbfa919..e23cd639a6 100644
+--- a/target/riscv/insn_trans/trans_rvf.inc.c
++++ b/target/riscv/insn_trans/trans_rvf.inc.c
+@@ -52,7 +52,6 @@ static bool trans_fsw(DisasContext *ctx, arg_fsw *a)
+     tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], t0, ctx->mem_idx, MO_TEUL);
+ 
+     tcg_temp_free(t0);
+-    mark_fs_dirty(ctx);
+     return true;
+ }
+ 
diff --git a/0005-target-riscv-update-mstatus.SD-when-FS-is-set-dirty.patch b/0005-target-riscv-update-mstatus.SD-when-FS-is-set-dirty.patch
deleted file mode 100644
index b3733a6..0000000
--- a/0005-target-riscv-update-mstatus.SD-when-FS-is-set-dirty.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 82f014671cf057de51c4a577c9e2ad637dcec6f9 Mon Sep 17 00:00:00 2001
-From: ShihPo Hung <shihpo.hung@sifive.com>
-Date: Tue, 14 Jan 2020 22:17:33 -0800
-Subject: [PATCH 5/5] target/riscv: update mstatus.SD when FS is set dirty
-
-remove the check becuase SD bit should summarize FS and XS fields
-unconditionally.
-
-Signed-off-by: ShihPo Hung <shihpo.hung@sifive.com>
-Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
-Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
-Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
----
- target/riscv/csr.c       | 3 +--
- target/riscv/translate.c | 2 +-
- 2 files changed, 2 insertions(+), 3 deletions(-)
-
-diff --git a/target/riscv/csr.c b/target/riscv/csr.c
-index da02f9f0b1..0e34c292c5 100644
---- a/target/riscv/csr.c
-+++ b/target/riscv/csr.c
-@@ -341,8 +341,7 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
- 
-     mstatus = (mstatus & ~mask) | (val & mask);
- 
--    dirty = (riscv_cpu_fp_enabled(env) &&
--             ((mstatus & MSTATUS_FS) == MSTATUS_FS)) |
-+    dirty = ((mstatus & MSTATUS_FS) == MSTATUS_FS) |
-             ((mstatus & MSTATUS_XS) == MSTATUS_XS);
-     mstatus = set_field(mstatus, MSTATUS_SD, dirty);
-     env->mstatus = mstatus;
-diff --git a/target/riscv/translate.c b/target/riscv/translate.c
-index ab6a891dc3..8e40ed3ac4 100644
---- a/target/riscv/translate.c
-+++ b/target/riscv/translate.c
-@@ -394,7 +394,7 @@ static void mark_fs_dirty(DisasContext *ctx)
- 
-     tmp = tcg_temp_new();
-     tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus));
--    tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS);
-+    tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS | MSTATUS_SD);
-     tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus));
-     tcg_temp_free(tmp);
- }
--- 
-2.24.1
-
diff --git a/0006-target-riscv-update-mstatus.SD-when-FS-is-set-dirty.patch b/0006-target-riscv-update-mstatus.SD-when-FS-is-set-dirty.patch
new file mode 100644
index 0000000..de413fb
--- /dev/null
+++ b/0006-target-riscv-update-mstatus.SD-when-FS-is-set-dirty.patch
@@ -0,0 +1,43 @@
+From: ShihPo Hung <shihpo.hung@sifive.com>
+Date: Tue, 14 Jan 2020 22:17:33 -0800
+Subject: [PATCH] target/riscv: update mstatus.SD when FS is set dirty
+
+remove the check becuase SD bit should summarize FS and XS fields
+unconditionally.
+
+Signed-off-by: ShihPo Hung <shihpo.hung@sifive.com>
+Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
+Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
+Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
+---
+ target/riscv/csr.c       | 3 +--
+ target/riscv/translate.c | 2 +-
+ 2 files changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/target/riscv/csr.c b/target/riscv/csr.c
+index da02f9f0b1..0e34c292c5 100644
+--- a/target/riscv/csr.c
++++ b/target/riscv/csr.c
+@@ -341,8 +341,7 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
+ 
+     mstatus = (mstatus & ~mask) | (val & mask);
+ 
+-    dirty = (riscv_cpu_fp_enabled(env) &&
+-             ((mstatus & MSTATUS_FS) == MSTATUS_FS)) |
++    dirty = ((mstatus & MSTATUS_FS) == MSTATUS_FS) |
+             ((mstatus & MSTATUS_XS) == MSTATUS_XS);
+     mstatus = set_field(mstatus, MSTATUS_SD, dirty);
+     env->mstatus = mstatus;
+diff --git a/target/riscv/translate.c b/target/riscv/translate.c
+index ab6a891dc3..8e40ed3ac4 100644
+--- a/target/riscv/translate.c
++++ b/target/riscv/translate.c
+@@ -394,7 +394,7 @@ static void mark_fs_dirty(DisasContext *ctx)
+ 
+     tmp = tcg_temp_new();
+     tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus));
+-    tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS);
++    tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS | MSTATUS_SD);
+     tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus));
+     tcg_temp_free(tmp);
+ }
diff --git a/0007-virtio-fs-fix-MSI-X-nvectors-calculation.patch b/0007-virtio-fs-fix-MSI-X-nvectors-calculation.patch
new file mode 100644
index 0000000..483a444
--- /dev/null
+++ b/0007-virtio-fs-fix-MSI-X-nvectors-calculation.patch
@@ -0,0 +1,41 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:36 +0000
+Subject: [PATCH] virtio-fs: fix MSI-X nvectors calculation
+
+The following MSI-X vectors are required:
+ * VIRTIO Configuration Change
+ * hiprio virtqueue
+ * requests virtqueues
+
+Fix the calculation to reserve enough MSI-X vectors.  Otherwise guest
+drivers fall back to a sub-optional configuration where all virtqueues
+share a single vector.
+
+This change does not break live migration compatibility since
+vhost-user-fs-pci devices are not migratable yet.
+
+Reported-by: Vivek Goyal <vgoyal@redhat.com>
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Message-Id: <20191209110759.35227-1-stefanha@redhat.com>
+Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 366844f3d1329c6423dd752891a28ccb3ee8fddd)
+---
+ hw/virtio/vhost-user-fs-pci.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/hw/virtio/vhost-user-fs-pci.c b/hw/virtio/vhost-user-fs-pci.c
+index 933a3f265b..e3a649d4a6 100644
+--- a/hw/virtio/vhost-user-fs-pci.c
++++ b/hw/virtio/vhost-user-fs-pci.c
+@@ -40,7 +40,8 @@ static void vhost_user_fs_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+     DeviceState *vdev = DEVICE(&dev->vdev);
+ 
+     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
+-        vpci_dev->nvectors = dev->vdev.conf.num_request_queues + 1;
++        /* Also reserve config change and hiprio queue vectors */
++        vpci_dev->nvectors = dev->vdev.conf.num_request_queues + 2;
+     }
+ 
+     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
diff --git a/0008-vhost-user-fs-remove-vhostfd-property.patch b/0008-vhost-user-fs-remove-vhostfd-property.patch
new file mode 100644
index 0000000..c77730d
--- /dev/null
+++ b/0008-vhost-user-fs-remove-vhostfd-property.patch
@@ -0,0 +1,43 @@
+From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:37 +0000
+Subject: [PATCH] vhost-user-fs: remove "vhostfd" property
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The property doesn't make much sense for a vhost-user device.
+
+Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
+Message-Id: <20191116112016.14872-1-marcandre.lureau@redhat.com>
+Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 703857348724319735d9be7b5b996e6445c6e6b9)
+---
+ hw/virtio/vhost-user-fs.c         | 1 -
+ include/hw/virtio/vhost-user-fs.h | 1 -
+ 2 files changed, 2 deletions(-)
+
+diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c
+index f0df7f4746..ca0b7fc9de 100644
+--- a/hw/virtio/vhost-user-fs.c
++++ b/hw/virtio/vhost-user-fs.c
+@@ -263,7 +263,6 @@ static Property vuf_properties[] = {
+     DEFINE_PROP_UINT16("num-request-queues", VHostUserFS,
+                        conf.num_request_queues, 1),
+     DEFINE_PROP_UINT16("queue-size", VHostUserFS, conf.queue_size, 128),
+-    DEFINE_PROP_STRING("vhostfd", VHostUserFS, conf.vhostfd),
+     DEFINE_PROP_END_OF_LIST(),
+ };
+ 
+diff --git a/include/hw/virtio/vhost-user-fs.h b/include/hw/virtio/vhost-user-fs.h
+index 539885b458..9ff1bdb7cf 100644
+--- a/include/hw/virtio/vhost-user-fs.h
++++ b/include/hw/virtio/vhost-user-fs.h
+@@ -28,7 +28,6 @@ typedef struct {
+     char *tag;
+     uint16_t num_request_queues;
+     uint16_t queue_size;
+-    char *vhostfd;
+ } VHostUserFSConf;
+ 
+ typedef struct {
diff --git a/0009-build-rename-CONFIG_LIBCAP-to-CONFIG_LIBCAP_NG.patch b/0009-build-rename-CONFIG_LIBCAP-to-CONFIG_LIBCAP_NG.patch
new file mode 100644
index 0000000..02ec43e
--- /dev/null
+++ b/0009-build-rename-CONFIG_LIBCAP-to-CONFIG_LIBCAP_NG.patch
@@ -0,0 +1,118 @@
+From: Paolo Bonzini <pbonzini@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:38 +0000
+Subject: [PATCH] build: rename CONFIG_LIBCAP to CONFIG_LIBCAP_NG
+
+Since we are actually testing for the newer capng library, rename the
+symbol to match.
+
+Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+(cherry picked from commit a358bca24026a377e0804e137a4499e4e041918d)
+---
+ configure             |  2 +-
+ qemu-bridge-helper.c  |  6 +++---
+ scsi/qemu-pr-helper.c | 12 ++++++------
+ 3 files changed, 10 insertions(+), 10 deletions(-)
+
+diff --git a/configure b/configure
+index 6099be1d84..afe9393f04 100755
+--- a/configure
++++ b/configure
+@@ -6759,7 +6759,7 @@ if test "$l2tpv3" = "yes" ; then
+   echo "CONFIG_L2TPV3=y" >> $config_host_mak
+ fi
+ if test "$cap_ng" = "yes" ; then
+-  echo "CONFIG_LIBCAP=y" >> $config_host_mak
++  echo "CONFIG_LIBCAP_NG=y" >> $config_host_mak
+ fi
+ echo "CONFIG_AUDIO_DRIVERS=$audio_drv_list" >> $config_host_mak
+ for drv in $audio_drv_list; do
+diff --git a/qemu-bridge-helper.c b/qemu-bridge-helper.c
+index 3d50ec094c..88b26747fc 100644
+--- a/qemu-bridge-helper.c
++++ b/qemu-bridge-helper.c
+@@ -43,7 +43,7 @@
+ 
+ #include "net/tap-linux.h"
+ 
+-#ifdef CONFIG_LIBCAP
++#ifdef CONFIG_LIBCAP_NG
+ #include <cap-ng.h>
+ #endif
+ 
+@@ -207,7 +207,7 @@ static int send_fd(int c, int fd)
+     return sendmsg(c, &msg, 0);
+ }
+ 
+-#ifdef CONFIG_LIBCAP
++#ifdef CONFIG_LIBCAP_NG
+ static int drop_privileges(void)
+ {
+     /* clear all capabilities */
+@@ -246,7 +246,7 @@ int main(int argc, char **argv)
+     int access_allowed, access_denied;
+     int ret = EXIT_SUCCESS;
+ 
+-#ifdef CONFIG_LIBCAP
++#ifdef CONFIG_LIBCAP_NG
+     /* if we're run from an suid binary, immediately drop privileges preserving
+      * cap_net_admin */
+     if (geteuid() == 0 && getuid() != geteuid()) {
+diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c
+index debb18f4aa..0659ceef09 100644
+--- a/scsi/qemu-pr-helper.c
++++ b/scsi/qemu-pr-helper.c
+@@ -24,7 +24,7 @@
+ #include <linux/dm-ioctl.h>
+ #include <scsi/sg.h>
+ 
+-#ifdef CONFIG_LIBCAP
++#ifdef CONFIG_LIBCAP_NG
+ #include <cap-ng.h>
+ #endif
+ #include <pwd.h>
+@@ -70,7 +70,7 @@ static int num_active_sockets = 1;
+ static int noisy;
+ static int verbose;
+ 
+-#ifdef CONFIG_LIBCAP
++#ifdef CONFIG_LIBCAP_NG
+ static int uid = -1;
+ static int gid = -1;
+ #endif
+@@ -97,7 +97,7 @@ static void usage(const char *name)
+ "                            (default '%s')\n"
+ "  -T, --trace [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
+ "                            specify tracing options\n"
+-#ifdef CONFIG_LIBCAP
++#ifdef CONFIG_LIBCAP_NG
+ "  -u, --user=USER           user to drop privileges to\n"
+ "  -g, --group=GROUP         group to drop privileges to\n"
+ #endif
+@@ -827,7 +827,7 @@ static void close_server_socket(void)
+     num_active_sockets--;
+ }
+ 
+-#ifdef CONFIG_LIBCAP
++#ifdef CONFIG_LIBCAP_NG
+ static int drop_privileges(void)
+ {
+     /* clear all capabilities */
+@@ -920,7 +920,7 @@ int main(int argc, char **argv)
+             pidfile = g_strdup(optarg);
+             pidfile_specified = true;
+             break;
+-#ifdef CONFIG_LIBCAP
++#ifdef CONFIG_LIBCAP_NG
+         case 'u': {
+             unsigned long res;
+             struct passwd *userinfo = getpwnam(optarg);
+@@ -1056,7 +1056,7 @@ int main(int argc, char **argv)
+         exit(EXIT_FAILURE);
+     }
+ 
+-#ifdef CONFIG_LIBCAP
++#ifdef CONFIG_LIBCAP_NG
+     if (drop_privileges() < 0) {
+         error_report("Failed to drop privileges: %s", strerror(errno));
+         exit(EXIT_FAILURE);
diff --git a/0010-virtiofsd-Pull-in-upstream-headers.patch b/0010-virtiofsd-Pull-in-upstream-headers.patch
new file mode 100644
index 0000000..cc049ad
--- /dev/null
+++ b/0010-virtiofsd-Pull-in-upstream-headers.patch
@@ -0,0 +1,4895 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:39 +0000
+Subject: [PATCH] virtiofsd: Pull in upstream headers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Pull in headers fromlibfuse's upstream fuse-3.8.0
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit ee46c78901eb7fa78e328e04c0494ad6d207238b)
+---
+ tools/virtiofsd/fuse.h                | 1275 +++++++++++++++
+ tools/virtiofsd/fuse_common.h         |  823 ++++++++++
+ tools/virtiofsd/fuse_i.h              |  139 ++
+ tools/virtiofsd/fuse_log.h            |   82 +
+ tools/virtiofsd/fuse_lowlevel.h       | 2089 +++++++++++++++++++++++++
+ tools/virtiofsd/fuse_misc.h           |   59 +
+ tools/virtiofsd/fuse_opt.h            |  271 ++++
+ tools/virtiofsd/passthrough_helpers.h |   76 +
+ 8 files changed, 4814 insertions(+)
+ create mode 100644 tools/virtiofsd/fuse.h
+ create mode 100644 tools/virtiofsd/fuse_common.h
+ create mode 100644 tools/virtiofsd/fuse_i.h
+ create mode 100644 tools/virtiofsd/fuse_log.h
+ create mode 100644 tools/virtiofsd/fuse_lowlevel.h
+ create mode 100644 tools/virtiofsd/fuse_misc.h
+ create mode 100644 tools/virtiofsd/fuse_opt.h
+ create mode 100644 tools/virtiofsd/passthrough_helpers.h
+
+diff --git a/tools/virtiofsd/fuse.h b/tools/virtiofsd/fuse.h
+new file mode 100644
+index 0000000000..883f6e59fb
+--- /dev/null
++++ b/tools/virtiofsd/fuse.h
+@@ -0,0 +1,1275 @@
++/*
++  FUSE: Filesystem in Userspace
++  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++
++  This program can be distributed under the terms of the GNU LGPLv2.
++  See the file COPYING.LIB.
++*/
++
++#ifndef FUSE_H_
++#define FUSE_H_
++
++/** @file
++ *
++ * This file defines the library interface of FUSE
++ *
++ * IMPORTANT: you should define FUSE_USE_VERSION before including this header.
++ */
++
++#include "fuse_common.h"
++
++#include <fcntl.h>
++#include <time.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <sys/statvfs.h>
++#include <sys/uio.h>
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* ----------------------------------------------------------- *
++ * Basic FUSE API					       *
++ * ----------------------------------------------------------- */
++
++/** Handle for a FUSE filesystem */
++struct fuse;
++
++/**
++ * Readdir flags, passed to ->readdir()
++ */
++enum fuse_readdir_flags {
++	/**
++	 * "Plus" mode.
++	 *
++	 * The kernel wants to prefill the inode cache during readdir.  The
++	 * filesystem may honour this by filling in the attributes and setting
++	 * FUSE_FILL_DIR_FLAGS for the filler function.  The filesystem may also
++	 * just ignore this flag completely.
++	 */
++	FUSE_READDIR_PLUS = (1 << 0),
++};
++
++enum fuse_fill_dir_flags {
++	/**
++	 * "Plus" mode: all file attributes are valid
++	 *
++	 * The attributes are used by the kernel to prefill the inode cache
++	 * during a readdir.
++	 *
++	 * It is okay to set FUSE_FILL_DIR_PLUS if FUSE_READDIR_PLUS is not set
++	 * and vice versa.
++	 */
++	FUSE_FILL_DIR_PLUS = (1 << 1),
++};
++
++/** Function to add an entry in a readdir() operation
++ *
++ * The *off* parameter can be any non-zero value that enables the
++ * filesystem to identify the current point in the directory
++ * stream. It does not need to be the actual physical position. A
++ * value of zero is reserved to indicate that seeking in directories
++ * is not supported.
++ * 
++ * @param buf the buffer passed to the readdir() operation
++ * @param name the file name of the directory entry
++ * @param stat file attributes, can be NULL
++ * @param off offset of the next entry or zero
++ * @param flags fill flags
++ * @return 1 if buffer is full, zero otherwise
++ */
++typedef int (*fuse_fill_dir_t) (void *buf, const char *name,
++				const struct stat *stbuf, off_t off,
++				enum fuse_fill_dir_flags flags);
++/**
++ * Configuration of the high-level API
++ *
++ * This structure is initialized from the arguments passed to
++ * fuse_new(), and then passed to the file system's init() handler
++ * which should ensure that the configuration is compatible with the
++ * file system implementation.
++ */
++struct fuse_config {
++	/**
++	 * If `set_gid` is non-zero, the st_gid attribute of each file
++	 * is overwritten with the value of `gid`.
++	 */
++	int set_gid;
++	unsigned int gid;
++
++	/**
++	 * If `set_uid` is non-zero, the st_uid attribute of each file
++	 * is overwritten with the value of `uid`.
++	 */
++	int set_uid;
++	unsigned int uid;
++
++	/**
++	 * If `set_mode` is non-zero, the any permissions bits set in
++	 * `umask` are unset in the st_mode attribute of each file.
++	 */
++	int set_mode;
++	unsigned int umask;
++
++	/**
++	 * The timeout in seconds for which name lookups will be
++	 * cached.
++	 */
++	double entry_timeout;
++
++	/**
++	 * The timeout in seconds for which a negative lookup will be
++	 * cached. This means, that if file did not exist (lookup
++	 * retuned ENOENT), the lookup will only be redone after the
++	 * timeout, and the file/directory will be assumed to not
++	 * exist until then. A value of zero means that negative
++	 * lookups are not cached.
++	 */
++	double negative_timeout;
++
++	/**
++	 * The timeout in seconds for which file/directory attributes
++	 * (as returned by e.g. the `getattr` handler) are cached.
++	 */
++	double attr_timeout;
++
++	/**
++	 * Allow requests to be interrupted
++	 */
++	int intr;
++
++	/**
++	 * Specify which signal number to send to the filesystem when
++	 * a request is interrupted.  The default is hardcoded to
++	 * USR1.
++	 */
++	int intr_signal;
++
++	/**
++	 * Normally, FUSE assigns inodes to paths only for as long as
++	 * the kernel is aware of them. With this option inodes are
++	 * instead remembered for at least this many seconds.  This
++	 * will require more memory, but may be necessary when using
++	 * applications that make use of inode numbers.
++	 *
++	 * A number of -1 means that inodes will be remembered for the
++	 * entire life-time of the file-system process.
++	 */
++	int remember;
++
++	/**
++	 * The default behavior is that if an open file is deleted,
++	 * the file is renamed to a hidden file (.fuse_hiddenXXX), and
++	 * only removed when the file is finally released.  This
++	 * relieves the filesystem implementation of having to deal
++	 * with this problem. This option disables the hiding
++	 * behavior, and files are removed immediately in an unlink
++	 * operation (or in a rename operation which overwrites an
++	 * existing file).
++	 *
++	 * It is recommended that you not use the hard_remove
++	 * option. When hard_remove is set, the following libc
++	 * functions fail on unlinked files (returning errno of
++	 * ENOENT): read(2), write(2), fsync(2), close(2), f*xattr(2),
++	 * ftruncate(2), fstat(2), fchmod(2), fchown(2)
++	 */
++	int hard_remove;
++
++	/**
++	 * Honor the st_ino field in the functions getattr() and
++	 * fill_dir(). This value is used to fill in the st_ino field
++	 * in the stat(2), lstat(2), fstat(2) functions and the d_ino
++	 * field in the readdir(2) function. The filesystem does not
++	 * have to guarantee uniqueness, however some applications
++	 * rely on this value being unique for the whole filesystem.
++	 *
++	 * Note that this does *not* affect the inode that libfuse 
++	 * and the kernel use internally (also called the "nodeid").
++	 */
++	int use_ino;
++
++	/**
++	 * If use_ino option is not given, still try to fill in the
++	 * d_ino field in readdir(2). If the name was previously
++	 * looked up, and is still in the cache, the inode number
++	 * found there will be used.  Otherwise it will be set to -1.
++	 * If use_ino option is given, this option is ignored.
++	 */
++	int readdir_ino;
++
++	/**
++	 * This option disables the use of page cache (file content cache)
++	 * in the kernel for this filesystem. This has several affects:
++	 *
++	 * 1. Each read(2) or write(2) system call will initiate one
++	 *    or more read or write operations, data will not be
++	 *    cached in the kernel.
++	 *
++	 * 2. The return value of the read() and write() system calls
++	 *    will correspond to the return values of the read and
++	 *    write operations. This is useful for example if the
++	 *    file size is not known in advance (before reading it).
++	 *
++	 * Internally, enabling this option causes fuse to set the
++	 * `direct_io` field of `struct fuse_file_info` - overwriting
++	 * any value that was put there by the file system.
++	 */
++	int direct_io;
++
++	/**
++	 * This option disables flushing the cache of the file
++	 * contents on every open(2).  This should only be enabled on
++	 * filesystems where the file data is never changed
++	 * externally (not through the mounted FUSE filesystem).  Thus
++	 * it is not suitable for network filesystems and other
++	 * intermediate filesystems.
++	 *
++	 * NOTE: if this option is not specified (and neither
++	 * direct_io) data is still cached after the open(2), so a
++	 * read(2) system call will not always initiate a read
++	 * operation.
++	 *
++	 * Internally, enabling this option causes fuse to set the
++	 * `keep_cache` field of `struct fuse_file_info` - overwriting
++	 * any value that was put there by the file system.
++	 */
++	int kernel_cache;
++
++	/**
++	 * This option is an alternative to `kernel_cache`. Instead of
++	 * unconditionally keeping cached data, the cached data is
++	 * invalidated on open(2) if if the modification time or the
++	 * size of the file has changed since it was last opened.
++	 */
++	int auto_cache;
++
++	/**
++	 * The timeout in seconds for which file attributes are cached
++	 * for the purpose of checking if auto_cache should flush the
++	 * file data on open.
++	 */
++	int ac_attr_timeout_set;
++	double ac_attr_timeout;
++
++	/**
++	 * If this option is given the file-system handlers for the
++	 * following operations will not receive path information:
++	 * read, write, flush, release, fsync, readdir, releasedir,
++	 * fsyncdir, lock, ioctl and poll.
++	 *
++	 * For the truncate, getattr, chmod, chown and utimens
++	 * operations the path will be provided only if the struct
++	 * fuse_file_info argument is NULL.
++	 */
++	int nullpath_ok;
++
++	/**
++	 * The remaining options are used by libfuse internally and
++	 * should not be touched.
++	 */
++	int show_help;
++	char *modules;
++	int debug;
++};
++
++
++/**
++ * The file system operations:
++ *
++ * Most of these should work very similarly to the well known UNIX
++ * file system operations.  A major exception is that instead of
++ * returning an error in 'errno', the operation should return the
++ * negated error value (-errno) directly.
++ *
++ * All methods are optional, but some are essential for a useful
++ * filesystem (e.g. getattr).  Open, flush, release, fsync, opendir,
++ * releasedir, fsyncdir, access, create, truncate, lock, init and
++ * destroy are special purpose methods, without which a full featured
++ * filesystem can still be implemented.
++ *
++ * In general, all methods are expected to perform any necessary
++ * permission checking. However, a filesystem may delegate this task
++ * to the kernel by passing the `default_permissions` mount option to
++ * `fuse_new()`. In this case, methods will only be called if
++ * the kernel's permission check has succeeded.
++ *
++ * Almost all operations take a path which can be of any length.
++ */
++struct fuse_operations {
++	/** Get file attributes.
++	 *
++	 * Similar to stat().  The 'st_dev' and 'st_blksize' fields are
++	 * ignored. The 'st_ino' field is ignored except if the 'use_ino'
++	 * mount option is given. In that case it is passed to userspace,
++	 * but libfuse and the kernel will still assign a different
++	 * inode for internal use (called the "nodeid").
++	 *
++	 * `fi` will always be NULL if the file is not currently open, but
++	 * may also be NULL if the file is open.
++	 */
++	int (*getattr) (const char *, struct stat *, struct fuse_file_info *fi);
++
++	/** Read the target of a symbolic link
++	 *
++	 * The buffer should be filled with a null terminated string.  The
++	 * buffer size argument includes the space for the terminating
++	 * null character.	If the linkname is too long to fit in the
++	 * buffer, it should be truncated.	The return value should be 0
++	 * for success.
++	 */
++	int (*readlink) (const char *, char *, size_t);
++
++	/** Create a file node
++	 *
++	 * This is called for creation of all non-directory, non-symlink
++	 * nodes.  If the filesystem defines a create() method, then for
++	 * regular files that will be called instead.
++	 */
++	int (*mknod) (const char *, mode_t, dev_t);
++
++	/** Create a directory
++	 *
++	 * Note that the mode argument may not have the type specification
++	 * bits set, i.e. S_ISDIR(mode) can be false.  To obtain the
++	 * correct directory type bits use  mode|S_IFDIR
++	 * */
++	int (*mkdir) (const char *, mode_t);
++
++	/** Remove a file */
++	int (*unlink) (const char *);
++
++	/** Remove a directory */
++	int (*rmdir) (const char *);
++
++	/** Create a symbolic link */
++	int (*symlink) (const char *, const char *);
++
++	/** Rename a file
++	 *
++	 * *flags* may be `RENAME_EXCHANGE` or `RENAME_NOREPLACE`. If
++	 * RENAME_NOREPLACE is specified, the filesystem must not
++	 * overwrite *newname* if it exists and return an error
++	 * instead. If `RENAME_EXCHANGE` is specified, the filesystem
++	 * must atomically exchange the two files, i.e. both must
++	 * exist and neither may be deleted.
++	 */
++	int (*rename) (const char *, const char *, unsigned int flags);
++
++	/** Create a hard link to a file */
++	int (*link) (const char *, const char *);
++
++	/** Change the permission bits of a file
++	 *
++	 * `fi` will always be NULL if the file is not currenlty open, but
++	 * may also be NULL if the file is open.
++	 */
++	int (*chmod) (const char *, mode_t, struct fuse_file_info *fi);
++
++	/** Change the owner and group of a file
++	 *
++	 * `fi` will always be NULL if the file is not currenlty open, but
++	 * may also be NULL if the file is open.
++	 *
++	 * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
++	 * expected to reset the setuid and setgid bits.
++	 */
++	int (*chown) (const char *, uid_t, gid_t, struct fuse_file_info *fi);
++
++	/** Change the size of a file
++	 *
++	 * `fi` will always be NULL if the file is not currenlty open, but
++	 * may also be NULL if the file is open.
++	 *
++	 * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
++	 * expected to reset the setuid and setgid bits.
++	 */
++	int (*truncate) (const char *, off_t, struct fuse_file_info *fi);
++
++	/** Open a file
++	 *
++	 * Open flags are available in fi->flags. The following rules
++	 * apply.
++	 *
++	 *  - Creation (O_CREAT, O_EXCL, O_NOCTTY) flags will be
++	 *    filtered out / handled by the kernel.
++	 *
++	 *  - Access modes (O_RDONLY, O_WRONLY, O_RDWR, O_EXEC, O_SEARCH)
++	 *    should be used by the filesystem to check if the operation is
++	 *    permitted.  If the ``-o default_permissions`` mount option is
++	 *    given, this check is already done by the kernel before calling
++	 *    open() and may thus be omitted by the filesystem.
++	 *
++	 *  - When writeback caching is enabled, the kernel may send
++	 *    read requests even for files opened with O_WRONLY. The
++	 *    filesystem should be prepared to handle this.
++	 *
++	 *  - When writeback caching is disabled, the filesystem is
++	 *    expected to properly handle the O_APPEND flag and ensure
++	 *    that each write is appending to the end of the file.
++	 * 
++         *  - When writeback caching is enabled, the kernel will
++	 *    handle O_APPEND. However, unless all changes to the file
++	 *    come through the kernel this will not work reliably. The
++	 *    filesystem should thus either ignore the O_APPEND flag
++	 *    (and let the kernel handle it), or return an error
++	 *    (indicating that reliably O_APPEND is not available).
++	 *
++	 * Filesystem may store an arbitrary file handle (pointer,
++	 * index, etc) in fi->fh, and use this in other all other file
++	 * operations (read, write, flush, release, fsync).
++	 *
++	 * Filesystem may also implement stateless file I/O and not store
++	 * anything in fi->fh.
++	 *
++	 * There are also some flags (direct_io, keep_cache) which the
++	 * filesystem may set in fi, to change the way the file is opened.
++	 * See fuse_file_info structure in <fuse_common.h> for more details.
++	 *
++	 * If this request is answered with an error code of ENOSYS
++	 * and FUSE_CAP_NO_OPEN_SUPPORT is set in
++	 * `fuse_conn_info.capable`, this is treated as success and
++	 * future calls to open will also succeed without being send
++	 * to the filesystem process.
++	 *
++	 */
++	int (*open) (const char *, struct fuse_file_info *);
++
++	/** Read data from an open file
++	 *
++	 * Read should return exactly the number of bytes requested except
++	 * on EOF or error, otherwise the rest of the data will be
++	 * substituted with zeroes.	 An exception to this is when the
++	 * 'direct_io' mount option is specified, in which case the return
++	 * value of the read system call will reflect the return value of
++	 * this operation.
++	 */
++	int (*read) (const char *, char *, size_t, off_t,
++		     struct fuse_file_info *);
++
++	/** Write data to an open file
++	 *
++	 * Write should return exactly the number of bytes requested
++	 * except on error.	 An exception to this is when the 'direct_io'
++	 * mount option is specified (see read operation).
++	 *
++	 * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
++	 * expected to reset the setuid and setgid bits.
++	 */
++	int (*write) (const char *, const char *, size_t, off_t,
++		      struct fuse_file_info *);
++
++	/** Get file system statistics
++	 *
++	 * The 'f_favail', 'f_fsid' and 'f_flag' fields are ignored
++	 */
++	int (*statfs) (const char *, struct statvfs *);
++
++	/** Possibly flush cached data
++	 *
++	 * BIG NOTE: This is not equivalent to fsync().  It's not a
++	 * request to sync dirty data.
++	 *
++	 * Flush is called on each close() of a file descriptor, as opposed to
++	 * release which is called on the close of the last file descriptor for
++	 * a file.  Under Linux, errors returned by flush() will be passed to 
++	 * userspace as errors from close(), so flush() is a good place to write
++	 * back any cached dirty data. However, many applications ignore errors 
++	 * on close(), and on non-Linux systems, close() may succeed even if flush()
++	 * returns an error. For these reasons, filesystems should not assume
++	 * that errors returned by flush will ever be noticed or even
++	 * delivered.
++	 *
++	 * NOTE: The flush() method may be called more than once for each
++	 * open().  This happens if more than one file descriptor refers to an
++	 * open file handle, e.g. due to dup(), dup2() or fork() calls.  It is
++	 * not possible to determine if a flush is final, so each flush should
++	 * be treated equally.  Multiple write-flush sequences are relatively
++	 * rare, so this shouldn't be a problem.
++	 *
++	 * Filesystems shouldn't assume that flush will be called at any
++	 * particular point.  It may be called more times than expected, or not
++	 * at all.
++	 *
++	 * [close]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html
++	 */
++	int (*flush) (const char *, struct fuse_file_info *);
++
++	/** Release an open file
++	 *
++	 * Release is called when there are no more references to an open
++	 * file: all file descriptors are closed and all memory mappings
++	 * are unmapped.
++	 *
++	 * For every open() call there will be exactly one release() call
++	 * with the same flags and file handle.  It is possible to
++	 * have a file opened more than once, in which case only the last
++	 * release will mean, that no more reads/writes will happen on the
++	 * file.  The return value of release is ignored.
++	 */
++	int (*release) (const char *, struct fuse_file_info *);
++
++	/** Synchronize file contents
++	 *
++	 * If the datasync parameter is non-zero, then only the user data
++	 * should be flushed, not the meta data.
++	 */
++	int (*fsync) (const char *, int, struct fuse_file_info *);
++
++	/** Set extended attributes */
++	int (*setxattr) (const char *, const char *, const char *, size_t, int);
++
++	/** Get extended attributes */
++	int (*getxattr) (const char *, const char *, char *, size_t);
++
++	/** List extended attributes */
++	int (*listxattr) (const char *, char *, size_t);
++
++	/** Remove extended attributes */
++	int (*removexattr) (const char *, const char *);
++
++	/** Open directory
++	 *
++	 * Unless the 'default_permissions' mount option is given,
++	 * this method should check if opendir is permitted for this
++	 * directory. Optionally opendir may also return an arbitrary
++	 * filehandle in the fuse_file_info structure, which will be
++	 * passed to readdir, releasedir and fsyncdir.
++	 */
++	int (*opendir) (const char *, struct fuse_file_info *);
++
++	/** Read directory
++	 *
++	 * The filesystem may choose between two modes of operation:
++	 *
++	 * 1) The readdir implementation ignores the offset parameter, and
++	 * passes zero to the filler function's offset.  The filler
++	 * function will not return '1' (unless an error happens), so the
++	 * whole directory is read in a single readdir operation.
++	 *
++	 * 2) The readdir implementation keeps track of the offsets of the
++	 * directory entries.  It uses the offset parameter and always
++	 * passes non-zero offset to the filler function.  When the buffer
++	 * is full (or an error happens) the filler function will return
++	 * '1'.
++	 */
++	int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
++			struct fuse_file_info *, enum fuse_readdir_flags);
++
++	/** Release directory
++	 */
++	int (*releasedir) (const char *, struct fuse_file_info *);
++
++	/** Synchronize directory contents
++	 *
++	 * If the datasync parameter is non-zero, then only the user data
++	 * should be flushed, not the meta data
++	 */
++	int (*fsyncdir) (const char *, int, struct fuse_file_info *);
++
++	/**
++	 * Initialize filesystem
++	 *
++	 * The return value will passed in the `private_data` field of
++	 * `struct fuse_context` to all file operations, and as a
++	 * parameter to the destroy() method. It overrides the initial
++	 * value provided to fuse_main() / fuse_new().
++	 */
++	void *(*init) (struct fuse_conn_info *conn,
++		       struct fuse_config *cfg);
++
++	/**
++	 * Clean up filesystem
++	 *
++	 * Called on filesystem exit.
++	 */
++	void (*destroy) (void *private_data);
++
++	/**
++	 * Check file access permissions
++	 *
++	 * This will be called for the access() system call.  If the
++	 * 'default_permissions' mount option is given, this method is not
++	 * called.
++	 *
++	 * This method is not called under Linux kernel versions 2.4.x
++	 */
++	int (*access) (const char *, int);
++
++	/**
++	 * Create and open a file
++	 *
++	 * If the file does not exist, first create it with the specified
++	 * mode, and then open it.
++	 *
++	 * If this method is not implemented or under Linux kernel
++	 * versions earlier than 2.6.15, the mknod() and open() methods
++	 * will be called instead.
++	 */
++	int (*create) (const char *, mode_t, struct fuse_file_info *);
++
++	/**
++	 * Perform POSIX file locking operation
++	 *
++	 * The cmd argument will be either F_GETLK, F_SETLK or F_SETLKW.
++	 *
++	 * For the meaning of fields in 'struct flock' see the man page
++	 * for fcntl(2).  The l_whence field will always be set to
++	 * SEEK_SET.
++	 *
++	 * For checking lock ownership, the 'fuse_file_info->owner'
++	 * argument must be used.
++	 *
++	 * For F_GETLK operation, the library will first check currently
++	 * held locks, and if a conflicting lock is found it will return
++	 * information without calling this method.	 This ensures, that
++	 * for local locks the l_pid field is correctly filled in.	The
++	 * results may not be accurate in case of race conditions and in
++	 * the presence of hard links, but it's unlikely that an
++	 * application would rely on accurate GETLK results in these
++	 * cases.  If a conflicting lock is not found, this method will be
++	 * called, and the filesystem may fill out l_pid by a meaningful
++	 * value, or it may leave this field zero.
++	 *
++	 * For F_SETLK and F_SETLKW the l_pid field will be set to the pid
++	 * of the process performing the locking operation.
++	 *
++	 * Note: if this method is not implemented, the kernel will still
++	 * allow file locking to work locally.  Hence it is only
++	 * interesting for network filesystems and similar.
++	 */
++	int (*lock) (const char *, struct fuse_file_info *, int cmd,
++		     struct flock *);
++
++	/**
++	 * Change the access and modification times of a file with
++	 * nanosecond resolution
++	 *
++	 * This supersedes the old utime() interface.  New applications
++	 * should use this.
++	 *
++	 * `fi` will always be NULL if the file is not currenlty open, but
++	 * may also be NULL if the file is open.
++	 *
++	 * See the utimensat(2) man page for details.
++	 */
++	 int (*utimens) (const char *, const struct timespec tv[2],
++			 struct fuse_file_info *fi);
++
++	/**
++	 * Map block index within file to block index within device
++	 *
++	 * Note: This makes sense only for block device backed filesystems
++	 * mounted with the 'blkdev' option
++	 */
++	int (*bmap) (const char *, size_t blocksize, uint64_t *idx);
++
++	/**
++	 * Ioctl
++	 *
++	 * flags will have FUSE_IOCTL_COMPAT set for 32bit ioctls in
++	 * 64bit environment.  The size and direction of data is
++	 * determined by _IOC_*() decoding of cmd.  For _IOC_NONE,
++	 * data will be NULL, for _IOC_WRITE data is out area, for
++	 * _IOC_READ in area and if both are set in/out area.  In all
++	 * non-NULL cases, the area is of _IOC_SIZE(cmd) bytes.
++	 *
++	 * If flags has FUSE_IOCTL_DIR then the fuse_file_info refers to a
++	 * directory file handle.
++	 *
++	 * Note : the unsigned long request submitted by the application
++	 * is truncated to 32 bits.
++	 */
++	int (*ioctl) (const char *, unsigned int cmd, void *arg,
++		      struct fuse_file_info *, unsigned int flags, void *data);
++
++	/**
++	 * Poll for IO readiness events
++	 *
++	 * Note: If ph is non-NULL, the client should notify
++	 * when IO readiness events occur by calling
++	 * fuse_notify_poll() with the specified ph.
++	 *
++	 * Regardless of the number of times poll with a non-NULL ph
++	 * is received, single notification is enough to clear all.
++	 * Notifying more times incurs overhead but doesn't harm
++	 * correctness.
++	 *
++	 * The callee is responsible for destroying ph with
++	 * fuse_pollhandle_destroy() when no longer in use.
++	 */
++	int (*poll) (const char *, struct fuse_file_info *,
++		     struct fuse_pollhandle *ph, unsigned *reventsp);
++
++	/** Write contents of buffer to an open file
++	 *
++	 * Similar to the write() method, but data is supplied in a
++	 * generic buffer.  Use fuse_buf_copy() to transfer data to
++	 * the destination.
++	 *
++	 * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
++	 * expected to reset the setuid and setgid bits.
++	 */
++	int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off,
++			  struct fuse_file_info *);
++
++	/** Store data from an open file in a buffer
++	 *
++	 * Similar to the read() method, but data is stored and
++	 * returned in a generic buffer.
++	 *
++	 * No actual copying of data has to take place, the source
++	 * file descriptor may simply be stored in the buffer for
++	 * later data transfer.
++	 *
++	 * The buffer must be allocated dynamically and stored at the
++	 * location pointed to by bufp.  If the buffer contains memory
++	 * regions, they too must be allocated using malloc().  The
++	 * allocated memory will be freed by the caller.
++	 */
++	int (*read_buf) (const char *, struct fuse_bufvec **bufp,
++			 size_t size, off_t off, struct fuse_file_info *);
++	/**
++	 * Perform BSD file locking operation
++	 *
++	 * The op argument will be either LOCK_SH, LOCK_EX or LOCK_UN
++	 *
++	 * Nonblocking requests will be indicated by ORing LOCK_NB to
++	 * the above operations
++	 *
++	 * For more information see the flock(2) manual page.
++	 *
++	 * Additionally fi->owner will be set to a value unique to
++	 * this open file.  This same value will be supplied to
++	 * ->release() when the file is released.
++	 *
++	 * Note: if this method is not implemented, the kernel will still
++	 * allow file locking to work locally.  Hence it is only
++	 * interesting for network filesystems and similar.
++	 */
++	int (*flock) (const char *, struct fuse_file_info *, int op);
++
++	/**
++	 * Allocates space for an open file
++	 *
++	 * This function ensures that required space is allocated for specified
++	 * file.  If this function returns success then any subsequent write
++	 * request to specified range is guaranteed not to fail because of lack
++	 * of space on the file system media.
++	 */
++	int (*fallocate) (const char *, int, off_t, off_t,
++			  struct fuse_file_info *);
++
++	/**
++	 * Copy a range of data from one file to another
++	 *
++	 * Performs an optimized copy between two file descriptors without the
++	 * additional cost of transferring data through the FUSE kernel module
++	 * to user space (glibc) and then back into the FUSE filesystem again.
++	 *
++	 * In case this method is not implemented, glibc falls back to reading
++	 * data from the source and writing to the destination. Effectively
++	 * doing an inefficient copy of the data.
++	 */
++	ssize_t (*copy_file_range) (const char *path_in,
++				    struct fuse_file_info *fi_in,
++				    off_t offset_in, const char *path_out,
++				    struct fuse_file_info *fi_out,
++				    off_t offset_out, size_t size, int flags);
++
++	/**
++	 * Find next data or hole after the specified offset
++	 */
++	off_t (*lseek) (const char *, off_t off, int whence, struct fuse_file_info *);
++};
++
++/** Extra context that may be needed by some filesystems
++ *
++ * The uid, gid and pid fields are not filled in case of a writepage
++ * operation.
++ */
++struct fuse_context {
++	/** Pointer to the fuse object */
++	struct fuse *fuse;
++
++	/** User ID of the calling process */
++	uid_t uid;
++
++	/** Group ID of the calling process */
++	gid_t gid;
++
++	/** Process ID of the calling thread */
++	pid_t pid;
++
++	/** Private filesystem data */
++	void *private_data;
++
++	/** Umask of the calling process */
++	mode_t umask;
++};
++
++/**
++ * Main function of FUSE.
++ *
++ * This is for the lazy.  This is all that has to be called from the
++ * main() function.
++ *
++ * This function does the following:
++ *   - parses command line options, and handles --help and
++ *     --version
++ *   - installs signal handlers for INT, HUP, TERM and PIPE
++ *   - registers an exit handler to unmount the filesystem on program exit
++ *   - creates a fuse handle
++ *   - registers the operations
++ *   - calls either the single-threaded or the multi-threaded event loop
++ *
++ * Most file systems will have to parse some file-system specific
++ * arguments before calling this function. It is recommended to do
++ * this with fuse_opt_parse() and a processing function that passes
++ * through any unknown options (this can also be achieved by just
++ * passing NULL as the processing function). That way, the remaining
++ * options can be passed directly to fuse_main().
++ *
++ * fuse_main() accepts all options that can be passed to
++ * fuse_parse_cmdline(), fuse_new(), or fuse_session_new().
++ *
++ * Option parsing skips argv[0], which is assumed to contain the
++ * program name. This element must always be present and is used to
++ * construct a basic ``usage: `` message for the --help
++ * output. argv[0] may also be set to the empty string. In this case
++ * the usage message is suppressed. This can be used by file systems
++ * to print their own usage line first. See hello.c for an example of
++ * how to do this.
++ *
++ * Note: this is currently implemented as a macro.
++ *
++ * The following error codes may be returned from fuse_main():
++ *   1: Invalid option arguments
++ *   2: No mount point specified
++ *   3: FUSE setup failed
++ *   4: Mounting failed
++ *   5: Failed to daemonize (detach from session)
++ *   6: Failed to set up signal handlers
++ *   7: An error occured during the life of the file system
++ *
++ * @param argc the argument counter passed to the main() function
++ * @param argv the argument vector passed to the main() function
++ * @param op the file system operation
++ * @param private_data Initial value for the `private_data`
++ *            field of `struct fuse_context`. May be overridden by the
++ *            `struct fuse_operations.init` handler.
++ * @return 0 on success, nonzero on failure
++ *
++ * Example usage, see hello.c
++ */
++/*
++  int fuse_main(int argc, char *argv[], const struct fuse_operations *op,
++  void *private_data);
++*/
++#define fuse_main(argc, argv, op, private_data)				\
++	fuse_main_real(argc, argv, op, sizeof(*(op)), private_data)
++
++/* ----------------------------------------------------------- *
++ * More detailed API					       *
++ * ----------------------------------------------------------- */
++
++/**
++ * Print available options (high- and low-level) to stdout.  This is
++ * not an exhaustive list, but includes only those options that may be
++ * of interest to an end-user of a file system.
++ *
++ * The function looks at the argument vector only to determine if
++ * there are additional modules to be loaded (module=foo option),
++ * and attempts to call their help functions as well.
++ *
++ * @param args the argument vector.
++ */
++void fuse_lib_help(struct fuse_args *args);
++
++/**
++ * Create a new FUSE filesystem.
++ *
++ * This function accepts most file-system independent mount options
++ * (like context, nodev, ro - see mount(8)), as well as the
++ * FUSE-specific mount options from mount.fuse(8).
++ *
++ * If the --help option is specified, the function writes a help text
++ * to stdout and returns NULL.
++ *
++ * Option parsing skips argv[0], which is assumed to contain the
++ * program name. This element must always be present and is used to
++ * construct a basic ``usage: `` message for the --help output. If
++ * argv[0] is set to the empty string, no usage message is included in
++ * the --help output.
++ *
++ * If an unknown option is passed in, an error message is written to
++ * stderr and the function returns NULL.
++ *
++ * @param args argument vector
++ * @param op the filesystem operations
++ * @param op_size the size of the fuse_operations structure
++ * @param private_data Initial value for the `private_data`
++ *            field of `struct fuse_context`. May be overridden by the
++ *            `struct fuse_operations.init` handler.
++ * @return the created FUSE handle
++ */
++#if FUSE_USE_VERSION == 30
++struct fuse *fuse_new_30(struct fuse_args *args, const struct fuse_operations *op,
++			 size_t op_size, void *private_data);
++#define fuse_new(args, op, size, data) fuse_new_30(args, op, size, data)
++#else
++struct fuse *fuse_new(struct fuse_args *args, const struct fuse_operations *op,
++		      size_t op_size, void *private_data);
++#endif
++
++/**
++ * Mount a FUSE file system.
++ *
++ * @param mountpoint the mount point path
++ * @param f the FUSE handle
++ *
++ * @return 0 on success, -1 on failure.
++ **/
++int fuse_mount(struct fuse *f, const char *mountpoint);
++
++/**
++ * Unmount a FUSE file system.
++ *
++ * See fuse_session_unmount() for additional information.
++ *
++ * @param f the FUSE handle
++ **/
++void fuse_unmount(struct fuse *f);
++
++/**
++ * Destroy the FUSE handle.
++ *
++ * NOTE: This function does not unmount the filesystem.	 If this is
++ * needed, call fuse_unmount() before calling this function.
++ *
++ * @param f the FUSE handle
++ */
++void fuse_destroy(struct fuse *f);
++
++/**
++ * FUSE event loop.
++ *
++ * Requests from the kernel are processed, and the appropriate
++ * operations are called.
++ *
++ * For a description of the return value and the conditions when the
++ * event loop exits, refer to the documentation of
++ * fuse_session_loop().
++ *
++ * @param f the FUSE handle
++ * @return see fuse_session_loop()
++ *
++ * See also: fuse_loop_mt()
++ */
++int fuse_loop(struct fuse *f);
++
++/**
++ * Flag session as terminated
++ *
++ * This function will cause any running event loops to exit on
++ * the next opportunity.
++ *
++ * @param f the FUSE handle
++ */
++void fuse_exit(struct fuse *f);
++
++/**
++ * FUSE event loop with multiple threads
++ *
++ * Requests from the kernel are processed, and the appropriate
++ * operations are called.  Request are processed in parallel by
++ * distributing them between multiple threads.
++ *
++ * For a description of the return value and the conditions when the
++ * event loop exits, refer to the documentation of
++ * fuse_session_loop().
++ *
++ * Note: using fuse_loop() instead of fuse_loop_mt() means you are running in
++ * single-threaded mode, and that you will not have to worry about reentrancy,
++ * though you will have to worry about recursive lookups. In single-threaded
++ * mode, FUSE will wait for one callback to return before calling another.
++ *
++ * Enabling multiple threads, by using fuse_loop_mt(), will cause FUSE to make
++ * multiple simultaneous calls into the various callback functions given by your
++ * fuse_operations record.
++ *
++ * If you are using multiple threads, you can enjoy all the parallel execution
++ * and interactive response benefits of threads, and you get to enjoy all the
++ * benefits of race conditions and locking bugs, too. Ensure that any code used
++ * in the callback function of fuse_operations is also thread-safe.
++ *
++ * @param f the FUSE handle
++ * @param config loop configuration
++ * @return see fuse_session_loop()
++ *
++ * See also: fuse_loop()
++ */
++#if FUSE_USE_VERSION < 32
++int fuse_loop_mt_31(struct fuse *f, int clone_fd);
++#define fuse_loop_mt(f, clone_fd) fuse_loop_mt_31(f, clone_fd)
++#else
++int fuse_loop_mt(struct fuse *f, struct fuse_loop_config *config);
++#endif
++
++/**
++ * Get the current context
++ *
++ * The context is only valid for the duration of a filesystem
++ * operation, and thus must not be stored and used later.
++ *
++ * @return the context
++ */
++struct fuse_context *fuse_get_context(void);
++
++/**
++ * Get the current supplementary group IDs for the current request
++ *
++ * Similar to the getgroups(2) system call, except the return value is
++ * always the total number of group IDs, even if it is larger than the
++ * specified size.
++ *
++ * The current fuse kernel module in linux (as of 2.6.30) doesn't pass
++ * the group list to userspace, hence this function needs to parse
++ * "/proc/$TID/task/$TID/status" to get the group IDs.
++ *
++ * This feature may not be supported on all operating systems.  In
++ * such a case this function will return -ENOSYS.
++ *
++ * @param size size of given array
++ * @param list array of group IDs to be filled in
++ * @return the total number of supplementary group IDs or -errno on failure
++ */
++int fuse_getgroups(int size, gid_t list[]);
++
++/**
++ * Check if the current request has already been interrupted
++ *
++ * @return 1 if the request has been interrupted, 0 otherwise
++ */
++int fuse_interrupted(void);
++
++/**
++ * Invalidates cache for the given path.
++ *
++ * This calls fuse_lowlevel_notify_inval_inode internally.
++ *
++ * @return 0 on successful invalidation, negative error value otherwise.
++ *         This routine may return -ENOENT to indicate that there was
++ *         no entry to be invalidated, e.g., because the path has not
++ *         been seen before or has been forgotten; this should not be
++ *         considered to be an error.
++ */
++int fuse_invalidate_path(struct fuse *f, const char *path);
++
++/**
++ * The real main function
++ *
++ * Do not call this directly, use fuse_main()
++ */
++int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
++		   size_t op_size, void *private_data);
++
++/**
++ * Start the cleanup thread when using option "remember".
++ *
++ * This is done automatically by fuse_loop_mt()
++ * @param fuse struct fuse pointer for fuse instance
++ * @return 0 on success and -1 on error
++ */
++int fuse_start_cleanup_thread(struct fuse *fuse);
++
++/**
++ * Stop the cleanup thread when using option "remember".
++ *
++ * This is done automatically by fuse_loop_mt()
++ * @param fuse struct fuse pointer for fuse instance
++ */
++void fuse_stop_cleanup_thread(struct fuse *fuse);
++
++/**
++ * Iterate over cache removing stale entries
++ * use in conjunction with "-oremember"
++ *
++ * NOTE: This is already done for the standard sessions
++ *
++ * @param fuse struct fuse pointer for fuse instance
++ * @return the number of seconds until the next cleanup
++ */
++int fuse_clean_cache(struct fuse *fuse);
++
++/*
++ * Stacking API
++ */
++
++/**
++ * Fuse filesystem object
++ *
++ * This is opaque object represents a filesystem layer
++ */
++struct fuse_fs;
++
++/*
++ * These functions call the relevant filesystem operation, and return
++ * the result.
++ *
++ * If the operation is not defined, they return -ENOSYS, with the
++ * exception of fuse_fs_open, fuse_fs_release, fuse_fs_opendir,
++ * fuse_fs_releasedir and fuse_fs_statfs, which return 0.
++ */
++
++int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf,
++		    struct fuse_file_info *fi);
++int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath,
++		   const char *newpath, unsigned int flags);
++int fuse_fs_unlink(struct fuse_fs *fs, const char *path);
++int fuse_fs_rmdir(struct fuse_fs *fs, const char *path);
++int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname,
++		    const char *path);
++int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath);
++int fuse_fs_release(struct fuse_fs *fs,	 const char *path,
++		    struct fuse_file_info *fi);
++int fuse_fs_open(struct fuse_fs *fs, const char *path,
++		 struct fuse_file_info *fi);
++int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
++		 off_t off, struct fuse_file_info *fi);
++int fuse_fs_read_buf(struct fuse_fs *fs, const char *path,
++		     struct fuse_bufvec **bufp, size_t size, off_t off,
++		     struct fuse_file_info *fi);
++int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf,
++		  size_t size, off_t off, struct fuse_file_info *fi);
++int fuse_fs_write_buf(struct fuse_fs *fs, const char *path,
++		      struct fuse_bufvec *buf, off_t off,
++		      struct fuse_file_info *fi);
++int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
++		  struct fuse_file_info *fi);
++int fuse_fs_flush(struct fuse_fs *fs, const char *path,
++		  struct fuse_file_info *fi);
++int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf);
++int fuse_fs_opendir(struct fuse_fs *fs, const char *path,
++		    struct fuse_file_info *fi);
++int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf,
++		    fuse_fill_dir_t filler, off_t off,
++		    struct fuse_file_info *fi, enum fuse_readdir_flags flags);
++int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync,
++		     struct fuse_file_info *fi);
++int fuse_fs_releasedir(struct fuse_fs *fs, const char *path,
++		       struct fuse_file_info *fi);
++int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
++		   struct fuse_file_info *fi);
++int fuse_fs_lock(struct fuse_fs *fs, const char *path,
++		 struct fuse_file_info *fi, int cmd, struct flock *lock);
++int fuse_fs_flock(struct fuse_fs *fs, const char *path,
++		  struct fuse_file_info *fi, int op);
++int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode,
++		  struct fuse_file_info *fi);
++int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid,
++		  struct fuse_file_info *fi);
++int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size,
++		     struct fuse_file_info *fi);
++int fuse_fs_utimens(struct fuse_fs *fs, const char *path,
++		    const struct timespec tv[2], struct fuse_file_info *fi);
++int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask);
++int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf,
++		     size_t len);
++int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode,
++		  dev_t rdev);
++int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode);
++int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name,
++		     const char *value, size_t size, int flags);
++int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name,
++		     char *value, size_t size);
++int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list,
++		      size_t size);
++int fuse_fs_removexattr(struct fuse_fs *fs, const char *path,
++			const char *name);
++int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
++		 uint64_t *idx);
++int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, unsigned int cmd,
++		  void *arg, struct fuse_file_info *fi, unsigned int flags,
++		  void *data);
++int fuse_fs_poll(struct fuse_fs *fs, const char *path,
++		 struct fuse_file_info *fi, struct fuse_pollhandle *ph,
++		 unsigned *reventsp);
++int fuse_fs_fallocate(struct fuse_fs *fs, const char *path, int mode,
++		 off_t offset, off_t length, struct fuse_file_info *fi);
++ssize_t fuse_fs_copy_file_range(struct fuse_fs *fs, const char *path_in,
++				struct fuse_file_info *fi_in, off_t off_in,
++				const char *path_out,
++				struct fuse_file_info *fi_out, off_t off_out,
++				size_t len, int flags);
++off_t fuse_fs_lseek(struct fuse_fs *fs, const char *path, off_t off, int whence,
++		    struct fuse_file_info *fi);
++void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn,
++		struct fuse_config *cfg);
++void fuse_fs_destroy(struct fuse_fs *fs);
++
++int fuse_notify_poll(struct fuse_pollhandle *ph);
++
++/**
++ * Create a new fuse filesystem object
++ *
++ * This is usually called from the factory of a fuse module to create
++ * a new instance of a filesystem.
++ *
++ * @param op the filesystem operations
++ * @param op_size the size of the fuse_operations structure
++ * @param private_data Initial value for the `private_data`
++ *            field of `struct fuse_context`. May be overridden by the
++ *            `struct fuse_operations.init` handler.
++ * @return a new filesystem object
++ */
++struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
++			    void *private_data);
++
++/**
++ * Factory for creating filesystem objects
++ *
++ * The function may use and remove options from 'args' that belong
++ * to this module.
++ *
++ * For now the 'fs' vector always contains exactly one filesystem.
++ * This is the filesystem which will be below the newly created
++ * filesystem in the stack.
++ *
++ * @param args the command line arguments
++ * @param fs NULL terminated filesystem object vector
++ * @return the new filesystem object
++ */
++typedef struct fuse_fs *(*fuse_module_factory_t)(struct fuse_args *args,
++						 struct fuse_fs *fs[]);
++/**
++ * Register filesystem module
++ *
++ * If the "-omodules=*name*_:..." option is present, filesystem
++ * objects are created and pushed onto the stack with the *factory_*
++ * function.
++ *
++ * @param name_ the name of this filesystem module
++ * @param factory_ the factory function for this filesystem module
++ */
++#define FUSE_REGISTER_MODULE(name_, factory_) \
++	fuse_module_factory_t fuse_module_ ## name_ ## _factory = factory_
++
++/** Get session from fuse object */
++struct fuse_session *fuse_get_session(struct fuse *f);
++
++/**
++ * Open a FUSE file descriptor and set up the mount for the given
++ * mountpoint and flags.
++ *
++ * @param mountpoint reference to the mount in the file system
++ * @param options mount options
++ * @return the FUSE file descriptor or -1 upon error
++ */
++int fuse_open_channel(const char *mountpoint, const char *options);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* FUSE_H_ */
+diff --git a/tools/virtiofsd/fuse_common.h b/tools/virtiofsd/fuse_common.h
+new file mode 100644
+index 0000000000..2d686b2ac4
+--- /dev/null
++++ b/tools/virtiofsd/fuse_common.h
+@@ -0,0 +1,823 @@
++/*  FUSE: Filesystem in Userspace
++  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++
++  This program can be distributed under the terms of the GNU LGPLv2.
++  See the file COPYING.LIB.
++*/
++
++/** @file */
++
++#if !defined(FUSE_H_) && !defined(FUSE_LOWLEVEL_H_)
++#error "Never include <fuse_common.h> directly; use <fuse.h> or <fuse_lowlevel.h> instead."
++#endif
++
++#ifndef FUSE_COMMON_H_
++#define FUSE_COMMON_H_
++
++#include "fuse_opt.h"
++#include "fuse_log.h"
++#include <stdint.h>
++#include <sys/types.h>
++
++/** Major version of FUSE library interface */
++#define FUSE_MAJOR_VERSION 3
++
++/** Minor version of FUSE library interface */
++#define FUSE_MINOR_VERSION 2
++
++#define FUSE_MAKE_VERSION(maj, min)  ((maj) * 10 + (min))
++#define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION)
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/**
++ * Information about an open file.
++ *
++ * File Handles are created by the open, opendir, and create methods and closed
++ * by the release and releasedir methods.  Multiple file handles may be
++ * concurrently open for the same file.  Generally, a client will create one
++ * file handle per file descriptor, though in some cases multiple file
++ * descriptors can share a single file handle.
++ */
++struct fuse_file_info {
++	/** Open flags.	 Available in open() and release() */
++	int flags;
++
++	/** In case of a write operation indicates if this was caused
++	    by a delayed write from the page cache. If so, then the
++	    context's pid, uid, and gid fields will not be valid, and
++	    the *fh* value may not match the *fh* value that would
++	    have been sent with the corresponding individual write
++	    requests if write caching had been disabled. */
++	unsigned int writepage : 1;
++
++	/** Can be filled in by open, to use direct I/O on this file. */
++	unsigned int direct_io : 1;
++
++	/** Can be filled in by open. It signals the kernel that any
++	    currently cached file data (ie., data that the filesystem
++	    provided the last time the file was open) need not be
++	    invalidated. Has no effect when set in other contexts (in
++	    particular it does nothing when set by opendir()). */
++	unsigned int keep_cache : 1;
++
++	/** Indicates a flush operation.  Set in flush operation, also
++	    maybe set in highlevel lock operation and lowlevel release
++	    operation. */
++	unsigned int flush : 1;
++
++	/** Can be filled in by open, to indicate that the file is not
++	    seekable. */
++	unsigned int nonseekable : 1;
++
++	/* Indicates that flock locks for this file should be
++	   released.  If set, lock_owner shall contain a valid value.
++	   May only be set in ->release(). */
++	unsigned int flock_release : 1;
++
++	/** Can be filled in by opendir. It signals the kernel to
++	    enable caching of entries returned by readdir().  Has no
++	    effect when set in other contexts (in particular it does
++	    nothing when set by open()). */
++	unsigned int cache_readdir : 1;
++
++	/** Padding.  Reserved for future use*/
++	unsigned int padding : 25;
++	unsigned int padding2 : 32;
++
++	/** File handle id.  May be filled in by filesystem in create,
++	 * open, and opendir().  Available in most other file operations on the
++	 * same file handle. */
++	uint64_t fh;
++
++	/** Lock owner id.  Available in locking operations and flush */
++	uint64_t lock_owner;
++
++	/** Requested poll events.  Available in ->poll.  Only set on kernels
++	    which support it.  If unsupported, this field is set to zero. */
++	uint32_t poll_events;
++};
++
++/**
++ * Configuration parameters passed to fuse_session_loop_mt() and
++ * fuse_loop_mt().
++ */
++struct fuse_loop_config {
++	/**
++	 * whether to use separate device fds for each thread
++	 * (may increase performance)
++	 */
++	int clone_fd;
++
++	/**
++	 * The maximum number of available worker threads before they
++	 * start to get deleted when they become idle. If not
++	 * specified, the default is 10.
++	 *
++	 * Adjusting this has performance implications; a very small number
++	 * of threads in the pool will cause a lot of thread creation and
++	 * deletion overhead and performance may suffer. When set to 0, a new
++	 * thread will be created to service every operation.
++	 */
++	unsigned int max_idle_threads;
++};
++
++/**************************************************************************
++ * Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want' *
++ **************************************************************************/
++
++/**
++ * Indicates that the filesystem supports asynchronous read requests.
++ *
++ * If this capability is not requested/available, the kernel will
++ * ensure that there is at most one pending read request per
++ * file-handle at any time, and will attempt to order read requests by
++ * increasing offset.
++ *
++ * This feature is enabled by default when supported by the kernel.
++ */
++#define FUSE_CAP_ASYNC_READ		(1 << 0)
++
++/**
++ * Indicates that the filesystem supports "remote" locking.
++ *
++ * This feature is enabled by default when supported by the kernel,
++ * and if getlk() and setlk() handlers are implemented.
++ */
++#define FUSE_CAP_POSIX_LOCKS		(1 << 1)
++
++/**
++ * Indicates that the filesystem supports the O_TRUNC open flag.  If
++ * disabled, and an application specifies O_TRUNC, fuse first calls
++ * truncate() and then open() with O_TRUNC filtered out.
++ *
++ * This feature is enabled by default when supported by the kernel.
++ */
++#define FUSE_CAP_ATOMIC_O_TRUNC		(1 << 3)
++
++/**
++ * Indicates that the filesystem supports lookups of "." and "..".
++ *
++ * This feature is disabled by default.
++ */
++#define FUSE_CAP_EXPORT_SUPPORT		(1 << 4)
++
++/**
++ * Indicates that the kernel should not apply the umask to the
++ * file mode on create operations.
++ *
++ * This feature is disabled by default.
++ */
++#define FUSE_CAP_DONT_MASK		(1 << 6)
++
++/**
++ * Indicates that libfuse should try to use splice() when writing to
++ * the fuse device. This may improve performance.
++ *
++ * This feature is disabled by default.
++ */
++#define FUSE_CAP_SPLICE_WRITE		(1 << 7)
++
++/**
++ * Indicates that libfuse should try to move pages instead of copying when
++ * writing to / reading from the fuse device. This may improve performance.
++ *
++ * This feature is disabled by default.
++ */
++#define FUSE_CAP_SPLICE_MOVE		(1 << 8)
++
++/**
++ * Indicates that libfuse should try to use splice() when reading from
++ * the fuse device. This may improve performance.
++ *
++ * This feature is enabled by default when supported by the kernel and
++ * if the filesystem implements a write_buf() handler.
++ */
++#define FUSE_CAP_SPLICE_READ		(1 << 9)
++
++/**
++ * If set, the calls to flock(2) will be emulated using POSIX locks and must
++ * then be handled by the filesystem's setlock() handler.
++ *
++ * If not set, flock(2) calls will be handled by the FUSE kernel module
++ * internally (so any access that does not go through the kernel cannot be taken
++ * into account).
++ *
++ * This feature is enabled by default when supported by the kernel and
++ * if the filesystem implements a flock() handler.
++ */
++#define FUSE_CAP_FLOCK_LOCKS		(1 << 10)
++
++/**
++ * Indicates that the filesystem supports ioctl's on directories.
++ *
++ * This feature is enabled by default when supported by the kernel.
++ */
++#define FUSE_CAP_IOCTL_DIR		(1 << 11)
++
++/**
++ * Traditionally, while a file is open the FUSE kernel module only
++ * asks the filesystem for an update of the file's attributes when a
++ * client attempts to read beyond EOF. This is unsuitable for
++ * e.g. network filesystems, where the file contents may change
++ * without the kernel knowing about it.
++ *
++ * If this flag is set, FUSE will check the validity of the attributes
++ * on every read. If the attributes are no longer valid (i.e., if the
++ * *attr_timeout* passed to fuse_reply_attr() or set in `struct
++ * fuse_entry_param` has passed), it will first issue a `getattr`
++ * request. If the new mtime differs from the previous value, any
++ * cached file *contents* will be invalidated as well.
++ *
++ * This flag should always be set when available. If all file changes
++ * go through the kernel, *attr_timeout* should be set to a very large
++ * number to avoid unnecessary getattr() calls.
++ *
++ * This feature is enabled by default when supported by the kernel.
++ */
++#define FUSE_CAP_AUTO_INVAL_DATA	(1 << 12)
++
++/**
++ * Indicates that the filesystem supports readdirplus.
++ *
++ * This feature is enabled by default when supported by the kernel and if the
++ * filesystem implements a readdirplus() handler.
++ */
++#define FUSE_CAP_READDIRPLUS		(1 << 13)
++
++/**
++ * Indicates that the filesystem supports adaptive readdirplus.
++ *
++ * If FUSE_CAP_READDIRPLUS is not set, this flag has no effect.
++ *
++ * If FUSE_CAP_READDIRPLUS is set and this flag is not set, the kernel
++ * will always issue readdirplus() requests to retrieve directory
++ * contents.
++ *
++ * If FUSE_CAP_READDIRPLUS is set and this flag is set, the kernel
++ * will issue both readdir() and readdirplus() requests, depending on
++ * how much information is expected to be required.
++ *
++ * As of Linux 4.20, the algorithm is as follows: when userspace
++ * starts to read directory entries, issue a READDIRPLUS request to
++ * the filesystem. If any entry attributes have been looked up by the
++ * time userspace requests the next batch of entries continue with
++ * READDIRPLUS, otherwise switch to plain READDIR.  This will reasult
++ * in eg plain "ls" triggering READDIRPLUS first then READDIR after
++ * that because it doesn't do lookups.  "ls -l" should result in all
++ * READDIRPLUS, except if dentries are already cached.
++ *
++ * This feature is enabled by default when supported by the kernel and
++ * if the filesystem implements both a readdirplus() and a readdir()
++ * handler.
++ */
++#define FUSE_CAP_READDIRPLUS_AUTO	(1 << 14)
++
++/**
++ * Indicates that the filesystem supports asynchronous direct I/O submission.
++ *
++ * If this capability is not requested/available, the kernel will ensure that
++ * there is at most one pending read and one pending write request per direct
++ * I/O file-handle at any time.
++ *
++ * This feature is enabled by default when supported by the kernel.
++ */
++#define FUSE_CAP_ASYNC_DIO		(1 << 15)
++
++/**
++ * Indicates that writeback caching should be enabled. This means that
++ * individual write request may be buffered and merged in the kernel
++ * before they are send to the filesystem.
++ *
++ * This feature is disabled by default.
++ */
++#define FUSE_CAP_WRITEBACK_CACHE	(1 << 16)
++
++/**
++ * Indicates support for zero-message opens. If this flag is set in
++ * the `capable` field of the `fuse_conn_info` structure, then the
++ * filesystem may return `ENOSYS` from the open() handler to indicate
++ * success. Further attempts to open files will be handled in the
++ * kernel. (If this flag is not set, returning ENOSYS will be treated
++ * as an error and signaled to the caller).
++ *
++ * Setting (or unsetting) this flag in the `want` field has *no
++ * effect*.
++ */
++#define FUSE_CAP_NO_OPEN_SUPPORT	(1 << 17)
++
++/**
++ * Indicates support for parallel directory operations. If this flag
++ * is unset, the FUSE kernel module will ensure that lookup() and
++ * readdir() requests are never issued concurrently for the same
++ * directory.
++ *
++ * This feature is enabled by default when supported by the kernel.
++ */
++#define FUSE_CAP_PARALLEL_DIROPS        (1 << 18)
++
++/**
++ * Indicates support for POSIX ACLs.
++ *
++ * If this feature is enabled, the kernel will cache and have
++ * responsibility for enforcing ACLs. ACL will be stored as xattrs and
++ * passed to userspace, which is responsible for updating the ACLs in
++ * the filesystem, keeping the file mode in sync with the ACL, and
++ * ensuring inheritance of default ACLs when new filesystem nodes are
++ * created. Note that this requires that the file system is able to
++ * parse and interpret the xattr representation of ACLs.
++ *
++ * Enabling this feature implicitly turns on the
++ * ``default_permissions`` mount option (even if it was not passed to
++ * mount(2)).
++ *
++ * This feature is disabled by default.
++ */
++#define FUSE_CAP_POSIX_ACL              (1 << 19)
++
++/**
++ * Indicates that the filesystem is responsible for unsetting
++ * setuid and setgid bits when a file is written, truncated, or
++ * its owner is changed.
++ *
++ * This feature is enabled by default when supported by the kernel.
++ */
++#define FUSE_CAP_HANDLE_KILLPRIV         (1 << 20)
++
++/**
++ * Indicates support for zero-message opendirs. If this flag is set in
++ * the `capable` field of the `fuse_conn_info` structure, then the filesystem
++ * may return `ENOSYS` from the opendir() handler to indicate success. Further
++ * opendir and releasedir messages will be handled in the kernel. (If this
++ * flag is not set, returning ENOSYS will be treated as an error and signalled
++ * to the caller.)
++ *
++ * Setting (or unsetting) this flag in the `want` field has *no effect*.
++ */
++#define FUSE_CAP_NO_OPENDIR_SUPPORT    (1 << 24)
++
++/**
++ * Ioctl flags
++ *
++ * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine
++ * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed
++ * FUSE_IOCTL_RETRY: retry with new iovecs
++ * FUSE_IOCTL_DIR: is a directory
++ *
++ * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs
++ */
++#define FUSE_IOCTL_COMPAT	(1 << 0)
++#define FUSE_IOCTL_UNRESTRICTED	(1 << 1)
++#define FUSE_IOCTL_RETRY	(1 << 2)
++#define FUSE_IOCTL_DIR		(1 << 4)
++
++#define FUSE_IOCTL_MAX_IOV	256
++
++/**
++ * Connection information, passed to the ->init() method
++ *
++ * Some of the elements are read-write, these can be changed to
++ * indicate the value requested by the filesystem.  The requested
++ * value must usually be smaller than the indicated value.
++ */
++struct fuse_conn_info {
++	/**
++	 * Major version of the protocol (read-only)
++	 */
++	unsigned proto_major;
++
++	/**
++	 * Minor version of the protocol (read-only)
++	 */
++	unsigned proto_minor;
++
++	/**
++	 * Maximum size of the write buffer
++	 */
++	unsigned max_write;
++
++	/**
++	 * Maximum size of read requests. A value of zero indicates no
++	 * limit. However, even if the filesystem does not specify a
++	 * limit, the maximum size of read requests will still be
++	 * limited by the kernel.
++	 *
++	 * NOTE: For the time being, the maximum size of read requests
++	 * must be set both here *and* passed to fuse_session_new()
++	 * using the ``-o max_read=<n>`` mount option. At some point
++	 * in the future, specifying the mount option will no longer
++	 * be necessary.
++	 */
++	unsigned max_read;
++
++	/**
++	 * Maximum readahead
++	 */
++	unsigned max_readahead;
++
++	/**
++	 * Capability flags that the kernel supports (read-only)
++	 */
++	unsigned capable;
++
++	/**
++	 * Capability flags that the filesystem wants to enable.
++	 *
++	 * libfuse attempts to initialize this field with
++	 * reasonable default values before calling the init() handler.
++	 */
++	unsigned want;
++
++	/**
++	 * Maximum number of pending "background" requests. A
++	 * background request is any type of request for which the
++	 * total number is not limited by other means. As of kernel
++	 * 4.8, only two types of requests fall into this category:
++	 *
++	 *   1. Read-ahead requests
++	 *   2. Asynchronous direct I/O requests
++	 *
++	 * Read-ahead requests are generated (if max_readahead is
++	 * non-zero) by the kernel to preemptively fill its caches
++	 * when it anticipates that userspace will soon read more
++	 * data.
++	 *
++	 * Asynchronous direct I/O requests are generated if
++	 * FUSE_CAP_ASYNC_DIO is enabled and userspace submits a large
++	 * direct I/O request. In this case the kernel will internally
++	 * split it up into multiple smaller requests and submit them
++	 * to the filesystem concurrently.
++	 *
++	 * Note that the following requests are *not* background
++	 * requests: writeback requests (limited by the kernel's
++	 * flusher algorithm), regular (i.e., synchronous and
++	 * buffered) userspace read/write requests (limited to one per
++	 * thread), asynchronous read requests (Linux's io_submit(2)
++	 * call actually blocks, so these are also limited to one per
++	 * thread).
++	 */
++	unsigned max_background;
++
++	/**
++	 * Kernel congestion threshold parameter. If the number of pending
++	 * background requests exceeds this number, the FUSE kernel module will
++	 * mark the filesystem as "congested". This instructs the kernel to
++	 * expect that queued requests will take some time to complete, and to
++	 * adjust its algorithms accordingly (e.g. by putting a waiting thread
++	 * to sleep instead of using a busy-loop).
++	 */
++	unsigned congestion_threshold;
++
++	/**
++	 * When FUSE_CAP_WRITEBACK_CACHE is enabled, the kernel is responsible
++	 * for updating mtime and ctime when write requests are received. The
++	 * updated values are passed to the filesystem with setattr() requests.
++	 * However, if the filesystem does not support the full resolution of
++	 * the kernel timestamps (nanoseconds), the mtime and ctime values used
++	 * by kernel and filesystem will differ (and result in an apparent
++	 * change of times after a cache flush).
++	 *
++	 * To prevent this problem, this variable can be used to inform the
++	 * kernel about the timestamp granularity supported by the file-system.
++	 * The value should be power of 10.  The default is 1, i.e. full
++	 * nano-second resolution. Filesystems supporting only second resolution
++	 * should set this to 1000000000.
++	 */
++	unsigned time_gran;
++
++	/**
++	 * For future use.
++	 */
++	unsigned reserved[22];
++};
++
++struct fuse_session;
++struct fuse_pollhandle;
++struct fuse_conn_info_opts;
++
++/**
++ * This function parses several command-line options that can be used
++ * to override elements of struct fuse_conn_info. The pointer returned
++ * by this function should be passed to the
++ * fuse_apply_conn_info_opts() method by the file system's init()
++ * handler.
++ *
++ * Before using this function, think twice if you really want these
++ * parameters to be adjustable from the command line. In most cases,
++ * they should be determined by the file system internally.
++ *
++ * The following options are recognized:
++ *
++ *   -o max_write=N         sets conn->max_write
++ *   -o max_readahead=N     sets conn->max_readahead
++ *   -o max_background=N    sets conn->max_background
++ *   -o congestion_threshold=N  sets conn->congestion_threshold
++ *   -o async_read          sets FUSE_CAP_ASYNC_READ in conn->want
++ *   -o sync_read           unsets FUSE_CAP_ASYNC_READ in conn->want
++ *   -o atomic_o_trunc      sets FUSE_CAP_ATOMIC_O_TRUNC in conn->want
++ *   -o no_remote_lock      Equivalent to -o no_remote_flock,no_remote_posix_lock
++ *   -o no_remote_flock     Unsets FUSE_CAP_FLOCK_LOCKS in conn->want
++ *   -o no_remote_posix_lock  Unsets FUSE_CAP_POSIX_LOCKS in conn->want
++ *   -o [no_]splice_write     (un-)sets FUSE_CAP_SPLICE_WRITE in conn->want
++ *   -o [no_]splice_move      (un-)sets FUSE_CAP_SPLICE_MOVE in conn->want
++ *   -o [no_]splice_read      (un-)sets FUSE_CAP_SPLICE_READ in conn->want
++ *   -o [no_]auto_inval_data  (un-)sets FUSE_CAP_AUTO_INVAL_DATA in conn->want
++ *   -o readdirplus=no        unsets FUSE_CAP_READDIRPLUS in conn->want
++ *   -o readdirplus=yes       sets FUSE_CAP_READDIRPLUS and unsets
++ *                            FUSE_CAP_READDIRPLUS_AUTO in conn->want
++ *   -o readdirplus=auto      sets FUSE_CAP_READDIRPLUS and
++ *                            FUSE_CAP_READDIRPLUS_AUTO in conn->want
++ *   -o [no_]async_dio        (un-)sets FUSE_CAP_ASYNC_DIO in conn->want
++ *   -o [no_]writeback_cache  (un-)sets FUSE_CAP_WRITEBACK_CACHE in conn->want
++ *   -o time_gran=N           sets conn->time_gran
++ *
++ * Known options will be removed from *args*, unknown options will be
++ * passed through unchanged.
++ *
++ * @param args argument vector (input+output)
++ * @return parsed options
++ **/
++struct fuse_conn_info_opts* fuse_parse_conn_info_opts(struct fuse_args *args);
++
++/**
++ * This function applies the (parsed) parameters in *opts* to the
++ * *conn* pointer. It may modify the following fields: wants,
++ * max_write, max_readahead, congestion_threshold, max_background,
++ * time_gran. A field is only set (or unset) if the corresponding
++ * option has been explicitly set.
++ */
++void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts,
++			  struct fuse_conn_info *conn);
++
++/**
++ * Go into the background
++ *
++ * @param foreground if true, stay in the foreground
++ * @return 0 on success, -1 on failure
++ */
++int fuse_daemonize(int foreground);
++
++/**
++ * Get the version of the library
++ *
++ * @return the version
++ */
++int fuse_version(void);
++
++/**
++ * Get the full package version string of the library
++ *
++ * @return the package version
++ */
++const char *fuse_pkgversion(void);
++
++/**
++ * Destroy poll handle
++ *
++ * @param ph the poll handle
++ */
++void fuse_pollhandle_destroy(struct fuse_pollhandle *ph);
++
++/* ----------------------------------------------------------- *
++ * Data buffer						       *
++ * ----------------------------------------------------------- */
++
++/**
++ * Buffer flags
++ */
++enum fuse_buf_flags {
++	/**
++	 * Buffer contains a file descriptor
++	 *
++	 * If this flag is set, the .fd field is valid, otherwise the
++	 * .mem fields is valid.
++	 */
++	FUSE_BUF_IS_FD		= (1 << 1),
++
++	/**
++	 * Seek on the file descriptor
++	 *
++	 * If this flag is set then the .pos field is valid and is
++	 * used to seek to the given offset before performing
++	 * operation on file descriptor.
++	 */
++	FUSE_BUF_FD_SEEK	= (1 << 2),
++
++	/**
++	 * Retry operation on file descriptor
++	 *
++	 * If this flag is set then retry operation on file descriptor
++	 * until .size bytes have been copied or an error or EOF is
++	 * detected.
++	 */
++	FUSE_BUF_FD_RETRY	= (1 << 3),
++};
++
++/**
++ * Buffer copy flags
++ */
++enum fuse_buf_copy_flags {
++	/**
++	 * Don't use splice(2)
++	 *
++	 * Always fall back to using read and write instead of
++	 * splice(2) to copy data from one file descriptor to another.
++	 *
++	 * If this flag is not set, then only fall back if splice is
++	 * unavailable.
++	 */
++	FUSE_BUF_NO_SPLICE	= (1 << 1),
++
++	/**
++	 * Force splice
++	 *
++	 * Always use splice(2) to copy data from one file descriptor
++	 * to another.  If splice is not available, return -EINVAL.
++	 */
++	FUSE_BUF_FORCE_SPLICE	= (1 << 2),
++
++	/**
++	 * Try to move data with splice.
++	 *
++	 * If splice is used, try to move pages from the source to the
++	 * destination instead of copying.  See documentation of
++	 * SPLICE_F_MOVE in splice(2) man page.
++	 */
++	FUSE_BUF_SPLICE_MOVE	= (1 << 3),
++
++	/**
++	 * Don't block on the pipe when copying data with splice
++	 *
++	 * Makes the operations on the pipe non-blocking (if the pipe
++	 * is full or empty).  See SPLICE_F_NONBLOCK in the splice(2)
++	 * man page.
++	 */
++	FUSE_BUF_SPLICE_NONBLOCK= (1 << 4),
++};
++
++/**
++ * Single data buffer
++ *
++ * Generic data buffer for I/O, extended attributes, etc...  Data may
++ * be supplied as a memory pointer or as a file descriptor
++ */
++struct fuse_buf {
++	/**
++	 * Size of data in bytes
++	 */
++	size_t size;
++
++	/**
++	 * Buffer flags
++	 */
++	enum fuse_buf_flags flags;
++
++	/**
++	 * Memory pointer
++	 *
++	 * Used unless FUSE_BUF_IS_FD flag is set.
++	 */
++	void *mem;
++
++	/**
++	 * File descriptor
++	 *
++	 * Used if FUSE_BUF_IS_FD flag is set.
++	 */
++	int fd;
++
++	/**
++	 * File position
++	 *
++	 * Used if FUSE_BUF_FD_SEEK flag is set.
++	 */
++	off_t pos;
++};
++
++/**
++ * Data buffer vector
++ *
++ * An array of data buffers, each containing a memory pointer or a
++ * file descriptor.
++ *
++ * Allocate dynamically to add more than one buffer.
++ */
++struct fuse_bufvec {
++	/**
++	 * Number of buffers in the array
++	 */
++	size_t count;
++
++	/**
++	 * Index of current buffer within the array
++	 */
++	size_t idx;
++
++	/**
++	 * Current offset within the current buffer
++	 */
++	size_t off;
++
++	/**
++	 * Array of buffers
++	 */
++	struct fuse_buf buf[1];
++};
++
++/* Initialize bufvec with a single buffer of given size */
++#define FUSE_BUFVEC_INIT(size__)				\
++	((struct fuse_bufvec) {					\
++		/* .count= */ 1,				\
++		/* .idx =  */ 0,				\
++		/* .off =  */ 0,				\
++		/* .buf =  */ { /* [0] = */ {			\
++			/* .size =  */ (size__),		\
++			/* .flags = */ (enum fuse_buf_flags) 0,	\
++			/* .mem =   */ NULL,			\
++			/* .fd =    */ -1,			\
++			/* .pos =   */ 0,			\
++		} }						\
++	} )
++
++/**
++ * Get total size of data in a fuse buffer vector
++ *
++ * @param bufv buffer vector
++ * @return size of data
++ */
++size_t fuse_buf_size(const struct fuse_bufvec *bufv);
++
++/**
++ * Copy data from one buffer vector to another
++ *
++ * @param dst destination buffer vector
++ * @param src source buffer vector
++ * @param flags flags controlling the copy
++ * @return actual number of bytes copied or -errno on error
++ */
++ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src,
++		      enum fuse_buf_copy_flags flags);
++
++/* ----------------------------------------------------------- *
++ * Signal handling					       *
++ * ----------------------------------------------------------- */
++
++/**
++ * Exit session on HUP, TERM and INT signals and ignore PIPE signal
++ *
++ * Stores session in a global variable.	 May only be called once per
++ * process until fuse_remove_signal_handlers() is called.
++ *
++ * Once either of the POSIX signals arrives, the signal handler calls
++ * fuse_session_exit().
++ *
++ * @param se the session to exit
++ * @return 0 on success, -1 on failure
++ *
++ * See also:
++ * fuse_remove_signal_handlers()
++ */
++int fuse_set_signal_handlers(struct fuse_session *se);
++
++/**
++ * Restore default signal handlers
++ *
++ * Resets global session.  After this fuse_set_signal_handlers() may
++ * be called again.
++ *
++ * @param se the same session as given in fuse_set_signal_handlers()
++ *
++ * See also:
++ * fuse_set_signal_handlers()
++ */
++void fuse_remove_signal_handlers(struct fuse_session *se);
++
++/* ----------------------------------------------------------- *
++ * Compatibility stuff					       *
++ * ----------------------------------------------------------- */
++
++#if !defined(FUSE_USE_VERSION) || FUSE_USE_VERSION < 30
++#  error only API version 30 or greater is supported
++#endif
++
++#ifdef __cplusplus
++}
++#endif
++
++
++/*
++ * This interface uses 64 bit off_t.
++ *
++ * On 32bit systems please add -D_FILE_OFFSET_BITS=64 to your compile flags!
++ */
++
++#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && !defined __cplusplus
++_Static_assert(sizeof(off_t) == 8, "fuse: off_t must be 64bit");
++#else
++struct _fuse_off_t_must_be_64bit_dummy_struct \
++	{ unsigned _fuse_off_t_must_be_64bit:((sizeof(off_t) == 8) ? 1 : -1); };
++#endif
++
++#endif /* FUSE_COMMON_H_ */
+diff --git a/tools/virtiofsd/fuse_i.h b/tools/virtiofsd/fuse_i.h
+new file mode 100644
+index 0000000000..d38b630ac5
+--- /dev/null
++++ b/tools/virtiofsd/fuse_i.h
+@@ -0,0 +1,139 @@
++/*
++  FUSE: Filesystem in Userspace
++  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++
++  This program can be distributed under the terms of the GNU LGPLv2.
++  See the file COPYING.LIB
++*/
++
++#include "fuse.h"
++#include "fuse_lowlevel.h"
++
++struct mount_opts;
++
++struct fuse_req {
++	struct fuse_session *se;
++	uint64_t unique;
++	int ctr;
++	pthread_mutex_t lock;
++	struct fuse_ctx ctx;
++	struct fuse_chan *ch;
++	int interrupted;
++	unsigned int ioctl_64bit : 1;
++	union {
++		struct {
++			uint64_t unique;
++		} i;
++		struct {
++			fuse_interrupt_func_t func;
++			void *data;
++		} ni;
++	} u;
++	struct fuse_req *next;
++	struct fuse_req *prev;
++};
++
++struct fuse_notify_req {
++	uint64_t unique;
++	void (*reply)(struct fuse_notify_req *, fuse_req_t, fuse_ino_t,
++		      const void *, const struct fuse_buf *);
++	struct fuse_notify_req *next;
++	struct fuse_notify_req *prev;
++};
++
++struct fuse_session {
++	char *mountpoint;
++	volatile int exited;
++	int fd;
++	struct mount_opts *mo;
++	int debug;
++	int deny_others;
++	struct fuse_lowlevel_ops op;
++	int got_init;
++	struct cuse_data *cuse_data;
++	void *userdata;
++	uid_t owner;
++	struct fuse_conn_info conn;
++	struct fuse_req list;
++	struct fuse_req interrupts;
++	pthread_mutex_t lock;
++	int got_destroy;
++	pthread_key_t pipe_key;
++	int broken_splice_nonblock;
++	uint64_t notify_ctr;
++	struct fuse_notify_req notify_list;
++	size_t bufsize;
++	int error;
++};
++
++struct fuse_chan {
++	pthread_mutex_t lock;
++	int ctr;
++	int fd;
++};
++
++/**
++ * Filesystem module
++ *
++ * Filesystem modules are registered with the FUSE_REGISTER_MODULE()
++ * macro.
++ *
++ */
++struct fuse_module {
++	char *name;
++	fuse_module_factory_t factory;
++	struct fuse_module *next;
++	struct fusemod_so *so;
++	int ctr;
++};
++
++/* ----------------------------------------------------------- *
++ * Channel interface (when using -o clone_fd)		       *
++ * ----------------------------------------------------------- */
++
++/**
++ * Obtain counted reference to the channel
++ *
++ * @param ch the channel
++ * @return the channel
++ */
++struct fuse_chan *fuse_chan_get(struct fuse_chan *ch);
++
++/**
++ * Drop counted reference to a channel
++ *
++ * @param ch the channel
++ */
++void fuse_chan_put(struct fuse_chan *ch);
++
++struct mount_opts *parse_mount_opts(struct fuse_args *args);
++void destroy_mount_opts(struct mount_opts *mo);
++void fuse_mount_version(void);
++unsigned get_max_read(struct mount_opts *o);
++void fuse_kern_unmount(const char *mountpoint, int fd);
++int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo);
++
++int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
++			       int count);
++void fuse_free_req(fuse_req_t req);
++
++void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeide, const void *inarg);
++
++int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg);
++
++int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
++				 struct fuse_chan *ch);
++void fuse_session_process_buf_int(struct fuse_session *se,
++				  const struct fuse_buf *buf, struct fuse_chan *ch);
++
++struct fuse *fuse_new_31(struct fuse_args *args, const struct fuse_operations *op,
++		      size_t op_size, void *private_data);
++int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config *config);
++int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config *config);
++
++#define FUSE_MAX_MAX_PAGES 256
++#define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32
++
++/* room needed in buffer to accommodate header */
++#define FUSE_BUFFER_HEADER_SIZE 0x1000
++
+diff --git a/tools/virtiofsd/fuse_log.h b/tools/virtiofsd/fuse_log.h
+new file mode 100644
+index 0000000000..5e112e0f53
+--- /dev/null
++++ b/tools/virtiofsd/fuse_log.h
+@@ -0,0 +1,82 @@
++/*
++  FUSE: Filesystem in Userspace
++  Copyright (C) 2019  Red Hat, Inc.
++
++  This program can be distributed under the terms of the GNU LGPLv2.
++  See the file COPYING.LIB.
++*/
++
++#ifndef FUSE_LOG_H_
++#define FUSE_LOG_H_
++
++/** @file
++ *
++ * This file defines the logging interface of FUSE
++ */
++
++#include <stdarg.h>
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/**
++ * Log severity level
++ *
++ * These levels correspond to syslog(2) log levels since they are widely used.
++ */
++enum fuse_log_level {
++	FUSE_LOG_EMERG,
++	FUSE_LOG_ALERT,
++	FUSE_LOG_CRIT,
++	FUSE_LOG_ERR,
++	FUSE_LOG_WARNING,
++	FUSE_LOG_NOTICE,
++	FUSE_LOG_INFO,
++	FUSE_LOG_DEBUG
++};
++
++/**
++ * Log message handler function.
++ *
++ * This function must be thread-safe.  It may be called from any libfuse
++ * function, including fuse_parse_cmdline() and other functions invoked before
++ * a FUSE filesystem is created.
++ *
++ * Install a custom log message handler function using fuse_set_log_func().
++ *
++ * @param level log severity level
++ * @param fmt sprintf-style format string including newline
++ * @param ap format string arguments
++ */
++typedef void (*fuse_log_func_t)(enum fuse_log_level level,
++				const char *fmt, va_list ap);
++
++/**
++ * Install a custom log handler function.
++ *
++ * Log messages are emitted by libfuse functions to report errors and debug
++ * information.  Messages are printed to stderr by default but this can be
++ * overridden by installing a custom log message handler function.
++ *
++ * The log message handler function is global and affects all FUSE filesystems
++ * created within this process.
++ *
++ * @param func a custom log message handler function or NULL to revert to
++ *             the default
++ */
++void fuse_set_log_func(fuse_log_func_t func);
++
++/**
++ * Emit a log message
++ *
++ * @param level severity level (FUSE_LOG_ERR, FUSE_LOG_DEBUG, etc)
++ * @param fmt sprintf-style format string including newline
++ */
++void fuse_log(enum fuse_log_level level, const char *fmt, ...);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* FUSE_LOG_H_ */
+diff --git a/tools/virtiofsd/fuse_lowlevel.h b/tools/virtiofsd/fuse_lowlevel.h
+new file mode 100644
+index 0000000000..18c6363f07
+--- /dev/null
++++ b/tools/virtiofsd/fuse_lowlevel.h
+@@ -0,0 +1,2089 @@
++/*
++  FUSE: Filesystem in Userspace
++  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++
++  This program can be distributed under the terms of the GNU LGPLv2.
++  See the file COPYING.LIB.
++*/
++
++#ifndef FUSE_LOWLEVEL_H_
++#define FUSE_LOWLEVEL_H_
++
++/** @file
++ *
++ * Low level API
++ *
++ * IMPORTANT: you should define FUSE_USE_VERSION before including this
++ * header.  To use the newest API define it to 31 (recommended for any
++ * new application).
++ */
++
++#ifndef FUSE_USE_VERSION
++#error FUSE_USE_VERSION not defined
++#endif
++
++#include "fuse_common.h"
++
++#include <utime.h>
++#include <fcntl.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <sys/statvfs.h>
++#include <sys/uio.h>
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* ----------------------------------------------------------- *
++ * Miscellaneous definitions				       *
++ * ----------------------------------------------------------- */
++
++/** The node ID of the root inode */
++#define FUSE_ROOT_ID 1
++
++/** Inode number type */
++typedef uint64_t fuse_ino_t;
++
++/** Request pointer type */
++typedef struct fuse_req *fuse_req_t;
++
++/**
++ * Session
++ *
++ * This provides hooks for processing requests, and exiting
++ */
++struct fuse_session;
++
++/** Directory entry parameters supplied to fuse_reply_entry() */
++struct fuse_entry_param {
++	/** Unique inode number
++	 *
++	 * In lookup, zero means negative entry (from version 2.5)
++	 * Returning ENOENT also means negative entry, but by setting zero
++	 * ino the kernel may cache negative entries for entry_timeout
++	 * seconds.
++	 */
++	fuse_ino_t ino;
++
++	/** Generation number for this entry.
++	 *
++	 * If the file system will be exported over NFS, the
++	 * ino/generation pairs need to be unique over the file
++	 * system's lifetime (rather than just the mount time). So if
++	 * the file system reuses an inode after it has been deleted,
++	 * it must assign a new, previously unused generation number
++	 * to the inode at the same time.
++	 *
++	 */
++	uint64_t generation;
++
++	/** Inode attributes.
++	 *
++	 * Even if attr_timeout == 0, attr must be correct. For example,
++	 * for open(), FUSE uses attr.st_size from lookup() to determine
++	 * how many bytes to request. If this value is not correct,
++	 * incorrect data will be returned.
++	 */
++	struct stat attr;
++
++	/** Validity timeout (in seconds) for inode attributes. If
++	    attributes only change as a result of requests that come
++	    through the kernel, this should be set to a very large
++	    value. */
++	double attr_timeout;
++
++	/** Validity timeout (in seconds) for the name. If directory
++	    entries are changed/deleted only as a result of requests
++	    that come through the kernel, this should be set to a very
++	    large value. */
++	double entry_timeout;
++};
++
++/**
++ * Additional context associated with requests.
++ *
++ * Note that the reported client uid, gid and pid may be zero in some
++ * situations. For example, if the FUSE file system is running in a
++ * PID or user namespace but then accessed from outside the namespace,
++ * there is no valid uid/pid/gid that could be reported.
++ */
++struct fuse_ctx {
++	/** User ID of the calling process */
++	uid_t uid;
++
++	/** Group ID of the calling process */
++	gid_t gid;
++
++	/** Thread ID of the calling process */
++	pid_t pid;
++
++	/** Umask of the calling process */
++	mode_t umask;
++};
++
++struct fuse_forget_data {
++	fuse_ino_t ino;
++	uint64_t nlookup;
++};
++
++/* 'to_set' flags in setattr */
++#define FUSE_SET_ATTR_MODE	(1 << 0)
++#define FUSE_SET_ATTR_UID	(1 << 1)
++#define FUSE_SET_ATTR_GID	(1 << 2)
++#define FUSE_SET_ATTR_SIZE	(1 << 3)
++#define FUSE_SET_ATTR_ATIME	(1 << 4)
++#define FUSE_SET_ATTR_MTIME	(1 << 5)
++#define FUSE_SET_ATTR_ATIME_NOW	(1 << 7)
++#define FUSE_SET_ATTR_MTIME_NOW	(1 << 8)
++#define FUSE_SET_ATTR_CTIME	(1 << 10)
++
++/* ----------------------------------------------------------- *
++ * Request methods and replies				       *
++ * ----------------------------------------------------------- */
++
++/**
++ * Low level filesystem operations
++ *
++ * Most of the methods (with the exception of init and destroy)
++ * receive a request handle (fuse_req_t) as their first argument.
++ * This handle must be passed to one of the specified reply functions.
++ *
++ * This may be done inside the method invocation, or after the call
++ * has returned.  The request handle is valid until one of the reply
++ * functions is called.
++ *
++ * Other pointer arguments (name, fuse_file_info, etc) are not valid
++ * after the call has returned, so if they are needed later, their
++ * contents have to be copied.
++ *
++ * In general, all methods are expected to perform any necessary
++ * permission checking. However, a filesystem may delegate this task
++ * to the kernel by passing the `default_permissions` mount option to
++ * `fuse_session_new()`. In this case, methods will only be called if
++ * the kernel's permission check has succeeded.
++ *
++ * The filesystem sometimes needs to handle a return value of -ENOENT
++ * from the reply function, which means, that the request was
++ * interrupted, and the reply discarded.  For example if
++ * fuse_reply_open() return -ENOENT means, that the release method for
++ * this file will not be called.
++ */
++struct fuse_lowlevel_ops {
++	/**
++	 * Initialize filesystem
++	 *
++	 * This function is called when libfuse establishes
++	 * communication with the FUSE kernel module. The file system
++	 * should use this module to inspect and/or modify the
++	 * connection parameters provided in the `conn` structure.
++	 *
++	 * Note that some parameters may be overwritten by options
++	 * passed to fuse_session_new() which take precedence over the
++	 * values set in this handler.
++	 *
++	 * There's no reply to this function
++	 *
++	 * @param userdata the user data passed to fuse_session_new()
++	 */
++	void (*init) (void *userdata, struct fuse_conn_info *conn);
++
++	/**
++	 * Clean up filesystem.
++	 *
++	 * Called on filesystem exit. When this method is called, the
++	 * connection to the kernel may be gone already, so that eg. calls
++	 * to fuse_lowlevel_notify_* will fail.
++	 *
++	 * There's no reply to this function
++	 *
++	 * @param userdata the user data passed to fuse_session_new()
++	 */
++	void (*destroy) (void *userdata);
++
++	/**
++	 * Look up a directory entry by name and get its attributes.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_entry
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param parent inode number of the parent directory
++	 * @param name the name to look up
++	 */
++	void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name);
++
++	/**
++	 * Forget about an inode
++	 *
++	 * This function is called when the kernel removes an inode
++	 * from its internal caches.
++	 *
++	 * The inode's lookup count increases by one for every call to
++	 * fuse_reply_entry and fuse_reply_create. The nlookup parameter
++	 * indicates by how much the lookup count should be decreased.
++	 *
++	 * Inodes with a non-zero lookup count may receive request from
++	 * the kernel even after calls to unlink, rmdir or (when
++	 * overwriting an existing file) rename. Filesystems must handle
++	 * such requests properly and it is recommended to defer removal
++	 * of the inode until the lookup count reaches zero. Calls to
++	 * unlink, rmdir or rename will be followed closely by forget
++	 * unless the file or directory is open, in which case the
++	 * kernel issues forget only after the release or releasedir
++	 * calls.
++	 *
++	 * Note that if a file system will be exported over NFS the
++	 * inodes lifetime must extend even beyond forget. See the
++	 * generation field in struct fuse_entry_param above.
++	 *
++	 * On unmount the lookup count for all inodes implicitly drops
++	 * to zero. It is not guaranteed that the file system will
++	 * receive corresponding forget messages for the affected
++	 * inodes.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_none
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param nlookup the number of lookups to forget
++	 */
++	void (*forget) (fuse_req_t req, fuse_ino_t ino, uint64_t nlookup);
++
++	/**
++	 * Get file attributes.
++	 *
++	 * If writeback caching is enabled, the kernel may have a
++	 * better idea of a file's length than the FUSE file system
++	 * (eg if there has been a write that extended the file size,
++	 * but that has not yet been passed to the filesystem.n
++	 *
++	 * In this case, the st_size value provided by the file system
++	 * will be ignored.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_attr
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param fi for future use, currently always NULL
++	 */
++	void (*getattr) (fuse_req_t req, fuse_ino_t ino,
++			 struct fuse_file_info *fi);
++
++	/**
++	 * Set file attributes
++	 *
++	 * In the 'attr' argument only members indicated by the 'to_set'
++	 * bitmask contain valid values.  Other members contain undefined
++	 * values.
++	 *
++	 * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
++	 * expected to reset the setuid and setgid bits if the file
++	 * size or owner is being changed.
++	 *
++	 * If the setattr was invoked from the ftruncate() system call
++	 * under Linux kernel versions 2.6.15 or later, the fi->fh will
++	 * contain the value set by the open method or will be undefined
++	 * if the open method didn't set any value.  Otherwise (not
++	 * ftruncate call, or kernel version earlier than 2.6.15) the fi
++	 * parameter will be NULL.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_attr
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param attr the attributes
++	 * @param to_set bit mask of attributes which should be set
++	 * @param fi file information, or NULL
++	 */
++	void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr,
++			 int to_set, struct fuse_file_info *fi);
++
++	/**
++	 * Read symbolic link
++	 *
++	 * Valid replies:
++	 *   fuse_reply_readlink
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 */
++	void (*readlink) (fuse_req_t req, fuse_ino_t ino);
++
++	/**
++	 * Create file node
++	 *
++	 * Create a regular file, character device, block device, fifo or
++	 * socket node.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_entry
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param parent inode number of the parent directory
++	 * @param name to create
++	 * @param mode file type and mode with which to create the new file
++	 * @param rdev the device number (only valid if created file is a device)
++	 */
++	void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name,
++		       mode_t mode, dev_t rdev);
++
++	/**
++	 * Create a directory
++	 *
++	 * Valid replies:
++	 *   fuse_reply_entry
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param parent inode number of the parent directory
++	 * @param name to create
++	 * @param mode with which to create the new file
++	 */
++	void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name,
++		       mode_t mode);
++
++	/**
++	 * Remove a file
++	 *
++	 * If the file's inode's lookup count is non-zero, the file
++	 * system is expected to postpone any removal of the inode
++	 * until the lookup count reaches zero (see description of the
++	 * forget function).
++	 *
++	 * Valid replies:
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param parent inode number of the parent directory
++	 * @param name to remove
++	 */
++	void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name);
++
++	/**
++	 * Remove a directory
++	 *
++	 * If the directory's inode's lookup count is non-zero, the
++	 * file system is expected to postpone any removal of the
++	 * inode until the lookup count reaches zero (see description
++	 * of the forget function).
++	 *
++	 * Valid replies:
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param parent inode number of the parent directory
++	 * @param name to remove
++	 */
++	void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name);
++
++	/**
++	 * Create a symbolic link
++	 *
++	 * Valid replies:
++	 *   fuse_reply_entry
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param link the contents of the symbolic link
++	 * @param parent inode number of the parent directory
++	 * @param name to create
++	 */
++	void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent,
++			 const char *name);
++
++	/** Rename a file
++	 *
++	 * If the target exists it should be atomically replaced. If
++	 * the target's inode's lookup count is non-zero, the file
++	 * system is expected to postpone any removal of the inode
++	 * until the lookup count reaches zero (see description of the
++	 * forget function).
++	 *
++	 * If this request is answered with an error code of ENOSYS, this is
++	 * treated as a permanent failure with error code EINVAL, i.e. all
++	 * future bmap requests will fail with EINVAL without being
++	 * send to the filesystem process.
++	 *
++	 * *flags* may be `RENAME_EXCHANGE` or `RENAME_NOREPLACE`. If
++	 * RENAME_NOREPLACE is specified, the filesystem must not
++	 * overwrite *newname* if it exists and return an error
++	 * instead. If `RENAME_EXCHANGE` is specified, the filesystem
++	 * must atomically exchange the two files, i.e. both must
++	 * exist and neither may be deleted.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param parent inode number of the old parent directory
++	 * @param name old name
++	 * @param newparent inode number of the new parent directory
++	 * @param newname new name
++	 */
++	void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name,
++			fuse_ino_t newparent, const char *newname,
++			unsigned int flags);
++
++	/**
++	 * Create a hard link
++	 *
++	 * Valid replies:
++	 *   fuse_reply_entry
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the old inode number
++	 * @param newparent inode number of the new parent directory
++	 * @param newname new name to create
++	 */
++	void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
++		      const char *newname);
++
++	/**
++	 * Open a file
++	 *
++	 * Open flags are available in fi->flags. The following rules
++	 * apply.
++	 *
++	 *  - Creation (O_CREAT, O_EXCL, O_NOCTTY) flags will be
++	 *    filtered out / handled by the kernel.
++	 *
++	 *  - Access modes (O_RDONLY, O_WRONLY, O_RDWR) should be used
++	 *    by the filesystem to check if the operation is
++	 *    permitted.  If the ``-o default_permissions`` mount
++	 *    option is given, this check is already done by the
++	 *    kernel before calling open() and may thus be omitted by
++	 *    the filesystem.
++	 *
++	 *  - When writeback caching is enabled, the kernel may send
++	 *    read requests even for files opened with O_WRONLY. The
++	 *    filesystem should be prepared to handle this.
++	 *
++	 *  - When writeback caching is disabled, the filesystem is
++	 *    expected to properly handle the O_APPEND flag and ensure
++	 *    that each write is appending to the end of the file.
++	 * 
++         *  - When writeback caching is enabled, the kernel will
++	 *    handle O_APPEND. However, unless all changes to the file
++	 *    come through the kernel this will not work reliably. The
++	 *    filesystem should thus either ignore the O_APPEND flag
++	 *    (and let the kernel handle it), or return an error
++	 *    (indicating that reliably O_APPEND is not available).
++	 *
++	 * Filesystem may store an arbitrary file handle (pointer,
++	 * index, etc) in fi->fh, and use this in other all other file
++	 * operations (read, write, flush, release, fsync).
++	 *
++	 * Filesystem may also implement stateless file I/O and not store
++	 * anything in fi->fh.
++	 *
++	 * There are also some flags (direct_io, keep_cache) which the
++	 * filesystem may set in fi, to change the way the file is opened.
++	 * See fuse_file_info structure in <fuse_common.h> for more details.
++	 *
++	 * If this request is answered with an error code of ENOSYS
++	 * and FUSE_CAP_NO_OPEN_SUPPORT is set in
++	 * `fuse_conn_info.capable`, this is treated as success and
++	 * future calls to open and release will also succeed without being
++	 * sent to the filesystem process.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_open
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param fi file information
++	 */
++	void (*open) (fuse_req_t req, fuse_ino_t ino,
++		      struct fuse_file_info *fi);
++
++	/**
++	 * Read data
++	 *
++	 * Read should send exactly the number of bytes requested except
++	 * on EOF or error, otherwise the rest of the data will be
++	 * substituted with zeroes.  An exception to this is when the file
++	 * has been opened in 'direct_io' mode, in which case the return
++	 * value of the read system call will reflect the return value of
++	 * this operation.
++	 *
++	 * fi->fh will contain the value set by the open method, or will
++	 * be undefined if the open method didn't set any value.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_buf
++	 *   fuse_reply_iov
++	 *   fuse_reply_data
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param size number of bytes to read
++	 * @param off offset to read from
++	 * @param fi file information
++	 */
++	void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
++		      struct fuse_file_info *fi);
++
++	/**
++	 * Write data
++	 *
++	 * Write should return exactly the number of bytes requested
++	 * except on error.  An exception to this is when the file has
++	 * been opened in 'direct_io' mode, in which case the return value
++	 * of the write system call will reflect the return value of this
++	 * operation.
++	 *
++	 * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
++	 * expected to reset the setuid and setgid bits.
++	 *
++	 * fi->fh will contain the value set by the open method, or will
++	 * be undefined if the open method didn't set any value.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_write
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param buf data to write
++	 * @param size number of bytes to write
++	 * @param off offset to write to
++	 * @param fi file information
++	 */
++	void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf,
++		       size_t size, off_t off, struct fuse_file_info *fi);
++
++	/**
++	 * Flush method
++	 *
++	 * This is called on each close() of the opened file.
++	 *
++	 * Since file descriptors can be duplicated (dup, dup2, fork), for
++	 * one open call there may be many flush calls.
++	 *
++	 * Filesystems shouldn't assume that flush will always be called
++	 * after some writes, or that if will be called at all.
++	 *
++	 * fi->fh will contain the value set by the open method, or will
++	 * be undefined if the open method didn't set any value.
++	 *
++	 * NOTE: the name of the method is misleading, since (unlike
++	 * fsync) the filesystem is not forced to flush pending writes.
++	 * One reason to flush data is if the filesystem wants to return
++	 * write errors during close.  However, such use is non-portable
++	 * because POSIX does not require [close] to wait for delayed I/O to
++	 * complete.
++	 *
++	 * If the filesystem supports file locking operations (setlk,
++	 * getlk) it should remove all locks belonging to 'fi->owner'.
++	 *
++	 * If this request is answered with an error code of ENOSYS,
++	 * this is treated as success and future calls to flush() will
++	 * succeed automatically without being send to the filesystem
++	 * process.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param fi file information
++	 *
++	 * [close]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html
++	 */
++	void (*flush) (fuse_req_t req, fuse_ino_t ino,
++		       struct fuse_file_info *fi);
++
++	/**
++	 * Release an open file
++	 *
++	 * Release is called when there are no more references to an open
++	 * file: all file descriptors are closed and all memory mappings
++	 * are unmapped.
++	 *
++	 * For every open call there will be exactly one release call (unless
++	 * the filesystem is force-unmounted).
++	 *
++	 * The filesystem may reply with an error, but error values are
++	 * not returned to close() or munmap() which triggered the
++	 * release.
++	 *
++	 * fi->fh will contain the value set by the open method, or will
++	 * be undefined if the open method didn't set any value.
++	 * fi->flags will contain the same flags as for open.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param fi file information
++	 */
++	void (*release) (fuse_req_t req, fuse_ino_t ino,
++			 struct fuse_file_info *fi);
++
++	/**
++	 * Synchronize file contents
++	 *
++	 * If the datasync parameter is non-zero, then only the user data
++	 * should be flushed, not the meta data.
++	 *
++	 * If this request is answered with an error code of ENOSYS,
++	 * this is treated as success and future calls to fsync() will
++	 * succeed automatically without being send to the filesystem
++	 * process.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param datasync flag indicating if only data should be flushed
++	 * @param fi file information
++	 */
++	void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync,
++		       struct fuse_file_info *fi);
++
++	/**
++	 * Open a directory
++	 *
++	 * Filesystem may store an arbitrary file handle (pointer, index,
++	 * etc) in fi->fh, and use this in other all other directory
++	 * stream operations (readdir, releasedir, fsyncdir).
++	 *
++	 * If this request is answered with an error code of ENOSYS and
++	 * FUSE_CAP_NO_OPENDIR_SUPPORT is set in `fuse_conn_info.capable`,
++	 * this is treated as success and future calls to opendir and
++	 * releasedir will also succeed without being sent to the filesystem
++	 * process. In addition, the kernel will cache readdir results
++	 * as if opendir returned FOPEN_KEEP_CACHE | FOPEN_CACHE_DIR.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_open
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param fi file information
++	 */
++	void (*opendir) (fuse_req_t req, fuse_ino_t ino,
++			 struct fuse_file_info *fi);
++
++	/**
++	 * Read directory
++	 *
++	 * Send a buffer filled using fuse_add_direntry(), with size not
++	 * exceeding the requested size.  Send an empty buffer on end of
++	 * stream.
++	 *
++	 * fi->fh will contain the value set by the opendir method, or
++	 * will be undefined if the opendir method didn't set any value.
++	 *
++	 * Returning a directory entry from readdir() does not affect
++	 * its lookup count.
++	 *
++         * If off_t is non-zero, then it will correspond to one of the off_t
++	 * values that was previously returned by readdir() for the same
++	 * directory handle. In this case, readdir() should skip over entries
++	 * coming before the position defined by the off_t value. If entries
++	 * are added or removed while the directory handle is open, they filesystem
++	 * may still include the entries that have been removed, and may not
++	 * report the entries that have been created. However, addition or
++	 * removal of entries must never cause readdir() to skip over unrelated
++	 * entries or to report them more than once. This means
++	 * that off_t can not be a simple index that enumerates the entries
++	 * that have been returned but must contain sufficient information to
++	 * uniquely determine the next directory entry to return even when the
++	 * set of entries is changing.
++	 *
++	 * The function does not have to report the '.' and '..'
++	 * entries, but is allowed to do so. Note that, if readdir does
++	 * not return '.' or '..', they will not be implicitly returned,
++	 * and this behavior is observable by the caller.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_buf
++	 *   fuse_reply_data
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param size maximum number of bytes to send
++	 * @param off offset to continue reading the directory stream
++	 * @param fi file information
++	 */
++	void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
++			 struct fuse_file_info *fi);
++
++	/**
++	 * Release an open directory
++	 *
++	 * For every opendir call there will be exactly one releasedir
++	 * call (unless the filesystem is force-unmounted).
++	 *
++	 * fi->fh will contain the value set by the opendir method, or
++	 * will be undefined if the opendir method didn't set any value.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param fi file information
++	 */
++	void (*releasedir) (fuse_req_t req, fuse_ino_t ino,
++			    struct fuse_file_info *fi);
++
++	/**
++	 * Synchronize directory contents
++	 *
++	 * If the datasync parameter is non-zero, then only the directory
++	 * contents should be flushed, not the meta data.
++	 *
++	 * fi->fh will contain the value set by the opendir method, or
++	 * will be undefined if the opendir method didn't set any value.
++	 *
++	 * If this request is answered with an error code of ENOSYS,
++	 * this is treated as success and future calls to fsyncdir() will
++	 * succeed automatically without being send to the filesystem
++	 * process.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param datasync flag indicating if only data should be flushed
++	 * @param fi file information
++	 */
++	void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync,
++			  struct fuse_file_info *fi);
++
++	/**
++	 * Get file system statistics
++	 *
++	 * Valid replies:
++	 *   fuse_reply_statfs
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number, zero means "undefined"
++	 */
++	void (*statfs) (fuse_req_t req, fuse_ino_t ino);
++
++	/**
++	 * Set an extended attribute
++	 *
++	 * If this request is answered with an error code of ENOSYS, this is
++	 * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
++	 * future setxattr() requests will fail with EOPNOTSUPP without being
++	 * send to the filesystem process.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_err
++	 */
++	void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
++			  const char *value, size_t size, int flags);
++
++	/**
++	 * Get an extended attribute
++	 *
++	 * If size is zero, the size of the value should be sent with
++	 * fuse_reply_xattr.
++	 *
++	 * If the size is non-zero, and the value fits in the buffer, the
++	 * value should be sent with fuse_reply_buf.
++	 *
++	 * If the size is too small for the value, the ERANGE error should
++	 * be sent.
++	 *
++	 * If this request is answered with an error code of ENOSYS, this is
++	 * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
++	 * future getxattr() requests will fail with EOPNOTSUPP without being
++	 * send to the filesystem process.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_buf
++	 *   fuse_reply_data
++	 *   fuse_reply_xattr
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param name of the extended attribute
++	 * @param size maximum size of the value to send
++	 */
++	void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
++			  size_t size);
++
++	/**
++	 * List extended attribute names
++	 *
++	 * If size is zero, the total size of the attribute list should be
++	 * sent with fuse_reply_xattr.
++	 *
++	 * If the size is non-zero, and the null character separated
++	 * attribute list fits in the buffer, the list should be sent with
++	 * fuse_reply_buf.
++	 *
++	 * If the size is too small for the list, the ERANGE error should
++	 * be sent.
++	 *
++	 * If this request is answered with an error code of ENOSYS, this is
++	 * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
++	 * future listxattr() requests will fail with EOPNOTSUPP without being
++	 * send to the filesystem process.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_buf
++	 *   fuse_reply_data
++	 *   fuse_reply_xattr
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param size maximum size of the list to send
++	 */
++	void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size);
++
++	/**
++	 * Remove an extended attribute
++	 *
++	 * If this request is answered with an error code of ENOSYS, this is
++	 * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
++	 * future removexattr() requests will fail with EOPNOTSUPP without being
++	 * send to the filesystem process.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param name of the extended attribute
++	 */
++	void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name);
++
++	/**
++	 * Check file access permissions
++	 *
++	 * This will be called for the access() and chdir() system
++	 * calls.  If the 'default_permissions' mount option is given,
++	 * this method is not called.
++	 *
++	 * This method is not called under Linux kernel versions 2.4.x
++	 *
++	 * If this request is answered with an error code of ENOSYS, this is
++	 * treated as a permanent success, i.e. this and all future access()
++	 * requests will succeed without being send to the filesystem process.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param mask requested access mode
++	 */
++	void (*access) (fuse_req_t req, fuse_ino_t ino, int mask);
++
++	/**
++	 * Create and open a file
++	 *
++	 * If the file does not exist, first create it with the specified
++	 * mode, and then open it.
++	 *
++	 * See the description of the open handler for more
++	 * information.
++	 *
++	 * If this method is not implemented or under Linux kernel
++	 * versions earlier than 2.6.15, the mknod() and open() methods
++	 * will be called instead.
++	 *
++	 * If this request is answered with an error code of ENOSYS, the handler
++	 * is treated as not implemented (i.e., for this and future requests the
++	 * mknod() and open() handlers will be called instead).
++	 *
++	 * Valid replies:
++	 *   fuse_reply_create
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param parent inode number of the parent directory
++	 * @param name to create
++	 * @param mode file type and mode with which to create the new file
++	 * @param fi file information
++	 */
++	void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name,
++			mode_t mode, struct fuse_file_info *fi);
++
++	/**
++	 * Test for a POSIX file lock
++	 *
++	 * Valid replies:
++	 *   fuse_reply_lock
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param fi file information
++	 * @param lock the region/type to test
++	 */
++	void (*getlk) (fuse_req_t req, fuse_ino_t ino,
++		       struct fuse_file_info *fi, struct flock *lock);
++
++	/**
++	 * Acquire, modify or release a POSIX file lock
++	 *
++	 * For POSIX threads (NPTL) there's a 1-1 relation between pid and
++	 * owner, but otherwise this is not always the case.  For checking
++	 * lock ownership, 'fi->owner' must be used.  The l_pid field in
++	 * 'struct flock' should only be used to fill in this field in
++	 * getlk().
++	 *
++	 * Note: if the locking methods are not implemented, the kernel
++	 * will still allow file locking to work locally.  Hence these are
++	 * only interesting for network filesystems and similar.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param fi file information
++	 * @param lock the region/type to set
++	 * @param sleep locking operation may sleep
++	 */
++	void (*setlk) (fuse_req_t req, fuse_ino_t ino,
++		       struct fuse_file_info *fi,
++		       struct flock *lock, int sleep);
++
++	/**
++	 * Map block index within file to block index within device
++	 *
++	 * Note: This makes sense only for block device backed filesystems
++	 * mounted with the 'blkdev' option
++	 *
++	 * If this request is answered with an error code of ENOSYS, this is
++	 * treated as a permanent failure, i.e. all future bmap() requests will
++	 * fail with the same error code without being send to the filesystem
++	 * process.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_bmap
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param blocksize unit of block index
++	 * @param idx block index within file
++	 */
++	void (*bmap) (fuse_req_t req, fuse_ino_t ino, size_t blocksize,
++		      uint64_t idx);
++
++	/**
++	 * Ioctl
++	 *
++	 * Note: For unrestricted ioctls (not allowed for FUSE
++	 * servers), data in and out areas can be discovered by giving
++	 * iovs and setting FUSE_IOCTL_RETRY in *flags*.  For
++	 * restricted ioctls, kernel prepares in/out data area
++	 * according to the information encoded in cmd.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_ioctl_retry
++	 *   fuse_reply_ioctl
++	 *   fuse_reply_ioctl_iov
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param cmd ioctl command
++	 * @param arg ioctl argument
++	 * @param fi file information
++	 * @param flags for FUSE_IOCTL_* flags
++	 * @param in_buf data fetched from the caller
++	 * @param in_bufsz number of fetched bytes
++	 * @param out_bufsz maximum size of output data
++	 *
++	 * Note : the unsigned long request submitted by the application
++	 * is truncated to 32 bits.
++	 */
++	void (*ioctl) (fuse_req_t req, fuse_ino_t ino, unsigned int cmd,
++		       void *arg, struct fuse_file_info *fi, unsigned flags,
++		       const void *in_buf, size_t in_bufsz, size_t out_bufsz);
++
++	/**
++	 * Poll for IO readiness
++	 *
++	 * Note: If ph is non-NULL, the client should notify
++	 * when IO readiness events occur by calling
++	 * fuse_lowlevel_notify_poll() with the specified ph.
++	 *
++	 * Regardless of the number of times poll with a non-NULL ph
++	 * is received, single notification is enough to clear all.
++	 * Notifying more times incurs overhead but doesn't harm
++	 * correctness.
++	 *
++	 * The callee is responsible for destroying ph with
++	 * fuse_pollhandle_destroy() when no longer in use.
++	 *
++	 * If this request is answered with an error code of ENOSYS, this is
++	 * treated as success (with a kernel-defined default poll-mask) and
++	 * future calls to pull() will succeed the same way without being send
++	 * to the filesystem process.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_poll
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param fi file information
++	 * @param ph poll handle to be used for notification
++	 */
++	void (*poll) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
++		      struct fuse_pollhandle *ph);
++
++	/**
++	 * Write data made available in a buffer
++	 *
++	 * This is a more generic version of the ->write() method.  If
++	 * FUSE_CAP_SPLICE_READ is set in fuse_conn_info.want and the
++	 * kernel supports splicing from the fuse device, then the
++	 * data will be made available in pipe for supporting zero
++	 * copy data transfer.
++	 *
++	 * buf->count is guaranteed to be one (and thus buf->idx is
++	 * always zero). The write_buf handler must ensure that
++	 * bufv->off is correctly updated (reflecting the number of
++	 * bytes read from bufv->buf[0]).
++	 *
++	 * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
++	 * expected to reset the setuid and setgid bits.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_write
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param bufv buffer containing the data
++	 * @param off offset to write to
++	 * @param fi file information
++	 */
++	void (*write_buf) (fuse_req_t req, fuse_ino_t ino,
++			   struct fuse_bufvec *bufv, off_t off,
++			   struct fuse_file_info *fi);
++
++	/**
++	 * Callback function for the retrieve request
++	 *
++	 * Valid replies:
++	 *	fuse_reply_none
++	 *
++	 * @param req request handle
++	 * @param cookie user data supplied to fuse_lowlevel_notify_retrieve()
++	 * @param ino the inode number supplied to fuse_lowlevel_notify_retrieve()
++	 * @param offset the offset supplied to fuse_lowlevel_notify_retrieve()
++	 * @param bufv the buffer containing the returned data
++	 */
++	void (*retrieve_reply) (fuse_req_t req, void *cookie, fuse_ino_t ino,
++				off_t offset, struct fuse_bufvec *bufv);
++
++	/**
++	 * Forget about multiple inodes
++	 *
++	 * See description of the forget function for more
++	 * information.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_none
++	 *
++	 * @param req request handle
++	 */
++	void (*forget_multi) (fuse_req_t req, size_t count,
++			      struct fuse_forget_data *forgets);
++
++	/**
++	 * Acquire, modify or release a BSD file lock
++	 *
++	 * Note: if the locking methods are not implemented, the kernel
++	 * will still allow file locking to work locally.  Hence these are
++	 * only interesting for network filesystems and similar.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param fi file information
++	 * @param op the locking operation, see flock(2)
++	 */
++	void (*flock) (fuse_req_t req, fuse_ino_t ino,
++		       struct fuse_file_info *fi, int op);
++
++	/**
++	 * Allocate requested space. If this function returns success then
++	 * subsequent writes to the specified range shall not fail due to the lack
++	 * of free space on the file system storage media.
++	 *
++	 * If this request is answered with an error code of ENOSYS, this is
++	 * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
++	 * future fallocate() requests will fail with EOPNOTSUPP without being
++	 * send to the filesystem process.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param offset starting point for allocated region
++	 * @param length size of allocated region
++	 * @param mode determines the operation to be performed on the given range,
++	 *             see fallocate(2)
++	 */
++	void (*fallocate) (fuse_req_t req, fuse_ino_t ino, int mode,
++		       off_t offset, off_t length, struct fuse_file_info *fi);
++
++	/**
++	 * Read directory with attributes
++	 *
++	 * Send a buffer filled using fuse_add_direntry_plus(), with size not
++	 * exceeding the requested size.  Send an empty buffer on end of
++	 * stream.
++	 *
++	 * fi->fh will contain the value set by the opendir method, or
++	 * will be undefined if the opendir method didn't set any value.
++	 *
++	 * In contrast to readdir() (which does not affect the lookup counts),
++	 * the lookup count of every entry returned by readdirplus(), except "."
++	 * and "..", is incremented by one.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_buf
++	 *   fuse_reply_data
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param size maximum number of bytes to send
++	 * @param off offset to continue reading the directory stream
++	 * @param fi file information
++	 */
++	void (*readdirplus) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
++			 struct fuse_file_info *fi);
++
++	/**
++	 * Copy a range of data from one file to another
++	 *
++	 * Performs an optimized copy between two file descriptors without the
++	 * additional cost of transferring data through the FUSE kernel module
++	 * to user space (glibc) and then back into the FUSE filesystem again.
++	 *
++	 * In case this method is not implemented, glibc falls back to reading
++	 * data from the source and writing to the destination. Effectively
++	 * doing an inefficient copy of the data.
++	 *
++	 * If this request is answered with an error code of ENOSYS, this is
++	 * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
++	 * future copy_file_range() requests will fail with EOPNOTSUPP without
++	 * being send to the filesystem process.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_write
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino_in the inode number or the source file
++	 * @param off_in starting point from were the data should be read
++	 * @param fi_in file information of the source file
++	 * @param ino_out the inode number or the destination file
++	 * @param off_out starting point where the data should be written
++	 * @param fi_out file information of the destination file
++	 * @param len maximum size of the data to copy
++	 * @param flags passed along with the copy_file_range() syscall
++	 */
++	void (*copy_file_range) (fuse_req_t req, fuse_ino_t ino_in,
++				 off_t off_in, struct fuse_file_info *fi_in,
++				 fuse_ino_t ino_out, off_t off_out,
++				 struct fuse_file_info *fi_out, size_t len,
++				 int flags);
++
++	/**
++	 * Find next data or hole after the specified offset
++	 *
++	 * If this request is answered with an error code of ENOSYS, this is
++	 * treated as a permanent failure, i.e. all future lseek() requests will
++	 * fail with the same error code without being send to the filesystem
++	 * process.
++	 *
++	 * Valid replies:
++	 *   fuse_reply_lseek
++	 *   fuse_reply_err
++	 *
++	 * @param req request handle
++	 * @param ino the inode number
++	 * @param off offset to start search from
++	 * @param whence either SEEK_DATA or SEEK_HOLE
++	 * @param fi file information
++	 */
++	void (*lseek) (fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
++		       struct fuse_file_info *fi);
++};
++
++/**
++ * Reply with an error code or success.
++ *
++ * Possible requests:
++ *   all except forget
++ *
++ * Whereever possible, error codes should be chosen from the list of
++ * documented error conditions in the corresponding system calls
++ * manpage.
++ *
++ * An error code of ENOSYS is sometimes treated specially. This is
++ * indicated in the documentation of the affected handler functions.
++ *
++ * The following requests may be answered with a zero error code:
++ * unlink, rmdir, rename, flush, release, fsync, fsyncdir, setxattr,
++ * removexattr, setlk.
++ *
++ * @param req request handle
++ * @param err the positive error value, or zero for success
++ * @return zero for success, -errno for failure to send reply
++ */
++int fuse_reply_err(fuse_req_t req, int err);
++
++/**
++ * Don't send reply
++ *
++ * Possible requests:
++ *   forget
++ *   forget_multi
++ *   retrieve_reply
++ *
++ * @param req request handle
++ */
++void fuse_reply_none(fuse_req_t req);
++
++/**
++ * Reply with a directory entry
++ *
++ * Possible requests:
++ *   lookup, mknod, mkdir, symlink, link
++ *
++ * Side effects:
++ *   increments the lookup count on success
++ *
++ * @param req request handle
++ * @param e the entry parameters
++ * @return zero for success, -errno for failure to send reply
++ */
++int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e);
++
++/**
++ * Reply with a directory entry and open parameters
++ *
++ * currently the following members of 'fi' are used:
++ *   fh, direct_io, keep_cache
++ *
++ * Possible requests:
++ *   create
++ *
++ * Side effects:
++ *   increments the lookup count on success
++ *
++ * @param req request handle
++ * @param e the entry parameters
++ * @param fi file information
++ * @return zero for success, -errno for failure to send reply
++ */
++int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
++		      const struct fuse_file_info *fi);
++
++/**
++ * Reply with attributes
++ *
++ * Possible requests:
++ *   getattr, setattr
++ *
++ * @param req request handle
++ * @param attr the attributes
++ * @param attr_timeout	validity timeout (in seconds) for the attributes
++ * @return zero for success, -errno for failure to send reply
++ */
++int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
++		    double attr_timeout);
++
++/**
++ * Reply with the contents of a symbolic link
++ *
++ * Possible requests:
++ *   readlink
++ *
++ * @param req request handle
++ * @param link symbolic link contents
++ * @return zero for success, -errno for failure to send reply
++ */
++int fuse_reply_readlink(fuse_req_t req, const char *link);
++
++/**
++ * Reply with open parameters
++ *
++ * currently the following members of 'fi' are used:
++ *   fh, direct_io, keep_cache
++ *
++ * Possible requests:
++ *   open, opendir
++ *
++ * @param req request handle
++ * @param fi file information
++ * @return zero for success, -errno for failure to send reply
++ */
++int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi);
++
++/**
++ * Reply with number of bytes written
++ *
++ * Possible requests:
++ *   write
++ *
++ * @param req request handle
++ * @param count the number of bytes written
++ * @return zero for success, -errno for failure to send reply
++ */
++int fuse_reply_write(fuse_req_t req, size_t count);
++
++/**
++ * Reply with data
++ *
++ * Possible requests:
++ *   read, readdir, getxattr, listxattr
++ *
++ * @param req request handle
++ * @param buf buffer containing data
++ * @param size the size of data in bytes
++ * @return zero for success, -errno for failure to send reply
++ */
++int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size);
++
++/**
++ * Reply with data copied/moved from buffer(s)
++ *
++ * Zero copy data transfer ("splicing") will be used under
++ * the following circumstances:
++ *
++ * 1. FUSE_CAP_SPLICE_WRITE is set in fuse_conn_info.want, and
++ * 2. the kernel supports splicing from the fuse device
++ *    (FUSE_CAP_SPLICE_WRITE is set in fuse_conn_info.capable), and
++ * 3. *flags* does not contain FUSE_BUF_NO_SPLICE
++ * 4. The amount of data that is provided in file-descriptor backed
++ *    buffers (i.e., buffers for which bufv[n].flags == FUSE_BUF_FD)
++ *    is at least twice the page size.
++ *
++ * In order for SPLICE_F_MOVE to be used, the following additional
++ * conditions have to be fulfilled:
++ *
++ * 1. FUSE_CAP_SPLICE_MOVE is set in fuse_conn_info.want, and
++ * 2. the kernel supports it (i.e, FUSE_CAP_SPLICE_MOVE is set in
++      fuse_conn_info.capable), and
++ * 3. *flags* contains FUSE_BUF_SPLICE_MOVE
++ *
++ * Note that, if splice is used, the data is actually spliced twice:
++ * once into a temporary pipe (to prepend header data), and then again
++ * into the kernel. If some of the provided buffers are memory-backed,
++ * the data in them is copied in step one and spliced in step two.
++ *
++ * The FUSE_BUF_SPLICE_FORCE_SPLICE and FUSE_BUF_SPLICE_NONBLOCK flags
++ * are silently ignored.
++ *
++ * Possible requests:
++ *   read, readdir, getxattr, listxattr
++ *
++ * Side effects:
++ *   when used to return data from a readdirplus() (but not readdir())
++ *   call, increments the lookup count of each returned entry by one
++ *   on success.
++ *
++ * @param req request handle
++ * @param bufv buffer vector
++ * @param flags flags controlling the copy
++ * @return zero for success, -errno for failure to send reply
++ */
++int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
++		    enum fuse_buf_copy_flags flags);
++
++/**
++ * Reply with data vector
++ *
++ * Possible requests:
++ *   read, readdir, getxattr, listxattr
++ *
++ * @param req request handle
++ * @param iov the vector containing the data
++ * @param count the size of vector
++ * @return zero for success, -errno for failure to send reply
++ */
++int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count);
++
++/**
++ * Reply with filesystem statistics
++ *
++ * Possible requests:
++ *   statfs
++ *
++ * @param req request handle
++ * @param stbuf filesystem statistics
++ * @return zero for success, -errno for failure to send reply
++ */
++int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf);
++
++/**
++ * Reply with needed buffer size
++ *
++ * Possible requests:
++ *   getxattr, listxattr
++ *
++ * @param req request handle
++ * @param count the buffer size needed in bytes
++ * @return zero for success, -errno for failure to send reply
++ */
++int fuse_reply_xattr(fuse_req_t req, size_t count);
++
++/**
++ * Reply with file lock information
++ *
++ * Possible requests:
++ *   getlk
++ *
++ * @param req request handle
++ * @param lock the lock information
++ * @return zero for success, -errno for failure to send reply
++ */
++int fuse_reply_lock(fuse_req_t req, const struct flock *lock);
++
++/**
++ * Reply with block index
++ *
++ * Possible requests:
++ *   bmap
++ *
++ * @param req request handle
++ * @param idx block index within device
++ * @return zero for success, -errno for failure to send reply
++ */
++int fuse_reply_bmap(fuse_req_t req, uint64_t idx);
++
++/* ----------------------------------------------------------- *
++ * Filling a buffer in readdir				       *
++ * ----------------------------------------------------------- */
++
++/**
++ * Add a directory entry to the buffer
++ *
++ * Buffer needs to be large enough to hold the entry.  If it's not,
++ * then the entry is not filled in but the size of the entry is still
++ * returned.  The caller can check this by comparing the bufsize
++ * parameter with the returned entry size.  If the entry size is
++ * larger than the buffer size, the operation failed.
++ *
++ * From the 'stbuf' argument the st_ino field and bits 12-15 of the
++ * st_mode field are used.  The other fields are ignored.
++ *
++ * *off* should be any non-zero value that the filesystem can use to
++ * identify the current point in the directory stream. It does not
++ * need to be the actual physical position. A value of zero is
++ * reserved to mean "from the beginning", and should therefore never
++ * be used (the first call to fuse_add_direntry should be passed the
++ * offset of the second directory entry).
++ *
++ * @param req request handle
++ * @param buf the point where the new entry will be added to the buffer
++ * @param bufsize remaining size of the buffer
++ * @param name the name of the entry
++ * @param stbuf the file attributes
++ * @param off the offset of the next entry
++ * @return the space needed for the entry
++ */
++size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
++			 const char *name, const struct stat *stbuf,
++			 off_t off);
++
++/**
++ * Add a directory entry to the buffer with the attributes
++ *
++ * See documentation of `fuse_add_direntry()` for more details.
++ *
++ * @param req request handle
++ * @param buf the point where the new entry will be added to the buffer
++ * @param bufsize remaining size of the buffer
++ * @param name the name of the entry
++ * @param e the directory entry
++ * @param off the offset of the next entry
++ * @return the space needed for the entry
++ */
++size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
++			      const char *name,
++			      const struct fuse_entry_param *e, off_t off);
++
++/**
++ * Reply to ask for data fetch and output buffer preparation.  ioctl
++ * will be retried with the specified input data fetched and output
++ * buffer prepared.
++ *
++ * Possible requests:
++ *   ioctl
++ *
++ * @param req request handle
++ * @param in_iov iovec specifying data to fetch from the caller
++ * @param in_count number of entries in in_iov
++ * @param out_iov iovec specifying addresses to write output to
++ * @param out_count number of entries in out_iov
++ * @return zero for success, -errno for failure to send reply
++ */
++int fuse_reply_ioctl_retry(fuse_req_t req,
++			   const struct iovec *in_iov, size_t in_count,
++			   const struct iovec *out_iov, size_t out_count);
++
++/**
++ * Reply to finish ioctl
++ *
++ * Possible requests:
++ *   ioctl
++ *
++ * @param req request handle
++ * @param result result to be passed to the caller
++ * @param buf buffer containing output data
++ * @param size length of output data
++ */
++int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size);
++
++/**
++ * Reply to finish ioctl with iov buffer
++ *
++ * Possible requests:
++ *   ioctl
++ *
++ * @param req request handle
++ * @param result result to be passed to the caller
++ * @param iov the vector containing the data
++ * @param count the size of vector
++ */
++int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov,
++			 int count);
++
++/**
++ * Reply with poll result event mask
++ *
++ * @param req request handle
++ * @param revents poll result event mask
++ */
++int fuse_reply_poll(fuse_req_t req, unsigned revents);
++
++/**
++ * Reply with offset
++ *
++ * Possible requests:
++ *   lseek
++ *
++ * @param req request handle
++ * @param off offset of next data or hole
++ * @return zero for success, -errno for failure to send reply
++ */
++int fuse_reply_lseek(fuse_req_t req, off_t off);
++
++/* ----------------------------------------------------------- *
++ * Notification						       *
++ * ----------------------------------------------------------- */
++
++/**
++ * Notify IO readiness event
++ *
++ * For more information, please read comment for poll operation.
++ *
++ * @param ph poll handle to notify IO readiness event for
++ */
++int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph);
++
++/**
++ * Notify to invalidate cache for an inode.
++ *
++ * Added in FUSE protocol version 7.12. If the kernel does not support
++ * this (or a newer) version, the function will return -ENOSYS and do
++ * nothing.
++ *
++ * If the filesystem has writeback caching enabled, invalidating an
++ * inode will first trigger a writeback of all dirty pages. The call
++ * will block until all writeback requests have completed and the
++ * inode has been invalidated. It will, however, not wait for
++ * completion of pending writeback requests that have been issued
++ * before.
++ *
++ * If there are no dirty pages, this function will never block.
++ *
++ * @param se the session object
++ * @param ino the inode number
++ * @param off the offset in the inode where to start invalidating
++ *            or negative to invalidate attributes only
++ * @param len the amount of cache to invalidate or 0 for all
++ * @return zero for success, -errno for failure
++ */
++int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
++				     off_t off, off_t len);
++
++/**
++ * Notify to invalidate parent attributes and the dentry matching
++ * parent/name
++ *
++ * To avoid a deadlock this function must not be called in the
++ * execution path of a related filesytem operation or within any code
++ * that could hold a lock that could be needed to execute such an
++ * operation. As of kernel 4.18, a "related operation" is a lookup(),
++ * symlink(), mknod(), mkdir(), unlink(), rename(), link() or create()
++ * request for the parent, and a setattr(), unlink(), rmdir(),
++ * rename(), setxattr(), removexattr(), readdir() or readdirplus()
++ * request for the inode itself.
++ *
++ * When called correctly, this function will never block.
++ *
++ * Added in FUSE protocol version 7.12. If the kernel does not support
++ * this (or a newer) version, the function will return -ENOSYS and do
++ * nothing.
++ *
++ * @param se the session object
++ * @param parent inode number
++ * @param name file name
++ * @param namelen strlen() of file name
++ * @return zero for success, -errno for failure
++ */
++int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
++				     const char *name, size_t namelen);
++
++/**
++ * This function behaves like fuse_lowlevel_notify_inval_entry() with
++ * the following additional effect (at least as of Linux kernel 4.8):
++ *
++ * If the provided *child* inode matches the inode that is currently
++ * associated with the cached dentry, and if there are any inotify
++ * watches registered for the dentry, then the watchers are informed
++ * that the dentry has been deleted.
++ *
++ * To avoid a deadlock this function must not be called while
++ * executing a related filesytem operation or while holding a lock
++ * that could be needed to execute such an operation (see the
++ * description of fuse_lowlevel_notify_inval_entry() for more
++ * details).
++ *
++ * When called correctly, this function will never block.
++ *
++ * Added in FUSE protocol version 7.18. If the kernel does not support
++ * this (or a newer) version, the function will return -ENOSYS and do
++ * nothing.
++ *
++ * @param se the session object
++ * @param parent inode number
++ * @param child inode number
++ * @param name file name
++ * @param namelen strlen() of file name
++ * @return zero for success, -errno for failure
++ */
++int fuse_lowlevel_notify_delete(struct fuse_session *se,
++				fuse_ino_t parent, fuse_ino_t child,
++				const char *name, size_t namelen);
++
++/**
++ * Store data to the kernel buffers
++ *
++ * Synchronously store data in the kernel buffers belonging to the
++ * given inode.  The stored data is marked up-to-date (no read will be
++ * performed against it, unless it's invalidated or evicted from the
++ * cache).
++ *
++ * If the stored data overflows the current file size, then the size
++ * is extended, similarly to a write(2) on the filesystem.
++ *
++ * If this function returns an error, then the store wasn't fully
++ * completed, but it may have been partially completed.
++ *
++ * Added in FUSE protocol version 7.15. If the kernel does not support
++ * this (or a newer) version, the function will return -ENOSYS and do
++ * nothing.
++ *
++ * @param se the session object
++ * @param ino the inode number
++ * @param offset the starting offset into the file to store to
++ * @param bufv buffer vector
++ * @param flags flags controlling the copy
++ * @return zero for success, -errno for failure
++ */
++int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
++			       off_t offset, struct fuse_bufvec *bufv,
++			       enum fuse_buf_copy_flags flags);
++/**
++ * Retrieve data from the kernel buffers
++ *
++ * Retrieve data in the kernel buffers belonging to the given inode.
++ * If successful then the retrieve_reply() method will be called with
++ * the returned data.
++ *
++ * Only present pages are returned in the retrieve reply.  Retrieving
++ * stops when it finds a non-present page and only data prior to that
++ * is returned.
++ *
++ * If this function returns an error, then the retrieve will not be
++ * completed and no reply will be sent.
++ *
++ * This function doesn't change the dirty state of pages in the kernel
++ * buffer.  For dirty pages the write() method will be called
++ * regardless of having been retrieved previously.
++ *
++ * Added in FUSE protocol version 7.15. If the kernel does not support
++ * this (or a newer) version, the function will return -ENOSYS and do
++ * nothing.
++ *
++ * @param se the session object
++ * @param ino the inode number
++ * @param size the number of bytes to retrieve
++ * @param offset the starting offset into the file to retrieve from
++ * @param cookie user data to supply to the reply callback
++ * @return zero for success, -errno for failure
++ */
++int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino,
++				  size_t size, off_t offset, void *cookie);
++
++
++/* ----------------------------------------------------------- *
++ * Utility functions					       *
++ * ----------------------------------------------------------- */
++
++/**
++ * Get the userdata from the request
++ *
++ * @param req request handle
++ * @return the user data passed to fuse_session_new()
++ */
++void *fuse_req_userdata(fuse_req_t req);
++
++/**
++ * Get the context from the request
++ *
++ * The pointer returned by this function will only be valid for the
++ * request's lifetime
++ *
++ * @param req request handle
++ * @return the context structure
++ */
++const struct fuse_ctx *fuse_req_ctx(fuse_req_t req);
++
++/**
++ * Get the current supplementary group IDs for the specified request
++ *
++ * Similar to the getgroups(2) system call, except the return value is
++ * always the total number of group IDs, even if it is larger than the
++ * specified size.
++ *
++ * The current fuse kernel module in linux (as of 2.6.30) doesn't pass
++ * the group list to userspace, hence this function needs to parse
++ * "/proc/$TID/task/$TID/status" to get the group IDs.
++ *
++ * This feature may not be supported on all operating systems.  In
++ * such a case this function will return -ENOSYS.
++ *
++ * @param req request handle
++ * @param size size of given array
++ * @param list array of group IDs to be filled in
++ * @return the total number of supplementary group IDs or -errno on failure
++ */
++int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[]);
++
++/**
++ * Callback function for an interrupt
++ *
++ * @param req interrupted request
++ * @param data user data
++ */
++typedef void (*fuse_interrupt_func_t)(fuse_req_t req, void *data);
++
++/**
++ * Register/unregister callback for an interrupt
++ *
++ * If an interrupt has already happened, then the callback function is
++ * called from within this function, hence it's not possible for
++ * interrupts to be lost.
++ *
++ * @param req request handle
++ * @param func the callback function or NULL for unregister
++ * @param data user data passed to the callback function
++ */
++void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
++			     void *data);
++
++/**
++ * Check if a request has already been interrupted
++ *
++ * @param req request handle
++ * @return 1 if the request has been interrupted, 0 otherwise
++ */
++int fuse_req_interrupted(fuse_req_t req);
++
++
++/* ----------------------------------------------------------- *
++ * Inquiry functions                                           *
++ * ----------------------------------------------------------- */
++
++/**
++ * Print low-level version information to stdout.
++ */
++void fuse_lowlevel_version(void);
++
++/**
++ * Print available low-level options to stdout. This is not an
++ * exhaustive list, but includes only those options that may be of
++ * interest to an end-user of a file system.
++ */
++void fuse_lowlevel_help(void);
++
++/**
++ * Print available options for `fuse_parse_cmdline()`.
++ */
++void fuse_cmdline_help(void);
++
++/* ----------------------------------------------------------- *
++ * Filesystem setup & teardown                                 *
++ * ----------------------------------------------------------- */
++
++struct fuse_cmdline_opts {
++	int singlethread;
++	int foreground;
++	int debug;
++	int nodefault_subtype;
++	char *mountpoint;
++	int show_version;
++	int show_help;
++	int clone_fd;
++	unsigned int max_idle_threads;
++};
++
++/**
++ * Utility function to parse common options for simple file systems
++ * using the low-level API. A help text that describes the available
++ * options can be printed with `fuse_cmdline_help`. A single
++ * non-option argument is treated as the mountpoint. Multiple
++ * non-option arguments will result in an error.
++ *
++ * If neither -o subtype= or -o fsname= options are given, a new
++ * subtype option will be added and set to the basename of the program
++ * (the fsname will remain unset, and then defaults to "fuse").
++ *
++ * Known options will be removed from *args*, unknown options will
++ * remain.
++ *
++ * @param args argument vector (input+output)
++ * @param opts output argument for parsed options
++ * @return 0 on success, -1 on failure
++ */
++int fuse_parse_cmdline(struct fuse_args *args,
++		       struct fuse_cmdline_opts *opts);
++
++/**
++ * Create a low level session.
++ *
++ * Returns a session structure suitable for passing to
++ * fuse_session_mount() and fuse_session_loop().
++ *
++ * This function accepts most file-system independent mount options
++ * (like context, nodev, ro - see mount(8)), as well as the general
++ * fuse mount options listed in mount.fuse(8) (e.g. -o allow_root and
++ * -o default_permissions, but not ``-o use_ino``).  Instead of `-o
++ * debug`, debugging may also enabled with `-d` or `--debug`.
++ *
++ * If not all options are known, an error message is written to stderr
++ * and the function returns NULL.
++ *
++ * Option parsing skips argv[0], which is assumed to contain the
++ * program name. To prevent accidentally passing an option in
++ * argv[0], this element must always be present (even if no options
++ * are specified). It may be set to the empty string ('\0') if no
++ * reasonable value can be provided.
++ *
++ * @param args argument vector
++ * @param op the (low-level) filesystem operations
++ * @param op_size sizeof(struct fuse_lowlevel_ops)
++ * @param userdata user data
++ *
++ * @return the fuse session on success, NULL on failure
++ **/
++struct fuse_session *fuse_session_new(struct fuse_args *args,
++				      const struct fuse_lowlevel_ops *op,
++				      size_t op_size, void *userdata);
++
++/**
++ * Mount a FUSE file system.
++ *
++ * @param mountpoint the mount point path
++ * @param se session object
++ *
++ * @return 0 on success, -1 on failure.
++ **/
++int fuse_session_mount(struct fuse_session *se, const char *mountpoint);
++
++/**
++ * Enter a single threaded, blocking event loop.
++ *
++ * When the event loop terminates because the connection to the FUSE
++ * kernel module has been closed, this function returns zero. This
++ * happens when the filesystem is unmounted regularly (by the
++ * filesystem owner or root running the umount(8) or fusermount(1)
++ * command), or if connection is explicitly severed by writing ``1``
++ * to the``abort`` file in ``/sys/fs/fuse/connections/NNN``. The only
++ * way to distinguish between these two conditions is to check if the
++ * filesystem is still mounted after the session loop returns.
++ *
++ * When some error occurs during request processing, the function
++ * returns a negated errno(3) value.
++ *
++ * If the loop has been terminated because of a signal handler
++ * installed by fuse_set_signal_handlers(), this function returns the
++ * (positive) signal value that triggered the exit.
++ *
++ * @param se the session
++ * @return 0, -errno, or a signal value
++ */
++int fuse_session_loop(struct fuse_session *se);
++
++/**
++ * Enter a multi-threaded event loop.
++ *
++ * For a description of the return value and the conditions when the
++ * event loop exits, refer to the documentation of
++ * fuse_session_loop().
++ *
++ * @param se the session
++ * @param config session loop configuration 
++ * @return see fuse_session_loop()
++ */
++#if FUSE_USE_VERSION < 32
++int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd);
++#define fuse_session_loop_mt(se, clone_fd) fuse_session_loop_mt_31(se, clone_fd)
++#else
++int fuse_session_loop_mt(struct fuse_session *se, struct fuse_loop_config *config);
++#endif
++
++/**
++ * Flag a session as terminated.
++ *
++ * This function is invoked by the POSIX signal handlers, when
++ * registered using fuse_set_signal_handlers(). It will cause any
++ * running event loops to terminate on the next opportunity.
++ *
++ * @param se the session
++ */
++void fuse_session_exit(struct fuse_session *se);
++
++/**
++ * Reset the terminated flag of a session
++ *
++ * @param se the session
++ */
++void fuse_session_reset(struct fuse_session *se);
++
++/**
++ * Query the terminated flag of a session
++ *
++ * @param se the session
++ * @return 1 if exited, 0 if not exited
++ */
++int fuse_session_exited(struct fuse_session *se);
++
++/**
++ * Ensure that file system is unmounted.
++ *
++ * In regular operation, the file system is typically unmounted by the
++ * user calling umount(8) or fusermount(1), which then terminates the
++ * FUSE session loop. However, the session loop may also terminate as
++ * a result of an explicit call to fuse_session_exit() (e.g. by a
++ * signal handler installed by fuse_set_signal_handler()). In this
++ * case the filesystem remains mounted, but any attempt to access it
++ * will block (while the filesystem process is still running) or give
++ * an ESHUTDOWN error (after the filesystem process has terminated).
++ *
++ * If the communication channel with the FUSE kernel module is still
++ * open (i.e., if the session loop was terminated by an explicit call
++ * to fuse_session_exit()), this function will close it and unmount
++ * the filesystem. If the communication channel has been closed by the
++ * kernel, this method will do (almost) nothing.
++ *
++ * NOTE: The above semantics mean that if the connection to the kernel
++ * is terminated via the ``/sys/fs/fuse/connections/NNN/abort`` file,
++ * this method will *not* unmount the filesystem.
++ *
++ * @param se the session
++ */
++void fuse_session_unmount(struct fuse_session *se);
++
++/**
++ * Destroy a session
++ *
++ * @param se the session
++ */
++void fuse_session_destroy(struct fuse_session *se);
++
++/* ----------------------------------------------------------- *
++ * Custom event loop support                                   *
++ * ----------------------------------------------------------- */
++
++/**
++ * Return file descriptor for communication with kernel.
++ *
++ * The file selector can be used to integrate FUSE with a custom event
++ * loop. Whenever data is available for reading on the provided fd,
++ * the event loop should call `fuse_session_receive_buf` followed by
++ * `fuse_session_process_buf` to process the request.
++ *
++ * The returned file descriptor is valid until `fuse_session_unmount`
++ * is called.
++ *
++ * @param se the session
++ * @return a file descriptor
++ */
++int fuse_session_fd(struct fuse_session *se);
++
++/**
++ * Process a raw request supplied in a generic buffer
++ *
++ * The fuse_buf may contain a memory buffer or a pipe file descriptor.
++ *
++ * @param se the session
++ * @param buf the fuse_buf containing the request
++ */
++void fuse_session_process_buf(struct fuse_session *se,
++			      const struct fuse_buf *buf);
++
++/**
++ * Read a raw request from the kernel into the supplied buffer.
++ *
++ * Depending on file system options, system capabilities, and request
++ * size the request is either read into a memory buffer or spliced
++ * into a temporary pipe.
++ *
++ * @param se the session
++ * @param buf the fuse_buf to store the request in
++ * @return the actual size of the raw request, or -errno on error
++ */
++int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* FUSE_LOWLEVEL_H_ */
+diff --git a/tools/virtiofsd/fuse_misc.h b/tools/virtiofsd/fuse_misc.h
+new file mode 100644
+index 0000000000..2f6663ed7d
+--- /dev/null
++++ b/tools/virtiofsd/fuse_misc.h
+@@ -0,0 +1,59 @@
++/*
++  FUSE: Filesystem in Userspace
++  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++
++  This program can be distributed under the terms of the GNU LGPLv2.
++  See the file COPYING.LIB
++*/
++
++#include <pthread.h>
++
++/*
++  Versioned symbols cannot be used in some cases because it
++    - confuse the dynamic linker in uClibc
++    - not supported on MacOSX (in MachO binary format)
++*/
++#if (!defined(__UCLIBC__) && !defined(__APPLE__))
++#define FUSE_SYMVER(x) __asm__(x)
++#else
++#define FUSE_SYMVER(x)
++#endif
++
++#ifndef USE_UCLIBC
++#define fuse_mutex_init(mut) pthread_mutex_init(mut, NULL)
++#else
++/* Is this hack still needed? */
++static inline void fuse_mutex_init(pthread_mutex_t *mut)
++{
++	pthread_mutexattr_t attr;
++	pthread_mutexattr_init(&attr);
++	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
++	pthread_mutex_init(mut, &attr);
++	pthread_mutexattr_destroy(&attr);
++}
++#endif
++
++#ifdef HAVE_STRUCT_STAT_ST_ATIM
++/* Linux */
++#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atim.tv_nsec)
++#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctim.tv_nsec)
++#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtim.tv_nsec)
++#define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atim.tv_nsec = (val)
++#define ST_CTIM_NSEC_SET(stbuf, val) (stbuf)->st_ctim.tv_nsec = (val)
++#define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtim.tv_nsec = (val)
++#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
++/* FreeBSD */
++#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atimespec.tv_nsec)
++#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctimespec.tv_nsec)
++#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtimespec.tv_nsec)
++#define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atimespec.tv_nsec = (val)
++#define ST_CTIM_NSEC_SET(stbuf, val) (stbuf)->st_ctimespec.tv_nsec = (val)
++#define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtimespec.tv_nsec = (val)
++#else
++#define ST_ATIM_NSEC(stbuf) 0
++#define ST_CTIM_NSEC(stbuf) 0
++#define ST_MTIM_NSEC(stbuf) 0
++#define ST_ATIM_NSEC_SET(stbuf, val) do { } while (0)
++#define ST_CTIM_NSEC_SET(stbuf, val) do { } while (0)
++#define ST_MTIM_NSEC_SET(stbuf, val) do { } while (0)
++#endif
+diff --git a/tools/virtiofsd/fuse_opt.h b/tools/virtiofsd/fuse_opt.h
+new file mode 100644
+index 0000000000..d8573e74fd
+--- /dev/null
++++ b/tools/virtiofsd/fuse_opt.h
+@@ -0,0 +1,271 @@
++/*
++  FUSE: Filesystem in Userspace
++  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++
++  This program can be distributed under the terms of the GNU LGPLv2.
++  See the file COPYING.LIB.
++*/
++
++#ifndef FUSE_OPT_H_
++#define FUSE_OPT_H_
++
++/** @file
++ *
++ * This file defines the option parsing interface of FUSE
++ */
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/**
++ * Option description
++ *
++ * This structure describes a single option, and action associated
++ * with it, in case it matches.
++ *
++ * More than one such match may occur, in which case the action for
++ * each match is executed.
++ *
++ * There are three possible actions in case of a match:
++ *
++ * i) An integer (int or unsigned) variable determined by 'offset' is
++ *    set to 'value'
++ *
++ * ii) The processing function is called, with 'value' as the key
++ *
++ * iii) An integer (any) or string (char *) variable determined by
++ *    'offset' is set to the value of an option parameter
++ *
++ * 'offset' should normally be either set to
++ *
++ *  - 'offsetof(struct foo, member)'  actions i) and iii)
++ *
++ *  - -1			      action ii)
++ *
++ * The 'offsetof()' macro is defined in the <stddef.h> header.
++ *
++ * The template determines which options match, and also have an
++ * effect on the action.  Normally the action is either i) or ii), but
++ * if a format is present in the template, then action iii) is
++ * performed.
++ *
++ * The types of templates are:
++ *
++ * 1) "-x", "-foo", "--foo", "--foo-bar", etc.	These match only
++ *   themselves.  Invalid values are "--" and anything beginning
++ *   with "-o"
++ *
++ * 2) "foo", "foo-bar", etc.  These match "-ofoo", "-ofoo-bar" or
++ *    the relevant option in a comma separated option list
++ *
++ * 3) "bar=", "--foo=", etc.  These are variations of 1) and 2)
++ *    which have a parameter
++ *
++ * 4) "bar=%s", "--foo=%lu", etc.  Same matching as above but perform
++ *    action iii).
++ *
++ * 5) "-x ", etc.  Matches either "-xparam" or "-x param" as
++ *    two separate arguments
++ *
++ * 6) "-x %s", etc.  Combination of 4) and 5)
++ *
++ * If the format is "%s", memory is allocated for the string unlike with
++ * scanf().  The previous value (if non-NULL) stored at the this location is
++ * freed.
++ */
++struct fuse_opt {
++	/** Matching template and optional parameter formatting */
++	const char *templ;
++
++	/**
++	 * Offset of variable within 'data' parameter of fuse_opt_parse()
++	 * or -1
++	 */
++	unsigned long offset;
++
++	/**
++	 * Value to set the variable to, or to be passed as 'key' to the
++	 * processing function.	 Ignored if template has a format
++	 */
++	int value;
++};
++
++/**
++ * Key option.	In case of a match, the processing function will be
++ * called with the specified key.
++ */
++#define FUSE_OPT_KEY(templ, key) { templ, -1U, key }
++
++/**
++ * Last option.	 An array of 'struct fuse_opt' must end with a NULL
++ * template value
++ */
++#define FUSE_OPT_END { NULL, 0, 0 }
++
++/**
++ * Argument list
++ */
++struct fuse_args {
++	/** Argument count */
++	int argc;
++
++	/** Argument vector.  NULL terminated */
++	char **argv;
++
++	/** Is 'argv' allocated? */
++	int allocated;
++};
++
++/**
++ * Initializer for 'struct fuse_args'
++ */
++#define FUSE_ARGS_INIT(argc, argv) { argc, argv, 0 }
++
++/**
++ * Key value passed to the processing function if an option did not
++ * match any template
++ */
++#define FUSE_OPT_KEY_OPT     -1
++
++/**
++ * Key value passed to the processing function for all non-options
++ *
++ * Non-options are the arguments beginning with a character other than
++ * '-' or all arguments after the special '--' option
++ */
++#define FUSE_OPT_KEY_NONOPT  -2
++
++/**
++ * Special key value for options to keep
++ *
++ * Argument is not passed to processing function, but behave as if the
++ * processing function returned 1
++ */
++#define FUSE_OPT_KEY_KEEP -3
++
++/**
++ * Special key value for options to discard
++ *
++ * Argument is not passed to processing function, but behave as if the
++ * processing function returned zero
++ */
++#define FUSE_OPT_KEY_DISCARD -4
++
++/**
++ * Processing function
++ *
++ * This function is called if
++ *    - option did not match any 'struct fuse_opt'
++ *    - argument is a non-option
++ *    - option did match and offset was set to -1
++ *
++ * The 'arg' parameter will always contain the whole argument or
++ * option including the parameter if exists.  A two-argument option
++ * ("-x foo") is always converted to single argument option of the
++ * form "-xfoo" before this function is called.
++ *
++ * Options of the form '-ofoo' are passed to this function without the
++ * '-o' prefix.
++ *
++ * The return value of this function determines whether this argument
++ * is to be inserted into the output argument vector, or discarded.
++ *
++ * @param data is the user data passed to the fuse_opt_parse() function
++ * @param arg is the whole argument or option
++ * @param key determines why the processing function was called
++ * @param outargs the current output argument list
++ * @return -1 on error, 0 if arg is to be discarded, 1 if arg should be kept
++ */
++typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key,
++			       struct fuse_args *outargs);
++
++/**
++ * Option parsing function
++ *
++ * If 'args' was returned from a previous call to fuse_opt_parse() or
++ * it was constructed from
++ *
++ * A NULL 'args' is equivalent to an empty argument vector
++ *
++ * A NULL 'opts' is equivalent to an 'opts' array containing a single
++ * end marker
++ *
++ * A NULL 'proc' is equivalent to a processing function always
++ * returning '1'
++ *
++ * @param args is the input and output argument list
++ * @param data is the user data
++ * @param opts is the option description array
++ * @param proc is the processing function
++ * @return -1 on error, 0 on success
++ */
++int fuse_opt_parse(struct fuse_args *args, void *data,
++		   const struct fuse_opt opts[], fuse_opt_proc_t proc);
++
++/**
++ * Add an option to a comma separated option list
++ *
++ * @param opts is a pointer to an option list, may point to a NULL value
++ * @param opt is the option to add
++ * @return -1 on allocation error, 0 on success
++ */
++int fuse_opt_add_opt(char **opts, const char *opt);
++
++/**
++ * Add an option, escaping commas, to a comma separated option list
++ *
++ * @param opts is a pointer to an option list, may point to a NULL value
++ * @param opt is the option to add
++ * @return -1 on allocation error, 0 on success
++ */
++int fuse_opt_add_opt_escaped(char **opts, const char *opt);
++
++/**
++ * Add an argument to a NULL terminated argument vector
++ *
++ * @param args is the structure containing the current argument list
++ * @param arg is the new argument to add
++ * @return -1 on allocation error, 0 on success
++ */
++int fuse_opt_add_arg(struct fuse_args *args, const char *arg);
++
++/**
++ * Add an argument at the specified position in a NULL terminated
++ * argument vector
++ *
++ * Adds the argument to the N-th position.  This is useful for adding
++ * options at the beginning of the array which must not come after the
++ * special '--' option.
++ *
++ * @param args is the structure containing the current argument list
++ * @param pos is the position at which to add the argument
++ * @param arg is the new argument to add
++ * @return -1 on allocation error, 0 on success
++ */
++int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg);
++
++/**
++ * Free the contents of argument list
++ *
++ * The structure itself is not freed
++ *
++ * @param args is the structure containing the argument list
++ */
++void fuse_opt_free_args(struct fuse_args *args);
++
++
++/**
++ * Check if an option matches
++ *
++ * @param opts is the option description array
++ * @param opt is the option to match
++ * @return 1 if a match is found, 0 if not
++ */
++int fuse_opt_match(const struct fuse_opt opts[], const char *opt);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* FUSE_OPT_H_ */
+diff --git a/tools/virtiofsd/passthrough_helpers.h b/tools/virtiofsd/passthrough_helpers.h
+new file mode 100644
+index 0000000000..6b77c33600
+--- /dev/null
++++ b/tools/virtiofsd/passthrough_helpers.h
+@@ -0,0 +1,76 @@
++/*
++ * FUSE: Filesystem in Userspace
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE
++ */
++
++/*
++ * Creates files on the underlying file system in response to a FUSE_MKNOD
++ * operation
++ */
++static int mknod_wrapper(int dirfd, const char *path, const char *link,
++	int mode, dev_t rdev)
++{
++	int res;
++
++	if (S_ISREG(mode)) {
++		res = openat(dirfd, path, O_CREAT | O_EXCL | O_WRONLY, mode);
++		if (res >= 0)
++			res = close(res);
++	} else if (S_ISDIR(mode)) {
++		res = mkdirat(dirfd, path, mode);
++	} else if (S_ISLNK(mode) && link != NULL) {
++		res = symlinkat(link, dirfd, path);
++	} else if (S_ISFIFO(mode)) {
++		res = mkfifoat(dirfd, path, mode);
++#ifdef __FreeBSD__
++	} else if (S_ISSOCK(mode)) {
++		struct sockaddr_un su;
++		int fd;
++
++		if (strlen(path) >= sizeof(su.sun_path)) {
++			errno = ENAMETOOLONG;
++			return -1;
++		}
++		fd = socket(AF_UNIX, SOCK_STREAM, 0);
++		if (fd >= 0) {
++			/*
++			 * We must bind the socket to the underlying file
++			 * system to create the socket file, even though
++			 * we'll never listen on this socket.
++			 */
++			su.sun_family = AF_UNIX;
++			strncpy(su.sun_path, path, sizeof(su.sun_path));
++			res = bindat(dirfd, fd, (struct sockaddr*)&su,
++				sizeof(su));
++			if (res == 0)
++				close(fd);
++		} else {
++			res = -1;
++		}
++#endif
++	} else {
++		res = mknodat(dirfd, path, mode, rdev);
++	}
++
++	return res;
++}
diff --git a/0011-virtiofsd-Pull-in-kernel-s-fuse.h.patch b/0011-virtiofsd-Pull-in-kernel-s-fuse.h.patch
new file mode 100644
index 0000000..fbf4e25
--- /dev/null
+++ b/0011-virtiofsd-Pull-in-kernel-s-fuse.h.patch
@@ -0,0 +1,929 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:40 +0000
+Subject: [PATCH] virtiofsd: Pull in kernel's fuse.h
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Update scripts/update-linux-headers.sh to add fuse.h and
+use it to pull in fuse.h from the kernel; from v5.5-rc1
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit a62a9e192bc5f0aa0bc076b51db5a069add87c78)
+---
+ include/standard-headers/linux/fuse.h | 891 ++++++++++++++++++++++++++
+ scripts/update-linux-headers.sh       |   1 +
+ 2 files changed, 892 insertions(+)
+ create mode 100644 include/standard-headers/linux/fuse.h
+
+diff --git a/include/standard-headers/linux/fuse.h b/include/standard-headers/linux/fuse.h
+new file mode 100644
+index 0000000000..f4df0a40f6
+--- /dev/null
++++ b/include/standard-headers/linux/fuse.h
+@@ -0,0 +1,891 @@
++/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) */
++/*
++    This file defines the kernel interface of FUSE
++    Copyright (C) 2001-2008  Miklos Szeredi <miklos@szeredi.hu>
++
++    This program can be distributed under the terms of the GNU GPL.
++    See the file COPYING.
++
++    This -- and only this -- header file may also be distributed under
++    the terms of the BSD Licence as follows:
++
++    Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved.
++
++    Redistribution and use in source and binary forms, with or without
++    modification, are permitted provided that the following conditions
++    are met:
++    1. Redistributions of source code must retain the above copyright
++       notice, this list of conditions and the following disclaimer.
++    2. Redistributions in binary form must reproduce the above copyright
++       notice, this list of conditions and the following disclaimer in the
++       documentation and/or other materials provided with the distribution.
++
++    THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
++    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++    ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
++    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++    SUCH DAMAGE.
++*/
++
++/*
++ * This file defines the kernel interface of FUSE
++ *
++ * Protocol changelog:
++ *
++ * 7.1:
++ *  - add the following messages:
++ *      FUSE_SETATTR, FUSE_SYMLINK, FUSE_MKNOD, FUSE_MKDIR, FUSE_UNLINK,
++ *      FUSE_RMDIR, FUSE_RENAME, FUSE_LINK, FUSE_OPEN, FUSE_READ, FUSE_WRITE,
++ *      FUSE_RELEASE, FUSE_FSYNC, FUSE_FLUSH, FUSE_SETXATTR, FUSE_GETXATTR,
++ *      FUSE_LISTXATTR, FUSE_REMOVEXATTR, FUSE_OPENDIR, FUSE_READDIR,
++ *      FUSE_RELEASEDIR
++ *  - add padding to messages to accommodate 32-bit servers on 64-bit kernels
++ *
++ * 7.2:
++ *  - add FOPEN_DIRECT_IO and FOPEN_KEEP_CACHE flags
++ *  - add FUSE_FSYNCDIR message
++ *
++ * 7.3:
++ *  - add FUSE_ACCESS message
++ *  - add FUSE_CREATE message
++ *  - add filehandle to fuse_setattr_in
++ *
++ * 7.4:
++ *  - add frsize to fuse_kstatfs
++ *  - clean up request size limit checking
++ *
++ * 7.5:
++ *  - add flags and max_write to fuse_init_out
++ *
++ * 7.6:
++ *  - add max_readahead to fuse_init_in and fuse_init_out
++ *
++ * 7.7:
++ *  - add FUSE_INTERRUPT message
++ *  - add POSIX file lock support
++ *
++ * 7.8:
++ *  - add lock_owner and flags fields to fuse_release_in
++ *  - add FUSE_BMAP message
++ *  - add FUSE_DESTROY message
++ *
++ * 7.9:
++ *  - new fuse_getattr_in input argument of GETATTR
++ *  - add lk_flags in fuse_lk_in
++ *  - add lock_owner field to fuse_setattr_in, fuse_read_in and fuse_write_in
++ *  - add blksize field to fuse_attr
++ *  - add file flags field to fuse_read_in and fuse_write_in
++ *  - Add ATIME_NOW and MTIME_NOW flags to fuse_setattr_in
++ *
++ * 7.10
++ *  - add nonseekable open flag
++ *
++ * 7.11
++ *  - add IOCTL message
++ *  - add unsolicited notification support
++ *  - add POLL message and NOTIFY_POLL notification
++ *
++ * 7.12
++ *  - add umask flag to input argument of create, mknod and mkdir
++ *  - add notification messages for invalidation of inodes and
++ *    directory entries
++ *
++ * 7.13
++ *  - make max number of background requests and congestion threshold
++ *    tunables
++ *
++ * 7.14
++ *  - add splice support to fuse device
++ *
++ * 7.15
++ *  - add store notify
++ *  - add retrieve notify
++ *
++ * 7.16
++ *  - add BATCH_FORGET request
++ *  - FUSE_IOCTL_UNRESTRICTED shall now return with array of 'struct
++ *    fuse_ioctl_iovec' instead of ambiguous 'struct iovec'
++ *  - add FUSE_IOCTL_32BIT flag
++ *
++ * 7.17
++ *  - add FUSE_FLOCK_LOCKS and FUSE_RELEASE_FLOCK_UNLOCK
++ *
++ * 7.18
++ *  - add FUSE_IOCTL_DIR flag
++ *  - add FUSE_NOTIFY_DELETE
++ *
++ * 7.19
++ *  - add FUSE_FALLOCATE
++ *
++ * 7.20
++ *  - add FUSE_AUTO_INVAL_DATA
++ *
++ * 7.21
++ *  - add FUSE_READDIRPLUS
++ *  - send the requested events in POLL request
++ *
++ * 7.22
++ *  - add FUSE_ASYNC_DIO
++ *
++ * 7.23
++ *  - add FUSE_WRITEBACK_CACHE
++ *  - add time_gran to fuse_init_out
++ *  - add reserved space to fuse_init_out
++ *  - add FATTR_CTIME
++ *  - add ctime and ctimensec to fuse_setattr_in
++ *  - add FUSE_RENAME2 request
++ *  - add FUSE_NO_OPEN_SUPPORT flag
++ *
++ *  7.24
++ *  - add FUSE_LSEEK for SEEK_HOLE and SEEK_DATA support
++ *
++ *  7.25
++ *  - add FUSE_PARALLEL_DIROPS
++ *
++ *  7.26
++ *  - add FUSE_HANDLE_KILLPRIV
++ *  - add FUSE_POSIX_ACL
++ *
++ *  7.27
++ *  - add FUSE_ABORT_ERROR
++ *
++ *  7.28
++ *  - add FUSE_COPY_FILE_RANGE
++ *  - add FOPEN_CACHE_DIR
++ *  - add FUSE_MAX_PAGES, add max_pages to init_out
++ *  - add FUSE_CACHE_SYMLINKS
++ *
++ *  7.29
++ *  - add FUSE_NO_OPENDIR_SUPPORT flag
++ *
++ *  7.30
++ *  - add FUSE_EXPLICIT_INVAL_DATA
++ *  - add FUSE_IOCTL_COMPAT_X32
++ *
++ *  7.31
++ *  - add FUSE_WRITE_KILL_PRIV flag
++ *  - add FUSE_SETUPMAPPING and FUSE_REMOVEMAPPING
++ *  - add map_alignment to fuse_init_out, add FUSE_MAP_ALIGNMENT flag
++ */
++
++#ifndef _LINUX_FUSE_H
++#define _LINUX_FUSE_H
++
++#include <stdint.h>
++
++/*
++ * Version negotiation:
++ *
++ * Both the kernel and userspace send the version they support in the
++ * INIT request and reply respectively.
++ *
++ * If the major versions match then both shall use the smallest
++ * of the two minor versions for communication.
++ *
++ * If the kernel supports a larger major version, then userspace shall
++ * reply with the major version it supports, ignore the rest of the
++ * INIT message and expect a new INIT message from the kernel with a
++ * matching major version.
++ *
++ * If the library supports a larger major version, then it shall fall
++ * back to the major protocol version sent by the kernel for
++ * communication and reply with that major version (and an arbitrary
++ * supported minor version).
++ */
++
++/** Version number of this interface */
++#define FUSE_KERNEL_VERSION 7
++
++/** Minor version number of this interface */
++#define FUSE_KERNEL_MINOR_VERSION 31
++
++/** The node ID of the root inode */
++#define FUSE_ROOT_ID 1
++
++/* Make sure all structures are padded to 64bit boundary, so 32bit
++   userspace works under 64bit kernels */
++
++struct fuse_attr {
++	uint64_t	ino;
++	uint64_t	size;
++	uint64_t	blocks;
++	uint64_t	atime;
++	uint64_t	mtime;
++	uint64_t	ctime;
++	uint32_t	atimensec;
++	uint32_t	mtimensec;
++	uint32_t	ctimensec;
++	uint32_t	mode;
++	uint32_t	nlink;
++	uint32_t	uid;
++	uint32_t	gid;
++	uint32_t	rdev;
++	uint32_t	blksize;
++	uint32_t	padding;
++};
++
++struct fuse_kstatfs {
++	uint64_t	blocks;
++	uint64_t	bfree;
++	uint64_t	bavail;
++	uint64_t	files;
++	uint64_t	ffree;
++	uint32_t	bsize;
++	uint32_t	namelen;
++	uint32_t	frsize;
++	uint32_t	padding;
++	uint32_t	spare[6];
++};
++
++struct fuse_file_lock {
++	uint64_t	start;
++	uint64_t	end;
++	uint32_t	type;
++	uint32_t	pid; /* tgid */
++};
++
++/**
++ * Bitmasks for fuse_setattr_in.valid
++ */
++#define FATTR_MODE	(1 << 0)
++#define FATTR_UID	(1 << 1)
++#define FATTR_GID	(1 << 2)
++#define FATTR_SIZE	(1 << 3)
++#define FATTR_ATIME	(1 << 4)
++#define FATTR_MTIME	(1 << 5)
++#define FATTR_FH	(1 << 6)
++#define FATTR_ATIME_NOW	(1 << 7)
++#define FATTR_MTIME_NOW	(1 << 8)
++#define FATTR_LOCKOWNER	(1 << 9)
++#define FATTR_CTIME	(1 << 10)
++
++/**
++ * Flags returned by the OPEN request
++ *
++ * FOPEN_DIRECT_IO: bypass page cache for this open file
++ * FOPEN_KEEP_CACHE: don't invalidate the data cache on open
++ * FOPEN_NONSEEKABLE: the file is not seekable
++ * FOPEN_CACHE_DIR: allow caching this directory
++ * FOPEN_STREAM: the file is stream-like (no file position at all)
++ */
++#define FOPEN_DIRECT_IO		(1 << 0)
++#define FOPEN_KEEP_CACHE	(1 << 1)
++#define FOPEN_NONSEEKABLE	(1 << 2)
++#define FOPEN_CACHE_DIR		(1 << 3)
++#define FOPEN_STREAM		(1 << 4)
++
++/**
++ * INIT request/reply flags
++ *
++ * FUSE_ASYNC_READ: asynchronous read requests
++ * FUSE_POSIX_LOCKS: remote locking for POSIX file locks
++ * FUSE_FILE_OPS: kernel sends file handle for fstat, etc... (not yet supported)
++ * FUSE_ATOMIC_O_TRUNC: handles the O_TRUNC open flag in the filesystem
++ * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
++ * FUSE_BIG_WRITES: filesystem can handle write size larger than 4kB
++ * FUSE_DONT_MASK: don't apply umask to file mode on create operations
++ * FUSE_SPLICE_WRITE: kernel supports splice write on the device
++ * FUSE_SPLICE_MOVE: kernel supports splice move on the device
++ * FUSE_SPLICE_READ: kernel supports splice read on the device
++ * FUSE_FLOCK_LOCKS: remote locking for BSD style file locks
++ * FUSE_HAS_IOCTL_DIR: kernel supports ioctl on directories
++ * FUSE_AUTO_INVAL_DATA: automatically invalidate cached pages
++ * FUSE_DO_READDIRPLUS: do READDIRPLUS (READDIR+LOOKUP in one)
++ * FUSE_READDIRPLUS_AUTO: adaptive readdirplus
++ * FUSE_ASYNC_DIO: asynchronous direct I/O submission
++ * FUSE_WRITEBACK_CACHE: use writeback cache for buffered writes
++ * FUSE_NO_OPEN_SUPPORT: kernel supports zero-message opens
++ * FUSE_PARALLEL_DIROPS: allow parallel lookups and readdir
++ * FUSE_HANDLE_KILLPRIV: fs handles killing suid/sgid/cap on write/chown/trunc
++ * FUSE_POSIX_ACL: filesystem supports posix acls
++ * FUSE_ABORT_ERROR: reading the device after abort returns ECONNABORTED
++ * FUSE_MAX_PAGES: init_out.max_pages contains the max number of req pages
++ * FUSE_CACHE_SYMLINKS: cache READLINK responses
++ * FUSE_NO_OPENDIR_SUPPORT: kernel supports zero-message opendir
++ * FUSE_EXPLICIT_INVAL_DATA: only invalidate cached pages on explicit request
++ * FUSE_MAP_ALIGNMENT: map_alignment field is valid
++ */
++#define FUSE_ASYNC_READ		(1 << 0)
++#define FUSE_POSIX_LOCKS	(1 << 1)
++#define FUSE_FILE_OPS		(1 << 2)
++#define FUSE_ATOMIC_O_TRUNC	(1 << 3)
++#define FUSE_EXPORT_SUPPORT	(1 << 4)
++#define FUSE_BIG_WRITES		(1 << 5)
++#define FUSE_DONT_MASK		(1 << 6)
++#define FUSE_SPLICE_WRITE	(1 << 7)
++#define FUSE_SPLICE_MOVE	(1 << 8)
++#define FUSE_SPLICE_READ	(1 << 9)
++#define FUSE_FLOCK_LOCKS	(1 << 10)
++#define FUSE_HAS_IOCTL_DIR	(1 << 11)
++#define FUSE_AUTO_INVAL_DATA	(1 << 12)
++#define FUSE_DO_READDIRPLUS	(1 << 13)
++#define FUSE_READDIRPLUS_AUTO	(1 << 14)
++#define FUSE_ASYNC_DIO		(1 << 15)
++#define FUSE_WRITEBACK_CACHE	(1 << 16)
++#define FUSE_NO_OPEN_SUPPORT	(1 << 17)
++#define FUSE_PARALLEL_DIROPS    (1 << 18)
++#define FUSE_HANDLE_KILLPRIV	(1 << 19)
++#define FUSE_POSIX_ACL		(1 << 20)
++#define FUSE_ABORT_ERROR	(1 << 21)
++#define FUSE_MAX_PAGES		(1 << 22)
++#define FUSE_CACHE_SYMLINKS	(1 << 23)
++#define FUSE_NO_OPENDIR_SUPPORT (1 << 24)
++#define FUSE_EXPLICIT_INVAL_DATA (1 << 25)
++#define FUSE_MAP_ALIGNMENT	(1 << 26)
++
++/**
++ * CUSE INIT request/reply flags
++ *
++ * CUSE_UNRESTRICTED_IOCTL:  use unrestricted ioctl
++ */
++#define CUSE_UNRESTRICTED_IOCTL	(1 << 0)
++
++/**
++ * Release flags
++ */
++#define FUSE_RELEASE_FLUSH	(1 << 0)
++#define FUSE_RELEASE_FLOCK_UNLOCK	(1 << 1)
++
++/**
++ * Getattr flags
++ */
++#define FUSE_GETATTR_FH		(1 << 0)
++
++/**
++ * Lock flags
++ */
++#define FUSE_LK_FLOCK		(1 << 0)
++
++/**
++ * WRITE flags
++ *
++ * FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed
++ * FUSE_WRITE_LOCKOWNER: lock_owner field is valid
++ * FUSE_WRITE_KILL_PRIV: kill suid and sgid bits
++ */
++#define FUSE_WRITE_CACHE	(1 << 0)
++#define FUSE_WRITE_LOCKOWNER	(1 << 1)
++#define FUSE_WRITE_KILL_PRIV	(1 << 2)
++
++/**
++ * Read flags
++ */
++#define FUSE_READ_LOCKOWNER	(1 << 1)
++
++/**
++ * Ioctl flags
++ *
++ * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine
++ * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed
++ * FUSE_IOCTL_RETRY: retry with new iovecs
++ * FUSE_IOCTL_32BIT: 32bit ioctl
++ * FUSE_IOCTL_DIR: is a directory
++ * FUSE_IOCTL_COMPAT_X32: x32 compat ioctl on 64bit machine (64bit time_t)
++ *
++ * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs
++ */
++#define FUSE_IOCTL_COMPAT	(1 << 0)
++#define FUSE_IOCTL_UNRESTRICTED	(1 << 1)
++#define FUSE_IOCTL_RETRY	(1 << 2)
++#define FUSE_IOCTL_32BIT	(1 << 3)
++#define FUSE_IOCTL_DIR		(1 << 4)
++#define FUSE_IOCTL_COMPAT_X32	(1 << 5)
++
++#define FUSE_IOCTL_MAX_IOV	256
++
++/**
++ * Poll flags
++ *
++ * FUSE_POLL_SCHEDULE_NOTIFY: request poll notify
++ */
++#define FUSE_POLL_SCHEDULE_NOTIFY (1 << 0)
++
++/**
++ * Fsync flags
++ *
++ * FUSE_FSYNC_FDATASYNC: Sync data only, not metadata
++ */
++#define FUSE_FSYNC_FDATASYNC	(1 << 0)
++
++enum fuse_opcode {
++	FUSE_LOOKUP		= 1,
++	FUSE_FORGET		= 2,  /* no reply */
++	FUSE_GETATTR		= 3,
++	FUSE_SETATTR		= 4,
++	FUSE_READLINK		= 5,
++	FUSE_SYMLINK		= 6,
++	FUSE_MKNOD		= 8,
++	FUSE_MKDIR		= 9,
++	FUSE_UNLINK		= 10,
++	FUSE_RMDIR		= 11,
++	FUSE_RENAME		= 12,
++	FUSE_LINK		= 13,
++	FUSE_OPEN		= 14,
++	FUSE_READ		= 15,
++	FUSE_WRITE		= 16,
++	FUSE_STATFS		= 17,
++	FUSE_RELEASE		= 18,
++	FUSE_FSYNC		= 20,
++	FUSE_SETXATTR		= 21,
++	FUSE_GETXATTR		= 22,
++	FUSE_LISTXATTR		= 23,
++	FUSE_REMOVEXATTR	= 24,
++	FUSE_FLUSH		= 25,
++	FUSE_INIT		= 26,
++	FUSE_OPENDIR		= 27,
++	FUSE_READDIR		= 28,
++	FUSE_RELEASEDIR		= 29,
++	FUSE_FSYNCDIR		= 30,
++	FUSE_GETLK		= 31,
++	FUSE_SETLK		= 32,
++	FUSE_SETLKW		= 33,
++	FUSE_ACCESS		= 34,
++	FUSE_CREATE		= 35,
++	FUSE_INTERRUPT		= 36,
++	FUSE_BMAP		= 37,
++	FUSE_DESTROY		= 38,
++	FUSE_IOCTL		= 39,
++	FUSE_POLL		= 40,
++	FUSE_NOTIFY_REPLY	= 41,
++	FUSE_BATCH_FORGET	= 42,
++	FUSE_FALLOCATE		= 43,
++	FUSE_READDIRPLUS	= 44,
++	FUSE_RENAME2		= 45,
++	FUSE_LSEEK		= 46,
++	FUSE_COPY_FILE_RANGE	= 47,
++	FUSE_SETUPMAPPING	= 48,
++	FUSE_REMOVEMAPPING	= 49,
++
++	/* CUSE specific operations */
++	CUSE_INIT		= 4096,
++
++	/* Reserved opcodes: helpful to detect structure endian-ness */
++	CUSE_INIT_BSWAP_RESERVED	= 1048576,	/* CUSE_INIT << 8 */
++	FUSE_INIT_BSWAP_RESERVED	= 436207616,	/* FUSE_INIT << 24 */
++};
++
++enum fuse_notify_code {
++	FUSE_NOTIFY_POLL   = 1,
++	FUSE_NOTIFY_INVAL_INODE = 2,
++	FUSE_NOTIFY_INVAL_ENTRY = 3,
++	FUSE_NOTIFY_STORE = 4,
++	FUSE_NOTIFY_RETRIEVE = 5,
++	FUSE_NOTIFY_DELETE = 6,
++	FUSE_NOTIFY_CODE_MAX,
++};
++
++/* The read buffer is required to be at least 8k, but may be much larger */
++#define FUSE_MIN_READ_BUFFER 8192
++
++#define FUSE_COMPAT_ENTRY_OUT_SIZE 120
++
++struct fuse_entry_out {
++	uint64_t	nodeid;		/* Inode ID */
++	uint64_t	generation;	/* Inode generation: nodeid:gen must
++					   be unique for the fs's lifetime */
++	uint64_t	entry_valid;	/* Cache timeout for the name */
++	uint64_t	attr_valid;	/* Cache timeout for the attributes */
++	uint32_t	entry_valid_nsec;
++	uint32_t	attr_valid_nsec;
++	struct fuse_attr attr;
++};
++
++struct fuse_forget_in {
++	uint64_t	nlookup;
++};
++
++struct fuse_forget_one {
++	uint64_t	nodeid;
++	uint64_t	nlookup;
++};
++
++struct fuse_batch_forget_in {
++	uint32_t	count;
++	uint32_t	dummy;
++};
++
++struct fuse_getattr_in {
++	uint32_t	getattr_flags;
++	uint32_t	dummy;
++	uint64_t	fh;
++};
++
++#define FUSE_COMPAT_ATTR_OUT_SIZE 96
++
++struct fuse_attr_out {
++	uint64_t	attr_valid;	/* Cache timeout for the attributes */
++	uint32_t	attr_valid_nsec;
++	uint32_t	dummy;
++	struct fuse_attr attr;
++};
++
++#define FUSE_COMPAT_MKNOD_IN_SIZE 8
++
++struct fuse_mknod_in {
++	uint32_t	mode;
++	uint32_t	rdev;
++	uint32_t	umask;
++	uint32_t	padding;
++};
++
++struct fuse_mkdir_in {
++	uint32_t	mode;
++	uint32_t	umask;
++};
++
++struct fuse_rename_in {
++	uint64_t	newdir;
++};
++
++struct fuse_rename2_in {
++	uint64_t	newdir;
++	uint32_t	flags;
++	uint32_t	padding;
++};
++
++struct fuse_link_in {
++	uint64_t	oldnodeid;
++};
++
++struct fuse_setattr_in {
++	uint32_t	valid;
++	uint32_t	padding;
++	uint64_t	fh;
++	uint64_t	size;
++	uint64_t	lock_owner;
++	uint64_t	atime;
++	uint64_t	mtime;
++	uint64_t	ctime;
++	uint32_t	atimensec;
++	uint32_t	mtimensec;
++	uint32_t	ctimensec;
++	uint32_t	mode;
++	uint32_t	unused4;
++	uint32_t	uid;
++	uint32_t	gid;
++	uint32_t	unused5;
++};
++
++struct fuse_open_in {
++	uint32_t	flags;
++	uint32_t	unused;
++};
++
++struct fuse_create_in {
++	uint32_t	flags;
++	uint32_t	mode;
++	uint32_t	umask;
++	uint32_t	padding;
++};
++
++struct fuse_open_out {
++	uint64_t	fh;
++	uint32_t	open_flags;
++	uint32_t	padding;
++};
++
++struct fuse_release_in {
++	uint64_t	fh;
++	uint32_t	flags;
++	uint32_t	release_flags;
++	uint64_t	lock_owner;
++};
++
++struct fuse_flush_in {
++	uint64_t	fh;
++	uint32_t	unused;
++	uint32_t	padding;
++	uint64_t	lock_owner;
++};
++
++struct fuse_read_in {
++	uint64_t	fh;
++	uint64_t	offset;
++	uint32_t	size;
++	uint32_t	read_flags;
++	uint64_t	lock_owner;
++	uint32_t	flags;
++	uint32_t	padding;
++};
++
++#define FUSE_COMPAT_WRITE_IN_SIZE 24
++
++struct fuse_write_in {
++	uint64_t	fh;
++	uint64_t	offset;
++	uint32_t	size;
++	uint32_t	write_flags;
++	uint64_t	lock_owner;
++	uint32_t	flags;
++	uint32_t	padding;
++};
++
++struct fuse_write_out {
++	uint32_t	size;
++	uint32_t	padding;
++};
++
++#define FUSE_COMPAT_STATFS_SIZE 48
++
++struct fuse_statfs_out {
++	struct fuse_kstatfs st;
++};
++
++struct fuse_fsync_in {
++	uint64_t	fh;
++	uint32_t	fsync_flags;
++	uint32_t	padding;
++};
++
++struct fuse_setxattr_in {
++	uint32_t	size;
++	uint32_t	flags;
++};
++
++struct fuse_getxattr_in {
++	uint32_t	size;
++	uint32_t	padding;
++};
++
++struct fuse_getxattr_out {
++	uint32_t	size;
++	uint32_t	padding;
++};
++
++struct fuse_lk_in {
++	uint64_t	fh;
++	uint64_t	owner;
++	struct fuse_file_lock lk;
++	uint32_t	lk_flags;
++	uint32_t	padding;
++};
++
++struct fuse_lk_out {
++	struct fuse_file_lock lk;
++};
++
++struct fuse_access_in {
++	uint32_t	mask;
++	uint32_t	padding;
++};
++
++struct fuse_init_in {
++	uint32_t	major;
++	uint32_t	minor;
++	uint32_t	max_readahead;
++	uint32_t	flags;
++};
++
++#define FUSE_COMPAT_INIT_OUT_SIZE 8
++#define FUSE_COMPAT_22_INIT_OUT_SIZE 24
++
++struct fuse_init_out {
++	uint32_t	major;
++	uint32_t	minor;
++	uint32_t	max_readahead;
++	uint32_t	flags;
++	uint16_t	max_background;
++	uint16_t	congestion_threshold;
++	uint32_t	max_write;
++	uint32_t	time_gran;
++	uint16_t	max_pages;
++	uint16_t	map_alignment;
++	uint32_t	unused[8];
++};
++
++#define CUSE_INIT_INFO_MAX 4096
++
++struct cuse_init_in {
++	uint32_t	major;
++	uint32_t	minor;
++	uint32_t	unused;
++	uint32_t	flags;
++};
++
++struct cuse_init_out {
++	uint32_t	major;
++	uint32_t	minor;
++	uint32_t	unused;
++	uint32_t	flags;
++	uint32_t	max_read;
++	uint32_t	max_write;
++	uint32_t	dev_major;		/* chardev major */
++	uint32_t	dev_minor;		/* chardev minor */
++	uint32_t	spare[10];
++};
++
++struct fuse_interrupt_in {
++	uint64_t	unique;
++};
++
++struct fuse_bmap_in {
++	uint64_t	block;
++	uint32_t	blocksize;
++	uint32_t	padding;
++};
++
++struct fuse_bmap_out {
++	uint64_t	block;
++};
++
++struct fuse_ioctl_in {
++	uint64_t	fh;
++	uint32_t	flags;
++	uint32_t	cmd;
++	uint64_t	arg;
++	uint32_t	in_size;
++	uint32_t	out_size;
++};
++
++struct fuse_ioctl_iovec {
++	uint64_t	base;
++	uint64_t	len;
++};
++
++struct fuse_ioctl_out {
++	int32_t		result;
++	uint32_t	flags;
++	uint32_t	in_iovs;
++	uint32_t	out_iovs;
++};
++
++struct fuse_poll_in {
++	uint64_t	fh;
++	uint64_t	kh;
++	uint32_t	flags;
++	uint32_t	events;
++};
++
++struct fuse_poll_out {
++	uint32_t	revents;
++	uint32_t	padding;
++};
++
++struct fuse_notify_poll_wakeup_out {
++	uint64_t	kh;
++};
++
++struct fuse_fallocate_in {
++	uint64_t	fh;
++	uint64_t	offset;
++	uint64_t	length;
++	uint32_t	mode;
++	uint32_t	padding;
++};
++
++struct fuse_in_header {
++	uint32_t	len;
++	uint32_t	opcode;
++	uint64_t	unique;
++	uint64_t	nodeid;
++	uint32_t	uid;
++	uint32_t	gid;
++	uint32_t	pid;
++	uint32_t	padding;
++};
++
++struct fuse_out_header {
++	uint32_t	len;
++	int32_t		error;
++	uint64_t	unique;
++};
++
++struct fuse_dirent {
++	uint64_t	ino;
++	uint64_t	off;
++	uint32_t	namelen;
++	uint32_t	type;
++	char name[];
++};
++
++#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
++#define FUSE_DIRENT_ALIGN(x) \
++	(((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1))
++#define FUSE_DIRENT_SIZE(d) \
++	FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
++
++struct fuse_direntplus {
++	struct fuse_entry_out entry_out;
++	struct fuse_dirent dirent;
++};
++
++#define FUSE_NAME_OFFSET_DIRENTPLUS \
++	offsetof(struct fuse_direntplus, dirent.name)
++#define FUSE_DIRENTPLUS_SIZE(d) \
++	FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET_DIRENTPLUS + (d)->dirent.namelen)
++
++struct fuse_notify_inval_inode_out {
++	uint64_t	ino;
++	int64_t		off;
++	int64_t		len;
++};
++
++struct fuse_notify_inval_entry_out {
++	uint64_t	parent;
++	uint32_t	namelen;
++	uint32_t	padding;
++};
++
++struct fuse_notify_delete_out {
++	uint64_t	parent;
++	uint64_t	child;
++	uint32_t	namelen;
++	uint32_t	padding;
++};
++
++struct fuse_notify_store_out {
++	uint64_t	nodeid;
++	uint64_t	offset;
++	uint32_t	size;
++	uint32_t	padding;
++};
++
++struct fuse_notify_retrieve_out {
++	uint64_t	notify_unique;
++	uint64_t	nodeid;
++	uint64_t	offset;
++	uint32_t	size;
++	uint32_t	padding;
++};
++
++/* Matches the size of fuse_write_in */
++struct fuse_notify_retrieve_in {
++	uint64_t	dummy1;
++	uint64_t	offset;
++	uint32_t	size;
++	uint32_t	dummy2;
++	uint64_t	dummy3;
++	uint64_t	dummy4;
++};
++
++/* Device ioctls: */
++#define FUSE_DEV_IOC_CLONE	_IOR(229, 0, uint32_t)
++
++struct fuse_lseek_in {
++	uint64_t	fh;
++	uint64_t	offset;
++	uint32_t	whence;
++	uint32_t	padding;
++};
++
++struct fuse_lseek_out {
++	uint64_t	offset;
++};
++
++struct fuse_copy_file_range_in {
++	uint64_t	fh_in;
++	uint64_t	off_in;
++	uint64_t	nodeid_out;
++	uint64_t	fh_out;
++	uint64_t	off_out;
++	uint64_t	len;
++	uint64_t	flags;
++};
++
++#endif /* _LINUX_FUSE_H */
+diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh
+index f76d77363b..29c27f4681 100755
+--- a/scripts/update-linux-headers.sh
++++ b/scripts/update-linux-headers.sh
+@@ -186,6 +186,7 @@ rm -rf "$output/include/standard-headers/linux"
+ mkdir -p "$output/include/standard-headers/linux"
+ for i in "$tmpdir"/include/linux/*virtio*.h \
+          "$tmpdir/include/linux/qemu_fw_cfg.h" \
++         "$tmpdir/include/linux/fuse.h" \
+          "$tmpdir/include/linux/input.h" \
+          "$tmpdir/include/linux/input-event-codes.h" \
+          "$tmpdir/include/linux/pci_regs.h" \
diff --git a/0012-virtiofsd-Add-auxiliary-.c-s.patch b/0012-virtiofsd-Add-auxiliary-.c-s.patch
new file mode 100644
index 0000000..645e280
--- /dev/null
+++ b/0012-virtiofsd-Add-auxiliary-.c-s.patch
@@ -0,0 +1,1371 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:41 +0000
+Subject: [PATCH] virtiofsd: Add auxiliary .c's
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add most of the non-main .c files we need from upstream fuse-3.8.0
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit ffcf8d9f8649c6e56b1193bbbc9c9f7388920043)
+---
+ tools/virtiofsd/buffer.c       | 321 ++++++++++++++++++++++++
+ tools/virtiofsd/fuse_log.c     |  40 +++
+ tools/virtiofsd/fuse_opt.c     | 423 +++++++++++++++++++++++++++++++
+ tools/virtiofsd/fuse_signals.c |  91 +++++++
+ tools/virtiofsd/helper.c       | 440 +++++++++++++++++++++++++++++++++
+ 5 files changed, 1315 insertions(+)
+ create mode 100644 tools/virtiofsd/buffer.c
+ create mode 100644 tools/virtiofsd/fuse_log.c
+ create mode 100644 tools/virtiofsd/fuse_opt.c
+ create mode 100644 tools/virtiofsd/fuse_signals.c
+ create mode 100644 tools/virtiofsd/helper.c
+
+diff --git a/tools/virtiofsd/buffer.c b/tools/virtiofsd/buffer.c
+new file mode 100644
+index 0000000000..5ab9b87455
+--- /dev/null
++++ b/tools/virtiofsd/buffer.c
+@@ -0,0 +1,321 @@
++/*
++  FUSE: Filesystem in Userspace
++  Copyright (C) 2010  Miklos Szeredi <miklos@szeredi.hu>
++
++  Functions for dealing with `struct fuse_buf` and `struct
++  fuse_bufvec`.
++
++  This program can be distributed under the terms of the GNU LGPLv2.
++  See the file COPYING.LIB
++*/
++
++#define _GNU_SOURCE
++
++#include "config.h"
++#include "fuse_i.h"
++#include "fuse_lowlevel.h"
++#include <string.h>
++#include <unistd.h>
++#include <errno.h>
++#include <assert.h>
++
++size_t fuse_buf_size(const struct fuse_bufvec *bufv)
++{
++	size_t i;
++	size_t size = 0;
++
++	for (i = 0; i < bufv->count; i++) {
++		if (bufv->buf[i].size == SIZE_MAX)
++			size = SIZE_MAX;
++		else
++			size += bufv->buf[i].size;
++	}
++
++	return size;
++}
++
++static size_t min_size(size_t s1, size_t s2)
++{
++	return s1 < s2 ? s1 : s2;
++}
++
++static ssize_t fuse_buf_write(const struct fuse_buf *dst, size_t dst_off,
++			      const struct fuse_buf *src, size_t src_off,
++			      size_t len)
++{
++	ssize_t res = 0;
++	size_t copied = 0;
++
++	while (len) {
++		if (dst->flags & FUSE_BUF_FD_SEEK) {
++			res = pwrite(dst->fd, (char *)src->mem + src_off, len,
++				     dst->pos + dst_off);
++		} else {
++			res = write(dst->fd, (char *)src->mem + src_off, len);
++		}
++		if (res == -1) {
++			if (!copied)
++				return -errno;
++			break;
++		}
++		if (res == 0)
++			break;
++
++		copied += res;
++		if (!(dst->flags & FUSE_BUF_FD_RETRY))
++			break;
++
++		src_off += res;
++		dst_off += res;
++		len -= res;
++	}
++
++	return copied;
++}
++
++static ssize_t fuse_buf_read(const struct fuse_buf *dst, size_t dst_off,
++			     const struct fuse_buf *src, size_t src_off,
++			     size_t len)
++{
++	ssize_t res = 0;
++	size_t copied = 0;
++
++	while (len) {
++		if (src->flags & FUSE_BUF_FD_SEEK) {
++			res = pread(src->fd, (char *)dst->mem + dst_off, len,
++				     src->pos + src_off);
++		} else {
++			res = read(src->fd, (char *)dst->mem + dst_off, len);
++		}
++		if (res == -1) {
++			if (!copied)
++				return -errno;
++			break;
++		}
++		if (res == 0)
++			break;
++
++		copied += res;
++		if (!(src->flags & FUSE_BUF_FD_RETRY))
++			break;
++
++		dst_off += res;
++		src_off += res;
++		len -= res;
++	}
++
++	return copied;
++}
++
++static ssize_t fuse_buf_fd_to_fd(const struct fuse_buf *dst, size_t dst_off,
++				 const struct fuse_buf *src, size_t src_off,
++				 size_t len)
++{
++	char buf[4096];
++	struct fuse_buf tmp = {
++		.size = sizeof(buf),
++		.flags = 0,
++	};
++	ssize_t res;
++	size_t copied = 0;
++
++	tmp.mem = buf;
++
++	while (len) {
++		size_t this_len = min_size(tmp.size, len);
++		size_t read_len;
++
++		res = fuse_buf_read(&tmp, 0, src, src_off, this_len);
++		if (res < 0) {
++			if (!copied)
++				return res;
++			break;
++		}
++		if (res == 0)
++			break;
++
++		read_len = res;
++		res = fuse_buf_write(dst, dst_off, &tmp, 0, read_len);
++		if (res < 0) {
++			if (!copied)
++				return res;
++			break;
++		}
++		if (res == 0)
++			break;
++
++		copied += res;
++
++		if (res < this_len)
++			break;
++
++		dst_off += res;
++		src_off += res;
++		len -= res;
++	}
++
++	return copied;
++}
++
++#ifdef HAVE_SPLICE
++static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off,
++			       const struct fuse_buf *src, size_t src_off,
++			       size_t len, enum fuse_buf_copy_flags flags)
++{
++	int splice_flags = 0;
++	off_t *srcpos = NULL;
++	off_t *dstpos = NULL;
++	off_t srcpos_val;
++	off_t dstpos_val;
++	ssize_t res;
++	size_t copied = 0;
++
++	if (flags & FUSE_BUF_SPLICE_MOVE)
++		splice_flags |= SPLICE_F_MOVE;
++	if (flags & FUSE_BUF_SPLICE_NONBLOCK)
++		splice_flags |= SPLICE_F_NONBLOCK;
++
++	if (src->flags & FUSE_BUF_FD_SEEK) {
++		srcpos_val = src->pos + src_off;
++		srcpos = &srcpos_val;
++	}
++	if (dst->flags & FUSE_BUF_FD_SEEK) {
++		dstpos_val = dst->pos + dst_off;
++		dstpos = &dstpos_val;
++	}
++
++	while (len) {
++		res = splice(src->fd, srcpos, dst->fd, dstpos, len,
++			     splice_flags);
++		if (res == -1) {
++			if (copied)
++				break;
++
++			if (errno != EINVAL || (flags & FUSE_BUF_FORCE_SPLICE))
++				return -errno;
++
++			/* Maybe splice is not supported for this combination */
++			return fuse_buf_fd_to_fd(dst, dst_off, src, src_off,
++						 len);
++		}
++		if (res == 0)
++			break;
++
++		copied += res;
++		if (!(src->flags & FUSE_BUF_FD_RETRY) &&
++		    !(dst->flags & FUSE_BUF_FD_RETRY)) {
++			break;
++		}
++
++		len -= res;
++	}
++
++	return copied;
++}
++#else
++static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off,
++			       const struct fuse_buf *src, size_t src_off,
++			       size_t len, enum fuse_buf_copy_flags flags)
++{
++	(void) flags;
++
++	return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
++}
++#endif
++
++
++static ssize_t fuse_buf_copy_one(const struct fuse_buf *dst, size_t dst_off,
++				 const struct fuse_buf *src, size_t src_off,
++				 size_t len, enum fuse_buf_copy_flags flags)
++{
++	int src_is_fd = src->flags & FUSE_BUF_IS_FD;
++	int dst_is_fd = dst->flags & FUSE_BUF_IS_FD;
++
++	if (!src_is_fd && !dst_is_fd) {
++		char *dstmem = (char *)dst->mem + dst_off;
++		char *srcmem = (char *)src->mem + src_off;
++
++		if (dstmem != srcmem) {
++			if (dstmem + len <= srcmem || srcmem + len <= dstmem)
++				memcpy(dstmem, srcmem, len);
++			else
++				memmove(dstmem, srcmem, len);
++		}
++
++		return len;
++	} else if (!src_is_fd) {
++		return fuse_buf_write(dst, dst_off, src, src_off, len);
++	} else if (!dst_is_fd) {
++		return fuse_buf_read(dst, dst_off, src, src_off, len);
++	} else if (flags & FUSE_BUF_NO_SPLICE) {
++		return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
++	} else {
++		return fuse_buf_splice(dst, dst_off, src, src_off, len, flags);
++	}
++}
++
++static const struct fuse_buf *fuse_bufvec_current(struct fuse_bufvec *bufv)
++{
++	if (bufv->idx < bufv->count)
++		return &bufv->buf[bufv->idx];
++	else
++		return NULL;
++}
++
++static int fuse_bufvec_advance(struct fuse_bufvec *bufv, size_t len)
++{
++	const struct fuse_buf *buf = fuse_bufvec_current(bufv);
++
++	bufv->off += len;
++	assert(bufv->off <= buf->size);
++	if (bufv->off == buf->size) {
++		assert(bufv->idx < bufv->count);
++		bufv->idx++;
++		if (bufv->idx == bufv->count)
++			return 0;
++		bufv->off = 0;
++	}
++	return 1;
++}
++
++ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv,
++		      enum fuse_buf_copy_flags flags)
++{
++	size_t copied = 0;
++
++	if (dstv == srcv)
++		return fuse_buf_size(dstv);
++
++	for (;;) {
++		const struct fuse_buf *src = fuse_bufvec_current(srcv);
++		const struct fuse_buf *dst = fuse_bufvec_current(dstv);
++		size_t src_len;
++		size_t dst_len;
++		size_t len;
++		ssize_t res;
++
++		if (src == NULL || dst == NULL)
++			break;
++
++		src_len = src->size - srcv->off;
++		dst_len = dst->size - dstv->off;
++		len = min_size(src_len, dst_len);
++
++		res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len, flags);
++		if (res < 0) {
++			if (!copied)
++				return res;
++			break;
++		}
++		copied += res;
++
++		if (!fuse_bufvec_advance(srcv, res) ||
++		    !fuse_bufvec_advance(dstv, res))
++			break;
++
++		if (res < len)
++			break;
++	}
++
++	return copied;
++}
+diff --git a/tools/virtiofsd/fuse_log.c b/tools/virtiofsd/fuse_log.c
+new file mode 100644
+index 0000000000..0d268ab014
+--- /dev/null
++++ b/tools/virtiofsd/fuse_log.c
+@@ -0,0 +1,40 @@
++/*
++  FUSE: Filesystem in Userspace
++  Copyright (C) 2019  Red Hat, Inc.
++
++  Logging API.
++
++  This program can be distributed under the terms of the GNU LGPLv2.
++  See the file COPYING.LIB
++*/
++
++#include "fuse_log.h"
++
++#include <stdarg.h>
++#include <stdio.h>
++
++static void default_log_func(
++		__attribute__(( unused )) enum fuse_log_level level,
++		const char *fmt, va_list ap)
++{
++	vfprintf(stderr, fmt, ap);
++}
++
++static fuse_log_func_t log_func = default_log_func;
++
++void fuse_set_log_func(fuse_log_func_t func)
++{
++	if (!func)
++		func = default_log_func;
++
++	log_func = func;
++}
++
++void fuse_log(enum fuse_log_level level, const char *fmt, ...)
++{
++	va_list ap;
++
++	va_start(ap, fmt);
++	log_func(level, fmt, ap);
++	va_end(ap);
++}
+diff --git a/tools/virtiofsd/fuse_opt.c b/tools/virtiofsd/fuse_opt.c
+new file mode 100644
+index 0000000000..93066b926e
+--- /dev/null
++++ b/tools/virtiofsd/fuse_opt.c
+@@ -0,0 +1,423 @@
++/*
++  FUSE: Filesystem in Userspace
++  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++
++  Implementation of option parsing routines (dealing with `struct
++  fuse_args`).
++
++  This program can be distributed under the terms of the GNU LGPLv2.
++  See the file COPYING.LIB
++*/
++
++#include "config.h"
++#include "fuse_i.h"
++#include "fuse_opt.h"
++#include "fuse_misc.h"
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <assert.h>
++
++struct fuse_opt_context {
++	void *data;
++	const struct fuse_opt *opt;
++	fuse_opt_proc_t proc;
++	int argctr;
++	int argc;
++	char **argv;
++	struct fuse_args outargs;
++	char *opts;
++	int nonopt;
++};
++
++void fuse_opt_free_args(struct fuse_args *args)
++{
++	if (args) {
++		if (args->argv && args->allocated) {
++			int i;
++			for (i = 0; i < args->argc; i++)
++				free(args->argv[i]);
++			free(args->argv);
++		}
++		args->argc = 0;
++		args->argv = NULL;
++		args->allocated = 0;
++	}
++}
++
++static int alloc_failed(void)
++{
++	fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
++	return -1;
++}
++
++int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
++{
++	char **newargv;
++	char *newarg;
++
++	assert(!args->argv || args->allocated);
++
++	newarg = strdup(arg);
++	if (!newarg)
++		return alloc_failed();
++
++	newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *));
++	if (!newargv) {
++		free(newarg);
++		return alloc_failed();
++	}
++
++	args->argv = newargv;
++	args->allocated = 1;
++	args->argv[args->argc++] = newarg;
++	args->argv[args->argc] = NULL;
++	return 0;
++}
++
++static int fuse_opt_insert_arg_common(struct fuse_args *args, int pos,
++				      const char *arg)
++{
++	assert(pos <= args->argc);
++	if (fuse_opt_add_arg(args, arg) == -1)
++		return -1;
++
++	if (pos != args->argc - 1) {
++		char *newarg = args->argv[args->argc - 1];
++		memmove(&args->argv[pos + 1], &args->argv[pos],
++			sizeof(char *) * (args->argc - pos - 1));
++		args->argv[pos] = newarg;
++	}
++	return 0;
++}
++
++int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
++{
++	return fuse_opt_insert_arg_common(args, pos, arg);
++}
++
++static int next_arg(struct fuse_opt_context *ctx, const char *opt)
++{
++	if (ctx->argctr + 1 >= ctx->argc) {
++		fuse_log(FUSE_LOG_ERR, "fuse: missing argument after `%s'\n", opt);
++		return -1;
++	}
++	ctx->argctr++;
++	return 0;
++}
++
++static int add_arg(struct fuse_opt_context *ctx, const char *arg)
++{
++	return fuse_opt_add_arg(&ctx->outargs, arg);
++}
++
++static int add_opt_common(char **opts, const char *opt, int esc)
++{
++	unsigned oldlen = *opts ? strlen(*opts) : 0;
++	char *d = realloc(*opts, oldlen + 1 + strlen(opt) * 2 + 1);
++
++	if (!d)
++		return alloc_failed();
++
++	*opts = d;
++	if (oldlen) {
++		d += oldlen;
++		*d++ = ',';
++	}
++
++	for (; *opt; opt++) {
++		if (esc && (*opt == ',' || *opt == '\\'))
++			*d++ = '\\';
++		*d++ = *opt;
++	}
++	*d = '\0';
++
++	return 0;
++}
++
++int fuse_opt_add_opt(char **opts, const char *opt)
++{
++	return add_opt_common(opts, opt, 0);
++}
++
++int fuse_opt_add_opt_escaped(char **opts, const char *opt)
++{
++	return add_opt_common(opts, opt, 1);
++}
++
++static int add_opt(struct fuse_opt_context *ctx, const char *opt)
++{
++	return add_opt_common(&ctx->opts, opt, 1);
++}
++
++static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key,
++		     int iso)
++{
++	if (key == FUSE_OPT_KEY_DISCARD)
++		return 0;
++
++	if (key != FUSE_OPT_KEY_KEEP && ctx->proc) {
++		int res = ctx->proc(ctx->data, arg, key, &ctx->outargs);
++		if (res == -1 || !res)
++			return res;
++	}
++	if (iso)
++		return add_opt(ctx, arg);
++	else
++		return add_arg(ctx, arg);
++}
++
++static int match_template(const char *t, const char *arg, unsigned *sepp)
++{
++	int arglen = strlen(arg);
++	const char *sep = strchr(t, '=');
++	sep = sep ? sep : strchr(t, ' ');
++	if (sep && (!sep[1] || sep[1] == '%')) {
++		int tlen = sep - t;
++		if (sep[0] == '=')
++			tlen ++;
++		if (arglen >= tlen && strncmp(arg, t, tlen) == 0) {
++			*sepp = sep - t;
++			return 1;
++		}
++	}
++	if (strcmp(t, arg) == 0) {
++		*sepp = 0;
++		return 1;
++	}
++	return 0;
++}
++
++static const struct fuse_opt *find_opt(const struct fuse_opt *opt,
++				       const char *arg, unsigned *sepp)
++{
++	for (; opt && opt->templ; opt++)
++		if (match_template(opt->templ, arg, sepp))
++			return opt;
++	return NULL;
++}
++
++int fuse_opt_match(const struct fuse_opt *opts, const char *opt)
++{
++	unsigned dummy;
++	return find_opt(opts, opt, &dummy) ? 1 : 0;
++}
++
++static int process_opt_param(void *var, const char *format, const char *param,
++			     const char *arg)
++{
++	assert(format[0] == '%');
++	if (format[1] == 's') {
++		char **s = var;
++		char *copy = strdup(param);
++		if (!copy)
++			return alloc_failed();
++
++		free(*s);
++		*s = copy;
++	} else {
++		if (sscanf(param, format, var) != 1) {
++			fuse_log(FUSE_LOG_ERR, "fuse: invalid parameter in option `%s'\n", arg);
++			return -1;
++		}
++	}
++	return 0;
++}
++
++static int process_opt(struct fuse_opt_context *ctx,
++		       const struct fuse_opt *opt, unsigned sep,
++		       const char *arg, int iso)
++{
++	if (opt->offset == -1U) {
++		if (call_proc(ctx, arg, opt->value, iso) == -1)
++			return -1;
++	} else {
++		void *var = (char *)ctx->data + opt->offset;
++		if (sep && opt->templ[sep + 1]) {
++			const char *param = arg + sep;
++			if (opt->templ[sep] == '=')
++				param ++;
++			if (process_opt_param(var, opt->templ + sep + 1,
++					      param, arg) == -1)
++				return -1;
++		} else
++			*(int *)var = opt->value;
++	}
++	return 0;
++}
++
++static int process_opt_sep_arg(struct fuse_opt_context *ctx,
++			       const struct fuse_opt *opt, unsigned sep,
++			       const char *arg, int iso)
++{
++	int res;
++	char *newarg;
++	char *param;
++
++	if (next_arg(ctx, arg) == -1)
++		return -1;
++
++	param = ctx->argv[ctx->argctr];
++	newarg = malloc(sep + strlen(param) + 1);
++	if (!newarg)
++		return alloc_failed();
++
++	memcpy(newarg, arg, sep);
++	strcpy(newarg + sep, param);
++	res = process_opt(ctx, opt, sep, newarg, iso);
++	free(newarg);
++
++	return res;
++}
++
++static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso)
++{
++	unsigned sep;
++	const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep);
++	if (opt) {
++		for (; opt; opt = find_opt(opt + 1, arg, &sep)) {
++			int res;
++			if (sep && opt->templ[sep] == ' ' && !arg[sep])
++				res = process_opt_sep_arg(ctx, opt, sep, arg,
++							  iso);
++			else
++				res = process_opt(ctx, opt, sep, arg, iso);
++			if (res == -1)
++				return -1;
++		}
++		return 0;
++	} else
++		return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso);
++}
++
++static int process_real_option_group(struct fuse_opt_context *ctx, char *opts)
++{
++	char *s = opts;
++	char *d = s;
++	int end = 0;
++
++	while (!end) {
++		if (*s == '\0')
++			end = 1;
++		if (*s == ',' || end) {
++			int res;
++
++			*d = '\0';
++			res = process_gopt(ctx, opts, 1);
++			if (res == -1)
++				return -1;
++			d = opts;
++		} else {
++			if (s[0] == '\\' && s[1] != '\0') {
++				s++;
++				if (s[0] >= '0' && s[0] <= '3' &&
++				    s[1] >= '0' && s[1] <= '7' &&
++				    s[2] >= '0' && s[2] <= '7') {
++					*d++ = (s[0] - '0') * 0100 +
++						(s[1] - '0') * 0010 +
++						(s[2] - '0');
++					s += 2;
++				} else {
++					*d++ = *s;
++				}
++			} else {
++				*d++ = *s;
++			}
++		}
++		s++;
++	}
++
++	return 0;
++}
++
++static int process_option_group(struct fuse_opt_context *ctx, const char *opts)
++{
++	int res;
++	char *copy = strdup(opts);
++
++	if (!copy) {
++		fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
++		return -1;
++	}
++	res = process_real_option_group(ctx, copy);
++	free(copy);
++	return res;
++}
++
++static int process_one(struct fuse_opt_context *ctx, const char *arg)
++{
++	if (ctx->nonopt || arg[0] != '-')
++		return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0);
++	else if (arg[1] == 'o') {
++		if (arg[2])
++			return process_option_group(ctx, arg + 2);
++		else {
++			if (next_arg(ctx, arg) == -1)
++				return -1;
++
++			return process_option_group(ctx,
++						    ctx->argv[ctx->argctr]);
++		}
++	} else if (arg[1] == '-' && !arg[2]) {
++		if (add_arg(ctx, arg) == -1)
++			return -1;
++		ctx->nonopt = ctx->outargs.argc;
++		return 0;
++	} else
++		return process_gopt(ctx, arg, 0);
++}
++
++static int opt_parse(struct fuse_opt_context *ctx)
++{
++	if (ctx->argc) {
++		if (add_arg(ctx, ctx->argv[0]) == -1)
++			return -1;
++	}
++
++	for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++)
++		if (process_one(ctx, ctx->argv[ctx->argctr]) == -1)
++			return -1;
++
++	if (ctx->opts) {
++		if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 ||
++		    fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1)
++			return -1;
++	}
++
++	/* If option separator ("--") is the last argument, remove it */
++	if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc &&
++	    strcmp(ctx->outargs.argv[ctx->outargs.argc - 1], "--") == 0) {
++		free(ctx->outargs.argv[ctx->outargs.argc - 1]);
++		ctx->outargs.argv[--ctx->outargs.argc] = NULL;
++	}
++
++	return 0;
++}
++
++int fuse_opt_parse(struct fuse_args *args, void *data,
++		   const struct fuse_opt opts[], fuse_opt_proc_t proc)
++{
++	int res;
++	struct fuse_opt_context ctx = {
++		.data = data,
++		.opt = opts,
++		.proc = proc,
++	};
++
++	if (!args || !args->argv || !args->argc)
++		return 0;
++
++	ctx.argc = args->argc;
++	ctx.argv = args->argv;
++
++	res = opt_parse(&ctx);
++	if (res != -1) {
++		struct fuse_args tmp = *args;
++		*args = ctx.outargs;
++		ctx.outargs = tmp;
++	}
++	free(ctx.opts);
++	fuse_opt_free_args(&ctx.outargs);
++	return res;
++}
+diff --git a/tools/virtiofsd/fuse_signals.c b/tools/virtiofsd/fuse_signals.c
+new file mode 100644
+index 0000000000..4271947bd4
+--- /dev/null
++++ b/tools/virtiofsd/fuse_signals.c
+@@ -0,0 +1,91 @@
++/*
++  FUSE: Filesystem in Userspace
++  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++
++  Utility functions for setting signal handlers.
++
++  This program can be distributed under the terms of the GNU LGPLv2.
++  See the file COPYING.LIB
++*/
++
++#include "config.h"
++#include "fuse_lowlevel.h"
++#include "fuse_i.h"
++
++#include <stdio.h>
++#include <string.h>
++#include <signal.h>
++#include <stdlib.h>
++
++static struct fuse_session *fuse_instance;
++
++static void exit_handler(int sig)
++{
++	if (fuse_instance) {
++		fuse_session_exit(fuse_instance);
++		if(sig <= 0) {
++			fuse_log(FUSE_LOG_ERR, "assertion error: signal value <= 0\n");
++			abort();
++		}
++		fuse_instance->error = sig;
++	}
++}
++
++static void do_nothing(int sig)
++{
++	(void) sig;
++}
++
++static int set_one_signal_handler(int sig, void (*handler)(int), int remove)
++{
++	struct sigaction sa;
++	struct sigaction old_sa;
++
++	memset(&sa, 0, sizeof(struct sigaction));
++	sa.sa_handler = remove ? SIG_DFL : handler;
++	sigemptyset(&(sa.sa_mask));
++	sa.sa_flags = 0;
++
++	if (sigaction(sig, NULL, &old_sa) == -1) {
++		perror("fuse: cannot get old signal handler");
++		return -1;
++	}
++
++	if (old_sa.sa_handler == (remove ? handler : SIG_DFL) &&
++	    sigaction(sig, &sa, NULL) == -1) {
++		perror("fuse: cannot set signal handler");
++		return -1;
++	}
++	return 0;
++}
++
++int fuse_set_signal_handlers(struct fuse_session *se)
++{
++	/* If we used SIG_IGN instead of the do_nothing function,
++	   then we would be unable to tell if we set SIG_IGN (and
++	   thus should reset to SIG_DFL in fuse_remove_signal_handlers)
++	   or if it was already set to SIG_IGN (and should be left
++	   untouched. */
++	if (set_one_signal_handler(SIGHUP, exit_handler, 0) == -1 ||
++	    set_one_signal_handler(SIGINT, exit_handler, 0) == -1 ||
++	    set_one_signal_handler(SIGTERM, exit_handler, 0) == -1 ||
++	    set_one_signal_handler(SIGPIPE, do_nothing, 0) == -1)
++		return -1;
++
++	fuse_instance = se;
++	return 0;
++}
++
++void fuse_remove_signal_handlers(struct fuse_session *se)
++{
++	if (fuse_instance != se)
++		fuse_log(FUSE_LOG_ERR,
++			"fuse: fuse_remove_signal_handlers: unknown session\n");
++	else
++		fuse_instance = NULL;
++
++	set_one_signal_handler(SIGHUP, exit_handler, 1);
++	set_one_signal_handler(SIGINT, exit_handler, 1);
++	set_one_signal_handler(SIGTERM, exit_handler, 1);
++	set_one_signal_handler(SIGPIPE, do_nothing, 1);
++}
+diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
+new file mode 100644
+index 0000000000..64ff7ad6d5
+--- /dev/null
++++ b/tools/virtiofsd/helper.c
+@@ -0,0 +1,440 @@
++/*
++  FUSE: Filesystem in Userspace
++  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++
++  Helper functions to create (simple) standalone programs. With the
++  aid of these functions it should be possible to create full FUSE
++  file system by implementing nothing but the request handlers.
++
++  This program can be distributed under the terms of the GNU LGPLv2.
++  See the file COPYING.LIB.
++*/
++
++#include "config.h"
++#include "fuse_i.h"
++#include "fuse_misc.h"
++#include "fuse_opt.h"
++#include "fuse_lowlevel.h"
++#include "mount_util.h"
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <unistd.h>
++#include <string.h>
++#include <limits.h>
++#include <errno.h>
++#include <sys/param.h>
++
++#define FUSE_HELPER_OPT(t, p) \
++	{ t, offsetof(struct fuse_cmdline_opts, p), 1 }
++
++static const struct fuse_opt fuse_helper_opts[] = {
++	FUSE_HELPER_OPT("-h",		show_help),
++	FUSE_HELPER_OPT("--help",	show_help),
++	FUSE_HELPER_OPT("-V",		show_version),
++	FUSE_HELPER_OPT("--version",	show_version),
++	FUSE_HELPER_OPT("-d",		debug),
++	FUSE_HELPER_OPT("debug",	debug),
++	FUSE_HELPER_OPT("-d",		foreground),
++	FUSE_HELPER_OPT("debug",	foreground),
++	FUSE_OPT_KEY("-d",		FUSE_OPT_KEY_KEEP),
++	FUSE_OPT_KEY("debug",		FUSE_OPT_KEY_KEEP),
++	FUSE_HELPER_OPT("-f",		foreground),
++	FUSE_HELPER_OPT("-s",		singlethread),
++	FUSE_HELPER_OPT("fsname=",	nodefault_subtype),
++	FUSE_OPT_KEY("fsname=",		FUSE_OPT_KEY_KEEP),
++#ifndef __FreeBSD__
++	FUSE_HELPER_OPT("subtype=",	nodefault_subtype),
++	FUSE_OPT_KEY("subtype=",	FUSE_OPT_KEY_KEEP),
++#endif
++	FUSE_HELPER_OPT("clone_fd",	clone_fd),
++	FUSE_HELPER_OPT("max_idle_threads=%u", max_idle_threads),
++	FUSE_OPT_END
++};
++
++struct fuse_conn_info_opts {
++	int atomic_o_trunc;
++	int no_remote_posix_lock;
++	int no_remote_flock;
++	int splice_write;
++	int splice_move;
++	int splice_read;
++	int no_splice_write;
++	int no_splice_move;
++	int no_splice_read;
++	int auto_inval_data;
++	int no_auto_inval_data;
++	int no_readdirplus;
++	int no_readdirplus_auto;
++	int async_dio;
++	int no_async_dio;
++	int writeback_cache;
++	int no_writeback_cache;
++	int async_read;
++	int sync_read;
++	unsigned max_write;
++	unsigned max_readahead;
++	unsigned max_background;
++	unsigned congestion_threshold;
++	unsigned time_gran;
++	int set_max_write;
++	int set_max_readahead;
++	int set_max_background;
++	int set_congestion_threshold;
++	int set_time_gran;
++};
++
++#define CONN_OPTION(t, p, v)					\
++	{ t, offsetof(struct fuse_conn_info_opts, p), v }
++static const struct fuse_opt conn_info_opt_spec[] = {
++	CONN_OPTION("max_write=%u", max_write, 0),
++	CONN_OPTION("max_write=", set_max_write, 1),
++	CONN_OPTION("max_readahead=%u", max_readahead, 0),
++	CONN_OPTION("max_readahead=", set_max_readahead, 1),
++	CONN_OPTION("max_background=%u", max_background, 0),
++	CONN_OPTION("max_background=", set_max_background, 1),
++	CONN_OPTION("congestion_threshold=%u", congestion_threshold, 0),
++	CONN_OPTION("congestion_threshold=", set_congestion_threshold, 1),
++	CONN_OPTION("sync_read", sync_read, 1),
++	CONN_OPTION("async_read", async_read, 1),
++	CONN_OPTION("atomic_o_trunc", atomic_o_trunc, 1),
++	CONN_OPTION("no_remote_lock", no_remote_posix_lock, 1),
++	CONN_OPTION("no_remote_lock", no_remote_flock, 1),
++	CONN_OPTION("no_remote_flock", no_remote_flock, 1),
++	CONN_OPTION("no_remote_posix_lock", no_remote_posix_lock, 1),
++	CONN_OPTION("splice_write", splice_write, 1),
++	CONN_OPTION("no_splice_write", no_splice_write, 1),
++	CONN_OPTION("splice_move", splice_move, 1),
++	CONN_OPTION("no_splice_move", no_splice_move, 1),
++	CONN_OPTION("splice_read", splice_read, 1),
++	CONN_OPTION("no_splice_read", no_splice_read, 1),
++	CONN_OPTION("auto_inval_data", auto_inval_data, 1),
++	CONN_OPTION("no_auto_inval_data", no_auto_inval_data, 1),
++	CONN_OPTION("readdirplus=no", no_readdirplus, 1),
++	CONN_OPTION("readdirplus=yes", no_readdirplus, 0),
++	CONN_OPTION("readdirplus=yes", no_readdirplus_auto, 1),
++	CONN_OPTION("readdirplus=auto", no_readdirplus, 0),
++	CONN_OPTION("readdirplus=auto", no_readdirplus_auto, 0),
++	CONN_OPTION("async_dio", async_dio, 1),
++	CONN_OPTION("no_async_dio", no_async_dio, 1),
++	CONN_OPTION("writeback_cache", writeback_cache, 1),
++	CONN_OPTION("no_writeback_cache", no_writeback_cache, 1),
++	CONN_OPTION("time_gran=%u", time_gran, 0),
++	CONN_OPTION("time_gran=", set_time_gran, 1),
++	FUSE_OPT_END
++};
++
++
++void fuse_cmdline_help(void)
++{
++	printf("    -h   --help            print help\n"
++	       "    -V   --version         print version\n"
++	       "    -d   -o debug          enable debug output (implies -f)\n"
++	       "    -f                     foreground operation\n"
++	       "    -s                     disable multi-threaded operation\n"
++	       "    -o clone_fd            use separate fuse device fd for each thread\n"
++	       "                           (may improve performance)\n"
++	       "    -o max_idle_threads    the maximum number of idle worker threads\n"
++	       "                           allowed (default: 10)\n");
++}
++
++static int fuse_helper_opt_proc(void *data, const char *arg, int key,
++				struct fuse_args *outargs)
++{
++	(void) outargs;
++	struct fuse_cmdline_opts *opts = data;
++
++	switch (key) {
++	case FUSE_OPT_KEY_NONOPT:
++		if (!opts->mountpoint) {
++			if (fuse_mnt_parse_fuse_fd(arg) != -1) {
++				return fuse_opt_add_opt(&opts->mountpoint, arg);
++			}
++
++			char mountpoint[PATH_MAX] = "";
++			if (realpath(arg, mountpoint) == NULL) {
++				fuse_log(FUSE_LOG_ERR,
++					"fuse: bad mount point `%s': %s\n",
++					arg, strerror(errno));
++				return -1;
++			}
++			return fuse_opt_add_opt(&opts->mountpoint, mountpoint);
++		} else {
++			fuse_log(FUSE_LOG_ERR, "fuse: invalid argument `%s'\n", arg);
++			return -1;
++		}
++
++	default:
++		/* Pass through unknown options */
++		return 1;
++	}
++}
++
++/* Under FreeBSD, there is no subtype option so this
++   function actually sets the fsname */
++static int add_default_subtype(const char *progname, struct fuse_args *args)
++{
++	int res;
++	char *subtype_opt;
++
++	const char *basename = strrchr(progname, '/');
++	if (basename == NULL)
++		basename = progname;
++	else if (basename[1] != '\0')
++		basename++;
++
++	subtype_opt = (char *) malloc(strlen(basename) + 64);
++	if (subtype_opt == NULL) {
++		fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
++		return -1;
++	}
++#ifdef __FreeBSD__
++	sprintf(subtype_opt, "-ofsname=%s", basename);
++#else
++	sprintf(subtype_opt, "-osubtype=%s", basename);
++#endif
++	res = fuse_opt_add_arg(args, subtype_opt);
++	free(subtype_opt);
++	return res;
++}
++
++int fuse_parse_cmdline(struct fuse_args *args,
++		       struct fuse_cmdline_opts *opts)
++{
++	memset(opts, 0, sizeof(struct fuse_cmdline_opts));
++
++	opts->max_idle_threads = 10;
++
++	if (fuse_opt_parse(args, opts, fuse_helper_opts,
++			   fuse_helper_opt_proc) == -1)
++		return -1;
++
++	/* *Linux*: if neither -o subtype nor -o fsname are specified,
++	   set subtype to program's basename.
++	   *FreeBSD*: if fsname is not specified, set to program's
++	   basename. */
++	if (!opts->nodefault_subtype)
++		if (add_default_subtype(args->argv[0], args) == -1)
++			return -1;
++
++	return 0;
++}
++
++
++int fuse_daemonize(int foreground)
++{
++	if (!foreground) {
++		int nullfd;
++		int waiter[2];
++		char completed;
++
++		if (pipe(waiter)) {
++			perror("fuse_daemonize: pipe");
++			return -1;
++		}
++
++		/*
++		 * demonize current process by forking it and killing the
++		 * parent.  This makes current process as a child of 'init'.
++		 */
++		switch(fork()) {
++		case -1:
++			perror("fuse_daemonize: fork");
++			return -1;
++		case 0:
++			break;
++		default:
++			(void) read(waiter[0], &completed, sizeof(completed));
++			_exit(0);
++		}
++
++		if (setsid() == -1) {
++			perror("fuse_daemonize: setsid");
++			return -1;
++		}
++
++		(void) chdir("/");
++
++		nullfd = open("/dev/null", O_RDWR, 0);
++		if (nullfd != -1) {
++			(void) dup2(nullfd, 0);
++			(void) dup2(nullfd, 1);
++			(void) dup2(nullfd, 2);
++			if (nullfd > 2)
++				close(nullfd);
++		}
++
++		/* Propagate completion of daemon initialization */
++		completed = 1;
++		(void) write(waiter[1], &completed, sizeof(completed));
++		close(waiter[0]);
++		close(waiter[1]);
++	} else {
++		(void) chdir("/");
++	}
++	return 0;
++}
++
++int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
++		   size_t op_size, void *user_data)
++{
++	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
++	struct fuse *fuse;
++	struct fuse_cmdline_opts opts;
++	int res;
++
++	if (fuse_parse_cmdline(&args, &opts) != 0)
++		return 1;
++
++	if (opts.show_version) {
++		printf("FUSE library version %s\n", PACKAGE_VERSION);
++		fuse_lowlevel_version();
++		res = 0;
++		goto out1;
++	}
++
++	if (opts.show_help) {
++		if(args.argv[0][0] != '\0')
++			printf("usage: %s [options] <mountpoint>\n\n",
++			       args.argv[0]);
++		printf("FUSE options:\n");
++		fuse_cmdline_help();
++		fuse_lib_help(&args);
++		res = 0;
++		goto out1;
++	}
++
++	if (!opts.show_help &&
++	    !opts.mountpoint) {
++		fuse_log(FUSE_LOG_ERR, "error: no mountpoint specified\n");
++		res = 2;
++		goto out1;
++	}
++
++
++	fuse = fuse_new_31(&args, op, op_size, user_data);
++	if (fuse == NULL) {
++		res = 3;
++		goto out1;
++	}
++
++	if (fuse_mount(fuse,opts.mountpoint) != 0) {
++		res = 4;
++		goto out2;
++	}
++
++	if (fuse_daemonize(opts.foreground) != 0) {
++		res = 5;
++		goto out3;
++	}
++
++	struct fuse_session *se = fuse_get_session(fuse);
++	if (fuse_set_signal_handlers(se) != 0) {
++		res = 6;
++		goto out3;
++	}
++
++	if (opts.singlethread)
++		res = fuse_loop(fuse);
++	else {
++		struct fuse_loop_config loop_config;
++		loop_config.clone_fd = opts.clone_fd;
++		loop_config.max_idle_threads = opts.max_idle_threads;
++		res = fuse_loop_mt_32(fuse, &loop_config);
++	}
++	if (res)
++		res = 7;
++
++	fuse_remove_signal_handlers(se);
++out3:
++	fuse_unmount(fuse);
++out2:
++	fuse_destroy(fuse);
++out1:
++	free(opts.mountpoint);
++	fuse_opt_free_args(&args);
++	return res;
++}
++
++
++void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts,
++			       struct fuse_conn_info *conn)
++{
++	if(opts->set_max_write)
++		conn->max_write = opts->max_write;
++	if(opts->set_max_background)
++		conn->max_background = opts->max_background;
++	if(opts->set_congestion_threshold)
++		conn->congestion_threshold = opts->congestion_threshold;
++	if(opts->set_time_gran)
++		conn->time_gran = opts->time_gran;
++	if(opts->set_max_readahead)
++		conn->max_readahead = opts->max_readahead;
++
++#define LL_ENABLE(cond,cap) \
++	if (cond) conn->want |= (cap)
++#define LL_DISABLE(cond,cap) \
++	if (cond) conn->want &= ~(cap)
++
++	LL_ENABLE(opts->splice_read, FUSE_CAP_SPLICE_READ);
++	LL_DISABLE(opts->no_splice_read, FUSE_CAP_SPLICE_READ);
++
++	LL_ENABLE(opts->splice_write, FUSE_CAP_SPLICE_WRITE);
++	LL_DISABLE(opts->no_splice_write, FUSE_CAP_SPLICE_WRITE);
++
++	LL_ENABLE(opts->splice_move, FUSE_CAP_SPLICE_MOVE);
++	LL_DISABLE(opts->no_splice_move, FUSE_CAP_SPLICE_MOVE);
++
++	LL_ENABLE(opts->auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA);
++	LL_DISABLE(opts->no_auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA);
++
++	LL_DISABLE(opts->no_readdirplus, FUSE_CAP_READDIRPLUS);
++	LL_DISABLE(opts->no_readdirplus_auto, FUSE_CAP_READDIRPLUS_AUTO);
++
++	LL_ENABLE(opts->async_dio, FUSE_CAP_ASYNC_DIO);
++	LL_DISABLE(opts->no_async_dio, FUSE_CAP_ASYNC_DIO);
++
++	LL_ENABLE(opts->writeback_cache, FUSE_CAP_WRITEBACK_CACHE);
++	LL_DISABLE(opts->no_writeback_cache, FUSE_CAP_WRITEBACK_CACHE);
++
++	LL_ENABLE(opts->async_read, FUSE_CAP_ASYNC_READ);
++	LL_DISABLE(opts->sync_read, FUSE_CAP_ASYNC_READ);
++
++	LL_DISABLE(opts->no_remote_posix_lock, FUSE_CAP_POSIX_LOCKS);
++	LL_DISABLE(opts->no_remote_flock, FUSE_CAP_FLOCK_LOCKS);
++}
++
++struct fuse_conn_info_opts* fuse_parse_conn_info_opts(struct fuse_args *args)
++{
++	struct fuse_conn_info_opts *opts;
++
++	opts = calloc(1, sizeof(struct fuse_conn_info_opts));
++	if(opts == NULL) {
++		fuse_log(FUSE_LOG_ERR, "calloc failed\n");
++		return NULL;
++	}
++	if(fuse_opt_parse(args, opts, conn_info_opt_spec, NULL) == -1) {
++		free(opts);
++		return NULL;
++	}
++	return opts;
++}
++
++int fuse_open_channel(const char *mountpoint, const char* options)
++{
++	struct mount_opts *opts = NULL;
++	int fd = -1;
++	const char *argv[] = { "", "-o", options };
++	int argc = sizeof(argv) / sizeof(argv[0]);
++	struct fuse_args args = FUSE_ARGS_INIT(argc, (char**) argv);
++
++	opts = parse_mount_opts(&args);
++	if (opts == NULL)
++		return -1;
++
++	fd = fuse_kern_mount(mountpoint, opts);
++	destroy_mount_opts(opts);
++
++	return fd;
++}
diff --git a/0013-virtiofsd-Add-fuse_lowlevel.c.patch b/0013-virtiofsd-Add-fuse_lowlevel.c.patch
new file mode 100644
index 0000000..c4a16e4
--- /dev/null
+++ b/0013-virtiofsd-Add-fuse_lowlevel.c.patch
@@ -0,0 +1,3156 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:42 +0000
+Subject: [PATCH] virtiofsd: Add fuse_lowlevel.c
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+fuse_lowlevel is one of the largest files from the library
+and does most of the work.  Add it separately to keep the diff
+sizes small.
+Again this is from upstream fuse-3.8.0
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 2de121f01e37e2fe98a4362f4abf7c0848697f76)
+---
+ tools/virtiofsd/fuse_lowlevel.c | 3129 +++++++++++++++++++++++++++++++
+ 1 file changed, 3129 insertions(+)
+ create mode 100644 tools/virtiofsd/fuse_lowlevel.c
+
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+new file mode 100644
+index 0000000000..f2d7038e34
+--- /dev/null
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -0,0 +1,3129 @@
++/*
++  FUSE: Filesystem in Userspace
++  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++
++  Implementation of (most of) the low-level FUSE API. The session loop
++  functions are implemented in separate files.
++
++  This program can be distributed under the terms of the GNU LGPLv2.
++  See the file COPYING.LIB
++*/
++
++#define _GNU_SOURCE
++
++#include "config.h"
++#include "fuse_i.h"
++#include "fuse_kernel.h"
++#include "fuse_opt.h"
++#include "fuse_misc.h"
++#include "mount_util.h"
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <stddef.h>
++#include <string.h>
++#include <unistd.h>
++#include <limits.h>
++#include <errno.h>
++#include <assert.h>
++#include <sys/file.h>
++
++#ifndef F_LINUX_SPECIFIC_BASE
++#define F_LINUX_SPECIFIC_BASE       1024
++#endif
++#ifndef F_SETPIPE_SZ
++#define F_SETPIPE_SZ	(F_LINUX_SPECIFIC_BASE + 7)
++#endif
++
++
++#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
++#define OFFSET_MAX 0x7fffffffffffffffLL
++
++#define container_of(ptr, type, member) ({				\
++			const typeof( ((type *)0)->member ) *__mptr = (ptr); \
++			(type *)( (char *)__mptr - offsetof(type,member) );})
++
++struct fuse_pollhandle {
++	uint64_t kh;
++	struct fuse_session *se;
++};
++
++static size_t pagesize;
++
++static __attribute__((constructor)) void fuse_ll_init_pagesize(void)
++{
++	pagesize = getpagesize();
++}
++
++static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
++{
++	attr->ino	= stbuf->st_ino;
++	attr->mode	= stbuf->st_mode;
++	attr->nlink	= stbuf->st_nlink;
++	attr->uid	= stbuf->st_uid;
++	attr->gid	= stbuf->st_gid;
++	attr->rdev	= stbuf->st_rdev;
++	attr->size	= stbuf->st_size;
++	attr->blksize	= stbuf->st_blksize;
++	attr->blocks	= stbuf->st_blocks;
++	attr->atime	= stbuf->st_atime;
++	attr->mtime	= stbuf->st_mtime;
++	attr->ctime	= stbuf->st_ctime;
++	attr->atimensec = ST_ATIM_NSEC(stbuf);
++	attr->mtimensec = ST_MTIM_NSEC(stbuf);
++	attr->ctimensec = ST_CTIM_NSEC(stbuf);
++}
++
++static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
++{
++	stbuf->st_mode	       = attr->mode;
++	stbuf->st_uid	       = attr->uid;
++	stbuf->st_gid	       = attr->gid;
++	stbuf->st_size	       = attr->size;
++	stbuf->st_atime	       = attr->atime;
++	stbuf->st_mtime	       = attr->mtime;
++	stbuf->st_ctime        = attr->ctime;
++	ST_ATIM_NSEC_SET(stbuf, attr->atimensec);
++	ST_MTIM_NSEC_SET(stbuf, attr->mtimensec);
++	ST_CTIM_NSEC_SET(stbuf, attr->ctimensec);
++}
++
++static	size_t iov_length(const struct iovec *iov, size_t count)
++{
++	size_t seg;
++	size_t ret = 0;
++
++	for (seg = 0; seg < count; seg++)
++		ret += iov[seg].iov_len;
++	return ret;
++}
++
++static void list_init_req(struct fuse_req *req)
++{
++	req->next = req;
++	req->prev = req;
++}
++
++static void list_del_req(struct fuse_req *req)
++{
++	struct fuse_req *prev = req->prev;
++	struct fuse_req *next = req->next;
++	prev->next = next;
++	next->prev = prev;
++}
++
++static void list_add_req(struct fuse_req *req, struct fuse_req *next)
++{
++	struct fuse_req *prev = next->prev;
++	req->next = next;
++	req->prev = prev;
++	prev->next = req;
++	next->prev = req;
++}
++
++static void destroy_req(fuse_req_t req)
++{
++	pthread_mutex_destroy(&req->lock);
++	free(req);
++}
++
++void fuse_free_req(fuse_req_t req)
++{
++	int ctr;
++	struct fuse_session *se = req->se;
++
++	pthread_mutex_lock(&se->lock);
++	req->u.ni.func = NULL;
++	req->u.ni.data = NULL;
++	list_del_req(req);
++	ctr = --req->ctr;
++	fuse_chan_put(req->ch);
++	req->ch = NULL;
++	pthread_mutex_unlock(&se->lock);
++	if (!ctr)
++		destroy_req(req);
++}
++
++static struct fuse_req *fuse_ll_alloc_req(struct fuse_session *se)
++{
++	struct fuse_req *req;
++
++	req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req));
++	if (req == NULL) {
++		fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate request\n");
++	} else {
++		req->se = se;
++		req->ctr = 1;
++		list_init_req(req);
++		fuse_mutex_init(&req->lock);
++	}
++
++	return req;
++}
++
++/* Send data. If *ch* is NULL, send via session master fd */
++static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
++			 struct iovec *iov, int count)
++{
++	struct fuse_out_header *out = iov[0].iov_base;
++
++	out->len = iov_length(iov, count);
++	if (se->debug) {
++		if (out->unique == 0) {
++			fuse_log(FUSE_LOG_DEBUG, "NOTIFY: code=%d length=%u\n",
++				out->error, out->len);
++		} else if (out->error) {
++			fuse_log(FUSE_LOG_DEBUG,
++				"   unique: %llu, error: %i (%s), outsize: %i\n",
++				(unsigned long long) out->unique, out->error,
++				strerror(-out->error), out->len);
++		} else {
++			fuse_log(FUSE_LOG_DEBUG,
++				"   unique: %llu, success, outsize: %i\n",
++				(unsigned long long) out->unique, out->len);
++		}
++	}
++
++	ssize_t res = writev(ch ? ch->fd : se->fd,
++			     iov, count);
++	int err = errno;
++
++	if (res == -1) {
++		assert(se != NULL);
++
++		/* ENOENT means the operation was interrupted */
++		if (!fuse_session_exited(se) && err != ENOENT)
++			perror("fuse: writing device");
++		return -err;
++	}
++
++	return 0;
++}
++
++
++int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
++			       int count)
++{
++	struct fuse_out_header out;
++
++	if (error <= -1000 || error > 0) {
++		fuse_log(FUSE_LOG_ERR, "fuse: bad error value: %i\n",	error);
++		error = -ERANGE;
++	}
++
++	out.unique = req->unique;
++	out.error = error;
++
++	iov[0].iov_base = &out;
++	iov[0].iov_len = sizeof(struct fuse_out_header);
++
++	return fuse_send_msg(req->se, req->ch, iov, count);
++}
++
++static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov,
++			  int count)
++{
++	int res;
++
++	res = fuse_send_reply_iov_nofree(req, error, iov, count);
++	fuse_free_req(req);
++	return res;
++}
++
++static int send_reply(fuse_req_t req, int error, const void *arg,
++		      size_t argsize)
++{
++	struct iovec iov[2];
++	int count = 1;
++	if (argsize) {
++		iov[1].iov_base = (void *) arg;
++		iov[1].iov_len = argsize;
++		count++;
++	}
++	return send_reply_iov(req, error, iov, count);
++}
++
++int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
++{
++	int res;
++	struct iovec *padded_iov;
++
++	padded_iov = malloc((count + 1) * sizeof(struct iovec));
++	if (padded_iov == NULL)
++		return fuse_reply_err(req, ENOMEM);
++
++	memcpy(padded_iov + 1, iov, count * sizeof(struct iovec));
++	count++;
++
++	res = send_reply_iov(req, 0, padded_iov, count);
++	free(padded_iov);
++
++	return res;
++}
++
++
++/* `buf` is allowed to be empty so that the proper size may be
++   allocated by the caller */
++size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
++			 const char *name, const struct stat *stbuf, off_t off)
++{
++	(void)req;
++	size_t namelen;
++	size_t entlen;
++	size_t entlen_padded;
++	struct fuse_dirent *dirent;
++
++	namelen = strlen(name);
++	entlen = FUSE_NAME_OFFSET + namelen;
++	entlen_padded = FUSE_DIRENT_ALIGN(entlen);
++
++	if ((buf == NULL) || (entlen_padded > bufsize))
++	  return entlen_padded;
++
++	dirent = (struct fuse_dirent*) buf;
++	dirent->ino = stbuf->st_ino;
++	dirent->off = off;
++	dirent->namelen = namelen;
++	dirent->type = (stbuf->st_mode & S_IFMT) >> 12;
++	memcpy(dirent->name, name, namelen);
++	memset(dirent->name + namelen, 0, entlen_padded - entlen);
++
++	return entlen_padded;
++}
++
++static void convert_statfs(const struct statvfs *stbuf,
++			   struct fuse_kstatfs *kstatfs)
++{
++	kstatfs->bsize	 = stbuf->f_bsize;
++	kstatfs->frsize	 = stbuf->f_frsize;
++	kstatfs->blocks	 = stbuf->f_blocks;
++	kstatfs->bfree	 = stbuf->f_bfree;
++	kstatfs->bavail	 = stbuf->f_bavail;
++	kstatfs->files	 = stbuf->f_files;
++	kstatfs->ffree	 = stbuf->f_ffree;
++	kstatfs->namelen = stbuf->f_namemax;
++}
++
++static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
++{
++	return send_reply(req, 0, arg, argsize);
++}
++
++int fuse_reply_err(fuse_req_t req, int err)
++{
++	return send_reply(req, -err, NULL, 0);
++}
++
++void fuse_reply_none(fuse_req_t req)
++{
++	fuse_free_req(req);
++}
++
++static unsigned long calc_timeout_sec(double t)
++{
++	if (t > (double) ULONG_MAX)
++		return ULONG_MAX;
++	else if (t < 0.0)
++		return 0;
++	else
++		return (unsigned long) t;
++}
++
++static unsigned int calc_timeout_nsec(double t)
++{
++	double f = t - (double) calc_timeout_sec(t);
++	if (f < 0.0)
++		return 0;
++	else if (f >= 0.999999999)
++		return 999999999;
++	else
++		return (unsigned int) (f * 1.0e9);
++}
++
++static void fill_entry(struct fuse_entry_out *arg,
++		       const struct fuse_entry_param *e)
++{
++	arg->nodeid = e->ino;
++	arg->generation = e->generation;
++	arg->entry_valid = calc_timeout_sec(e->entry_timeout);
++	arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
++	arg->attr_valid = calc_timeout_sec(e->attr_timeout);
++	arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
++	convert_stat(&e->attr, &arg->attr);
++}
++
++/* `buf` is allowed to be empty so that the proper size may be
++   allocated by the caller */
++size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
++			      const char *name,
++			      const struct fuse_entry_param *e, off_t off)
++{
++	(void)req;
++	size_t namelen;
++	size_t entlen;
++	size_t entlen_padded;
++
++	namelen = strlen(name);
++	entlen = FUSE_NAME_OFFSET_DIRENTPLUS + namelen;
++	entlen_padded = FUSE_DIRENT_ALIGN(entlen);
++	if ((buf == NULL) || (entlen_padded > bufsize))
++	  return entlen_padded;
++
++	struct fuse_direntplus *dp = (struct fuse_direntplus *) buf;
++	memset(&dp->entry_out, 0, sizeof(dp->entry_out));
++	fill_entry(&dp->entry_out, e);
++
++	struct fuse_dirent *dirent = &dp->dirent;
++	dirent->ino = e->attr.st_ino;
++	dirent->off = off;
++	dirent->namelen = namelen;
++	dirent->type = (e->attr.st_mode & S_IFMT) >> 12;
++	memcpy(dirent->name, name, namelen);
++	memset(dirent->name + namelen, 0, entlen_padded - entlen);
++
++	return entlen_padded;
++}
++
++static void fill_open(struct fuse_open_out *arg,
++		      const struct fuse_file_info *f)
++{
++	arg->fh = f->fh;
++	if (f->direct_io)
++		arg->open_flags |= FOPEN_DIRECT_IO;
++	if (f->keep_cache)
++		arg->open_flags |= FOPEN_KEEP_CACHE;
++	if (f->cache_readdir)
++		arg->open_flags |= FOPEN_CACHE_DIR;
++	if (f->nonseekable)
++		arg->open_flags |= FOPEN_NONSEEKABLE;
++}
++
++int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
++{
++	struct fuse_entry_out arg;
++	size_t size = req->se->conn.proto_minor < 9 ?
++		FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg);
++
++	/* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
++	   negative entry */
++	if (!e->ino && req->se->conn.proto_minor < 4)
++		return fuse_reply_err(req, ENOENT);
++
++	memset(&arg, 0, sizeof(arg));
++	fill_entry(&arg, e);
++	return send_reply_ok(req, &arg, size);
++}
++
++int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
++		      const struct fuse_file_info *f)
++{
++	char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)];
++	size_t entrysize = req->se->conn.proto_minor < 9 ?
++		FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(struct fuse_entry_out);
++	struct fuse_entry_out *earg = (struct fuse_entry_out *) buf;
++	struct fuse_open_out *oarg = (struct fuse_open_out *) (buf + entrysize);
++
++	memset(buf, 0, sizeof(buf));
++	fill_entry(earg, e);
++	fill_open(oarg, f);
++	return send_reply_ok(req, buf,
++			     entrysize + sizeof(struct fuse_open_out));
++}
++
++int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
++		    double attr_timeout)
++{
++	struct fuse_attr_out arg;
++	size_t size = req->se->conn.proto_minor < 9 ?
++		FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg);
++
++	memset(&arg, 0, sizeof(arg));
++	arg.attr_valid = calc_timeout_sec(attr_timeout);
++	arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
++	convert_stat(attr, &arg.attr);
++
++	return send_reply_ok(req, &arg, size);
++}
++
++int fuse_reply_readlink(fuse_req_t req, const char *linkname)
++{
++	return send_reply_ok(req, linkname, strlen(linkname));
++}
++
++int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
++{
++	struct fuse_open_out arg;
++
++	memset(&arg, 0, sizeof(arg));
++	fill_open(&arg, f);
++	return send_reply_ok(req, &arg, sizeof(arg));
++}
++
++int fuse_reply_write(fuse_req_t req, size_t count)
++{
++	struct fuse_write_out arg;
++
++	memset(&arg, 0, sizeof(arg));
++	arg.size = count;
++
++	return send_reply_ok(req, &arg, sizeof(arg));
++}
++
++int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
++{
++	return send_reply_ok(req, buf, size);
++}
++
++static int fuse_send_data_iov_fallback(struct fuse_session *se,
++				       struct fuse_chan *ch,
++				       struct iovec *iov, int iov_count,
++				       struct fuse_bufvec *buf,
++				       size_t len)
++{
++	struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
++	void *mbuf;
++	int res;
++
++	/* Optimize common case */
++	if (buf->count == 1 && buf->idx == 0 && buf->off == 0 &&
++	    !(buf->buf[0].flags & FUSE_BUF_IS_FD)) {
++		/* FIXME: also avoid memory copy if there are multiple buffers
++		   but none of them contain an fd */
++
++		iov[iov_count].iov_base = buf->buf[0].mem;
++		iov[iov_count].iov_len = len;
++		iov_count++;
++		return fuse_send_msg(se, ch, iov, iov_count);
++	}
++
++	res = posix_memalign(&mbuf, pagesize, len);
++	if (res != 0)
++		return res;
++
++	mem_buf.buf[0].mem = mbuf;
++	res = fuse_buf_copy(&mem_buf, buf, 0);
++	if (res < 0) {
++		free(mbuf);
++		return -res;
++	}
++	len = res;
++
++	iov[iov_count].iov_base = mbuf;
++	iov[iov_count].iov_len = len;
++	iov_count++;
++	res = fuse_send_msg(se, ch, iov, iov_count);
++	free(mbuf);
++
++	return res;
++}
++
++struct fuse_ll_pipe {
++	size_t size;
++	int can_grow;
++	int pipe[2];
++};
++
++static void fuse_ll_pipe_free(struct fuse_ll_pipe *llp)
++{
++	close(llp->pipe[0]);
++	close(llp->pipe[1]);
++	free(llp);
++}
++
++#ifdef HAVE_SPLICE
++#if !defined(HAVE_PIPE2) || !defined(O_CLOEXEC)
++static int fuse_pipe(int fds[2])
++{
++	int rv = pipe(fds);
++
++	if (rv == -1)
++		return rv;
++
++	if (fcntl(fds[0], F_SETFL, O_NONBLOCK) == -1 ||
++	    fcntl(fds[1], F_SETFL, O_NONBLOCK) == -1 ||
++	    fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
++	    fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
++		close(fds[0]);
++		close(fds[1]);
++		rv = -1;
++	}
++	return rv;
++}
++#else
++static int fuse_pipe(int fds[2])
++{
++	return pipe2(fds, O_CLOEXEC | O_NONBLOCK);
++}
++#endif
++
++static struct fuse_ll_pipe *fuse_ll_get_pipe(struct fuse_session *se)
++{
++	struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key);
++	if (llp == NULL) {
++		int res;
++
++		llp = malloc(sizeof(struct fuse_ll_pipe));
++		if (llp == NULL)
++			return NULL;
++
++		res = fuse_pipe(llp->pipe);
++		if (res == -1) {
++			free(llp);
++			return NULL;
++		}
++
++		/*
++		 *the default size is 16 pages on linux
++		 */
++		llp->size = pagesize * 16;
++		llp->can_grow = 1;
++
++		pthread_setspecific(se->pipe_key, llp);
++	}
++
++	return llp;
++}
++#endif
++
++static void fuse_ll_clear_pipe(struct fuse_session *se)
++{
++	struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key);
++	if (llp) {
++		pthread_setspecific(se->pipe_key, NULL);
++		fuse_ll_pipe_free(llp);
++	}
++}
++
++#if defined(HAVE_SPLICE) && defined(HAVE_VMSPLICE)
++static int read_back(int fd, char *buf, size_t len)
++{
++	int res;
++
++	res = read(fd, buf, len);
++	if (res == -1) {
++		fuse_log(FUSE_LOG_ERR, "fuse: internal error: failed to read back from pipe: %s\n", strerror(errno));
++		return -EIO;
++	}
++	if (res != len) {
++		fuse_log(FUSE_LOG_ERR, "fuse: internal error: short read back from pipe: %i from %zi\n", res, len);
++		return -EIO;
++	}
++	return 0;
++}
++
++static int grow_pipe_to_max(int pipefd)
++{
++	int max;
++	int res;
++	int maxfd;
++	char buf[32];
++
++	maxfd = open("/proc/sys/fs/pipe-max-size", O_RDONLY);
++	if (maxfd < 0)
++		return -errno;
++
++	res = read(maxfd, buf, sizeof(buf) - 1);
++	if (res < 0) {
++		int saved_errno;
++
++		saved_errno = errno;
++		close(maxfd);
++		return -saved_errno;
++	}
++	close(maxfd);
++	buf[res] = '\0';
++
++	max = atoi(buf);
++	res = fcntl(pipefd, F_SETPIPE_SZ, max);
++	if (res < 0)
++		return -errno;
++	return max;
++}
++
++static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
++			       struct iovec *iov, int iov_count,
++			       struct fuse_bufvec *buf, unsigned int flags)
++{
++	int res;
++	size_t len = fuse_buf_size(buf);
++	struct fuse_out_header *out = iov[0].iov_base;
++	struct fuse_ll_pipe *llp;
++	int splice_flags;
++	size_t pipesize;
++	size_t total_fd_size;
++	size_t idx;
++	size_t headerlen;
++	struct fuse_bufvec pipe_buf = FUSE_BUFVEC_INIT(len);
++
++	if (se->broken_splice_nonblock)
++		goto fallback;
++
++	if (flags & FUSE_BUF_NO_SPLICE)
++		goto fallback;
++
++	total_fd_size = 0;
++	for (idx = buf->idx; idx < buf->count; idx++) {
++		if (buf->buf[idx].flags & FUSE_BUF_IS_FD) {
++			total_fd_size = buf->buf[idx].size;
++			if (idx == buf->idx)
++				total_fd_size -= buf->off;
++		}
++	}
++	if (total_fd_size < 2 * pagesize)
++		goto fallback;
++
++	if (se->conn.proto_minor < 14 ||
++	    !(se->conn.want & FUSE_CAP_SPLICE_WRITE))
++		goto fallback;
++
++	llp = fuse_ll_get_pipe(se);
++	if (llp == NULL)
++		goto fallback;
++
++
++	headerlen = iov_length(iov, iov_count);
++
++	out->len = headerlen + len;
++
++	/*
++	 * Heuristic for the required pipe size, does not work if the
++	 * source contains less than page size fragments
++	 */
++	pipesize = pagesize * (iov_count + buf->count + 1) + out->len;
++
++	if (llp->size < pipesize) {
++		if (llp->can_grow) {
++			res = fcntl(llp->pipe[0], F_SETPIPE_SZ, pipesize);
++			if (res == -1) {
++				res = grow_pipe_to_max(llp->pipe[0]);
++				if (res > 0)
++					llp->size = res;
++				llp->can_grow = 0;
++				goto fallback;
++			}
++			llp->size = res;
++		}
++		if (llp->size < pipesize)
++			goto fallback;
++	}
++
++
++	res = vmsplice(llp->pipe[1], iov, iov_count, SPLICE_F_NONBLOCK);
++	if (res == -1)
++		goto fallback;
++
++	if (res != headerlen) {
++		res = -EIO;
++		fuse_log(FUSE_LOG_ERR, "fuse: short vmsplice to pipe: %u/%zu\n", res,
++			headerlen);
++		goto clear_pipe;
++	}
++
++	pipe_buf.buf[0].flags = FUSE_BUF_IS_FD;
++	pipe_buf.buf[0].fd = llp->pipe[1];
++
++	res = fuse_buf_copy(&pipe_buf, buf,
++			    FUSE_BUF_FORCE_SPLICE | FUSE_BUF_SPLICE_NONBLOCK);
++	if (res < 0) {
++		if (res == -EAGAIN || res == -EINVAL) {
++			/*
++			 * Should only get EAGAIN on kernels with
++			 * broken SPLICE_F_NONBLOCK support (<=
++			 * 2.6.35) where this error or a short read is
++			 * returned even if the pipe itself is not
++			 * full
++			 *
++			 * EINVAL might mean that splice can't handle
++			 * this combination of input and output.
++			 */
++			if (res == -EAGAIN)
++				se->broken_splice_nonblock = 1;
++
++			pthread_setspecific(se->pipe_key, NULL);
++			fuse_ll_pipe_free(llp);
++			goto fallback;
++		}
++		res = -res;
++		goto clear_pipe;
++	}
++
++	if (res != 0 && res < len) {
++		struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
++		void *mbuf;
++		size_t now_len = res;
++		/*
++		 * For regular files a short count is either
++		 *  1) due to EOF, or
++		 *  2) because of broken SPLICE_F_NONBLOCK (see above)
++		 *
++		 * For other inputs it's possible that we overflowed
++		 * the pipe because of small buffer fragments.
++		 */
++
++		res = posix_memalign(&mbuf, pagesize, len);
++		if (res != 0)
++			goto clear_pipe;
++
++		mem_buf.buf[0].mem = mbuf;
++		mem_buf.off = now_len;
++		res = fuse_buf_copy(&mem_buf, buf, 0);
++		if (res > 0) {
++			char *tmpbuf;
++			size_t extra_len = res;
++			/*
++			 * Trickiest case: got more data.  Need to get
++			 * back the data from the pipe and then fall
++			 * back to regular write.
++			 */
++			tmpbuf = malloc(headerlen);
++			if (tmpbuf == NULL) {
++				free(mbuf);
++				res = ENOMEM;
++				goto clear_pipe;
++			}
++			res = read_back(llp->pipe[0], tmpbuf, headerlen);
++			free(tmpbuf);
++			if (res != 0) {
++				free(mbuf);
++				goto clear_pipe;
++			}
++			res = read_back(llp->pipe[0], mbuf, now_len);
++			if (res != 0) {
++				free(mbuf);
++				goto clear_pipe;
++			}
++			len = now_len + extra_len;
++			iov[iov_count].iov_base = mbuf;
++			iov[iov_count].iov_len = len;
++			iov_count++;
++			res = fuse_send_msg(se, ch, iov, iov_count);
++			free(mbuf);
++			return res;
++		}
++		free(mbuf);
++		res = now_len;
++	}
++	len = res;
++	out->len = headerlen + len;
++
++	if (se->debug) {
++		fuse_log(FUSE_LOG_DEBUG,
++			"   unique: %llu, success, outsize: %i (splice)\n",
++			(unsigned long long) out->unique, out->len);
++	}
++
++	splice_flags = 0;
++	if ((flags & FUSE_BUF_SPLICE_MOVE) &&
++	    (se->conn.want & FUSE_CAP_SPLICE_MOVE))
++		splice_flags |= SPLICE_F_MOVE;
++
++	res = splice(llp->pipe[0], NULL, ch ? ch->fd : se->fd,
++		     NULL, out->len, splice_flags);
++	if (res == -1) {
++		res = -errno;
++		perror("fuse: splice from pipe");
++		goto clear_pipe;
++	}
++	if (res != out->len) {
++		res = -EIO;
++		fuse_log(FUSE_LOG_ERR, "fuse: short splice from pipe: %u/%u\n",
++			res, out->len);
++		goto clear_pipe;
++	}
++	return 0;
++
++clear_pipe:
++	fuse_ll_clear_pipe(se);
++	return res;
++
++fallback:
++	return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
++}
++#else
++static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
++			       struct iovec *iov, int iov_count,
++			       struct fuse_bufvec *buf, unsigned int flags)
++{
++	size_t len = fuse_buf_size(buf);
++	(void) flags;
++
++	return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
++}
++#endif
++
++int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
++		    enum fuse_buf_copy_flags flags)
++{
++	struct iovec iov[2];
++	struct fuse_out_header out;
++	int res;
++
++	iov[0].iov_base = &out;
++	iov[0].iov_len = sizeof(struct fuse_out_header);
++
++	out.unique = req->unique;
++	out.error = 0;
++
++	res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags);
++	if (res <= 0) {
++		fuse_free_req(req);
++		return res;
++	} else {
++		return fuse_reply_err(req, res);
++	}
++}
++
++int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
++{
++	struct fuse_statfs_out arg;
++	size_t size = req->se->conn.proto_minor < 4 ?
++		FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
++
++	memset(&arg, 0, sizeof(arg));
++	convert_statfs(stbuf, &arg.st);
++
++	return send_reply_ok(req, &arg, size);
++}
++
++int fuse_reply_xattr(fuse_req_t req, size_t count)
++{
++	struct fuse_getxattr_out arg;
++
++	memset(&arg, 0, sizeof(arg));
++	arg.size = count;
++
++	return send_reply_ok(req, &arg, sizeof(arg));
++}
++
++int fuse_reply_lock(fuse_req_t req, const struct flock *lock)
++{
++	struct fuse_lk_out arg;
++
++	memset(&arg, 0, sizeof(arg));
++	arg.lk.type = lock->l_type;
++	if (lock->l_type != F_UNLCK) {
++		arg.lk.start = lock->l_start;
++		if (lock->l_len == 0)
++			arg.lk.end = OFFSET_MAX;
++		else
++			arg.lk.end = lock->l_start + lock->l_len - 1;
++	}
++	arg.lk.pid = lock->l_pid;
++	return send_reply_ok(req, &arg, sizeof(arg));
++}
++
++int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
++{
++	struct fuse_bmap_out arg;
++
++	memset(&arg, 0, sizeof(arg));
++	arg.block = idx;
++
++	return send_reply_ok(req, &arg, sizeof(arg));
++}
++
++static struct fuse_ioctl_iovec *fuse_ioctl_iovec_copy(const struct iovec *iov,
++						      size_t count)
++{
++	struct fuse_ioctl_iovec *fiov;
++	size_t i;
++
++	fiov = malloc(sizeof(fiov[0]) * count);
++	if (!fiov)
++		return NULL;
++
++	for (i = 0; i < count; i++) {
++		fiov[i].base = (uintptr_t) iov[i].iov_base;
++		fiov[i].len = iov[i].iov_len;
++	}
++
++	return fiov;
++}
++
++int fuse_reply_ioctl_retry(fuse_req_t req,
++			   const struct iovec *in_iov, size_t in_count,
++			   const struct iovec *out_iov, size_t out_count)
++{
++	struct fuse_ioctl_out arg;
++	struct fuse_ioctl_iovec *in_fiov = NULL;
++	struct fuse_ioctl_iovec *out_fiov = NULL;
++	struct iovec iov[4];
++	size_t count = 1;
++	int res;
++
++	memset(&arg, 0, sizeof(arg));
++	arg.flags |= FUSE_IOCTL_RETRY;
++	arg.in_iovs = in_count;
++	arg.out_iovs = out_count;
++	iov[count].iov_base = &arg;
++	iov[count].iov_len = sizeof(arg);
++	count++;
++
++	if (req->se->conn.proto_minor < 16) {
++		if (in_count) {
++			iov[count].iov_base = (void *)in_iov;
++			iov[count].iov_len = sizeof(in_iov[0]) * in_count;
++			count++;
++		}
++
++		if (out_count) {
++			iov[count].iov_base = (void *)out_iov;
++			iov[count].iov_len = sizeof(out_iov[0]) * out_count;
++			count++;
++		}
++	} else {
++		/* Can't handle non-compat 64bit ioctls on 32bit */
++		if (sizeof(void *) == 4 && req->ioctl_64bit) {
++			res = fuse_reply_err(req, EINVAL);
++			goto out;
++		}
++
++		if (in_count) {
++			in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count);
++			if (!in_fiov)
++				goto enomem;
++
++			iov[count].iov_base = (void *)in_fiov;
++			iov[count].iov_len = sizeof(in_fiov[0]) * in_count;
++			count++;
++		}
++		if (out_count) {
++			out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count);
++			if (!out_fiov)
++				goto enomem;
++
++			iov[count].iov_base = (void *)out_fiov;
++			iov[count].iov_len = sizeof(out_fiov[0]) * out_count;
++			count++;
++		}
++	}
++
++	res = send_reply_iov(req, 0, iov, count);
++out:
++	free(in_fiov);
++	free(out_fiov);
++
++	return res;
++
++enomem:
++	res = fuse_reply_err(req, ENOMEM);
++	goto out;
++}
++
++int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
++{
++	struct fuse_ioctl_out arg;
++	struct iovec iov[3];
++	size_t count = 1;
++
++	memset(&arg, 0, sizeof(arg));
++	arg.result = result;
++	iov[count].iov_base = &arg;
++	iov[count].iov_len = sizeof(arg);
++	count++;
++
++	if (size) {
++		iov[count].iov_base = (char *) buf;
++		iov[count].iov_len = size;
++		count++;
++	}
++
++	return send_reply_iov(req, 0, iov, count);
++}
++
++int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov,
++			 int count)
++{
++	struct iovec *padded_iov;
++	struct fuse_ioctl_out arg;
++	int res;
++
++	padded_iov = malloc((count + 2) * sizeof(struct iovec));
++	if (padded_iov == NULL)
++		return fuse_reply_err(req, ENOMEM);
++
++	memset(&arg, 0, sizeof(arg));
++	arg.result = result;
++	padded_iov[1].iov_base = &arg;
++	padded_iov[1].iov_len = sizeof(arg);
++
++	memcpy(&padded_iov[2], iov, count * sizeof(struct iovec));
++
++	res = send_reply_iov(req, 0, padded_iov, count + 2);
++	free(padded_iov);
++
++	return res;
++}
++
++int fuse_reply_poll(fuse_req_t req, unsigned revents)
++{
++	struct fuse_poll_out arg;
++
++	memset(&arg, 0, sizeof(arg));
++	arg.revents = revents;
++
++	return send_reply_ok(req, &arg, sizeof(arg));
++}
++
++int fuse_reply_lseek(fuse_req_t req, off_t off)
++{
++	struct fuse_lseek_out arg;
++
++	memset(&arg, 0, sizeof(arg));
++	arg.offset = off;
++
++	return send_reply_ok(req, &arg, sizeof(arg));
++}
++
++static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	char *name = (char *) inarg;
++
++	if (req->se->op.lookup)
++		req->se->op.lookup(req, nodeid, name);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_forget_in *arg = (struct fuse_forget_in *) inarg;
++
++	if (req->se->op.forget)
++		req->se->op.forget(req, nodeid, arg->nlookup);
++	else
++		fuse_reply_none(req);
++}
++
++static void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid,
++			    const void *inarg)
++{
++	struct fuse_batch_forget_in *arg = (void *) inarg;
++	struct fuse_forget_one *param = (void *) PARAM(arg);
++	unsigned int i;
++
++	(void) nodeid;
++
++	if (req->se->op.forget_multi) {
++		req->se->op.forget_multi(req, arg->count,
++				     (struct fuse_forget_data *) param);
++	} else if (req->se->op.forget) {
++		for (i = 0; i < arg->count; i++) {
++			struct fuse_forget_one *forget = &param[i];
++			struct fuse_req *dummy_req;
++
++			dummy_req = fuse_ll_alloc_req(req->se);
++			if (dummy_req == NULL)
++				break;
++
++			dummy_req->unique = req->unique;
++			dummy_req->ctx = req->ctx;
++			dummy_req->ch = NULL;
++
++			req->se->op.forget(dummy_req, forget->nodeid,
++					  forget->nlookup);
++		}
++		fuse_reply_none(req);
++	} else {
++		fuse_reply_none(req);
++	}
++}
++
++static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_file_info *fip = NULL;
++	struct fuse_file_info fi;
++
++	if (req->se->conn.proto_minor >= 9) {
++		struct fuse_getattr_in *arg = (struct fuse_getattr_in *) inarg;
++
++		if (arg->getattr_flags & FUSE_GETATTR_FH) {
++			memset(&fi, 0, sizeof(fi));
++			fi.fh = arg->fh;
++			fip = &fi;
++		}
++	}
++
++	if (req->se->op.getattr)
++		req->se->op.getattr(req, nodeid, fip);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_setattr_in *arg = (struct fuse_setattr_in *) inarg;
++
++	if (req->se->op.setattr) {
++		struct fuse_file_info *fi = NULL;
++		struct fuse_file_info fi_store;
++		struct stat stbuf;
++		memset(&stbuf, 0, sizeof(stbuf));
++		convert_attr(arg, &stbuf);
++		if (arg->valid & FATTR_FH) {
++			arg->valid &= ~FATTR_FH;
++			memset(&fi_store, 0, sizeof(fi_store));
++			fi = &fi_store;
++			fi->fh = arg->fh;
++		}
++		arg->valid &=
++			FUSE_SET_ATTR_MODE	|
++			FUSE_SET_ATTR_UID	|
++			FUSE_SET_ATTR_GID	|
++			FUSE_SET_ATTR_SIZE	|
++			FUSE_SET_ATTR_ATIME	|
++			FUSE_SET_ATTR_MTIME	|
++			FUSE_SET_ATTR_ATIME_NOW	|
++			FUSE_SET_ATTR_MTIME_NOW |
++			FUSE_SET_ATTR_CTIME;
++
++		req->se->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
++	} else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_access_in *arg = (struct fuse_access_in *) inarg;
++
++	if (req->se->op.access)
++		req->se->op.access(req, nodeid, arg->mask);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	(void) inarg;
++
++	if (req->se->op.readlink)
++		req->se->op.readlink(req, nodeid);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg;
++	char *name = PARAM(arg);
++
++	if (req->se->conn.proto_minor >= 12)
++		req->ctx.umask = arg->umask;
++	else
++		name = (char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
++
++	if (req->se->op.mknod)
++		req->se->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg;
++
++	if (req->se->conn.proto_minor >= 12)
++		req->ctx.umask = arg->umask;
++
++	if (req->se->op.mkdir)
++		req->se->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	char *name = (char *) inarg;
++
++	if (req->se->op.unlink)
++		req->se->op.unlink(req, nodeid, name);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	char *name = (char *) inarg;
++
++	if (req->se->op.rmdir)
++		req->se->op.rmdir(req, nodeid, name);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	char *name = (char *) inarg;
++	char *linkname = ((char *) inarg) + strlen((char *) inarg) + 1;
++
++	if (req->se->op.symlink)
++		req->se->op.symlink(req, linkname, nodeid, name);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_rename_in *arg = (struct fuse_rename_in *) inarg;
++	char *oldname = PARAM(arg);
++	char *newname = oldname + strlen(oldname) + 1;
++
++	if (req->se->op.rename)
++		req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
++				  0);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_rename2(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_rename2_in *arg = (struct fuse_rename2_in *) inarg;
++	char *oldname = PARAM(arg);
++	char *newname = oldname + strlen(oldname) + 1;
++
++	if (req->se->op.rename)
++		req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
++				  arg->flags);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_link_in *arg = (struct fuse_link_in *) inarg;
++
++	if (req->se->op.link)
++		req->se->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_create_in *arg = (struct fuse_create_in *) inarg;
++
++	if (req->se->op.create) {
++		struct fuse_file_info fi;
++		char *name = PARAM(arg);
++
++		memset(&fi, 0, sizeof(fi));
++		fi.flags = arg->flags;
++
++		if (req->se->conn.proto_minor >= 12)
++			req->ctx.umask = arg->umask;
++		else
++			name = (char *) inarg + sizeof(struct fuse_open_in);
++
++		req->se->op.create(req, nodeid, name, arg->mode, &fi);
++	} else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
++	struct fuse_file_info fi;
++
++	memset(&fi, 0, sizeof(fi));
++	fi.flags = arg->flags;
++
++	if (req->se->op.open)
++		req->se->op.open(req, nodeid, &fi);
++	else
++		fuse_reply_open(req, &fi);
++}
++
++static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
++
++	if (req->se->op.read) {
++		struct fuse_file_info fi;
++
++		memset(&fi, 0, sizeof(fi));
++		fi.fh = arg->fh;
++		if (req->se->conn.proto_minor >= 9) {
++			fi.lock_owner = arg->lock_owner;
++			fi.flags = arg->flags;
++		}
++		req->se->op.read(req, nodeid, arg->size, arg->offset, &fi);
++	} else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
++	struct fuse_file_info fi;
++	char *param;
++
++	memset(&fi, 0, sizeof(fi));
++	fi.fh = arg->fh;
++	fi.writepage = (arg->write_flags & FUSE_WRITE_CACHE) != 0;
++
++	if (req->se->conn.proto_minor < 9) {
++		param = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE;
++	} else {
++		fi.lock_owner = arg->lock_owner;
++		fi.flags = arg->flags;
++		param = PARAM(arg);
++	}
++
++	if (req->se->op.write)
++		req->se->op.write(req, nodeid, param, arg->size,
++				 arg->offset, &fi);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid, const void *inarg,
++			 const struct fuse_buf *ibuf)
++{
++	struct fuse_session *se = req->se;
++	struct fuse_bufvec bufv = {
++		.buf[0] = *ibuf,
++		.count = 1,
++	};
++	struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
++	struct fuse_file_info fi;
++
++	memset(&fi, 0, sizeof(fi));
++	fi.fh = arg->fh;
++	fi.writepage = arg->write_flags & FUSE_WRITE_CACHE;
++
++	if (se->conn.proto_minor < 9) {
++		bufv.buf[0].mem = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE;
++		bufv.buf[0].size -= sizeof(struct fuse_in_header) +
++			FUSE_COMPAT_WRITE_IN_SIZE;
++		assert(!(bufv.buf[0].flags & FUSE_BUF_IS_FD));
++	} else {
++		fi.lock_owner = arg->lock_owner;
++		fi.flags = arg->flags;
++		if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
++			bufv.buf[0].mem = PARAM(arg);
++
++		bufv.buf[0].size -= sizeof(struct fuse_in_header) +
++			sizeof(struct fuse_write_in);
++	}
++	if (bufv.buf[0].size < arg->size) {
++		fuse_log(FUSE_LOG_ERR, "fuse: do_write_buf: buffer size too small\n");
++		fuse_reply_err(req, EIO);
++		goto out;
++	}
++	bufv.buf[0].size = arg->size;
++
++	se->op.write_buf(req, nodeid, &bufv, arg->offset, &fi);
++
++out:
++	/* Need to reset the pipe if ->write_buf() didn't consume all data */
++	if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count)
++		fuse_ll_clear_pipe(se);
++}
++
++static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_flush_in *arg = (struct fuse_flush_in *) inarg;
++	struct fuse_file_info fi;
++
++	memset(&fi, 0, sizeof(fi));
++	fi.fh = arg->fh;
++	fi.flush = 1;
++	if (req->se->conn.proto_minor >= 7)
++		fi.lock_owner = arg->lock_owner;
++
++	if (req->se->op.flush)
++		req->se->op.flush(req, nodeid, &fi);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
++	struct fuse_file_info fi;
++
++	memset(&fi, 0, sizeof(fi));
++	fi.flags = arg->flags;
++	fi.fh = arg->fh;
++	if (req->se->conn.proto_minor >= 8) {
++		fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
++		fi.lock_owner = arg->lock_owner;
++	}
++	if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) {
++		fi.flock_release = 1;
++		fi.lock_owner = arg->lock_owner;
++	}
++
++	if (req->se->op.release)
++		req->se->op.release(req, nodeid, &fi);
++	else
++		fuse_reply_err(req, 0);
++}
++
++static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
++	struct fuse_file_info fi;
++	int datasync = arg->fsync_flags & 1;
++
++	memset(&fi, 0, sizeof(fi));
++	fi.fh = arg->fh;
++
++	if (req->se->op.fsync)
++		req->se->op.fsync(req, nodeid, datasync, &fi);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
++	struct fuse_file_info fi;
++
++	memset(&fi, 0, sizeof(fi));
++	fi.flags = arg->flags;
++
++	if (req->se->op.opendir)
++		req->se->op.opendir(req, nodeid, &fi);
++	else
++		fuse_reply_open(req, &fi);
++}
++
++static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
++	struct fuse_file_info fi;
++
++	memset(&fi, 0, sizeof(fi));
++	fi.fh = arg->fh;
++
++	if (req->se->op.readdir)
++		req->se->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_readdirplus(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
++	struct fuse_file_info fi;
++
++	memset(&fi, 0, sizeof(fi));
++	fi.fh = arg->fh;
++
++	if (req->se->op.readdirplus)
++		req->se->op.readdirplus(req, nodeid, arg->size, arg->offset, &fi);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
++	struct fuse_file_info fi;
++
++	memset(&fi, 0, sizeof(fi));
++	fi.flags = arg->flags;
++	fi.fh = arg->fh;
++
++	if (req->se->op.releasedir)
++		req->se->op.releasedir(req, nodeid, &fi);
++	else
++		fuse_reply_err(req, 0);
++}
++
++static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
++	struct fuse_file_info fi;
++	int datasync = arg->fsync_flags & 1;
++
++	memset(&fi, 0, sizeof(fi));
++	fi.fh = arg->fh;
++
++	if (req->se->op.fsyncdir)
++		req->se->op.fsyncdir(req, nodeid, datasync, &fi);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	(void) nodeid;
++	(void) inarg;
++
++	if (req->se->op.statfs)
++		req->se->op.statfs(req, nodeid);
++	else {
++		struct statvfs buf = {
++			.f_namemax = 255,
++			.f_bsize = 512,
++		};
++		fuse_reply_statfs(req, &buf);
++	}
++}
++
++static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg;
++	char *name = PARAM(arg);
++	char *value = name + strlen(name) + 1;
++
++	if (req->se->op.setxattr)
++		req->se->op.setxattr(req, nodeid, name, value, arg->size,
++				    arg->flags);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
++
++	if (req->se->op.getxattr)
++		req->se->op.getxattr(req, nodeid, PARAM(arg), arg->size);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
++
++	if (req->se->op.listxattr)
++		req->se->op.listxattr(req, nodeid, arg->size);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	char *name = (char *) inarg;
++
++	if (req->se->op.removexattr)
++		req->se->op.removexattr(req, nodeid, name);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void convert_fuse_file_lock(struct fuse_file_lock *fl,
++				   struct flock *flock)
++{
++	memset(flock, 0, sizeof(struct flock));
++	flock->l_type = fl->type;
++	flock->l_whence = SEEK_SET;
++	flock->l_start = fl->start;
++	if (fl->end == OFFSET_MAX)
++		flock->l_len = 0;
++	else
++		flock->l_len = fl->end - fl->start + 1;
++	flock->l_pid = fl->pid;
++}
++
++static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg;
++	struct fuse_file_info fi;
++	struct flock flock;
++
++	memset(&fi, 0, sizeof(fi));
++	fi.fh = arg->fh;
++	fi.lock_owner = arg->owner;
++
++	convert_fuse_file_lock(&arg->lk, &flock);
++	if (req->se->op.getlk)
++		req->se->op.getlk(req, nodeid, &fi, &flock);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid,
++			    const void *inarg, int sleep)
++{
++	struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg;
++	struct fuse_file_info fi;
++	struct flock flock;
++
++	memset(&fi, 0, sizeof(fi));
++	fi.fh = arg->fh;
++	fi.lock_owner = arg->owner;
++
++	if (arg->lk_flags & FUSE_LK_FLOCK) {
++		int op = 0;
++
++		switch (arg->lk.type) {
++		case F_RDLCK:
++			op = LOCK_SH;
++			break;
++		case F_WRLCK:
++			op = LOCK_EX;
++			break;
++		case F_UNLCK:
++			op = LOCK_UN;
++			break;
++		}
++		if (!sleep)
++			op |= LOCK_NB;
++
++		if (req->se->op.flock)
++			req->se->op.flock(req, nodeid, &fi, op);
++		else
++			fuse_reply_err(req, ENOSYS);
++	} else {
++		convert_fuse_file_lock(&arg->lk, &flock);
++		if (req->se->op.setlk)
++			req->se->op.setlk(req, nodeid, &fi, &flock, sleep);
++		else
++			fuse_reply_err(req, ENOSYS);
++	}
++}
++
++static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	do_setlk_common(req, nodeid, inarg, 0);
++}
++
++static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	do_setlk_common(req, nodeid, inarg, 1);
++}
++
++static int find_interrupted(struct fuse_session *se, struct fuse_req *req)
++{
++	struct fuse_req *curr;
++
++	for (curr = se->list.next; curr != &se->list; curr = curr->next) {
++		if (curr->unique == req->u.i.unique) {
++			fuse_interrupt_func_t func;
++			void *data;
++
++			curr->ctr++;
++			pthread_mutex_unlock(&se->lock);
++
++			/* Ugh, ugly locking */
++			pthread_mutex_lock(&curr->lock);
++			pthread_mutex_lock(&se->lock);
++			curr->interrupted = 1;
++			func = curr->u.ni.func;
++			data = curr->u.ni.data;
++			pthread_mutex_unlock(&se->lock);
++			if (func)
++				func(curr, data);
++			pthread_mutex_unlock(&curr->lock);
++
++			pthread_mutex_lock(&se->lock);
++			curr->ctr--;
++			if (!curr->ctr)
++				destroy_req(curr);
++
++			return 1;
++		}
++	}
++	for (curr = se->interrupts.next; curr != &se->interrupts;
++	     curr = curr->next) {
++		if (curr->u.i.unique == req->u.i.unique)
++			return 1;
++	}
++	return 0;
++}
++
++static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *) inarg;
++	struct fuse_session *se = req->se;
++
++	(void) nodeid;
++	if (se->debug)
++		fuse_log(FUSE_LOG_DEBUG, "INTERRUPT: %llu\n",
++			(unsigned long long) arg->unique);
++
++	req->u.i.unique = arg->unique;
++
++	pthread_mutex_lock(&se->lock);
++	if (find_interrupted(se, req))
++		destroy_req(req);
++	else
++		list_add_req(req, &se->interrupts);
++	pthread_mutex_unlock(&se->lock);
++}
++
++static struct fuse_req *check_interrupt(struct fuse_session *se,
++					struct fuse_req *req)
++{
++	struct fuse_req *curr;
++
++	for (curr = se->interrupts.next; curr != &se->interrupts;
++	     curr = curr->next) {
++		if (curr->u.i.unique == req->unique) {
++			req->interrupted = 1;
++			list_del_req(curr);
++			free(curr);
++			return NULL;
++		}
++	}
++	curr = se->interrupts.next;
++	if (curr != &se->interrupts) {
++		list_del_req(curr);
++		list_init_req(curr);
++		return curr;
++	} else
++		return NULL;
++}
++
++static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_bmap_in *arg = (struct fuse_bmap_in *) inarg;
++
++	if (req->se->op.bmap)
++		req->se->op.bmap(req, nodeid, arg->blocksize, arg->block);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_ioctl_in *arg = (struct fuse_ioctl_in *) inarg;
++	unsigned int flags = arg->flags;
++	void *in_buf = arg->in_size ? PARAM(arg) : NULL;
++	struct fuse_file_info fi;
++
++	if (flags & FUSE_IOCTL_DIR &&
++	    !(req->se->conn.want & FUSE_CAP_IOCTL_DIR)) {
++		fuse_reply_err(req, ENOTTY);
++		return;
++	}
++
++	memset(&fi, 0, sizeof(fi));
++	fi.fh = arg->fh;
++
++	if (sizeof(void *) == 4 && req->se->conn.proto_minor >= 16 &&
++	    !(flags & FUSE_IOCTL_32BIT)) {
++		req->ioctl_64bit = 1;
++	}
++
++	if (req->se->op.ioctl)
++		req->se->op.ioctl(req, nodeid, arg->cmd,
++				 (void *)(uintptr_t)arg->arg, &fi, flags,
++				 in_buf, arg->in_size, arg->out_size);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
++{
++	free(ph);
++}
++
++static void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_poll_in *arg = (struct fuse_poll_in *) inarg;
++	struct fuse_file_info fi;
++
++	memset(&fi, 0, sizeof(fi));
++	fi.fh = arg->fh;
++	fi.poll_events = arg->events;
++
++	if (req->se->op.poll) {
++		struct fuse_pollhandle *ph = NULL;
++
++		if (arg->flags & FUSE_POLL_SCHEDULE_NOTIFY) {
++			ph = malloc(sizeof(struct fuse_pollhandle));
++			if (ph == NULL) {
++				fuse_reply_err(req, ENOMEM);
++				return;
++			}
++			ph->kh = arg->kh;
++			ph->se = req->se;
++		}
++
++		req->se->op.poll(req, nodeid, &fi, ph);
++	} else {
++		fuse_reply_err(req, ENOSYS);
++	}
++}
++
++static void do_fallocate(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_fallocate_in *arg = (struct fuse_fallocate_in *) inarg;
++	struct fuse_file_info fi;
++
++	memset(&fi, 0, sizeof(fi));
++	fi.fh = arg->fh;
++
++	if (req->se->op.fallocate)
++		req->se->op.fallocate(req, nodeid, arg->mode, arg->offset, arg->length, &fi);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in, const void *inarg)
++{
++	struct fuse_copy_file_range_in *arg = (struct fuse_copy_file_range_in *) inarg;
++	struct fuse_file_info fi_in, fi_out;
++
++	memset(&fi_in, 0, sizeof(fi_in));
++	fi_in.fh = arg->fh_in;
++
++	memset(&fi_out, 0, sizeof(fi_out));
++	fi_out.fh = arg->fh_out;
++
++
++	if (req->se->op.copy_file_range)
++		req->se->op.copy_file_range(req, nodeid_in, arg->off_in,
++					    &fi_in, arg->nodeid_out,
++					    arg->off_out, &fi_out, arg->len,
++					    arg->flags);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_lseek(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_lseek_in *arg = (struct fuse_lseek_in *) inarg;
++	struct fuse_file_info fi;
++
++	memset(&fi, 0, sizeof(fi));
++	fi.fh = arg->fh;
++
++	if (req->se->op.lseek)
++		req->se->op.lseek(req, nodeid, arg->offset, arg->whence, &fi);
++	else
++		fuse_reply_err(req, ENOSYS);
++}
++
++static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
++	struct fuse_init_out outarg;
++	struct fuse_session *se = req->se;
++	size_t bufsize = se->bufsize;
++	size_t outargsize = sizeof(outarg);
++
++	(void) nodeid;
++	if (se->debug) {
++		fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor);
++		if (arg->major == 7 && arg->minor >= 6) {
++			fuse_log(FUSE_LOG_DEBUG, "flags=0x%08x\n", arg->flags);
++			fuse_log(FUSE_LOG_DEBUG, "max_readahead=0x%08x\n",
++				arg->max_readahead);
++		}
++	}
++	se->conn.proto_major = arg->major;
++	se->conn.proto_minor = arg->minor;
++	se->conn.capable = 0;
++	se->conn.want = 0;
++
++	memset(&outarg, 0, sizeof(outarg));
++	outarg.major = FUSE_KERNEL_VERSION;
++	outarg.minor = FUSE_KERNEL_MINOR_VERSION;
++
++	if (arg->major < 7) {
++		fuse_log(FUSE_LOG_ERR, "fuse: unsupported protocol version: %u.%u\n",
++			arg->major, arg->minor);
++		fuse_reply_err(req, EPROTO);
++		return;
++	}
++
++	if (arg->major > 7) {
++		/* Wait for a second INIT request with a 7.X version */
++		send_reply_ok(req, &outarg, sizeof(outarg));
++		return;
++	}
++
++	if (arg->minor >= 6) {
++		if (arg->max_readahead < se->conn.max_readahead)
++			se->conn.max_readahead = arg->max_readahead;
++		if (arg->flags & FUSE_ASYNC_READ)
++			se->conn.capable |= FUSE_CAP_ASYNC_READ;
++		if (arg->flags & FUSE_POSIX_LOCKS)
++			se->conn.capable |= FUSE_CAP_POSIX_LOCKS;
++		if (arg->flags & FUSE_ATOMIC_O_TRUNC)
++			se->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC;
++		if (arg->flags & FUSE_EXPORT_SUPPORT)
++			se->conn.capable |= FUSE_CAP_EXPORT_SUPPORT;
++		if (arg->flags & FUSE_DONT_MASK)
++			se->conn.capable |= FUSE_CAP_DONT_MASK;
++		if (arg->flags & FUSE_FLOCK_LOCKS)
++			se->conn.capable |= FUSE_CAP_FLOCK_LOCKS;
++		if (arg->flags & FUSE_AUTO_INVAL_DATA)
++			se->conn.capable |= FUSE_CAP_AUTO_INVAL_DATA;
++		if (arg->flags & FUSE_DO_READDIRPLUS)
++			se->conn.capable |= FUSE_CAP_READDIRPLUS;
++		if (arg->flags & FUSE_READDIRPLUS_AUTO)
++			se->conn.capable |= FUSE_CAP_READDIRPLUS_AUTO;
++		if (arg->flags & FUSE_ASYNC_DIO)
++			se->conn.capable |= FUSE_CAP_ASYNC_DIO;
++		if (arg->flags & FUSE_WRITEBACK_CACHE)
++			se->conn.capable |= FUSE_CAP_WRITEBACK_CACHE;
++		if (arg->flags & FUSE_NO_OPEN_SUPPORT)
++			se->conn.capable |= FUSE_CAP_NO_OPEN_SUPPORT;
++		if (arg->flags & FUSE_PARALLEL_DIROPS)
++			se->conn.capable |= FUSE_CAP_PARALLEL_DIROPS;
++		if (arg->flags & FUSE_POSIX_ACL)
++			se->conn.capable |= FUSE_CAP_POSIX_ACL;
++		if (arg->flags & FUSE_HANDLE_KILLPRIV)
++			se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV;
++		if (arg->flags & FUSE_NO_OPENDIR_SUPPORT)
++			se->conn.capable |= FUSE_CAP_NO_OPENDIR_SUPPORT;
++		if (!(arg->flags & FUSE_MAX_PAGES)) {
++			size_t max_bufsize =
++				FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize()
++				+ FUSE_BUFFER_HEADER_SIZE;
++			if (bufsize > max_bufsize) {
++				bufsize = max_bufsize;
++			}
++		}
++	} else {
++		se->conn.max_readahead = 0;
++	}
++
++	if (se->conn.proto_minor >= 14) {
++#ifdef HAVE_SPLICE
++#ifdef HAVE_VMSPLICE
++		se->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE;
++#endif
++		se->conn.capable |= FUSE_CAP_SPLICE_READ;
++#endif
++	}
++	if (se->conn.proto_minor >= 18)
++		se->conn.capable |= FUSE_CAP_IOCTL_DIR;
++
++	/* Default settings for modern filesystems.
++	 *
++	 * Most of these capabilities were disabled by default in
++	 * libfuse2 for backwards compatibility reasons. In libfuse3,
++	 * we can finally enable them by default (as long as they're
++	 * supported by the kernel).
++	 */
++#define LL_SET_DEFAULT(cond, cap) \
++	if ((cond) && (se->conn.capable & (cap))) \
++		se->conn.want |= (cap)
++	LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_READ);
++	LL_SET_DEFAULT(1, FUSE_CAP_PARALLEL_DIROPS);
++	LL_SET_DEFAULT(1, FUSE_CAP_AUTO_INVAL_DATA);
++	LL_SET_DEFAULT(1, FUSE_CAP_HANDLE_KILLPRIV);
++	LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_DIO);
++	LL_SET_DEFAULT(1, FUSE_CAP_IOCTL_DIR);
++	LL_SET_DEFAULT(1, FUSE_CAP_ATOMIC_O_TRUNC);
++	LL_SET_DEFAULT(se->op.write_buf, FUSE_CAP_SPLICE_READ);
++	LL_SET_DEFAULT(se->op.getlk && se->op.setlk,
++		       FUSE_CAP_POSIX_LOCKS);
++	LL_SET_DEFAULT(se->op.flock, FUSE_CAP_FLOCK_LOCKS);
++	LL_SET_DEFAULT(se->op.readdirplus, FUSE_CAP_READDIRPLUS);
++	LL_SET_DEFAULT(se->op.readdirplus && se->op.readdir,
++		       FUSE_CAP_READDIRPLUS_AUTO);
++	se->conn.time_gran = 1;
++	
++	if (bufsize < FUSE_MIN_READ_BUFFER) {
++		fuse_log(FUSE_LOG_ERR, "fuse: warning: buffer size too small: %zu\n",
++			bufsize);
++		bufsize = FUSE_MIN_READ_BUFFER;
++	}
++	se->bufsize = bufsize;
++
++	if (se->conn.max_write > bufsize - FUSE_BUFFER_HEADER_SIZE)
++		se->conn.max_write = bufsize - FUSE_BUFFER_HEADER_SIZE;
++
++	se->got_init = 1;
++	if (se->op.init)
++		se->op.init(se->userdata, &se->conn);
++
++	if (se->conn.want & (~se->conn.capable)) {
++		fuse_log(FUSE_LOG_ERR, "fuse: error: filesystem requested capabilities "
++			"0x%x that are not supported by kernel, aborting.\n",
++			se->conn.want & (~se->conn.capable));
++		fuse_reply_err(req, EPROTO);
++		se->error = -EPROTO;
++		fuse_session_exit(se);
++		return;
++	}
++
++	unsigned max_read_mo = get_max_read(se->mo);
++	if (se->conn.max_read != max_read_mo) {
++		fuse_log(FUSE_LOG_ERR, "fuse: error: init() and fuse_session_new() "
++			"requested different maximum read size (%u vs %u)\n",
++			se->conn.max_read, max_read_mo);
++		fuse_reply_err(req, EPROTO);
++		se->error = -EPROTO;
++		fuse_session_exit(se);
++		return;
++	}
++
++	if (se->conn.max_write < bufsize - FUSE_BUFFER_HEADER_SIZE) {
++		se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
++	}
++	if (arg->flags & FUSE_MAX_PAGES) {
++		outarg.flags |= FUSE_MAX_PAGES;
++		outarg.max_pages = (se->conn.max_write - 1) / getpagesize() + 1;
++	}
++
++	/* Always enable big writes, this is superseded
++	   by the max_write option */
++	outarg.flags |= FUSE_BIG_WRITES;
++
++	if (se->conn.want & FUSE_CAP_ASYNC_READ)
++		outarg.flags |= FUSE_ASYNC_READ;
++	if (se->conn.want & FUSE_CAP_POSIX_LOCKS)
++		outarg.flags |= FUSE_POSIX_LOCKS;
++	if (se->conn.want & FUSE_CAP_ATOMIC_O_TRUNC)
++		outarg.flags |= FUSE_ATOMIC_O_TRUNC;
++	if (se->conn.want & FUSE_CAP_EXPORT_SUPPORT)
++		outarg.flags |= FUSE_EXPORT_SUPPORT;
++	if (se->conn.want & FUSE_CAP_DONT_MASK)
++		outarg.flags |= FUSE_DONT_MASK;
++	if (se->conn.want & FUSE_CAP_FLOCK_LOCKS)
++		outarg.flags |= FUSE_FLOCK_LOCKS;
++	if (se->conn.want & FUSE_CAP_AUTO_INVAL_DATA)
++		outarg.flags |= FUSE_AUTO_INVAL_DATA;
++	if (se->conn.want & FUSE_CAP_READDIRPLUS)
++		outarg.flags |= FUSE_DO_READDIRPLUS;
++	if (se->conn.want & FUSE_CAP_READDIRPLUS_AUTO)
++		outarg.flags |= FUSE_READDIRPLUS_AUTO;
++	if (se->conn.want & FUSE_CAP_ASYNC_DIO)
++		outarg.flags |= FUSE_ASYNC_DIO;
++	if (se->conn.want & FUSE_CAP_WRITEBACK_CACHE)
++		outarg.flags |= FUSE_WRITEBACK_CACHE;
++	if (se->conn.want & FUSE_CAP_POSIX_ACL)
++		outarg.flags |= FUSE_POSIX_ACL;
++	outarg.max_readahead = se->conn.max_readahead;
++	outarg.max_write = se->conn.max_write;
++	if (se->conn.proto_minor >= 13) {
++		if (se->conn.max_background >= (1 << 16))
++			se->conn.max_background = (1 << 16) - 1;
++		if (se->conn.congestion_threshold > se->conn.max_background)
++			se->conn.congestion_threshold = se->conn.max_background;
++		if (!se->conn.congestion_threshold) {
++			se->conn.congestion_threshold =
++				se->conn.max_background * 3 / 4;
++		}
++
++		outarg.max_background = se->conn.max_background;
++		outarg.congestion_threshold = se->conn.congestion_threshold;
++	}
++	if (se->conn.proto_minor >= 23)
++		outarg.time_gran = se->conn.time_gran;
++
++	if (se->debug) {
++		fuse_log(FUSE_LOG_DEBUG, "   INIT: %u.%u\n", outarg.major, outarg.minor);
++		fuse_log(FUSE_LOG_DEBUG, "   flags=0x%08x\n", outarg.flags);
++		fuse_log(FUSE_LOG_DEBUG, "   max_readahead=0x%08x\n",
++			outarg.max_readahead);
++		fuse_log(FUSE_LOG_DEBUG, "   max_write=0x%08x\n", outarg.max_write);
++		fuse_log(FUSE_LOG_DEBUG, "   max_background=%i\n",
++			outarg.max_background);
++		fuse_log(FUSE_LOG_DEBUG, "   congestion_threshold=%i\n",
++			outarg.congestion_threshold);
++		fuse_log(FUSE_LOG_DEBUG, "   time_gran=%u\n",
++			outarg.time_gran);
++	}
++	if (arg->minor < 5)
++		outargsize = FUSE_COMPAT_INIT_OUT_SIZE;
++	else if (arg->minor < 23)
++		outargsize = FUSE_COMPAT_22_INIT_OUT_SIZE;
++
++	send_reply_ok(req, &outarg, outargsize);
++}
++
++static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++	struct fuse_session *se = req->se;
++
++	(void) nodeid;
++	(void) inarg;
++
++	se->got_destroy = 1;
++	if (se->op.destroy)
++		se->op.destroy(se->userdata);
++
++	send_reply_ok(req, NULL, 0);
++}
++
++static void list_del_nreq(struct fuse_notify_req *nreq)
++{
++	struct fuse_notify_req *prev = nreq->prev;
++	struct fuse_notify_req *next = nreq->next;
++	prev->next = next;
++	next->prev = prev;
++}
++
++static void list_add_nreq(struct fuse_notify_req *nreq,
++			  struct fuse_notify_req *next)
++{
++	struct fuse_notify_req *prev = next->prev;
++	nreq->next = next;
++	nreq->prev = prev;
++	prev->next = nreq;
++	next->prev = nreq;
++}
++
++static void list_init_nreq(struct fuse_notify_req *nreq)
++{
++	nreq->next = nreq;
++	nreq->prev = nreq;
++}
++
++static void do_notify_reply(fuse_req_t req, fuse_ino_t nodeid,
++			    const void *inarg, const struct fuse_buf *buf)
++{
++	struct fuse_session *se = req->se;
++	struct fuse_notify_req *nreq;
++	struct fuse_notify_req *head;
++
++	pthread_mutex_lock(&se->lock);
++	head = &se->notify_list;
++	for (nreq = head->next; nreq != head; nreq = nreq->next) {
++		if (nreq->unique == req->unique) {
++			list_del_nreq(nreq);
++			break;
++		}
++	}
++	pthread_mutex_unlock(&se->lock);
++
++	if (nreq != head)
++		nreq->reply(nreq, req, nodeid, inarg, buf);
++}
++
++static int send_notify_iov(struct fuse_session *se, int notify_code,
++			   struct iovec *iov, int count)
++{
++	struct fuse_out_header out;
++
++	if (!se->got_init)
++		return -ENOTCONN;
++
++	out.unique = 0;
++	out.error = notify_code;
++	iov[0].iov_base = &out;
++	iov[0].iov_len = sizeof(struct fuse_out_header);
++
++	return fuse_send_msg(se, NULL, iov, count);
++}
++
++int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
++{
++	if (ph != NULL) {
++		struct fuse_notify_poll_wakeup_out outarg;
++		struct iovec iov[2];
++
++		outarg.kh = ph->kh;
++
++		iov[1].iov_base = &outarg;
++		iov[1].iov_len = sizeof(outarg);
++
++		return send_notify_iov(ph->se, FUSE_NOTIFY_POLL, iov, 2);
++	} else {
++		return 0;
++	}
++}
++
++int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
++				     off_t off, off_t len)
++{
++	struct fuse_notify_inval_inode_out outarg;
++	struct iovec iov[2];
++
++	if (!se)
++		return -EINVAL;
++
++	if (se->conn.proto_major < 6 || se->conn.proto_minor < 12)
++		return -ENOSYS;
++	
++	outarg.ino = ino;
++	outarg.off = off;
++	outarg.len = len;
++
++	iov[1].iov_base = &outarg;
++	iov[1].iov_len = sizeof(outarg);
++
++	return send_notify_iov(se, FUSE_NOTIFY_INVAL_INODE, iov, 2);
++}
++
++int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
++				     const char *name, size_t namelen)
++{
++	struct fuse_notify_inval_entry_out outarg;
++	struct iovec iov[3];
++
++	if (!se)
++		return -EINVAL;
++	
++	if (se->conn.proto_major < 6 || se->conn.proto_minor < 12)
++		return -ENOSYS;
++
++	outarg.parent = parent;
++	outarg.namelen = namelen;
++	outarg.padding = 0;
++
++	iov[1].iov_base = &outarg;
++	iov[1].iov_len = sizeof(outarg);
++	iov[2].iov_base = (void *)name;
++	iov[2].iov_len = namelen + 1;
++
++	return send_notify_iov(se, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
++}
++
++int fuse_lowlevel_notify_delete(struct fuse_session *se,
++				fuse_ino_t parent, fuse_ino_t child,
++				const char *name, size_t namelen)
++{
++	struct fuse_notify_delete_out outarg;
++	struct iovec iov[3];
++
++	if (!se)
++		return -EINVAL;
++
++	if (se->conn.proto_major < 6 || se->conn.proto_minor < 18)
++		return -ENOSYS;
++
++	outarg.parent = parent;
++	outarg.child = child;
++	outarg.namelen = namelen;
++	outarg.padding = 0;
++
++	iov[1].iov_base = &outarg;
++	iov[1].iov_len = sizeof(outarg);
++	iov[2].iov_base = (void *)name;
++	iov[2].iov_len = namelen + 1;
++
++	return send_notify_iov(se, FUSE_NOTIFY_DELETE, iov, 3);
++}
++
++int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
++			       off_t offset, struct fuse_bufvec *bufv,
++			       enum fuse_buf_copy_flags flags)
++{
++	struct fuse_out_header out;
++	struct fuse_notify_store_out outarg;
++	struct iovec iov[3];
++	size_t size = fuse_buf_size(bufv);
++	int res;
++
++	if (!se)
++		return -EINVAL;
++
++	if (se->conn.proto_major < 6 || se->conn.proto_minor < 15)
++		return -ENOSYS;
++
++	out.unique = 0;
++	out.error = FUSE_NOTIFY_STORE;
++
++	outarg.nodeid = ino;
++	outarg.offset = offset;
++	outarg.size = size;
++	outarg.padding = 0;
++
++	iov[0].iov_base = &out;
++	iov[0].iov_len = sizeof(out);
++	iov[1].iov_base = &outarg;
++	iov[1].iov_len = sizeof(outarg);
++
++	res = fuse_send_data_iov(se, NULL, iov, 2, bufv, flags);
++	if (res > 0)
++		res = -res;
++
++	return res;
++}
++
++struct fuse_retrieve_req {
++	struct fuse_notify_req nreq;
++	void *cookie;
++};
++
++static void fuse_ll_retrieve_reply(struct fuse_notify_req *nreq,
++				   fuse_req_t req, fuse_ino_t ino,
++				   const void *inarg,
++				   const struct fuse_buf *ibuf)
++{
++	struct fuse_session *se = req->se;
++	struct fuse_retrieve_req *rreq =
++		container_of(nreq, struct fuse_retrieve_req, nreq);
++	const struct fuse_notify_retrieve_in *arg = inarg;
++	struct fuse_bufvec bufv = {
++		.buf[0] = *ibuf,
++		.count = 1,
++	};
++
++	if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
++		bufv.buf[0].mem = PARAM(arg);
++
++	bufv.buf[0].size -= sizeof(struct fuse_in_header) +
++		sizeof(struct fuse_notify_retrieve_in);
++
++	if (bufv.buf[0].size < arg->size) {
++		fuse_log(FUSE_LOG_ERR, "fuse: retrieve reply: buffer size too small\n");
++		fuse_reply_none(req);
++		goto out;
++	}
++	bufv.buf[0].size = arg->size;
++
++	if (se->op.retrieve_reply) {
++		se->op.retrieve_reply(req, rreq->cookie, ino,
++					  arg->offset, &bufv);
++	} else {
++		fuse_reply_none(req);
++	}
++out:
++	free(rreq);
++	if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count)
++		fuse_ll_clear_pipe(se);
++}
++
++int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino,
++				  size_t size, off_t offset, void *cookie)
++{
++	struct fuse_notify_retrieve_out outarg;
++	struct iovec iov[2];
++	struct fuse_retrieve_req *rreq;
++	int err;
++
++	if (!se)
++		return -EINVAL;
++
++	if (se->conn.proto_major < 6 || se->conn.proto_minor < 15)
++		return -ENOSYS;
++
++	rreq = malloc(sizeof(*rreq));
++	if (rreq == NULL)
++		return -ENOMEM;
++
++	pthread_mutex_lock(&se->lock);
++	rreq->cookie = cookie;
++	rreq->nreq.unique = se->notify_ctr++;
++	rreq->nreq.reply = fuse_ll_retrieve_reply;
++	list_add_nreq(&rreq->nreq, &se->notify_list);
++	pthread_mutex_unlock(&se->lock);
++
++	outarg.notify_unique = rreq->nreq.unique;
++	outarg.nodeid = ino;
++	outarg.offset = offset;
++	outarg.size = size;
++	outarg.padding = 0;
++
++	iov[1].iov_base = &outarg;
++	iov[1].iov_len = sizeof(outarg);
++
++	err = send_notify_iov(se, FUSE_NOTIFY_RETRIEVE, iov, 2);
++	if (err) {
++		pthread_mutex_lock(&se->lock);
++		list_del_nreq(&rreq->nreq);
++		pthread_mutex_unlock(&se->lock);
++		free(rreq);
++	}
++
++	return err;
++}
++
++void *fuse_req_userdata(fuse_req_t req)
++{
++	return req->se->userdata;
++}
++
++const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
++{
++	return &req->ctx;
++}
++
++void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
++			     void *data)
++{
++	pthread_mutex_lock(&req->lock);
++	pthread_mutex_lock(&req->se->lock);
++	req->u.ni.func = func;
++	req->u.ni.data = data;
++	pthread_mutex_unlock(&req->se->lock);
++	if (req->interrupted && func)
++		func(req, data);
++	pthread_mutex_unlock(&req->lock);
++}
++
++int fuse_req_interrupted(fuse_req_t req)
++{
++	int interrupted;
++
++	pthread_mutex_lock(&req->se->lock);
++	interrupted = req->interrupted;
++	pthread_mutex_unlock(&req->se->lock);
++
++	return interrupted;
++}
++
++static struct {
++	void (*func)(fuse_req_t, fuse_ino_t, const void *);
++	const char *name;
++} fuse_ll_ops[] = {
++	[FUSE_LOOKUP]	   = { do_lookup,      "LOOKUP"	     },
++	[FUSE_FORGET]	   = { do_forget,      "FORGET"	     },
++	[FUSE_GETATTR]	   = { do_getattr,     "GETATTR"     },
++	[FUSE_SETATTR]	   = { do_setattr,     "SETATTR"     },
++	[FUSE_READLINK]	   = { do_readlink,    "READLINK"    },
++	[FUSE_SYMLINK]	   = { do_symlink,     "SYMLINK"     },
++	[FUSE_MKNOD]	   = { do_mknod,       "MKNOD"	     },
++	[FUSE_MKDIR]	   = { do_mkdir,       "MKDIR"	     },
++	[FUSE_UNLINK]	   = { do_unlink,      "UNLINK"	     },
++	[FUSE_RMDIR]	   = { do_rmdir,       "RMDIR"	     },
++	[FUSE_RENAME]	   = { do_rename,      "RENAME"	     },
++	[FUSE_LINK]	   = { do_link,	       "LINK"	     },
++	[FUSE_OPEN]	   = { do_open,	       "OPEN"	     },
++	[FUSE_READ]	   = { do_read,	       "READ"	     },
++	[FUSE_WRITE]	   = { do_write,       "WRITE"	     },
++	[FUSE_STATFS]	   = { do_statfs,      "STATFS"	     },
++	[FUSE_RELEASE]	   = { do_release,     "RELEASE"     },
++	[FUSE_FSYNC]	   = { do_fsync,       "FSYNC"	     },
++	[FUSE_SETXATTR]	   = { do_setxattr,    "SETXATTR"    },
++	[FUSE_GETXATTR]	   = { do_getxattr,    "GETXATTR"    },
++	[FUSE_LISTXATTR]   = { do_listxattr,   "LISTXATTR"   },
++	[FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" },
++	[FUSE_FLUSH]	   = { do_flush,       "FLUSH"	     },
++	[FUSE_INIT]	   = { do_init,	       "INIT"	     },
++	[FUSE_OPENDIR]	   = { do_opendir,     "OPENDIR"     },
++	[FUSE_READDIR]	   = { do_readdir,     "READDIR"     },
++	[FUSE_RELEASEDIR]  = { do_releasedir,  "RELEASEDIR"  },
++	[FUSE_FSYNCDIR]	   = { do_fsyncdir,    "FSYNCDIR"    },
++	[FUSE_GETLK]	   = { do_getlk,       "GETLK"	     },
++	[FUSE_SETLK]	   = { do_setlk,       "SETLK"	     },
++	[FUSE_SETLKW]	   = { do_setlkw,      "SETLKW"	     },
++	[FUSE_ACCESS]	   = { do_access,      "ACCESS"	     },
++	[FUSE_CREATE]	   = { do_create,      "CREATE"	     },
++	[FUSE_INTERRUPT]   = { do_interrupt,   "INTERRUPT"   },
++	[FUSE_BMAP]	   = { do_bmap,	       "BMAP"	     },
++	[FUSE_IOCTL]	   = { do_ioctl,       "IOCTL"	     },
++	[FUSE_POLL]	   = { do_poll,        "POLL"	     },
++	[FUSE_FALLOCATE]   = { do_fallocate,   "FALLOCATE"   },
++	[FUSE_DESTROY]	   = { do_destroy,     "DESTROY"     },
++	[FUSE_NOTIFY_REPLY] = { (void *) 1,    "NOTIFY_REPLY" },
++	[FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" },
++	[FUSE_READDIRPLUS] = { do_readdirplus,	"READDIRPLUS"},
++	[FUSE_RENAME2]     = { do_rename2,      "RENAME2"    },
++	[FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" },
++	[FUSE_LSEEK]	   = { do_lseek,       "LSEEK"	     },
++	[CUSE_INIT]	   = { cuse_lowlevel_init, "CUSE_INIT"   },
++};
++
++#define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
++
++static const char *opname(enum fuse_opcode opcode)
++{
++	if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name)
++		return "???";
++	else
++		return fuse_ll_ops[opcode].name;
++}
++
++static int fuse_ll_copy_from_pipe(struct fuse_bufvec *dst,
++				  struct fuse_bufvec *src)
++{
++	ssize_t res = fuse_buf_copy(dst, src, 0);
++	if (res < 0) {
++		fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: %s\n", strerror(-res));
++		return res;
++	}
++	if ((size_t)res < fuse_buf_size(dst)) {
++		fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: short read\n");
++		return -1;
++	}
++	return 0;
++}
++
++void fuse_session_process_buf(struct fuse_session *se,
++			      const struct fuse_buf *buf)
++{
++	fuse_session_process_buf_int(se, buf, NULL);
++}
++
++void fuse_session_process_buf_int(struct fuse_session *se,
++				  const struct fuse_buf *buf, struct fuse_chan *ch)
++{
++	const size_t write_header_size = sizeof(struct fuse_in_header) +
++		sizeof(struct fuse_write_in);
++	struct fuse_bufvec bufv = { .buf[0] = *buf, .count = 1 };
++	struct fuse_bufvec tmpbuf = FUSE_BUFVEC_INIT(write_header_size);
++	struct fuse_in_header *in;
++	const void *inarg;
++	struct fuse_req *req;
++	void *mbuf = NULL;
++	int err;
++	int res;
++
++	if (buf->flags & FUSE_BUF_IS_FD) {
++		if (buf->size < tmpbuf.buf[0].size)
++			tmpbuf.buf[0].size = buf->size;
++
++		mbuf = malloc(tmpbuf.buf[0].size);
++		if (mbuf == NULL) {
++			fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate header\n");
++			goto clear_pipe;
++		}
++		tmpbuf.buf[0].mem = mbuf;
++
++		res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
++		if (res < 0)
++			goto clear_pipe;
++
++		in = mbuf;
++	} else {
++		in = buf->mem;
++	}
++
++	if (se->debug) {
++		fuse_log(FUSE_LOG_DEBUG,
++			"unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n",
++			(unsigned long long) in->unique,
++			opname((enum fuse_opcode) in->opcode), in->opcode,
++			(unsigned long long) in->nodeid, buf->size, in->pid);
++	}
++
++	req = fuse_ll_alloc_req(se);
++	if (req == NULL) {
++		struct fuse_out_header out = {
++			.unique = in->unique,
++			.error = -ENOMEM,
++		};
++		struct iovec iov = {
++			.iov_base = &out,
++			.iov_len = sizeof(struct fuse_out_header),
++		};
++
++		fuse_send_msg(se, ch, &iov, 1);
++		goto clear_pipe;
++	}
++
++	req->unique = in->unique;
++	req->ctx.uid = in->uid;
++	req->ctx.gid = in->gid;
++	req->ctx.pid = in->pid;
++	req->ch = ch ? fuse_chan_get(ch) : NULL;
++
++	err = EIO;
++	if (!se->got_init) {
++		enum fuse_opcode expected;
++
++		expected = se->cuse_data ? CUSE_INIT : FUSE_INIT;
++		if (in->opcode != expected)
++			goto reply_err;
++	} else if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT)
++		goto reply_err;
++
++	err = EACCES;
++	/* Implement -o allow_root */
++	if (se->deny_others && in->uid != se->owner && in->uid != 0 &&
++		 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
++		 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
++		 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
++		 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR &&
++		 in->opcode != FUSE_NOTIFY_REPLY &&
++		 in->opcode != FUSE_READDIRPLUS)
++		goto reply_err;
++
++	err = ENOSYS;
++	if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func)
++		goto reply_err;
++	if (in->opcode != FUSE_INTERRUPT) {
++		struct fuse_req *intr;
++		pthread_mutex_lock(&se->lock);
++		intr = check_interrupt(se, req);
++		list_add_req(req, &se->list);
++		pthread_mutex_unlock(&se->lock);
++		if (intr)
++			fuse_reply_err(intr, EAGAIN);
++	}
++
++	if ((buf->flags & FUSE_BUF_IS_FD) && write_header_size < buf->size &&
++	    (in->opcode != FUSE_WRITE || !se->op.write_buf) &&
++	    in->opcode != FUSE_NOTIFY_REPLY) {
++		void *newmbuf;
++
++		err = ENOMEM;
++		newmbuf = realloc(mbuf, buf->size);
++		if (newmbuf == NULL)
++			goto reply_err;
++		mbuf = newmbuf;
++
++		tmpbuf = FUSE_BUFVEC_INIT(buf->size - write_header_size);
++		tmpbuf.buf[0].mem = (char *)mbuf + write_header_size;
++
++		res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
++		err = -res;
++		if (res < 0)
++			goto reply_err;
++
++		in = mbuf;
++	}
++
++	inarg = (void *) &in[1];
++	if (in->opcode == FUSE_WRITE && se->op.write_buf)
++		do_write_buf(req, in->nodeid, inarg, buf);
++	else if (in->opcode == FUSE_NOTIFY_REPLY)
++		do_notify_reply(req, in->nodeid, inarg, buf);
++	else
++		fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
++
++out_free:
++	free(mbuf);
++	return;
++
++reply_err:
++	fuse_reply_err(req, err);
++clear_pipe:
++	if (buf->flags & FUSE_BUF_IS_FD)
++		fuse_ll_clear_pipe(se);
++	goto out_free;
++}
++
++#define LL_OPTION(n,o,v) \
++	{ n, offsetof(struct fuse_session, o), v }
++
++static const struct fuse_opt fuse_ll_opts[] = {
++	LL_OPTION("debug", debug, 1),
++	LL_OPTION("-d", debug, 1),
++	LL_OPTION("--debug", debug, 1),
++	LL_OPTION("allow_root", deny_others, 1),
++	FUSE_OPT_END
++};
++
++void fuse_lowlevel_version(void)
++{
++	printf("using FUSE kernel interface version %i.%i\n",
++	       FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
++	fuse_mount_version();
++}
++
++void fuse_lowlevel_help(void)
++{
++	/* These are not all options, but the ones that are
++	   potentially of interest to an end-user */
++	printf(
++"    -o allow_other         allow access by all users\n"
++"    -o allow_root          allow access by root\n"
++"    -o auto_unmount        auto unmount on process termination\n");
++}
++
++void fuse_session_destroy(struct fuse_session *se)
++{
++	struct fuse_ll_pipe *llp;
++
++	if (se->got_init && !se->got_destroy) {
++		if (se->op.destroy)
++			se->op.destroy(se->userdata);
++	}
++	llp = pthread_getspecific(se->pipe_key);
++	if (llp != NULL)
++		fuse_ll_pipe_free(llp);
++	pthread_key_delete(se->pipe_key);
++	pthread_mutex_destroy(&se->lock);
++	free(se->cuse_data);
++	if (se->fd != -1)
++		close(se->fd);
++	destroy_mount_opts(se->mo);
++	free(se);
++}
++
++
++static void fuse_ll_pipe_destructor(void *data)
++{
++	struct fuse_ll_pipe *llp = data;
++	fuse_ll_pipe_free(llp);
++}
++
++int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf)
++{
++	return fuse_session_receive_buf_int(se, buf, NULL);
++}
++
++int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
++				 struct fuse_chan *ch)
++{
++	int err;
++	ssize_t res;
++#ifdef HAVE_SPLICE
++	size_t bufsize = se->bufsize;
++	struct fuse_ll_pipe *llp;
++	struct fuse_buf tmpbuf;
++
++	if (se->conn.proto_minor < 14 || !(se->conn.want & FUSE_CAP_SPLICE_READ))
++		goto fallback;
++
++	llp = fuse_ll_get_pipe(se);
++	if (llp == NULL)
++		goto fallback;
++
++	if (llp->size < bufsize) {
++		if (llp->can_grow) {
++			res = fcntl(llp->pipe[0], F_SETPIPE_SZ, bufsize);
++			if (res == -1) {
++				llp->can_grow = 0;
++				res = grow_pipe_to_max(llp->pipe[0]);
++				if (res > 0)
++					llp->size = res;
++				goto fallback;
++			}
++			llp->size = res;
++		}
++		if (llp->size < bufsize)
++			goto fallback;
++	}
++
++	res = splice(ch ? ch->fd : se->fd,
++		     NULL, llp->pipe[1], NULL, bufsize, 0);
++	err = errno;
++
++	if (fuse_session_exited(se))
++		return 0;
++
++	if (res == -1) {
++		if (err == ENODEV) {
++			/* Filesystem was unmounted, or connection was aborted
++			   via /sys/fs/fuse/connections */
++			fuse_session_exit(se);
++			return 0;
++		}
++		if (err != EINTR && err != EAGAIN)
++			perror("fuse: splice from device");
++		return -err;
++	}
++
++	if (res < sizeof(struct fuse_in_header)) {
++		fuse_log(FUSE_LOG_ERR, "short splice from fuse device\n");
++		return -EIO;
++	}
++
++	tmpbuf = (struct fuse_buf) {
++		.size = res,
++		.flags = FUSE_BUF_IS_FD,
++		.fd = llp->pipe[0],
++	};
++
++	/*
++	 * Don't bother with zero copy for small requests.
++	 * fuse_loop_mt() needs to check for FORGET so this more than
++	 * just an optimization.
++	 */
++	if (res < sizeof(struct fuse_in_header) +
++	    sizeof(struct fuse_write_in) + pagesize) {
++		struct fuse_bufvec src = { .buf[0] = tmpbuf, .count = 1 };
++		struct fuse_bufvec dst = { .count = 1 };
++
++		if (!buf->mem) {
++			buf->mem = malloc(se->bufsize);
++			if (!buf->mem) {
++				fuse_log(FUSE_LOG_ERR,
++					"fuse: failed to allocate read buffer\n");
++				return -ENOMEM;
++			}
++		}
++		buf->size = se->bufsize;
++		buf->flags = 0;
++		dst.buf[0] = *buf;
++
++		res = fuse_buf_copy(&dst, &src, 0);
++		if (res < 0) {
++			fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: %s\n",
++				strerror(-res));
++			fuse_ll_clear_pipe(se);
++			return res;
++		}
++		if (res < tmpbuf.size) {
++			fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: short read\n");
++			fuse_ll_clear_pipe(se);
++			return -EIO;
++		}
++		assert(res == tmpbuf.size);
++
++	} else {
++		/* Don't overwrite buf->mem, as that would cause a leak */
++		buf->fd = tmpbuf.fd;
++		buf->flags = tmpbuf.flags;
++	}
++	buf->size = tmpbuf.size;
++
++	return res;
++
++fallback:
++#endif
++	if (!buf->mem) {
++		buf->mem = malloc(se->bufsize);
++		if (!buf->mem) {
++			fuse_log(FUSE_LOG_ERR,
++				"fuse: failed to allocate read buffer\n");
++			return -ENOMEM;
++		}
++	}
++
++restart:
++	res = read(ch ? ch->fd : se->fd, buf->mem, se->bufsize);
++	err = errno;
++
++	if (fuse_session_exited(se))
++		return 0;
++	if (res == -1) {
++		/* ENOENT means the operation was interrupted, it's safe
++		   to restart */
++		if (err == ENOENT)
++			goto restart;
++
++		if (err == ENODEV) {
++			/* Filesystem was unmounted, or connection was aborted
++			   via /sys/fs/fuse/connections */
++			fuse_session_exit(se);
++			return 0;
++		}
++		/* Errors occurring during normal operation: EINTR (read
++		   interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem
++		   umounted) */
++		if (err != EINTR && err != EAGAIN)
++			perror("fuse: reading device");
++		return -err;
++	}
++	if ((size_t) res < sizeof(struct fuse_in_header)) {
++		fuse_log(FUSE_LOG_ERR, "short read on fuse device\n");
++		return -EIO;
++	}
++
++	buf->size = res;
++
++	return res;
++}
++
++struct fuse_session *fuse_session_new(struct fuse_args *args,
++				      const struct fuse_lowlevel_ops *op,
++				      size_t op_size, void *userdata)
++{
++	int err;
++	struct fuse_session *se;
++	struct mount_opts *mo;
++
++	if (sizeof(struct fuse_lowlevel_ops) < op_size) {
++		fuse_log(FUSE_LOG_ERR, "fuse: warning: library too old, some operations may not work\n");
++		op_size = sizeof(struct fuse_lowlevel_ops);
++	}
++
++	if (args->argc == 0) {
++		fuse_log(FUSE_LOG_ERR, "fuse: empty argv passed to fuse_session_new().\n");
++		return NULL;
++	}
++
++	se = (struct fuse_session *) calloc(1, sizeof(struct fuse_session));
++	if (se == NULL) {
++		fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse object\n");
++		goto out1;
++	}
++	se->fd = -1;
++	se->conn.max_write = UINT_MAX;
++	se->conn.max_readahead = UINT_MAX;
++
++	/* Parse options */
++	if(fuse_opt_parse(args, se, fuse_ll_opts, NULL) == -1)
++		goto out2;
++	if(se->deny_others) {
++		/* Allowing access only by root is done by instructing
++		 * kernel to allow access by everyone, and then restricting
++		 * access to root and mountpoint owner in libfuse.
++		 */
++		// We may be adding the option a second time, but
++		// that doesn't hurt.
++		if(fuse_opt_add_arg(args, "-oallow_other") == -1)
++			goto out2;
++	}
++	mo = parse_mount_opts(args);
++	if (mo == NULL)
++		goto out3;
++
++	if(args->argc == 1 &&
++	   args->argv[0][0] == '-') {
++		fuse_log(FUSE_LOG_ERR, "fuse: warning: argv[0] looks like an option, but "
++			"will be ignored\n");
++	} else if (args->argc != 1) {
++		int i;
++		fuse_log(FUSE_LOG_ERR, "fuse: unknown option(s): `");
++		for(i = 1; i < args->argc-1; i++)
++			fuse_log(FUSE_LOG_ERR, "%s ", args->argv[i]);
++		fuse_log(FUSE_LOG_ERR, "%s'\n", args->argv[i]);
++		goto out4;
++	}
++
++	if (se->debug)
++		fuse_log(FUSE_LOG_DEBUG, "FUSE library version: %s\n", PACKAGE_VERSION);
++
++	se->bufsize = FUSE_MAX_MAX_PAGES * getpagesize() +
++		FUSE_BUFFER_HEADER_SIZE;
++
++	list_init_req(&se->list);
++	list_init_req(&se->interrupts);
++	list_init_nreq(&se->notify_list);
++	se->notify_ctr = 1;
++	fuse_mutex_init(&se->lock);
++
++	err = pthread_key_create(&se->pipe_key, fuse_ll_pipe_destructor);
++	if (err) {
++		fuse_log(FUSE_LOG_ERR, "fuse: failed to create thread specific key: %s\n",
++			strerror(err));
++		goto out5;
++	}
++
++	memcpy(&se->op, op, op_size);
++	se->owner = getuid();
++	se->userdata = userdata;
++
++	se->mo = mo;
++	return se;
++
++out5:
++	pthread_mutex_destroy(&se->lock);
++out4:
++	fuse_opt_free_args(args);
++out3:
++	free(mo);
++out2:
++	free(se);
++out1:
++	return NULL;
++}
++
++int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
++{
++	int fd;
++
++	/*
++	 * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
++	 * would ensue.
++	 */
++	do {
++		fd = open("/dev/null", O_RDWR);
++		if (fd > 2)
++			close(fd);
++	} while (fd >= 0 && fd <= 2);
++
++	/*
++	 * To allow FUSE daemons to run without privileges, the caller may open
++	 * /dev/fuse before launching the file system and pass on the file
++	 * descriptor by specifying /dev/fd/N as the mount point. Note that the
++	 * parent process takes care of performing the mount in this case.
++	 */
++	fd = fuse_mnt_parse_fuse_fd(mountpoint);
++	if (fd != -1) {
++		if (fcntl(fd, F_GETFD) == -1) {
++			fuse_log(FUSE_LOG_ERR,
++				"fuse: Invalid file descriptor /dev/fd/%u\n",
++				fd);
++			return -1;
++		}
++		se->fd = fd;
++		return 0;
++	}
++
++	/* Open channel */
++	fd = fuse_kern_mount(mountpoint, se->mo);
++	if (fd == -1)
++		return -1;
++	se->fd = fd;
++
++	/* Save mountpoint */
++	se->mountpoint = strdup(mountpoint);
++	if (se->mountpoint == NULL)
++		goto error_out;
++
++	return 0;
++
++error_out:
++	fuse_kern_unmount(mountpoint, fd);
++	return -1;
++}
++
++int fuse_session_fd(struct fuse_session *se)
++{
++	return se->fd;
++}
++
++void fuse_session_unmount(struct fuse_session *se)
++{
++	if (se->mountpoint != NULL) {
++		fuse_kern_unmount(se->mountpoint, se->fd);
++		free(se->mountpoint);
++		se->mountpoint = NULL;
++	}
++}
++
++#ifdef linux
++int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
++{
++	char *buf;
++	size_t bufsize = 1024;
++	char path[128];
++	int ret;
++	int fd;
++	unsigned long pid = req->ctx.pid;
++	char *s;
++
++	sprintf(path, "/proc/%lu/task/%lu/status", pid, pid);
++
++retry:
++	buf = malloc(bufsize);
++	if (buf == NULL)
++		return -ENOMEM;
++
++	ret = -EIO;
++	fd = open(path, O_RDONLY);
++	if (fd == -1)
++		goto out_free;
++
++	ret = read(fd, buf, bufsize);
++	close(fd);
++	if (ret < 0) {
++		ret = -EIO;
++		goto out_free;
++	}
++
++	if ((size_t)ret == bufsize) {
++		free(buf);
++		bufsize *= 4;
++		goto retry;
++	}
++
++	ret = -EIO;
++	s = strstr(buf, "\nGroups:");
++	if (s == NULL)
++		goto out_free;
++
++	s += 8;
++	ret = 0;
++	while (1) {
++		char *end;
++		unsigned long val = strtoul(s, &end, 0);
++		if (end == s)
++			break;
++
++		s = end;
++		if (ret < size)
++			list[ret] = val;
++		ret++;
++	}
++
++out_free:
++	free(buf);
++	return ret;
++}
++#else /* linux */
++/*
++ * This is currently not implemented on other than Linux...
++ */
++int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
++{
++	(void) req; (void) size; (void) list;
++	return -ENOSYS;
++}
++#endif
++
++void fuse_session_exit(struct fuse_session *se)
++{
++	se->exited = 1;
++}
++
++void fuse_session_reset(struct fuse_session *se)
++{
++	se->exited = 0;
++	se->error = 0;
++}
++
++int fuse_session_exited(struct fuse_session *se)
++{
++	return se->exited;
++}
diff --git a/0014-virtiofsd-Add-passthrough_ll.patch b/0014-virtiofsd-Add-passthrough_ll.patch
new file mode 100644
index 0000000..3e1f0b0
--- /dev/null
+++ b/0014-virtiofsd-Add-passthrough_ll.patch
@@ -0,0 +1,1370 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:43 +0000
+Subject: [PATCH] virtiofsd: Add passthrough_ll
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+passthrough_ll is one of the examples in the upstream fuse project
+and is the main part of our daemon here.  It passes through requests
+from fuse to the underlying filesystem, using syscalls as directly
+as possible.
+
+>From libfuse fuse-3.8.0
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+  Fixed up 'GPL' to 'GPLv2' as per Dan's comments and consistent
+  with the 'LICENSE' file in libfuse;  patch sent to libfuse to fix
+  it upstream.
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 7c6b66027241f41720240fc6ee1021cdbd975b2e)
+---
+ tools/virtiofsd/passthrough_ll.c | 1338 ++++++++++++++++++++++++++++++
+ 1 file changed, 1338 insertions(+)
+ create mode 100644 tools/virtiofsd/passthrough_ll.c
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+new file mode 100644
+index 0000000000..e1a605691a
+--- /dev/null
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -0,0 +1,1338 @@
++/*
++  FUSE: Filesystem in Userspace
++  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++
++  This program can be distributed under the terms of the GNU GPLv2.
++  See the file COPYING.
++*/
++
++/** @file
++ *
++ * This file system mirrors the existing file system hierarchy of the
++ * system, starting at the root file system. This is implemented by
++ * just "passing through" all requests to the corresponding user-space
++ * libc functions. In contrast to passthrough.c and passthrough_fh.c,
++ * this implementation uses the low-level API. Its performance should
++ * be the least bad among the three, but many operations are not
++ * implemented. In particular, it is not possible to remove files (or
++ * directories) because the code necessary to defer actual removal
++ * until the file is not opened anymore would make the example much
++ * more complicated.
++ *
++ * When writeback caching is enabled (-o writeback mount option), it
++ * is only possible to write to files for which the mounting user has
++ * read permissions. This is because the writeback cache requires the
++ * kernel to be able to issue read requests for all files (which the
++ * passthrough filesystem cannot satisfy if it can't read the file in
++ * the underlying filesystem).
++ *
++ * Compile with:
++ *
++ *     gcc -Wall passthrough_ll.c `pkg-config fuse3 --cflags --libs` -o passthrough_ll
++ *
++ * ## Source code ##
++ * \include passthrough_ll.c
++ */
++
++#define _GNU_SOURCE
++#define FUSE_USE_VERSION 31
++
++#include "config.h"
++
++#include <fuse_lowlevel.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <stddef.h>
++#include <stdbool.h>
++#include <string.h>
++#include <limits.h>
++#include <dirent.h>
++#include <assert.h>
++#include <errno.h>
++#include <inttypes.h>
++#include <pthread.h>
++#include <sys/file.h>
++#include <sys/xattr.h>
++
++#include "passthrough_helpers.h"
++
++/* We are re-using pointers to our `struct lo_inode` and `struct
++   lo_dirp` elements as inodes. This means that we must be able to
++   store uintptr_t values in a fuse_ino_t variable. The following
++   incantation checks this condition at compile time. */
++#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && !defined __cplusplus
++_Static_assert(sizeof(fuse_ino_t) >= sizeof(uintptr_t),
++	       "fuse_ino_t too small to hold uintptr_t values!");
++#else
++struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct \
++	{ unsigned _uintptr_to_must_hold_fuse_ino_t:
++			((sizeof(fuse_ino_t) >= sizeof(uintptr_t)) ? 1 : -1); };
++#endif
++
++struct lo_inode {
++	struct lo_inode *next; /* protected by lo->mutex */
++	struct lo_inode *prev; /* protected by lo->mutex */
++	int fd;
++	bool is_symlink;
++	ino_t ino;
++	dev_t dev;
++	uint64_t refcount; /* protected by lo->mutex */
++};
++
++enum {
++	CACHE_NEVER,
++	CACHE_NORMAL,
++	CACHE_ALWAYS,
++};
++
++struct lo_data {
++	pthread_mutex_t mutex;
++	int debug;
++	int writeback;
++	int flock;
++	int xattr;
++	const char *source;
++	double timeout;
++	int cache;
++	int timeout_set;
++	struct lo_inode root; /* protected by lo->mutex */
++};
++
++static const struct fuse_opt lo_opts[] = {
++	{ "writeback",
++	  offsetof(struct lo_data, writeback), 1 },
++	{ "no_writeback",
++	  offsetof(struct lo_data, writeback), 0 },
++	{ "source=%s",
++	  offsetof(struct lo_data, source), 0 },
++	{ "flock",
++	  offsetof(struct lo_data, flock), 1 },
++	{ "no_flock",
++	  offsetof(struct lo_data, flock), 0 },
++	{ "xattr",
++	  offsetof(struct lo_data, xattr), 1 },
++	{ "no_xattr",
++	  offsetof(struct lo_data, xattr), 0 },
++	{ "timeout=%lf",
++	  offsetof(struct lo_data, timeout), 0 },
++	{ "timeout=",
++	  offsetof(struct lo_data, timeout_set), 1 },
++	{ "cache=never",
++	  offsetof(struct lo_data, cache), CACHE_NEVER },
++	{ "cache=auto",
++	  offsetof(struct lo_data, cache), CACHE_NORMAL },
++	{ "cache=always",
++	  offsetof(struct lo_data, cache), CACHE_ALWAYS },
++
++	FUSE_OPT_END
++};
++
++static struct lo_data *lo_data(fuse_req_t req)
++{
++	return (struct lo_data *) fuse_req_userdata(req);
++}
++
++static struct lo_inode *lo_inode(fuse_req_t req, fuse_ino_t ino)
++{
++	if (ino == FUSE_ROOT_ID)
++		return &lo_data(req)->root;
++	else
++		return (struct lo_inode *) (uintptr_t) ino;
++}
++
++static int lo_fd(fuse_req_t req, fuse_ino_t ino)
++{
++	return lo_inode(req, ino)->fd;
++}
++
++static bool lo_debug(fuse_req_t req)
++{
++	return lo_data(req)->debug != 0;
++}
++
++static void lo_init(void *userdata,
++		    struct fuse_conn_info *conn)
++{
++	struct lo_data *lo = (struct lo_data*) userdata;
++
++	if(conn->capable & FUSE_CAP_EXPORT_SUPPORT)
++		conn->want |= FUSE_CAP_EXPORT_SUPPORT;
++
++	if (lo->writeback &&
++	    conn->capable & FUSE_CAP_WRITEBACK_CACHE) {
++		if (lo->debug)
++			fuse_log(FUSE_LOG_DEBUG, "lo_init: activating writeback\n");
++		conn->want |= FUSE_CAP_WRITEBACK_CACHE;
++	}
++	if (lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) {
++		if (lo->debug)
++			fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
++		conn->want |= FUSE_CAP_FLOCK_LOCKS;
++	}
++}
++
++static void lo_getattr(fuse_req_t req, fuse_ino_t ino,
++			     struct fuse_file_info *fi)
++{
++	int res;
++	struct stat buf;
++	struct lo_data *lo = lo_data(req);
++
++	(void) fi;
++
++	res = fstatat(lo_fd(req, ino), "", &buf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
++	if (res == -1)
++		return (void) fuse_reply_err(req, errno);
++
++	fuse_reply_attr(req, &buf, lo->timeout);
++}
++
++static int utimensat_empty_nofollow(struct lo_inode *inode,
++				    const struct timespec *tv)
++{
++	int res;
++	char procname[64];
++
++	if (inode->is_symlink) {
++		res = utimensat(inode->fd, "", tv,
++				AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
++		if (res == -1 && errno == EINVAL) {
++			/* Sorry, no race free way to set times on symlink. */
++			errno = EPERM;
++		}
++		return res;
++	}
++	sprintf(procname, "/proc/self/fd/%i", inode->fd);
++
++	return utimensat(AT_FDCWD, procname, tv, 0);
++}
++
++static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
++		       int valid, struct fuse_file_info *fi)
++{
++	int saverr;
++	char procname[64];
++	struct lo_inode *inode = lo_inode(req, ino);
++	int ifd = inode->fd;
++	int res;
++
++	if (valid & FUSE_SET_ATTR_MODE) {
++		if (fi) {
++			res = fchmod(fi->fh, attr->st_mode);
++		} else {
++			sprintf(procname, "/proc/self/fd/%i", ifd);
++			res = chmod(procname, attr->st_mode);
++		}
++		if (res == -1)
++			goto out_err;
++	}
++	if (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) {
++		uid_t uid = (valid & FUSE_SET_ATTR_UID) ?
++			attr->st_uid : (uid_t) -1;
++		gid_t gid = (valid & FUSE_SET_ATTR_GID) ?
++			attr->st_gid : (gid_t) -1;
++
++		res = fchownat(ifd, "", uid, gid,
++			       AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
++		if (res == -1)
++			goto out_err;
++	}
++	if (valid & FUSE_SET_ATTR_SIZE) {
++		if (fi) {
++			res = ftruncate(fi->fh, attr->st_size);
++		} else {
++			sprintf(procname, "/proc/self/fd/%i", ifd);
++			res = truncate(procname, attr->st_size);
++		}
++		if (res == -1)
++			goto out_err;
++	}
++	if (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
++		struct timespec tv[2];
++
++		tv[0].tv_sec = 0;
++		tv[1].tv_sec = 0;
++		tv[0].tv_nsec = UTIME_OMIT;
++		tv[1].tv_nsec = UTIME_OMIT;
++
++		if (valid & FUSE_SET_ATTR_ATIME_NOW)
++			tv[0].tv_nsec = UTIME_NOW;
++		else if (valid & FUSE_SET_ATTR_ATIME)
++			tv[0] = attr->st_atim;
++
++		if (valid & FUSE_SET_ATTR_MTIME_NOW)
++			tv[1].tv_nsec = UTIME_NOW;
++		else if (valid & FUSE_SET_ATTR_MTIME)
++			tv[1] = attr->st_mtim;
++
++		if (fi)
++			res = futimens(fi->fh, tv);
++		else
++			res = utimensat_empty_nofollow(inode, tv);
++		if (res == -1)
++			goto out_err;
++	}
++
++	return lo_getattr(req, ino, fi);
++
++out_err:
++	saverr = errno;
++	fuse_reply_err(req, saverr);
++}
++
++static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st)
++{
++	struct lo_inode *p;
++	struct lo_inode *ret = NULL;
++
++	pthread_mutex_lock(&lo->mutex);
++	for (p = lo->root.next; p != &lo->root; p = p->next) {
++		if (p->ino == st->st_ino && p->dev == st->st_dev) {
++			assert(p->refcount > 0);
++			ret = p;
++			ret->refcount++;
++			break;
++		}
++	}
++	pthread_mutex_unlock(&lo->mutex);
++	return ret;
++}
++
++static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
++			 struct fuse_entry_param *e)
++{
++	int newfd;
++	int res;
++	int saverr;
++	struct lo_data *lo = lo_data(req);
++	struct lo_inode *inode;
++
++	memset(e, 0, sizeof(*e));
++	e->attr_timeout = lo->timeout;
++	e->entry_timeout = lo->timeout;
++
++	newfd = openat(lo_fd(req, parent), name, O_PATH | O_NOFOLLOW);
++	if (newfd == -1)
++		goto out_err;
++
++	res = fstatat(newfd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
++	if (res == -1)
++		goto out_err;
++
++	inode = lo_find(lo_data(req), &e->attr);
++	if (inode) {
++		close(newfd);
++		newfd = -1;
++	} else {
++		struct lo_inode *prev, *next;
++
++		saverr = ENOMEM;
++		inode = calloc(1, sizeof(struct lo_inode));
++		if (!inode)
++			goto out_err;
++
++		inode->is_symlink = S_ISLNK(e->attr.st_mode);
++		inode->refcount = 1;
++		inode->fd = newfd;
++		inode->ino = e->attr.st_ino;
++		inode->dev = e->attr.st_dev;
++
++		pthread_mutex_lock(&lo->mutex);
++		prev = &lo->root;
++		next = prev->next;
++		next->prev = inode;
++		inode->next = next;
++		inode->prev = prev;
++		prev->next = inode;
++		pthread_mutex_unlock(&lo->mutex);
++	}
++	e->ino = (uintptr_t) inode;
++
++	if (lo_debug(req))
++		fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
++			(unsigned long long) parent, name, (unsigned long long) e->ino);
++
++	return 0;
++
++out_err:
++	saverr = errno;
++	if (newfd != -1)
++		close(newfd);
++	return saverr;
++}
++
++static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
++{
++	struct fuse_entry_param e;
++	int err;
++
++	if (lo_debug(req))
++		fuse_log(FUSE_LOG_DEBUG, "lo_lookup(parent=%" PRIu64 ", name=%s)\n",
++			parent, name);
++
++	err = lo_do_lookup(req, parent, name, &e);
++	if (err)
++		fuse_reply_err(req, err);
++	else
++		fuse_reply_entry(req, &e);
++}
++
++static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent,
++			     const char *name, mode_t mode, dev_t rdev,
++			     const char *link)
++{
++	int res;
++	int saverr;
++	struct lo_inode *dir = lo_inode(req, parent);
++	struct fuse_entry_param e;
++
++	saverr = ENOMEM;
++
++	res = mknod_wrapper(dir->fd, name, link, mode, rdev);
++
++	saverr = errno;
++	if (res == -1)
++		goto out;
++
++	saverr = lo_do_lookup(req, parent, name, &e);
++	if (saverr)
++		goto out;
++
++	if (lo_debug(req))
++		fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
++			(unsigned long long) parent, name, (unsigned long long) e.ino);
++
++	fuse_reply_entry(req, &e);
++	return;
++
++out:
++	fuse_reply_err(req, saverr);
++}
++
++static void lo_mknod(fuse_req_t req, fuse_ino_t parent,
++		     const char *name, mode_t mode, dev_t rdev)
++{
++	lo_mknod_symlink(req, parent, name, mode, rdev, NULL);
++}
++
++static void lo_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
++		     mode_t mode)
++{
++	lo_mknod_symlink(req, parent, name, S_IFDIR | mode, 0, NULL);
++}
++
++static void lo_symlink(fuse_req_t req, const char *link,
++		       fuse_ino_t parent, const char *name)
++{
++	lo_mknod_symlink(req, parent, name, S_IFLNK, 0, link);
++}
++
++static int linkat_empty_nofollow(struct lo_inode *inode, int dfd,
++				 const char *name)
++{
++	int res;
++	char procname[64];
++
++	if (inode->is_symlink) {
++		res = linkat(inode->fd, "", dfd, name, AT_EMPTY_PATH);
++		if (res == -1 && (errno == ENOENT || errno == EINVAL)) {
++			/* Sorry, no race free way to hard-link a symlink. */
++			errno = EPERM;
++		}
++		return res;
++	}
++
++	sprintf(procname, "/proc/self/fd/%i", inode->fd);
++
++	return linkat(AT_FDCWD, procname, dfd, name, AT_SYMLINK_FOLLOW);
++}
++
++static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
++		    const char *name)
++{
++	int res;
++	struct lo_data *lo = lo_data(req);
++	struct lo_inode *inode = lo_inode(req, ino);
++	struct fuse_entry_param e;
++	int saverr;
++
++	memset(&e, 0, sizeof(struct fuse_entry_param));
++	e.attr_timeout = lo->timeout;
++	e.entry_timeout = lo->timeout;
++
++	res = linkat_empty_nofollow(inode, lo_fd(req, parent), name);
++	if (res == -1)
++		goto out_err;
++
++	res = fstatat(inode->fd, "", &e.attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
++	if (res == -1)
++		goto out_err;
++
++	pthread_mutex_lock(&lo->mutex);
++	inode->refcount++;
++	pthread_mutex_unlock(&lo->mutex);
++	e.ino = (uintptr_t) inode;
++
++	if (lo_debug(req))
++		fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
++			(unsigned long long) parent, name,
++			(unsigned long long) e.ino);
++
++	fuse_reply_entry(req, &e);
++	return;
++
++out_err:
++	saverr = errno;
++	fuse_reply_err(req, saverr);
++}
++
++static void lo_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
++{
++	int res;
++
++	res = unlinkat(lo_fd(req, parent), name, AT_REMOVEDIR);
++
++	fuse_reply_err(req, res == -1 ? errno : 0);
++}
++
++static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
++		      fuse_ino_t newparent, const char *newname,
++		      unsigned int flags)
++{
++	int res;
++
++	if (flags) {
++		fuse_reply_err(req, EINVAL);
++		return;
++	}
++
++	res = renameat(lo_fd(req, parent), name,
++			lo_fd(req, newparent), newname);
++
++	fuse_reply_err(req, res == -1 ? errno : 0);
++}
++
++static void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
++{
++	int res;
++
++	res = unlinkat(lo_fd(req, parent), name, 0);
++
++	fuse_reply_err(req, res == -1 ? errno : 0);
++}
++
++static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n)
++{
++	if (!inode)
++		return;
++
++	pthread_mutex_lock(&lo->mutex);
++	assert(inode->refcount >= n);
++	inode->refcount -= n;
++	if (!inode->refcount) {
++		struct lo_inode *prev, *next;
++
++		prev = inode->prev;
++		next = inode->next;
++		next->prev = prev;
++		prev->next = next;
++
++		pthread_mutex_unlock(&lo->mutex);
++		close(inode->fd);
++		free(inode);
++
++	} else {
++		pthread_mutex_unlock(&lo->mutex);
++	}
++}
++
++static void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
++{
++	struct lo_data *lo = lo_data(req);
++	struct lo_inode *inode = lo_inode(req, ino);
++
++	if (lo_debug(req)) {
++		fuse_log(FUSE_LOG_DEBUG, "  forget %lli %lli -%lli\n",
++			(unsigned long long) ino,
++			(unsigned long long) inode->refcount,
++			(unsigned long long) nlookup);
++	}
++
++	unref_inode(lo, inode, nlookup);
++}
++
++static void lo_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
++{
++	lo_forget_one(req, ino, nlookup);
++	fuse_reply_none(req);
++}
++
++static void lo_forget_multi(fuse_req_t req, size_t count,
++				struct fuse_forget_data *forgets)
++{
++	int i;
++
++	for (i = 0; i < count; i++)
++		lo_forget_one(req, forgets[i].ino, forgets[i].nlookup);
++	fuse_reply_none(req);
++}
++
++static void lo_readlink(fuse_req_t req, fuse_ino_t ino)
++{
++	char buf[PATH_MAX + 1];
++	int res;
++
++	res = readlinkat(lo_fd(req, ino), "", buf, sizeof(buf));
++	if (res == -1)
++		return (void) fuse_reply_err(req, errno);
++
++	if (res == sizeof(buf))
++		return (void) fuse_reply_err(req, ENAMETOOLONG);
++
++	buf[res] = '\0';
++
++	fuse_reply_readlink(req, buf);
++}
++
++struct lo_dirp {
++	DIR *dp;
++	struct dirent *entry;
++	off_t offset;
++};
++
++static struct lo_dirp *lo_dirp(struct fuse_file_info *fi)
++{
++	return (struct lo_dirp *) (uintptr_t) fi->fh;
++}
++
++static void lo_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
++{
++	int error = ENOMEM;
++	struct lo_data *lo = lo_data(req);
++	struct lo_dirp *d;
++	int fd;
++
++	d = calloc(1, sizeof(struct lo_dirp));
++	if (d == NULL)
++		goto out_err;
++
++	fd = openat(lo_fd(req, ino), ".", O_RDONLY);
++	if (fd == -1)
++		goto out_errno;
++
++	d->dp = fdopendir(fd);
++	if (d->dp == NULL)
++		goto out_errno;
++
++	d->offset = 0;
++	d->entry = NULL;
++
++	fi->fh = (uintptr_t) d;
++	if (lo->cache == CACHE_ALWAYS)
++		fi->keep_cache = 1;
++	fuse_reply_open(req, fi);
++	return;
++
++out_errno:
++	error = errno;
++out_err:
++	if (d) {
++		if (fd != -1)
++			close(fd);
++		free(d);
++	}
++	fuse_reply_err(req, error);
++}
++
++static int is_dot_or_dotdot(const char *name)
++{
++	return name[0] == '.' && (name[1] == '\0' ||
++				  (name[1] == '.' && name[2] == '\0'));
++}
++
++static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
++			  off_t offset, struct fuse_file_info *fi, int plus)
++{
++	struct lo_dirp *d = lo_dirp(fi);
++	char *buf;
++	char *p;
++	size_t rem = size;
++	int err;
++
++	(void) ino;
++
++	buf = calloc(1, size);
++	if (!buf) {
++		err = ENOMEM;
++		goto error;
++	}
++	p = buf;
++
++	if (offset != d->offset) {
++		seekdir(d->dp, offset);
++		d->entry = NULL;
++		d->offset = offset;
++	}
++	while (1) {
++		size_t entsize;
++		off_t nextoff;
++		const char *name;
++
++		if (!d->entry) {
++			errno = 0;
++			d->entry = readdir(d->dp);
++			if (!d->entry) {
++				if (errno) {  // Error
++					err = errno;
++					goto error;
++				} else {  // End of stream
++					break; 
++				}
++			}
++		}
++		nextoff = d->entry->d_off;
++		name = d->entry->d_name;
++		fuse_ino_t entry_ino = 0;
++		if (plus) {
++			struct fuse_entry_param e;
++			if (is_dot_or_dotdot(name)) {
++				e = (struct fuse_entry_param) {
++					.attr.st_ino = d->entry->d_ino,
++					.attr.st_mode = d->entry->d_type << 12,
++				};
++			} else {
++				err = lo_do_lookup(req, ino, name, &e);
++				if (err)
++					goto error;
++				entry_ino = e.ino;
++			}
++
++			entsize = fuse_add_direntry_plus(req, p, rem, name,
++							 &e, nextoff);
++		} else {
++			struct stat st = {
++				.st_ino = d->entry->d_ino,
++				.st_mode = d->entry->d_type << 12,
++			};
++			entsize = fuse_add_direntry(req, p, rem, name,
++						    &st, nextoff);
++		}
++		if (entsize > rem) {
++			if (entry_ino != 0) 
++				lo_forget_one(req, entry_ino, 1);
++			break;
++		}
++		
++		p += entsize;
++		rem -= entsize;
++
++		d->entry = NULL;
++		d->offset = nextoff;
++	}
++
++    err = 0;
++error:
++    // If there's an error, we can only signal it if we haven't stored
++    // any entries yet - otherwise we'd end up with wrong lookup
++    // counts for the entries that are already in the buffer. So we
++    // return what we've collected until that point.
++    if (err && rem == size)
++	    fuse_reply_err(req, err);
++    else
++	    fuse_reply_buf(req, buf, size - rem);
++    free(buf);
++}
++
++static void lo_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
++		       off_t offset, struct fuse_file_info *fi)
++{
++	lo_do_readdir(req, ino, size, offset, fi, 0);
++}
++
++static void lo_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size,
++			   off_t offset, struct fuse_file_info *fi)
++{
++	lo_do_readdir(req, ino, size, offset, fi, 1);
++}
++
++static void lo_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
++{
++	struct lo_dirp *d = lo_dirp(fi);
++	(void) ino;
++	closedir(d->dp);
++	free(d);
++	fuse_reply_err(req, 0);
++}
++
++static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
++		      mode_t mode, struct fuse_file_info *fi)
++{
++	int fd;
++	struct lo_data *lo = lo_data(req);
++	struct fuse_entry_param e;
++	int err;
++
++	if (lo_debug(req))
++		fuse_log(FUSE_LOG_DEBUG, "lo_create(parent=%" PRIu64 ", name=%s)\n",
++			parent, name);
++
++	fd = openat(lo_fd(req, parent), name,
++		    (fi->flags | O_CREAT) & ~O_NOFOLLOW, mode);
++	if (fd == -1)
++		return (void) fuse_reply_err(req, errno);
++
++	fi->fh = fd;
++	if (lo->cache == CACHE_NEVER)
++		fi->direct_io = 1;
++	else if (lo->cache == CACHE_ALWAYS)
++		fi->keep_cache = 1;
++
++	err = lo_do_lookup(req, parent, name, &e);
++	if (err)
++		fuse_reply_err(req, err);
++	else
++		fuse_reply_create(req, &e, fi);
++}
++
++static void lo_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
++			struct fuse_file_info *fi)
++{
++	int res;
++	int fd = dirfd(lo_dirp(fi)->dp);
++	(void) ino;
++	if (datasync)
++		res = fdatasync(fd);
++	else
++		res = fsync(fd);
++	fuse_reply_err(req, res == -1 ? errno : 0);
++}
++
++static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
++{
++	int fd;
++	char buf[64];
++	struct lo_data *lo = lo_data(req);
++
++	if (lo_debug(req))
++		fuse_log(FUSE_LOG_DEBUG, "lo_open(ino=%" PRIu64 ", flags=%d)\n",
++			ino, fi->flags);
++
++	/* With writeback cache, kernel may send read requests even
++	   when userspace opened write-only */
++	if (lo->writeback && (fi->flags & O_ACCMODE) == O_WRONLY) {
++		fi->flags &= ~O_ACCMODE;
++		fi->flags |= O_RDWR;
++	}
++
++	/* With writeback cache, O_APPEND is handled by the kernel.
++	   This breaks atomicity (since the file may change in the
++	   underlying filesystem, so that the kernel's idea of the
++	   end of the file isn't accurate anymore). In this example,
++	   we just accept that. A more rigorous filesystem may want
++	   to return an error here */
++	if (lo->writeback && (fi->flags & O_APPEND))
++		fi->flags &= ~O_APPEND;
++
++	sprintf(buf, "/proc/self/fd/%i", lo_fd(req, ino));
++	fd = open(buf, fi->flags & ~O_NOFOLLOW);
++	if (fd == -1)
++		return (void) fuse_reply_err(req, errno);
++
++	fi->fh = fd;
++	if (lo->cache == CACHE_NEVER)
++		fi->direct_io = 1;
++	else if (lo->cache == CACHE_ALWAYS)
++		fi->keep_cache = 1;
++	fuse_reply_open(req, fi);
++}
++
++static void lo_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
++{
++	(void) ino;
++
++	close(fi->fh);
++	fuse_reply_err(req, 0);
++}
++
++static void lo_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
++{
++	int res;
++	(void) ino;
++	res = close(dup(fi->fh));
++	fuse_reply_err(req, res == -1 ? errno : 0);
++}
++
++static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
++		     struct fuse_file_info *fi)
++{
++	int res;
++	(void) ino;
++	if (datasync)
++		res = fdatasync(fi->fh);
++	else
++		res = fsync(fi->fh);
++	fuse_reply_err(req, res == -1 ? errno : 0);
++}
++
++static void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size,
++		    off_t offset, struct fuse_file_info *fi)
++{
++	struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size);
++
++	if (lo_debug(req))
++		fuse_log(FUSE_LOG_DEBUG, "lo_read(ino=%" PRIu64 ", size=%zd, "
++			"off=%lu)\n", ino, size, (unsigned long) offset);
++
++	buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
++	buf.buf[0].fd = fi->fh;
++	buf.buf[0].pos = offset;
++
++	fuse_reply_data(req, &buf, FUSE_BUF_SPLICE_MOVE);
++}
++
++static void lo_write_buf(fuse_req_t req, fuse_ino_t ino,
++			 struct fuse_bufvec *in_buf, off_t off,
++			 struct fuse_file_info *fi)
++{
++	(void) ino;
++	ssize_t res;
++	struct fuse_bufvec out_buf = FUSE_BUFVEC_INIT(fuse_buf_size(in_buf));
++
++	out_buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
++	out_buf.buf[0].fd = fi->fh;
++	out_buf.buf[0].pos = off;
++
++	if (lo_debug(req))
++		fuse_log(FUSE_LOG_DEBUG, "lo_write(ino=%" PRIu64 ", size=%zd, off=%lu)\n",
++			ino, out_buf.buf[0].size, (unsigned long) off);
++
++	res = fuse_buf_copy(&out_buf, in_buf, 0);
++	if(res < 0)
++		fuse_reply_err(req, -res);
++	else
++		fuse_reply_write(req, (size_t) res);
++}
++
++static void lo_statfs(fuse_req_t req, fuse_ino_t ino)
++{
++	int res;
++	struct statvfs stbuf;
++
++	res = fstatvfs(lo_fd(req, ino), &stbuf);
++	if (res == -1)
++		fuse_reply_err(req, errno);
++	else
++		fuse_reply_statfs(req, &stbuf);
++}
++
++static void lo_fallocate(fuse_req_t req, fuse_ino_t ino, int mode,
++			 off_t offset, off_t length, struct fuse_file_info *fi)
++{
++	int err = EOPNOTSUPP;
++	(void) ino;
++
++#ifdef HAVE_FALLOCATE
++	err = fallocate(fi->fh, mode, offset, length);
++	if (err < 0)
++		err = errno;
++
++#elif defined(HAVE_POSIX_FALLOCATE)
++	if (mode) {
++		fuse_reply_err(req, EOPNOTSUPP);
++		return;
++	}
++
++	err = posix_fallocate(fi->fh, offset, length);
++#endif
++
++	fuse_reply_err(req, err);
++}
++
++static void lo_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
++		     int op)
++{
++	int res;
++	(void) ino;
++
++	res = flock(fi->fh, op);
++
++	fuse_reply_err(req, res == -1 ? errno : 0);
++}
++
++static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
++			size_t size)
++{
++	char *value = NULL;
++	char procname[64];
++	struct lo_inode *inode = lo_inode(req, ino);
++	ssize_t ret;
++	int saverr;
++
++	saverr = ENOSYS;
++	if (!lo_data(req)->xattr)
++		goto out;
++
++	if (lo_debug(req)) {
++		fuse_log(FUSE_LOG_DEBUG, "lo_getxattr(ino=%" PRIu64 ", name=%s size=%zd)\n",
++			ino, name, size);
++	}
++
++	if (inode->is_symlink) {
++		/* Sorry, no race free way to getxattr on symlink. */
++		saverr = EPERM;
++		goto out;
++	}
++
++	sprintf(procname, "/proc/self/fd/%i", inode->fd);
++
++	if (size) {
++		value = malloc(size);
++		if (!value)
++			goto out_err;
++
++		ret = getxattr(procname, name, value, size);
++		if (ret == -1)
++			goto out_err;
++		saverr = 0;
++		if (ret == 0)
++			goto out;
++
++		fuse_reply_buf(req, value, ret);
++	} else {
++		ret = getxattr(procname, name, NULL, 0);
++		if (ret == -1)
++			goto out_err;
++
++		fuse_reply_xattr(req, ret);
++	}
++out_free:
++	free(value);
++	return;
++
++out_err:
++	saverr = errno;
++out:
++	fuse_reply_err(req, saverr);
++	goto out_free;
++}
++
++static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
++{
++	char *value = NULL;
++	char procname[64];
++	struct lo_inode *inode = lo_inode(req, ino);
++	ssize_t ret;
++	int saverr;
++
++	saverr = ENOSYS;
++	if (!lo_data(req)->xattr)
++		goto out;
++
++	if (lo_debug(req)) {
++		fuse_log(FUSE_LOG_DEBUG, "lo_listxattr(ino=%" PRIu64 ", size=%zd)\n",
++			ino, size);
++	}
++
++	if (inode->is_symlink) {
++		/* Sorry, no race free way to listxattr on symlink. */
++		saverr = EPERM;
++		goto out;
++	}
++
++	sprintf(procname, "/proc/self/fd/%i", inode->fd);
++
++	if (size) {
++		value = malloc(size);
++		if (!value)
++			goto out_err;
++
++		ret = listxattr(procname, value, size);
++		if (ret == -1)
++			goto out_err;
++		saverr = 0;
++		if (ret == 0)
++			goto out;
++
++		fuse_reply_buf(req, value, ret);
++	} else {
++		ret = listxattr(procname, NULL, 0);
++		if (ret == -1)
++			goto out_err;
++
++		fuse_reply_xattr(req, ret);
++	}
++out_free:
++	free(value);
++	return;
++
++out_err:
++	saverr = errno;
++out:
++	fuse_reply_err(req, saverr);
++	goto out_free;
++}
++
++static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
++			const char *value, size_t size, int flags)
++{
++	char procname[64];
++	struct lo_inode *inode = lo_inode(req, ino);
++	ssize_t ret;
++	int saverr;
++
++	saverr = ENOSYS;
++	if (!lo_data(req)->xattr)
++		goto out;
++
++	if (lo_debug(req)) {
++		fuse_log(FUSE_LOG_DEBUG, "lo_setxattr(ino=%" PRIu64 ", name=%s value=%s size=%zd)\n",
++			ino, name, value, size);
++	}
++
++	if (inode->is_symlink) {
++		/* Sorry, no race free way to setxattr on symlink. */
++		saverr = EPERM;
++		goto out;
++	}
++
++	sprintf(procname, "/proc/self/fd/%i", inode->fd);
++
++	ret = setxattr(procname, name, value, size, flags);
++	saverr = ret == -1 ? errno : 0;
++
++out:
++	fuse_reply_err(req, saverr);
++}
++
++static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
++{
++	char procname[64];
++	struct lo_inode *inode = lo_inode(req, ino);
++	ssize_t ret;
++	int saverr;
++
++	saverr = ENOSYS;
++	if (!lo_data(req)->xattr)
++		goto out;
++
++	if (lo_debug(req)) {
++		fuse_log(FUSE_LOG_DEBUG, "lo_removexattr(ino=%" PRIu64 ", name=%s)\n",
++			ino, name);
++	}
++
++	if (inode->is_symlink) {
++		/* Sorry, no race free way to setxattr on symlink. */
++		saverr = EPERM;
++		goto out;
++	}
++
++	sprintf(procname, "/proc/self/fd/%i", inode->fd);
++
++	ret = removexattr(procname, name);
++	saverr = ret == -1 ? errno : 0;
++
++out:
++	fuse_reply_err(req, saverr);
++}
++
++#ifdef HAVE_COPY_FILE_RANGE
++static void lo_copy_file_range(fuse_req_t req, fuse_ino_t ino_in, off_t off_in,
++			       struct fuse_file_info *fi_in,
++			       fuse_ino_t ino_out, off_t off_out,
++			       struct fuse_file_info *fi_out, size_t len,
++			       int flags)
++{
++	ssize_t res;
++
++	if (lo_debug(req))
++		fuse_log(FUSE_LOG_DEBUG, "lo_copy_file_range(ino=%" PRIu64 "/fd=%lu, "
++				"off=%lu, ino=%" PRIu64 "/fd=%lu, "
++				"off=%lu, size=%zd, flags=0x%x)\n",
++			ino_in, fi_in->fh, off_in, ino_out, fi_out->fh, off_out,
++			len, flags);
++
++	res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len,
++			      flags);
++	if (res < 0)
++		fuse_reply_err(req, -errno);
++	else
++		fuse_reply_write(req, res);
++}
++#endif
++
++static void lo_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
++		     struct fuse_file_info *fi)
++{
++	off_t res;
++
++	(void)ino;
++	res = lseek(fi->fh, off, whence);
++	if (res != -1)
++		fuse_reply_lseek(req, res);
++	else
++		fuse_reply_err(req, errno);
++}
++
++static struct fuse_lowlevel_ops lo_oper = {
++	.init		= lo_init,
++	.lookup		= lo_lookup,
++	.mkdir		= lo_mkdir,
++	.mknod		= lo_mknod,
++	.symlink	= lo_symlink,
++	.link		= lo_link,
++	.unlink		= lo_unlink,
++	.rmdir		= lo_rmdir,
++	.rename		= lo_rename,
++	.forget		= lo_forget,
++	.forget_multi	= lo_forget_multi,
++	.getattr	= lo_getattr,
++	.setattr	= lo_setattr,
++	.readlink	= lo_readlink,
++	.opendir	= lo_opendir,
++	.readdir	= lo_readdir,
++	.readdirplus	= lo_readdirplus,
++	.releasedir	= lo_releasedir,
++	.fsyncdir	= lo_fsyncdir,
++	.create		= lo_create,
++	.open		= lo_open,
++	.release	= lo_release,
++	.flush		= lo_flush,
++	.fsync		= lo_fsync,
++	.read		= lo_read,
++	.write_buf      = lo_write_buf,
++	.statfs		= lo_statfs,
++	.fallocate	= lo_fallocate,
++	.flock		= lo_flock,
++	.getxattr	= lo_getxattr,
++	.listxattr	= lo_listxattr,
++	.setxattr	= lo_setxattr,
++	.removexattr	= lo_removexattr,
++#ifdef HAVE_COPY_FILE_RANGE
++	.copy_file_range = lo_copy_file_range,
++#endif
++	.lseek		= lo_lseek,
++};
++
++int main(int argc, char *argv[])
++{
++	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
++	struct fuse_session *se;
++	struct fuse_cmdline_opts opts;
++	struct lo_data lo = { .debug = 0,
++	                      .writeback = 0 };
++	int ret = -1;
++
++	/* Don't mask creation mode, kernel already did that */
++	umask(0);
++
++	pthread_mutex_init(&lo.mutex, NULL);
++	lo.root.next = lo.root.prev = &lo.root;
++	lo.root.fd = -1;
++	lo.cache = CACHE_NORMAL;
++
++	if (fuse_parse_cmdline(&args, &opts) != 0)
++		return 1;
++	if (opts.show_help) {
++		printf("usage: %s [options] <mountpoint>\n\n", argv[0]);
++		fuse_cmdline_help();
++		fuse_lowlevel_help();
++		ret = 0;
++		goto err_out1;
++	} else if (opts.show_version) {
++		printf("FUSE library version %s\n", fuse_pkgversion());
++		fuse_lowlevel_version();
++		ret = 0;
++		goto err_out1;
++	}
++
++	if(opts.mountpoint == NULL) {
++		printf("usage: %s [options] <mountpoint>\n", argv[0]);
++		printf("       %s --help\n", argv[0]);
++		ret = 1;
++		goto err_out1;
++	}
++
++	if (fuse_opt_parse(&args, &lo, lo_opts, NULL)== -1)
++		return 1;
++
++	lo.debug = opts.debug;
++	lo.root.refcount = 2;
++	if (lo.source) {
++		struct stat stat;
++		int res;
++
++		res = lstat(lo.source, &stat);
++		if (res == -1) {
++			fuse_log(FUSE_LOG_ERR, "failed to stat source (\"%s\"): %m\n",
++				 lo.source);
++			exit(1);
++		}
++		if (!S_ISDIR(stat.st_mode)) {
++			fuse_log(FUSE_LOG_ERR, "source is not a directory\n");
++			exit(1);
++		}
++
++	} else {
++		lo.source = "/";
++	}
++	lo.root.is_symlink = false;
++	if (!lo.timeout_set) {
++		switch (lo.cache) {
++		case CACHE_NEVER:
++			lo.timeout = 0.0;
++			break;
++
++		case CACHE_NORMAL:
++			lo.timeout = 1.0;
++			break;
++
++		case CACHE_ALWAYS:
++			lo.timeout = 86400.0;
++			break;
++		}
++	} else if (lo.timeout < 0) {
++		fuse_log(FUSE_LOG_ERR, "timeout is negative (%lf)\n",
++			 lo.timeout);
++		exit(1);
++	}
++
++	lo.root.fd = open(lo.source, O_PATH);
++	if (lo.root.fd == -1) {
++		fuse_log(FUSE_LOG_ERR, "open(\"%s\", O_PATH): %m\n",
++			 lo.source);
++		exit(1);
++	}
++
++	se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo);
++	if (se == NULL)
++	    goto err_out1;
++
++	if (fuse_set_signal_handlers(se) != 0)
++	    goto err_out2;
++
++	if (fuse_session_mount(se, opts.mountpoint) != 0)
++	    goto err_out3;
++
++	fuse_daemonize(opts.foreground);
++
++	/* Block until ctrl+c or fusermount -u */
++	if (opts.singlethread)
++		ret = fuse_session_loop(se);
++	else
++		ret = fuse_session_loop_mt(se, opts.clone_fd);
++
++	fuse_session_unmount(se);
++err_out3:
++	fuse_remove_signal_handlers(se);
++err_out2:
++	fuse_session_destroy(se);
++err_out1:
++	free(opts.mountpoint);
++	fuse_opt_free_args(&args);
++
++	if (lo.root.fd >= 0)
++		close(lo.root.fd);
++
++	return ret ? 1 : 0;
++}
diff --git a/0015-virtiofsd-Trim-down-imported-files.patch b/0015-virtiofsd-Trim-down-imported-files.patch
new file mode 100644
index 0000000..98ee88d
--- /dev/null
+++ b/0015-virtiofsd-Trim-down-imported-files.patch
@@ -0,0 +1,1565 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:44 +0000
+Subject: [PATCH] virtiofsd: Trim down imported files
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There's a lot of the original fuse code we don't need; trim them down.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+with additional trimming by:
+Signed-off-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Reviewed-by: Xiao Yang <yangx.jy@cn.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit a3e23f325439a290c504d6bbc48c2e742149ecab)
+---
+ tools/virtiofsd/buffer.c              |  71 +--
+ tools/virtiofsd/fuse.h                |  46 --
+ tools/virtiofsd/fuse_common.h         |  32 --
+ tools/virtiofsd/fuse_i.h              |  41 --
+ tools/virtiofsd/fuse_log.h            |   8 -
+ tools/virtiofsd/fuse_lowlevel.c       | 675 +-------------------------
+ tools/virtiofsd/fuse_lowlevel.h       |  28 --
+ tools/virtiofsd/fuse_opt.h            |   8 -
+ tools/virtiofsd/helper.c              | 143 ------
+ tools/virtiofsd/passthrough_helpers.h |  26 -
+ tools/virtiofsd/passthrough_ll.c      |   1 -
+ 11 files changed, 8 insertions(+), 1071 deletions(-)
+
+diff --git a/tools/virtiofsd/buffer.c b/tools/virtiofsd/buffer.c
+index 5ab9b87455..aefb7dbf15 100644
+--- a/tools/virtiofsd/buffer.c
++++ b/tools/virtiofsd/buffer.c
+@@ -157,73 +157,6 @@ static ssize_t fuse_buf_fd_to_fd(const struct fuse_buf *dst, size_t dst_off,
+ 	return copied;
+ }
+ 
+-#ifdef HAVE_SPLICE
+-static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off,
+-			       const struct fuse_buf *src, size_t src_off,
+-			       size_t len, enum fuse_buf_copy_flags flags)
+-{
+-	int splice_flags = 0;
+-	off_t *srcpos = NULL;
+-	off_t *dstpos = NULL;
+-	off_t srcpos_val;
+-	off_t dstpos_val;
+-	ssize_t res;
+-	size_t copied = 0;
+-
+-	if (flags & FUSE_BUF_SPLICE_MOVE)
+-		splice_flags |= SPLICE_F_MOVE;
+-	if (flags & FUSE_BUF_SPLICE_NONBLOCK)
+-		splice_flags |= SPLICE_F_NONBLOCK;
+-
+-	if (src->flags & FUSE_BUF_FD_SEEK) {
+-		srcpos_val = src->pos + src_off;
+-		srcpos = &srcpos_val;
+-	}
+-	if (dst->flags & FUSE_BUF_FD_SEEK) {
+-		dstpos_val = dst->pos + dst_off;
+-		dstpos = &dstpos_val;
+-	}
+-
+-	while (len) {
+-		res = splice(src->fd, srcpos, dst->fd, dstpos, len,
+-			     splice_flags);
+-		if (res == -1) {
+-			if (copied)
+-				break;
+-
+-			if (errno != EINVAL || (flags & FUSE_BUF_FORCE_SPLICE))
+-				return -errno;
+-
+-			/* Maybe splice is not supported for this combination */
+-			return fuse_buf_fd_to_fd(dst, dst_off, src, src_off,
+-						 len);
+-		}
+-		if (res == 0)
+-			break;
+-
+-		copied += res;
+-		if (!(src->flags & FUSE_BUF_FD_RETRY) &&
+-		    !(dst->flags & FUSE_BUF_FD_RETRY)) {
+-			break;
+-		}
+-
+-		len -= res;
+-	}
+-
+-	return copied;
+-}
+-#else
+-static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off,
+-			       const struct fuse_buf *src, size_t src_off,
+-			       size_t len, enum fuse_buf_copy_flags flags)
+-{
+-	(void) flags;
+-
+-	return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
+-}
+-#endif
+-
+-
+ static ssize_t fuse_buf_copy_one(const struct fuse_buf *dst, size_t dst_off,
+ 				 const struct fuse_buf *src, size_t src_off,
+ 				 size_t len, enum fuse_buf_copy_flags flags)
+@@ -247,10 +180,8 @@ static ssize_t fuse_buf_copy_one(const struct fuse_buf *dst, size_t dst_off,
+ 		return fuse_buf_write(dst, dst_off, src, src_off, len);
+ 	} else if (!dst_is_fd) {
+ 		return fuse_buf_read(dst, dst_off, src, src_off, len);
+-	} else if (flags & FUSE_BUF_NO_SPLICE) {
+-		return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
+ 	} else {
+-		return fuse_buf_splice(dst, dst_off, src, src_off, len, flags);
++		return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
+ 	}
+ }
+ 
+diff --git a/tools/virtiofsd/fuse.h b/tools/virtiofsd/fuse.h
+index 883f6e59fb..3202fba6bb 100644
+--- a/tools/virtiofsd/fuse.h
++++ b/tools/virtiofsd/fuse.h
+@@ -25,10 +25,6 @@
+ #include <sys/statvfs.h>
+ #include <sys/uio.h>
+ 
+-#ifdef __cplusplus
+-extern "C" {
+-#endif
+-
+ /* ----------------------------------------------------------- *
+  * Basic FUSE API					       *
+  * ----------------------------------------------------------- */
+@@ -978,44 +974,6 @@ int fuse_loop(struct fuse *f);
+  */
+ void fuse_exit(struct fuse *f);
+ 
+-/**
+- * FUSE event loop with multiple threads
+- *
+- * Requests from the kernel are processed, and the appropriate
+- * operations are called.  Request are processed in parallel by
+- * distributing them between multiple threads.
+- *
+- * For a description of the return value and the conditions when the
+- * event loop exits, refer to the documentation of
+- * fuse_session_loop().
+- *
+- * Note: using fuse_loop() instead of fuse_loop_mt() means you are running in
+- * single-threaded mode, and that you will not have to worry about reentrancy,
+- * though you will have to worry about recursive lookups. In single-threaded
+- * mode, FUSE will wait for one callback to return before calling another.
+- *
+- * Enabling multiple threads, by using fuse_loop_mt(), will cause FUSE to make
+- * multiple simultaneous calls into the various callback functions given by your
+- * fuse_operations record.
+- *
+- * If you are using multiple threads, you can enjoy all the parallel execution
+- * and interactive response benefits of threads, and you get to enjoy all the
+- * benefits of race conditions and locking bugs, too. Ensure that any code used
+- * in the callback function of fuse_operations is also thread-safe.
+- *
+- * @param f the FUSE handle
+- * @param config loop configuration
+- * @return see fuse_session_loop()
+- *
+- * See also: fuse_loop()
+- */
+-#if FUSE_USE_VERSION < 32
+-int fuse_loop_mt_31(struct fuse *f, int clone_fd);
+-#define fuse_loop_mt(f, clone_fd) fuse_loop_mt_31(f, clone_fd)
+-#else
+-int fuse_loop_mt(struct fuse *f, struct fuse_loop_config *config);
+-#endif
+-
+ /**
+  * Get the current context
+  *
+@@ -1268,8 +1226,4 @@ struct fuse_session *fuse_get_session(struct fuse *f);
+  */
+ int fuse_open_channel(const char *mountpoint, const char *options);
+ 
+-#ifdef __cplusplus
+-}
+-#endif
+-
+ #endif /* FUSE_H_ */
+diff --git a/tools/virtiofsd/fuse_common.h b/tools/virtiofsd/fuse_common.h
+index 2d686b2ac4..bf8f8cc865 100644
+--- a/tools/virtiofsd/fuse_common.h
++++ b/tools/virtiofsd/fuse_common.h
+@@ -28,10 +28,6 @@
+ #define FUSE_MAKE_VERSION(maj, min)  ((maj) * 10 + (min))
+ #define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION)
+ 
+-#ifdef __cplusplus
+-extern "C" {
+-#endif
+-
+ /**
+  * Information about an open file.
+  *
+@@ -100,30 +96,6 @@ struct fuse_file_info {
+ 	uint32_t poll_events;
+ };
+ 
+-/**
+- * Configuration parameters passed to fuse_session_loop_mt() and
+- * fuse_loop_mt().
+- */
+-struct fuse_loop_config {
+-	/**
+-	 * whether to use separate device fds for each thread
+-	 * (may increase performance)
+-	 */
+-	int clone_fd;
+-
+-	/**
+-	 * The maximum number of available worker threads before they
+-	 * start to get deleted when they become idle. If not
+-	 * specified, the default is 10.
+-	 *
+-	 * Adjusting this has performance implications; a very small number
+-	 * of threads in the pool will cause a lot of thread creation and
+-	 * deletion overhead and performance may suffer. When set to 0, a new
+-	 * thread will be created to service every operation.
+-	 */
+-	unsigned int max_idle_threads;
+-};
+-
+ /**************************************************************************
+  * Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want' *
+  **************************************************************************/
+@@ -802,10 +774,6 @@ void fuse_remove_signal_handlers(struct fuse_session *se);
+ #  error only API version 30 or greater is supported
+ #endif
+ 
+-#ifdef __cplusplus
+-}
+-#endif
+-
+ 
+ /*
+  * This interface uses 64 bit off_t.
+diff --git a/tools/virtiofsd/fuse_i.h b/tools/virtiofsd/fuse_i.h
+index d38b630ac5..b39522e3ca 100644
+--- a/tools/virtiofsd/fuse_i.h
++++ b/tools/virtiofsd/fuse_i.h
+@@ -9,8 +9,6 @@
+ #include "fuse.h"
+ #include "fuse_lowlevel.h"
+ 
+-struct mount_opts;
+-
+ struct fuse_req {
+ 	struct fuse_session *se;
+ 	uint64_t unique;
+@@ -45,7 +43,6 @@ struct fuse_session {
+ 	char *mountpoint;
+ 	volatile int exited;
+ 	int fd;
+-	struct mount_opts *mo;
+ 	int debug;
+ 	int deny_others;
+ 	struct fuse_lowlevel_ops op;
+@@ -58,7 +55,6 @@ struct fuse_session {
+ 	struct fuse_req interrupts;
+ 	pthread_mutex_t lock;
+ 	int got_destroy;
+-	pthread_key_t pipe_key;
+ 	int broken_splice_nonblock;
+ 	uint64_t notify_ctr;
+ 	struct fuse_notify_req notify_list;
+@@ -87,53 +83,16 @@ struct fuse_module {
+ 	int ctr;
+ };
+ 
+-/* ----------------------------------------------------------- *
+- * Channel interface (when using -o clone_fd)		       *
+- * ----------------------------------------------------------- */
+-
+-/**
+- * Obtain counted reference to the channel
+- *
+- * @param ch the channel
+- * @return the channel
+- */
+-struct fuse_chan *fuse_chan_get(struct fuse_chan *ch);
+-
+-/**
+- * Drop counted reference to a channel
+- *
+- * @param ch the channel
+- */
+-void fuse_chan_put(struct fuse_chan *ch);
+-
+-struct mount_opts *parse_mount_opts(struct fuse_args *args);
+-void destroy_mount_opts(struct mount_opts *mo);
+-void fuse_mount_version(void);
+-unsigned get_max_read(struct mount_opts *o);
+-void fuse_kern_unmount(const char *mountpoint, int fd);
+-int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo);
+-
+ int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
+ 			       int count);
+ void fuse_free_req(fuse_req_t req);
+ 
+-void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeide, const void *inarg);
+-
+-int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg);
+-
+-int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
+-				 struct fuse_chan *ch);
+ void fuse_session_process_buf_int(struct fuse_session *se,
+ 				  const struct fuse_buf *buf, struct fuse_chan *ch);
+ 
+-struct fuse *fuse_new_31(struct fuse_args *args, const struct fuse_operations *op,
+-		      size_t op_size, void *private_data);
+-int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config *config);
+-int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config *config);
+ 
+ #define FUSE_MAX_MAX_PAGES 256
+ #define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32
+ 
+ /* room needed in buffer to accommodate header */
+ #define FUSE_BUFFER_HEADER_SIZE 0x1000
+-
+diff --git a/tools/virtiofsd/fuse_log.h b/tools/virtiofsd/fuse_log.h
+index 5e112e0f53..0af700da6b 100644
+--- a/tools/virtiofsd/fuse_log.h
++++ b/tools/virtiofsd/fuse_log.h
+@@ -16,10 +16,6 @@
+ 
+ #include <stdarg.h>
+ 
+-#ifdef __cplusplus
+-extern "C" {
+-#endif
+-
+ /**
+  * Log severity level
+  *
+@@ -75,8 +71,4 @@ void fuse_set_log_func(fuse_log_func_t func);
+  */
+ void fuse_log(enum fuse_log_level level, const char *fmt, ...);
+ 
+-#ifdef __cplusplus
+-}
+-#endif
+-
+ #endif /* FUSE_LOG_H_ */
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index f2d7038e34..e6fa247924 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -16,7 +16,6 @@
+ #include "fuse_kernel.h"
+ #include "fuse_opt.h"
+ #include "fuse_misc.h"
+-#include "mount_util.h"
+ 
+ #include <stdio.h>
+ #include <stdlib.h>
+@@ -28,12 +27,6 @@
+ #include <assert.h>
+ #include <sys/file.h>
+ 
+-#ifndef F_LINUX_SPECIFIC_BASE
+-#define F_LINUX_SPECIFIC_BASE       1024
+-#endif
+-#ifndef F_SETPIPE_SZ
+-#define F_SETPIPE_SZ	(F_LINUX_SPECIFIC_BASE + 7)
+-#endif
+ 
+ 
+ #define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
+@@ -137,7 +130,6 @@ void fuse_free_req(fuse_req_t req)
+ 	req->u.ni.data = NULL;
+ 	list_del_req(req);
+ 	ctr = --req->ctr;
+-	fuse_chan_put(req->ch);
+ 	req->ch = NULL;
+ 	pthread_mutex_unlock(&se->lock);
+ 	if (!ctr)
+@@ -184,19 +176,7 @@ static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
+ 		}
+ 	}
+ 
+-	ssize_t res = writev(ch ? ch->fd : se->fd,
+-			     iov, count);
+-	int err = errno;
+-
+-	if (res == -1) {
+-		assert(se != NULL);
+-
+-		/* ENOENT means the operation was interrupted */
+-		if (!fuse_session_exited(se) && err != ENOENT)
+-			perror("fuse: writing device");
+-		return -err;
+-	}
+-
++	abort(); /* virtio should have taken it before here */
+ 	return 0;
+ }
+ 
+@@ -480,10 +460,6 @@ static int fuse_send_data_iov_fallback(struct fuse_session *se,
+ 				       struct fuse_bufvec *buf,
+ 				       size_t len)
+ {
+-	struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
+-	void *mbuf;
+-	int res;
+-
+ 	/* Optimize common case */
+ 	if (buf->count == 1 && buf->idx == 0 && buf->off == 0 &&
+ 	    !(buf->buf[0].flags & FUSE_BUF_IS_FD)) {
+@@ -496,350 +472,10 @@ static int fuse_send_data_iov_fallback(struct fuse_session *se,
+ 		return fuse_send_msg(se, ch, iov, iov_count);
+ 	}
+ 
+-	res = posix_memalign(&mbuf, pagesize, len);
+-	if (res != 0)
+-		return res;
+-
+-	mem_buf.buf[0].mem = mbuf;
+-	res = fuse_buf_copy(&mem_buf, buf, 0);
+-	if (res < 0) {
+-		free(mbuf);
+-		return -res;
+-	}
+-	len = res;
+-
+-	iov[iov_count].iov_base = mbuf;
+-	iov[iov_count].iov_len = len;
+-	iov_count++;
+-	res = fuse_send_msg(se, ch, iov, iov_count);
+-	free(mbuf);
+-
+-	return res;
+-}
+-
+-struct fuse_ll_pipe {
+-	size_t size;
+-	int can_grow;
+-	int pipe[2];
+-};
+-
+-static void fuse_ll_pipe_free(struct fuse_ll_pipe *llp)
+-{
+-	close(llp->pipe[0]);
+-	close(llp->pipe[1]);
+-	free(llp);
+-}
+-
+-#ifdef HAVE_SPLICE
+-#if !defined(HAVE_PIPE2) || !defined(O_CLOEXEC)
+-static int fuse_pipe(int fds[2])
+-{
+-	int rv = pipe(fds);
+-
+-	if (rv == -1)
+-		return rv;
+-
+-	if (fcntl(fds[0], F_SETFL, O_NONBLOCK) == -1 ||
+-	    fcntl(fds[1], F_SETFL, O_NONBLOCK) == -1 ||
+-	    fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
+-	    fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
+-		close(fds[0]);
+-		close(fds[1]);
+-		rv = -1;
+-	}
+-	return rv;
+-}
+-#else
+-static int fuse_pipe(int fds[2])
+-{
+-	return pipe2(fds, O_CLOEXEC | O_NONBLOCK);
+-}
+-#endif
+-
+-static struct fuse_ll_pipe *fuse_ll_get_pipe(struct fuse_session *se)
+-{
+-	struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key);
+-	if (llp == NULL) {
+-		int res;
+-
+-		llp = malloc(sizeof(struct fuse_ll_pipe));
+-		if (llp == NULL)
+-			return NULL;
+-
+-		res = fuse_pipe(llp->pipe);
+-		if (res == -1) {
+-			free(llp);
+-			return NULL;
+-		}
+-
+-		/*
+-		 *the default size is 16 pages on linux
+-		 */
+-		llp->size = pagesize * 16;
+-		llp->can_grow = 1;
+-
+-		pthread_setspecific(se->pipe_key, llp);
+-	}
+-
+-	return llp;
+-}
+-#endif
+-
+-static void fuse_ll_clear_pipe(struct fuse_session *se)
+-{
+-	struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key);
+-	if (llp) {
+-		pthread_setspecific(se->pipe_key, NULL);
+-		fuse_ll_pipe_free(llp);
+-	}
+-}
+-
+-#if defined(HAVE_SPLICE) && defined(HAVE_VMSPLICE)
+-static int read_back(int fd, char *buf, size_t len)
+-{
+-	int res;
+-
+-	res = read(fd, buf, len);
+-	if (res == -1) {
+-		fuse_log(FUSE_LOG_ERR, "fuse: internal error: failed to read back from pipe: %s\n", strerror(errno));
+-		return -EIO;
+-	}
+-	if (res != len) {
+-		fuse_log(FUSE_LOG_ERR, "fuse: internal error: short read back from pipe: %i from %zi\n", res, len);
+-		return -EIO;
+-	}
++	abort(); /* Will have taken vhost path */
+ 	return 0;
+ }
+ 
+-static int grow_pipe_to_max(int pipefd)
+-{
+-	int max;
+-	int res;
+-	int maxfd;
+-	char buf[32];
+-
+-	maxfd = open("/proc/sys/fs/pipe-max-size", O_RDONLY);
+-	if (maxfd < 0)
+-		return -errno;
+-
+-	res = read(maxfd, buf, sizeof(buf) - 1);
+-	if (res < 0) {
+-		int saved_errno;
+-
+-		saved_errno = errno;
+-		close(maxfd);
+-		return -saved_errno;
+-	}
+-	close(maxfd);
+-	buf[res] = '\0';
+-
+-	max = atoi(buf);
+-	res = fcntl(pipefd, F_SETPIPE_SZ, max);
+-	if (res < 0)
+-		return -errno;
+-	return max;
+-}
+-
+-static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
+-			       struct iovec *iov, int iov_count,
+-			       struct fuse_bufvec *buf, unsigned int flags)
+-{
+-	int res;
+-	size_t len = fuse_buf_size(buf);
+-	struct fuse_out_header *out = iov[0].iov_base;
+-	struct fuse_ll_pipe *llp;
+-	int splice_flags;
+-	size_t pipesize;
+-	size_t total_fd_size;
+-	size_t idx;
+-	size_t headerlen;
+-	struct fuse_bufvec pipe_buf = FUSE_BUFVEC_INIT(len);
+-
+-	if (se->broken_splice_nonblock)
+-		goto fallback;
+-
+-	if (flags & FUSE_BUF_NO_SPLICE)
+-		goto fallback;
+-
+-	total_fd_size = 0;
+-	for (idx = buf->idx; idx < buf->count; idx++) {
+-		if (buf->buf[idx].flags & FUSE_BUF_IS_FD) {
+-			total_fd_size = buf->buf[idx].size;
+-			if (idx == buf->idx)
+-				total_fd_size -= buf->off;
+-		}
+-	}
+-	if (total_fd_size < 2 * pagesize)
+-		goto fallback;
+-
+-	if (se->conn.proto_minor < 14 ||
+-	    !(se->conn.want & FUSE_CAP_SPLICE_WRITE))
+-		goto fallback;
+-
+-	llp = fuse_ll_get_pipe(se);
+-	if (llp == NULL)
+-		goto fallback;
+-
+-
+-	headerlen = iov_length(iov, iov_count);
+-
+-	out->len = headerlen + len;
+-
+-	/*
+-	 * Heuristic for the required pipe size, does not work if the
+-	 * source contains less than page size fragments
+-	 */
+-	pipesize = pagesize * (iov_count + buf->count + 1) + out->len;
+-
+-	if (llp->size < pipesize) {
+-		if (llp->can_grow) {
+-			res = fcntl(llp->pipe[0], F_SETPIPE_SZ, pipesize);
+-			if (res == -1) {
+-				res = grow_pipe_to_max(llp->pipe[0]);
+-				if (res > 0)
+-					llp->size = res;
+-				llp->can_grow = 0;
+-				goto fallback;
+-			}
+-			llp->size = res;
+-		}
+-		if (llp->size < pipesize)
+-			goto fallback;
+-	}
+-
+-
+-	res = vmsplice(llp->pipe[1], iov, iov_count, SPLICE_F_NONBLOCK);
+-	if (res == -1)
+-		goto fallback;
+-
+-	if (res != headerlen) {
+-		res = -EIO;
+-		fuse_log(FUSE_LOG_ERR, "fuse: short vmsplice to pipe: %u/%zu\n", res,
+-			headerlen);
+-		goto clear_pipe;
+-	}
+-
+-	pipe_buf.buf[0].flags = FUSE_BUF_IS_FD;
+-	pipe_buf.buf[0].fd = llp->pipe[1];
+-
+-	res = fuse_buf_copy(&pipe_buf, buf,
+-			    FUSE_BUF_FORCE_SPLICE | FUSE_BUF_SPLICE_NONBLOCK);
+-	if (res < 0) {
+-		if (res == -EAGAIN || res == -EINVAL) {
+-			/*
+-			 * Should only get EAGAIN on kernels with
+-			 * broken SPLICE_F_NONBLOCK support (<=
+-			 * 2.6.35) where this error or a short read is
+-			 * returned even if the pipe itself is not
+-			 * full
+-			 *
+-			 * EINVAL might mean that splice can't handle
+-			 * this combination of input and output.
+-			 */
+-			if (res == -EAGAIN)
+-				se->broken_splice_nonblock = 1;
+-
+-			pthread_setspecific(se->pipe_key, NULL);
+-			fuse_ll_pipe_free(llp);
+-			goto fallback;
+-		}
+-		res = -res;
+-		goto clear_pipe;
+-	}
+-
+-	if (res != 0 && res < len) {
+-		struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
+-		void *mbuf;
+-		size_t now_len = res;
+-		/*
+-		 * For regular files a short count is either
+-		 *  1) due to EOF, or
+-		 *  2) because of broken SPLICE_F_NONBLOCK (see above)
+-		 *
+-		 * For other inputs it's possible that we overflowed
+-		 * the pipe because of small buffer fragments.
+-		 */
+-
+-		res = posix_memalign(&mbuf, pagesize, len);
+-		if (res != 0)
+-			goto clear_pipe;
+-
+-		mem_buf.buf[0].mem = mbuf;
+-		mem_buf.off = now_len;
+-		res = fuse_buf_copy(&mem_buf, buf, 0);
+-		if (res > 0) {
+-			char *tmpbuf;
+-			size_t extra_len = res;
+-			/*
+-			 * Trickiest case: got more data.  Need to get
+-			 * back the data from the pipe and then fall
+-			 * back to regular write.
+-			 */
+-			tmpbuf = malloc(headerlen);
+-			if (tmpbuf == NULL) {
+-				free(mbuf);
+-				res = ENOMEM;
+-				goto clear_pipe;
+-			}
+-			res = read_back(llp->pipe[0], tmpbuf, headerlen);
+-			free(tmpbuf);
+-			if (res != 0) {
+-				free(mbuf);
+-				goto clear_pipe;
+-			}
+-			res = read_back(llp->pipe[0], mbuf, now_len);
+-			if (res != 0) {
+-				free(mbuf);
+-				goto clear_pipe;
+-			}
+-			len = now_len + extra_len;
+-			iov[iov_count].iov_base = mbuf;
+-			iov[iov_count].iov_len = len;
+-			iov_count++;
+-			res = fuse_send_msg(se, ch, iov, iov_count);
+-			free(mbuf);
+-			return res;
+-		}
+-		free(mbuf);
+-		res = now_len;
+-	}
+-	len = res;
+-	out->len = headerlen + len;
+-
+-	if (se->debug) {
+-		fuse_log(FUSE_LOG_DEBUG,
+-			"   unique: %llu, success, outsize: %i (splice)\n",
+-			(unsigned long long) out->unique, out->len);
+-	}
+-
+-	splice_flags = 0;
+-	if ((flags & FUSE_BUF_SPLICE_MOVE) &&
+-	    (se->conn.want & FUSE_CAP_SPLICE_MOVE))
+-		splice_flags |= SPLICE_F_MOVE;
+-
+-	res = splice(llp->pipe[0], NULL, ch ? ch->fd : se->fd,
+-		     NULL, out->len, splice_flags);
+-	if (res == -1) {
+-		res = -errno;
+-		perror("fuse: splice from pipe");
+-		goto clear_pipe;
+-	}
+-	if (res != out->len) {
+-		res = -EIO;
+-		fuse_log(FUSE_LOG_ERR, "fuse: short splice from pipe: %u/%u\n",
+-			res, out->len);
+-		goto clear_pipe;
+-	}
+-	return 0;
+-
+-clear_pipe:
+-	fuse_ll_clear_pipe(se);
+-	return res;
+-
+-fallback:
+-	return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
+-}
+-#else
+ static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
+ 			       struct iovec *iov, int iov_count,
+ 			       struct fuse_bufvec *buf, unsigned int flags)
+@@ -849,7 +485,6 @@ static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
+ 
+ 	return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
+ }
+-#endif
+ 
+ int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
+ 		    enum fuse_buf_copy_flags flags)
+@@ -1408,16 +1043,11 @@ static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid, const void *inarg,
+ 	if (bufv.buf[0].size < arg->size) {
+ 		fuse_log(FUSE_LOG_ERR, "fuse: do_write_buf: buffer size too small\n");
+ 		fuse_reply_err(req, EIO);
+-		goto out;
++		return;
+ 	}
+ 	bufv.buf[0].size = arg->size;
+ 
+ 	se->op.write_buf(req, nodeid, &bufv, arg->offset, &fi);
+-
+-out:
+-	/* Need to reset the pipe if ->write_buf() didn't consume all data */
+-	if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count)
+-		fuse_ll_clear_pipe(se);
+ }
+ 
+ static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+@@ -2038,17 +1668,6 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ 		return;
+ 	}
+ 
+-	unsigned max_read_mo = get_max_read(se->mo);
+-	if (se->conn.max_read != max_read_mo) {
+-		fuse_log(FUSE_LOG_ERR, "fuse: error: init() and fuse_session_new() "
+-			"requested different maximum read size (%u vs %u)\n",
+-			se->conn.max_read, max_read_mo);
+-		fuse_reply_err(req, EPROTO);
+-		se->error = -EPROTO;
+-		fuse_session_exit(se);
+-		return;
+-	}
+-
+ 	if (se->conn.max_write < bufsize - FUSE_BUFFER_HEADER_SIZE) {
+ 		se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
+ 	}
+@@ -2364,8 +1983,6 @@ static void fuse_ll_retrieve_reply(struct fuse_notify_req *nreq,
+ 	}
+ out:
+ 	free(rreq);
+-	if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count)
+-		fuse_ll_clear_pipe(se);
+ }
+ 
+ int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino,
+@@ -2496,7 +2113,6 @@ static struct {
+ 	[FUSE_RENAME2]     = { do_rename2,      "RENAME2"    },
+ 	[FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" },
+ 	[FUSE_LSEEK]	   = { do_lseek,       "LSEEK"	     },
+-	[CUSE_INIT]	   = { cuse_lowlevel_init, "CUSE_INIT"   },
+ };
+ 
+ #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
+@@ -2509,21 +2125,6 @@ static const char *opname(enum fuse_opcode opcode)
+ 		return fuse_ll_ops[opcode].name;
+ }
+ 
+-static int fuse_ll_copy_from_pipe(struct fuse_bufvec *dst,
+-				  struct fuse_bufvec *src)
+-{
+-	ssize_t res = fuse_buf_copy(dst, src, 0);
+-	if (res < 0) {
+-		fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: %s\n", strerror(-res));
+-		return res;
+-	}
+-	if ((size_t)res < fuse_buf_size(dst)) {
+-		fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: short read\n");
+-		return -1;
+-	}
+-	return 0;
+-}
+-
+ void fuse_session_process_buf(struct fuse_session *se,
+ 			      const struct fuse_buf *buf)
+ {
+@@ -2533,36 +2134,12 @@ void fuse_session_process_buf(struct fuse_session *se,
+ void fuse_session_process_buf_int(struct fuse_session *se,
+ 				  const struct fuse_buf *buf, struct fuse_chan *ch)
+ {
+-	const size_t write_header_size = sizeof(struct fuse_in_header) +
+-		sizeof(struct fuse_write_in);
+-	struct fuse_bufvec bufv = { .buf[0] = *buf, .count = 1 };
+-	struct fuse_bufvec tmpbuf = FUSE_BUFVEC_INIT(write_header_size);
+ 	struct fuse_in_header *in;
+ 	const void *inarg;
+ 	struct fuse_req *req;
+-	void *mbuf = NULL;
+ 	int err;
+-	int res;
+-
+-	if (buf->flags & FUSE_BUF_IS_FD) {
+-		if (buf->size < tmpbuf.buf[0].size)
+-			tmpbuf.buf[0].size = buf->size;
+ 
+-		mbuf = malloc(tmpbuf.buf[0].size);
+-		if (mbuf == NULL) {
+-			fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate header\n");
+-			goto clear_pipe;
+-		}
+-		tmpbuf.buf[0].mem = mbuf;
+-
+-		res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
+-		if (res < 0)
+-			goto clear_pipe;
+-
+-		in = mbuf;
+-	} else {
+-		in = buf->mem;
+-	}
++	in = buf->mem;
+ 
+ 	if (se->debug) {
+ 		fuse_log(FUSE_LOG_DEBUG,
+@@ -2584,14 +2161,14 @@ void fuse_session_process_buf_int(struct fuse_session *se,
+ 		};
+ 
+ 		fuse_send_msg(se, ch, &iov, 1);
+-		goto clear_pipe;
++		return;
+ 	}
+ 
+ 	req->unique = in->unique;
+ 	req->ctx.uid = in->uid;
+ 	req->ctx.gid = in->gid;
+ 	req->ctx.pid = in->pid;
+-	req->ch = ch ? fuse_chan_get(ch) : NULL;
++	req->ch = ch;
+ 
+ 	err = EIO;
+ 	if (!se->got_init) {
+@@ -2627,28 +2204,6 @@ void fuse_session_process_buf_int(struct fuse_session *se,
+ 			fuse_reply_err(intr, EAGAIN);
+ 	}
+ 
+-	if ((buf->flags & FUSE_BUF_IS_FD) && write_header_size < buf->size &&
+-	    (in->opcode != FUSE_WRITE || !se->op.write_buf) &&
+-	    in->opcode != FUSE_NOTIFY_REPLY) {
+-		void *newmbuf;
+-
+-		err = ENOMEM;
+-		newmbuf = realloc(mbuf, buf->size);
+-		if (newmbuf == NULL)
+-			goto reply_err;
+-		mbuf = newmbuf;
+-
+-		tmpbuf = FUSE_BUFVEC_INIT(buf->size - write_header_size);
+-		tmpbuf.buf[0].mem = (char *)mbuf + write_header_size;
+-
+-		res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
+-		err = -res;
+-		if (res < 0)
+-			goto reply_err;
+-
+-		in = mbuf;
+-	}
+-
+ 	inarg = (void *) &in[1];
+ 	if (in->opcode == FUSE_WRITE && se->op.write_buf)
+ 		do_write_buf(req, in->nodeid, inarg, buf);
+@@ -2657,16 +2212,10 @@ void fuse_session_process_buf_int(struct fuse_session *se,
+ 	else
+ 		fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
+ 
+-out_free:
+-	free(mbuf);
+ 	return;
+ 
+ reply_err:
+ 	fuse_reply_err(req, err);
+-clear_pipe:
+-	if (buf->flags & FUSE_BUF_IS_FD)
+-		fuse_ll_clear_pipe(se);
+-	goto out_free;
+ }
+ 
+ #define LL_OPTION(n,o,v) \
+@@ -2684,7 +2233,6 @@ void fuse_lowlevel_version(void)
+ {
+ 	printf("using FUSE kernel interface version %i.%i\n",
+ 	       FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
+-	fuse_mount_version();
+ }
+ 
+ void fuse_lowlevel_help(void)
+@@ -2692,204 +2240,29 @@ void fuse_lowlevel_help(void)
+ 	/* These are not all options, but the ones that are
+ 	   potentially of interest to an end-user */
+ 	printf(
+-"    -o allow_other         allow access by all users\n"
+ "    -o allow_root          allow access by root\n"
+-"    -o auto_unmount        auto unmount on process termination\n");
++);
+ }
+ 
+ void fuse_session_destroy(struct fuse_session *se)
+ {
+-	struct fuse_ll_pipe *llp;
+-
+ 	if (se->got_init && !se->got_destroy) {
+ 		if (se->op.destroy)
+ 			se->op.destroy(se->userdata);
+ 	}
+-	llp = pthread_getspecific(se->pipe_key);
+-	if (llp != NULL)
+-		fuse_ll_pipe_free(llp);
+-	pthread_key_delete(se->pipe_key);
+ 	pthread_mutex_destroy(&se->lock);
+ 	free(se->cuse_data);
+ 	if (se->fd != -1)
+ 		close(se->fd);
+-	destroy_mount_opts(se->mo);
+ 	free(se);
+ }
+ 
+ 
+-static void fuse_ll_pipe_destructor(void *data)
+-{
+-	struct fuse_ll_pipe *llp = data;
+-	fuse_ll_pipe_free(llp);
+-}
+-
+-int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf)
+-{
+-	return fuse_session_receive_buf_int(se, buf, NULL);
+-}
+-
+-int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
+-				 struct fuse_chan *ch)
+-{
+-	int err;
+-	ssize_t res;
+-#ifdef HAVE_SPLICE
+-	size_t bufsize = se->bufsize;
+-	struct fuse_ll_pipe *llp;
+-	struct fuse_buf tmpbuf;
+-
+-	if (se->conn.proto_minor < 14 || !(se->conn.want & FUSE_CAP_SPLICE_READ))
+-		goto fallback;
+-
+-	llp = fuse_ll_get_pipe(se);
+-	if (llp == NULL)
+-		goto fallback;
+-
+-	if (llp->size < bufsize) {
+-		if (llp->can_grow) {
+-			res = fcntl(llp->pipe[0], F_SETPIPE_SZ, bufsize);
+-			if (res == -1) {
+-				llp->can_grow = 0;
+-				res = grow_pipe_to_max(llp->pipe[0]);
+-				if (res > 0)
+-					llp->size = res;
+-				goto fallback;
+-			}
+-			llp->size = res;
+-		}
+-		if (llp->size < bufsize)
+-			goto fallback;
+-	}
+-
+-	res = splice(ch ? ch->fd : se->fd,
+-		     NULL, llp->pipe[1], NULL, bufsize, 0);
+-	err = errno;
+-
+-	if (fuse_session_exited(se))
+-		return 0;
+-
+-	if (res == -1) {
+-		if (err == ENODEV) {
+-			/* Filesystem was unmounted, or connection was aborted
+-			   via /sys/fs/fuse/connections */
+-			fuse_session_exit(se);
+-			return 0;
+-		}
+-		if (err != EINTR && err != EAGAIN)
+-			perror("fuse: splice from device");
+-		return -err;
+-	}
+-
+-	if (res < sizeof(struct fuse_in_header)) {
+-		fuse_log(FUSE_LOG_ERR, "short splice from fuse device\n");
+-		return -EIO;
+-	}
+-
+-	tmpbuf = (struct fuse_buf) {
+-		.size = res,
+-		.flags = FUSE_BUF_IS_FD,
+-		.fd = llp->pipe[0],
+-	};
+-
+-	/*
+-	 * Don't bother with zero copy for small requests.
+-	 * fuse_loop_mt() needs to check for FORGET so this more than
+-	 * just an optimization.
+-	 */
+-	if (res < sizeof(struct fuse_in_header) +
+-	    sizeof(struct fuse_write_in) + pagesize) {
+-		struct fuse_bufvec src = { .buf[0] = tmpbuf, .count = 1 };
+-		struct fuse_bufvec dst = { .count = 1 };
+-
+-		if (!buf->mem) {
+-			buf->mem = malloc(se->bufsize);
+-			if (!buf->mem) {
+-				fuse_log(FUSE_LOG_ERR,
+-					"fuse: failed to allocate read buffer\n");
+-				return -ENOMEM;
+-			}
+-		}
+-		buf->size = se->bufsize;
+-		buf->flags = 0;
+-		dst.buf[0] = *buf;
+-
+-		res = fuse_buf_copy(&dst, &src, 0);
+-		if (res < 0) {
+-			fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: %s\n",
+-				strerror(-res));
+-			fuse_ll_clear_pipe(se);
+-			return res;
+-		}
+-		if (res < tmpbuf.size) {
+-			fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: short read\n");
+-			fuse_ll_clear_pipe(se);
+-			return -EIO;
+-		}
+-		assert(res == tmpbuf.size);
+-
+-	} else {
+-		/* Don't overwrite buf->mem, as that would cause a leak */
+-		buf->fd = tmpbuf.fd;
+-		buf->flags = tmpbuf.flags;
+-	}
+-	buf->size = tmpbuf.size;
+-
+-	return res;
+-
+-fallback:
+-#endif
+-	if (!buf->mem) {
+-		buf->mem = malloc(se->bufsize);
+-		if (!buf->mem) {
+-			fuse_log(FUSE_LOG_ERR,
+-				"fuse: failed to allocate read buffer\n");
+-			return -ENOMEM;
+-		}
+-	}
+-
+-restart:
+-	res = read(ch ? ch->fd : se->fd, buf->mem, se->bufsize);
+-	err = errno;
+-
+-	if (fuse_session_exited(se))
+-		return 0;
+-	if (res == -1) {
+-		/* ENOENT means the operation was interrupted, it's safe
+-		   to restart */
+-		if (err == ENOENT)
+-			goto restart;
+-
+-		if (err == ENODEV) {
+-			/* Filesystem was unmounted, or connection was aborted
+-			   via /sys/fs/fuse/connections */
+-			fuse_session_exit(se);
+-			return 0;
+-		}
+-		/* Errors occurring during normal operation: EINTR (read
+-		   interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem
+-		   umounted) */
+-		if (err != EINTR && err != EAGAIN)
+-			perror("fuse: reading device");
+-		return -err;
+-	}
+-	if ((size_t) res < sizeof(struct fuse_in_header)) {
+-		fuse_log(FUSE_LOG_ERR, "short read on fuse device\n");
+-		return -EIO;
+-	}
+-
+-	buf->size = res;
+-
+-	return res;
+-}
+-
+ struct fuse_session *fuse_session_new(struct fuse_args *args,
+ 				      const struct fuse_lowlevel_ops *op,
+ 				      size_t op_size, void *userdata)
+ {
+-	int err;
+ 	struct fuse_session *se;
+-	struct mount_opts *mo;
+ 
+ 	if (sizeof(struct fuse_lowlevel_ops) < op_size) {
+ 		fuse_log(FUSE_LOG_ERR, "fuse: warning: library too old, some operations may not work\n");
+@@ -2913,20 +2286,6 @@ struct fuse_session *fuse_session_new(struct fuse_args *args,
+ 	/* Parse options */
+ 	if(fuse_opt_parse(args, se, fuse_ll_opts, NULL) == -1)
+ 		goto out2;
+-	if(se->deny_others) {
+-		/* Allowing access only by root is done by instructing
+-		 * kernel to allow access by everyone, and then restricting
+-		 * access to root and mountpoint owner in libfuse.
+-		 */
+-		// We may be adding the option a second time, but
+-		// that doesn't hurt.
+-		if(fuse_opt_add_arg(args, "-oallow_other") == -1)
+-			goto out2;
+-	}
+-	mo = parse_mount_opts(args);
+-	if (mo == NULL)
+-		goto out3;
+-
+ 	if(args->argc == 1 &&
+ 	   args->argv[0][0] == '-') {
+ 		fuse_log(FUSE_LOG_ERR, "fuse: warning: argv[0] looks like an option, but "
+@@ -2940,9 +2299,6 @@ struct fuse_session *fuse_session_new(struct fuse_args *args,
+ 		goto out4;
+ 	}
+ 
+-	if (se->debug)
+-		fuse_log(FUSE_LOG_DEBUG, "FUSE library version: %s\n", PACKAGE_VERSION);
+-
+ 	se->bufsize = FUSE_MAX_MAX_PAGES * getpagesize() +
+ 		FUSE_BUFFER_HEADER_SIZE;
+ 
+@@ -2952,26 +2308,14 @@ struct fuse_session *fuse_session_new(struct fuse_args *args,
+ 	se->notify_ctr = 1;
+ 	fuse_mutex_init(&se->lock);
+ 
+-	err = pthread_key_create(&se->pipe_key, fuse_ll_pipe_destructor);
+-	if (err) {
+-		fuse_log(FUSE_LOG_ERR, "fuse: failed to create thread specific key: %s\n",
+-			strerror(err));
+-		goto out5;
+-	}
+-
+ 	memcpy(&se->op, op, op_size);
+ 	se->owner = getuid();
+ 	se->userdata = userdata;
+ 
+-	se->mo = mo;
+ 	return se;
+ 
+-out5:
+-	pthread_mutex_destroy(&se->lock);
+ out4:
+ 	fuse_opt_free_args(args);
+-out3:
+-	free(mo);
+ out2:
+ 	free(se);
+ out1:
+@@ -3035,11 +2379,6 @@ int fuse_session_fd(struct fuse_session *se)
+ 
+ void fuse_session_unmount(struct fuse_session *se)
+ {
+-	if (se->mountpoint != NULL) {
+-		fuse_kern_unmount(se->mountpoint, se->fd);
+-		free(se->mountpoint);
+-		se->mountpoint = NULL;
+-	}
+ }
+ 
+ #ifdef linux
+diff --git a/tools/virtiofsd/fuse_lowlevel.h b/tools/virtiofsd/fuse_lowlevel.h
+index 18c6363f07..6b1adfcfd1 100644
+--- a/tools/virtiofsd/fuse_lowlevel.h
++++ b/tools/virtiofsd/fuse_lowlevel.h
+@@ -31,10 +31,6 @@
+ #include <sys/statvfs.h>
+ #include <sys/uio.h>
+ 
+-#ifdef __cplusplus
+-extern "C" {
+-#endif
+-
+ /* ----------------------------------------------------------- *
+  * Miscellaneous definitions				       *
+  * ----------------------------------------------------------- */
+@@ -1863,14 +1859,12 @@ void fuse_cmdline_help(void);
+  * ----------------------------------------------------------- */
+ 
+ struct fuse_cmdline_opts {
+-	int singlethread;
+ 	int foreground;
+ 	int debug;
+ 	int nodefault_subtype;
+ 	char *mountpoint;
+ 	int show_version;
+ 	int show_help;
+-	int clone_fd;
+ 	unsigned int max_idle_threads;
+ };
+ 
+@@ -1961,24 +1955,6 @@ int fuse_session_mount(struct fuse_session *se, const char *mountpoint);
+  */
+ int fuse_session_loop(struct fuse_session *se);
+ 
+-/**
+- * Enter a multi-threaded event loop.
+- *
+- * For a description of the return value and the conditions when the
+- * event loop exits, refer to the documentation of
+- * fuse_session_loop().
+- *
+- * @param se the session
+- * @param config session loop configuration 
+- * @return see fuse_session_loop()
+- */
+-#if FUSE_USE_VERSION < 32
+-int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd);
+-#define fuse_session_loop_mt(se, clone_fd) fuse_session_loop_mt_31(se, clone_fd)
+-#else
+-int fuse_session_loop_mt(struct fuse_session *se, struct fuse_loop_config *config);
+-#endif
+-
+ /**
+  * Flag a session as terminated.
+  *
+@@ -2082,8 +2058,4 @@ void fuse_session_process_buf(struct fuse_session *se,
+  */
+ int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf);
+ 
+-#ifdef __cplusplus
+-}
+-#endif
+-
+ #endif /* FUSE_LOWLEVEL_H_ */
+diff --git a/tools/virtiofsd/fuse_opt.h b/tools/virtiofsd/fuse_opt.h
+index d8573e74fd..69102555be 100644
+--- a/tools/virtiofsd/fuse_opt.h
++++ b/tools/virtiofsd/fuse_opt.h
+@@ -14,10 +14,6 @@
+  * This file defines the option parsing interface of FUSE
+  */
+ 
+-#ifdef __cplusplus
+-extern "C" {
+-#endif
+-
+ /**
+  * Option description
+  *
+@@ -264,8 +260,4 @@ void fuse_opt_free_args(struct fuse_args *args);
+  */
+ int fuse_opt_match(const struct fuse_opt opts[], const char *opt);
+ 
+-#ifdef __cplusplus
+-}
+-#endif
+-
+ #endif /* FUSE_OPT_H_ */
+diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
+index 64ff7ad6d5..5a2e64c6d0 100644
+--- a/tools/virtiofsd/helper.c
++++ b/tools/virtiofsd/helper.c
+@@ -41,14 +41,10 @@ static const struct fuse_opt fuse_helper_opts[] = {
+ 	FUSE_OPT_KEY("-d",		FUSE_OPT_KEY_KEEP),
+ 	FUSE_OPT_KEY("debug",		FUSE_OPT_KEY_KEEP),
+ 	FUSE_HELPER_OPT("-f",		foreground),
+-	FUSE_HELPER_OPT("-s",		singlethread),
+ 	FUSE_HELPER_OPT("fsname=",	nodefault_subtype),
+ 	FUSE_OPT_KEY("fsname=",		FUSE_OPT_KEY_KEEP),
+-#ifndef __FreeBSD__
+ 	FUSE_HELPER_OPT("subtype=",	nodefault_subtype),
+ 	FUSE_OPT_KEY("subtype=",	FUSE_OPT_KEY_KEEP),
+-#endif
+-	FUSE_HELPER_OPT("clone_fd",	clone_fd),
+ 	FUSE_HELPER_OPT("max_idle_threads=%u", max_idle_threads),
+ 	FUSE_OPT_END
+ };
+@@ -132,9 +128,6 @@ void fuse_cmdline_help(void)
+ 	       "    -V   --version         print version\n"
+ 	       "    -d   -o debug          enable debug output (implies -f)\n"
+ 	       "    -f                     foreground operation\n"
+-	       "    -s                     disable multi-threaded operation\n"
+-	       "    -o clone_fd            use separate fuse device fd for each thread\n"
+-	       "                           (may improve performance)\n"
+ 	       "    -o max_idle_threads    the maximum number of idle worker threads\n"
+ 	       "                           allowed (default: 10)\n");
+ }
+@@ -171,34 +164,6 @@ static int fuse_helper_opt_proc(void *data, const char *arg, int key,
+ 	}
+ }
+ 
+-/* Under FreeBSD, there is no subtype option so this
+-   function actually sets the fsname */
+-static int add_default_subtype(const char *progname, struct fuse_args *args)
+-{
+-	int res;
+-	char *subtype_opt;
+-
+-	const char *basename = strrchr(progname, '/');
+-	if (basename == NULL)
+-		basename = progname;
+-	else if (basename[1] != '\0')
+-		basename++;
+-
+-	subtype_opt = (char *) malloc(strlen(basename) + 64);
+-	if (subtype_opt == NULL) {
+-		fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
+-		return -1;
+-	}
+-#ifdef __FreeBSD__
+-	sprintf(subtype_opt, "-ofsname=%s", basename);
+-#else
+-	sprintf(subtype_opt, "-osubtype=%s", basename);
+-#endif
+-	res = fuse_opt_add_arg(args, subtype_opt);
+-	free(subtype_opt);
+-	return res;
+-}
+-
+ int fuse_parse_cmdline(struct fuse_args *args,
+ 		       struct fuse_cmdline_opts *opts)
+ {
+@@ -210,14 +175,6 @@ int fuse_parse_cmdline(struct fuse_args *args,
+ 			   fuse_helper_opt_proc) == -1)
+ 		return -1;
+ 
+-	/* *Linux*: if neither -o subtype nor -o fsname are specified,
+-	   set subtype to program's basename.
+-	   *FreeBSD*: if fsname is not specified, set to program's
+-	   basename. */
+-	if (!opts->nodefault_subtype)
+-		if (add_default_subtype(args->argv[0], args) == -1)
+-			return -1;
+-
+ 	return 0;
+ }
+ 
+@@ -276,88 +233,6 @@ int fuse_daemonize(int foreground)
+ 	return 0;
+ }
+ 
+-int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
+-		   size_t op_size, void *user_data)
+-{
+-	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+-	struct fuse *fuse;
+-	struct fuse_cmdline_opts opts;
+-	int res;
+-
+-	if (fuse_parse_cmdline(&args, &opts) != 0)
+-		return 1;
+-
+-	if (opts.show_version) {
+-		printf("FUSE library version %s\n", PACKAGE_VERSION);
+-		fuse_lowlevel_version();
+-		res = 0;
+-		goto out1;
+-	}
+-
+-	if (opts.show_help) {
+-		if(args.argv[0][0] != '\0')
+-			printf("usage: %s [options] <mountpoint>\n\n",
+-			       args.argv[0]);
+-		printf("FUSE options:\n");
+-		fuse_cmdline_help();
+-		fuse_lib_help(&args);
+-		res = 0;
+-		goto out1;
+-	}
+-
+-	if (!opts.show_help &&
+-	    !opts.mountpoint) {
+-		fuse_log(FUSE_LOG_ERR, "error: no mountpoint specified\n");
+-		res = 2;
+-		goto out1;
+-	}
+-
+-
+-	fuse = fuse_new_31(&args, op, op_size, user_data);
+-	if (fuse == NULL) {
+-		res = 3;
+-		goto out1;
+-	}
+-
+-	if (fuse_mount(fuse,opts.mountpoint) != 0) {
+-		res = 4;
+-		goto out2;
+-	}
+-
+-	if (fuse_daemonize(opts.foreground) != 0) {
+-		res = 5;
+-		goto out3;
+-	}
+-
+-	struct fuse_session *se = fuse_get_session(fuse);
+-	if (fuse_set_signal_handlers(se) != 0) {
+-		res = 6;
+-		goto out3;
+-	}
+-
+-	if (opts.singlethread)
+-		res = fuse_loop(fuse);
+-	else {
+-		struct fuse_loop_config loop_config;
+-		loop_config.clone_fd = opts.clone_fd;
+-		loop_config.max_idle_threads = opts.max_idle_threads;
+-		res = fuse_loop_mt_32(fuse, &loop_config);
+-	}
+-	if (res)
+-		res = 7;
+-
+-	fuse_remove_signal_handlers(se);
+-out3:
+-	fuse_unmount(fuse);
+-out2:
+-	fuse_destroy(fuse);
+-out1:
+-	free(opts.mountpoint);
+-	fuse_opt_free_args(&args);
+-	return res;
+-}
+-
+-
+ void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts,
+ 			       struct fuse_conn_info *conn)
+ {
+@@ -420,21 +295,3 @@ struct fuse_conn_info_opts* fuse_parse_conn_info_opts(struct fuse_args *args)
+ 	}
+ 	return opts;
+ }
+-
+-int fuse_open_channel(const char *mountpoint, const char* options)
+-{
+-	struct mount_opts *opts = NULL;
+-	int fd = -1;
+-	const char *argv[] = { "", "-o", options };
+-	int argc = sizeof(argv) / sizeof(argv[0]);
+-	struct fuse_args args = FUSE_ARGS_INIT(argc, (char**) argv);
+-
+-	opts = parse_mount_opts(&args);
+-	if (opts == NULL)
+-		return -1;
+-
+-	fd = fuse_kern_mount(mountpoint, opts);
+-	destroy_mount_opts(opts);
+-
+-	return fd;
+-}
+diff --git a/tools/virtiofsd/passthrough_helpers.h b/tools/virtiofsd/passthrough_helpers.h
+index 6b77c33600..7c5f561fbc 100644
+--- a/tools/virtiofsd/passthrough_helpers.h
++++ b/tools/virtiofsd/passthrough_helpers.h
+@@ -42,32 +42,6 @@ static int mknod_wrapper(int dirfd, const char *path, const char *link,
+ 		res = symlinkat(link, dirfd, path);
+ 	} else if (S_ISFIFO(mode)) {
+ 		res = mkfifoat(dirfd, path, mode);
+-#ifdef __FreeBSD__
+-	} else if (S_ISSOCK(mode)) {
+-		struct sockaddr_un su;
+-		int fd;
+-
+-		if (strlen(path) >= sizeof(su.sun_path)) {
+-			errno = ENAMETOOLONG;
+-			return -1;
+-		}
+-		fd = socket(AF_UNIX, SOCK_STREAM, 0);
+-		if (fd >= 0) {
+-			/*
+-			 * We must bind the socket to the underlying file
+-			 * system to create the socket file, even though
+-			 * we'll never listen on this socket.
+-			 */
+-			su.sun_family = AF_UNIX;
+-			strncpy(su.sun_path, path, sizeof(su.sun_path));
+-			res = bindat(dirfd, fd, (struct sockaddr*)&su,
+-				sizeof(su));
+-			if (res == 0)
+-				close(fd);
+-		} else {
+-			res = -1;
+-		}
+-#endif
+ 	} else {
+ 		res = mknodat(dirfd, path, mode, rdev);
+ 	}
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index e1a605691a..e5f7115bc1 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -1240,7 +1240,6 @@ int main(int argc, char *argv[])
+ 		ret = 0;
+ 		goto err_out1;
+ 	} else if (opts.show_version) {
+-		printf("FUSE library version %s\n", fuse_pkgversion());
+ 		fuse_lowlevel_version();
+ 		ret = 0;
+ 		goto err_out1;
diff --git a/0016-virtiofsd-Format-imported-files-to-qemu-style.patch b/0016-virtiofsd-Format-imported-files-to-qemu-style.patch
new file mode 100644
index 0000000..e050d14
--- /dev/null
+++ b/0016-virtiofsd-Format-imported-files-to-qemu-style.patch
@@ -0,0 +1,14727 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:45 +0000
+Subject: [PATCH] virtiofsd: Format imported files to qemu style
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Mostly using a set like:
+
+indent -nut -i 4 -nlp -br -cs -ce --no-space-after-function-call-names file
+clang-format -style=file -i -- file
+clang-tidy -fix-errors -checks=readability-braces-around-statements file
+clang-format -style=file -i -- file
+
+With manual cleanups.
+
+The .clang-format used is below.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Reviewed by: Aleksandar Markovic <amarkovic@wavecomp.com>
+
+Language:        Cpp
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false # although we like it, it creates churn
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlinesLeft: true
+AlignOperands:   true
+AlignTrailingComments: false # churn
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterReturnType: None # AlwaysBreakAfterDefinitionReturnType is taken into account
+AlwaysBreakBeforeMultilineStrings: false
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+  AfterControlStatement: false
+  AfterEnum:       false
+  AfterFunction:   true
+  AfterStruct:     false
+  AfterUnion:      false
+  BeforeElse:      false
+  IndentBraces:    false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: false
+BreakStringLiterals: true
+ColumnLimit:     80
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: false
+DerivePointerAlignment: false
+DisableFormat:   false
+ForEachMacros:   [
+  'CPU_FOREACH',
+  'CPU_FOREACH_REVERSE',
+  'CPU_FOREACH_SAFE',
+  'IOMMU_NOTIFIER_FOREACH',
+  'QLIST_FOREACH',
+  'QLIST_FOREACH_ENTRY',
+  'QLIST_FOREACH_RCU',
+  'QLIST_FOREACH_SAFE',
+  'QLIST_FOREACH_SAFE_RCU',
+  'QSIMPLEQ_FOREACH',
+  'QSIMPLEQ_FOREACH_SAFE',
+  'QSLIST_FOREACH',
+  'QSLIST_FOREACH_SAFE',
+  'QTAILQ_FOREACH',
+  'QTAILQ_FOREACH_REVERSE',
+  'QTAILQ_FOREACH_SAFE',
+  'QTAILQ_RAW_FOREACH',
+  'RAMBLOCK_FOREACH'
+]
+IncludeCategories:
+  - Regex:           '^"qemu/osdep.h'
+    Priority:        -3
+  - Regex:           '^"(block|chardev|crypto|disas|exec|fpu|hw|io|libdecnumber|migration|monitor|net|qapi|qemu|qom|standard-headers|sysemu|ui)/'
+    Priority:        -2
+  - Regex:           '^"(elf.h|qemu-common.h|glib-compat.h|qemu-io.h|trace-tcg.h)'
+    Priority:        -1
+  - Regex:           '.*'
+    Priority:        1
+IncludeIsMainRegex: '$'
+IndentCaseLabels: false
+IndentWidth:     4
+IndentWrappedFunctionNames: false
+KeepEmptyLinesAtTheStartOfBlocks: false
+MacroBlockBegin: '.*_BEGIN$' # only PREC_BEGIN ?
+MacroBlockEnd:   '.*_END$'
+MaxEmptyLinesToKeep: 2
+PointerAlignment: Right
+ReflowComments:  true
+SortIncludes:    true
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInContainerLiterals: true
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard:        Auto
+UseTab:          Never
+...
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 7387863d033e8028aa09a815736617a7c4490827)
+---
+ tools/virtiofsd/buffer.c              |  434 +--
+ tools/virtiofsd/fuse.h                | 1572 +++++------
+ tools/virtiofsd/fuse_common.h         |  730 ++---
+ tools/virtiofsd/fuse_i.h              |  121 +-
+ tools/virtiofsd/fuse_log.c            |   38 +-
+ tools/virtiofsd/fuse_log.h            |   32 +-
+ tools/virtiofsd/fuse_lowlevel.c       | 3638 +++++++++++++------------
+ tools/virtiofsd/fuse_lowlevel.h       | 2392 ++++++++--------
+ tools/virtiofsd/fuse_misc.h           |   30 +-
+ tools/virtiofsd/fuse_opt.c            |  659 ++---
+ tools/virtiofsd/fuse_opt.h            |   79 +-
+ tools/virtiofsd/fuse_signals.c        |  118 +-
+ tools/virtiofsd/helper.c              |  506 ++--
+ tools/virtiofsd/passthrough_helpers.h |   33 +-
+ tools/virtiofsd/passthrough_ll.c      | 2061 +++++++-------
+ 15 files changed, 6382 insertions(+), 6061 deletions(-)
+
+diff --git a/tools/virtiofsd/buffer.c b/tools/virtiofsd/buffer.c
+index aefb7dbf15..5df946c82c 100644
+--- a/tools/virtiofsd/buffer.c
++++ b/tools/virtiofsd/buffer.c
+@@ -1,252 +1,272 @@
+ /*
+-  FUSE: Filesystem in Userspace
+-  Copyright (C) 2010  Miklos Szeredi <miklos@szeredi.hu>
+-
+-  Functions for dealing with `struct fuse_buf` and `struct
+-  fuse_bufvec`.
+-
+-  This program can be distributed under the terms of the GNU LGPLv2.
+-  See the file COPYING.LIB
+-*/
++ * FUSE: Filesystem in Userspace
++ * Copyright (C) 2010  Miklos Szeredi <miklos@szeredi.hu>
++ *
++ * Functions for dealing with `struct fuse_buf` and `struct
++ * fuse_bufvec`.
++ *
++ * This program can be distributed under the terms of the GNU LGPLv2.
++ * See the file COPYING.LIB
++ */
+ 
+ #define _GNU_SOURCE
+ 
+ #include "config.h"
+ #include "fuse_i.h"
+ #include "fuse_lowlevel.h"
++#include <assert.h>
++#include <errno.h>
+ #include <string.h>
+ #include <unistd.h>
+-#include <errno.h>
+-#include <assert.h>
+ 
+ size_t fuse_buf_size(const struct fuse_bufvec *bufv)
+ {
+-	size_t i;
+-	size_t size = 0;
+-
+-	for (i = 0; i < bufv->count; i++) {
+-		if (bufv->buf[i].size == SIZE_MAX)
+-			size = SIZE_MAX;
+-		else
+-			size += bufv->buf[i].size;
+-	}
+-
+-	return size;
++    size_t i;
++    size_t size = 0;
++
++    for (i = 0; i < bufv->count; i++) {
++        if (bufv->buf[i].size == SIZE_MAX) {
++            size = SIZE_MAX;
++        } else {
++            size += bufv->buf[i].size;
++        }
++    }
++
++    return size;
+ }
+ 
+ static size_t min_size(size_t s1, size_t s2)
+ {
+-	return s1 < s2 ? s1 : s2;
++    return s1 < s2 ? s1 : s2;
+ }
+ 
+ static ssize_t fuse_buf_write(const struct fuse_buf *dst, size_t dst_off,
+-			      const struct fuse_buf *src, size_t src_off,
+-			      size_t len)
++                              const struct fuse_buf *src, size_t src_off,
++                              size_t len)
+ {
+-	ssize_t res = 0;
+-	size_t copied = 0;
+-
+-	while (len) {
+-		if (dst->flags & FUSE_BUF_FD_SEEK) {
+-			res = pwrite(dst->fd, (char *)src->mem + src_off, len,
+-				     dst->pos + dst_off);
+-		} else {
+-			res = write(dst->fd, (char *)src->mem + src_off, len);
+-		}
+-		if (res == -1) {
+-			if (!copied)
+-				return -errno;
+-			break;
+-		}
+-		if (res == 0)
+-			break;
+-
+-		copied += res;
+-		if (!(dst->flags & FUSE_BUF_FD_RETRY))
+-			break;
+-
+-		src_off += res;
+-		dst_off += res;
+-		len -= res;
+-	}
+-
+-	return copied;
++    ssize_t res = 0;
++    size_t copied = 0;
++
++    while (len) {
++        if (dst->flags & FUSE_BUF_FD_SEEK) {
++            res = pwrite(dst->fd, (char *)src->mem + src_off, len,
++                         dst->pos + dst_off);
++        } else {
++            res = write(dst->fd, (char *)src->mem + src_off, len);
++        }
++        if (res == -1) {
++            if (!copied) {
++                return -errno;
++            }
++            break;
++        }
++        if (res == 0) {
++            break;
++        }
++
++        copied += res;
++        if (!(dst->flags & FUSE_BUF_FD_RETRY)) {
++            break;
++        }
++
++        src_off += res;
++        dst_off += res;
++        len -= res;
++    }
++
++    return copied;
+ }
+ 
+ static ssize_t fuse_buf_read(const struct fuse_buf *dst, size_t dst_off,
+-			     const struct fuse_buf *src, size_t src_off,
+-			     size_t len)
++                             const struct fuse_buf *src, size_t src_off,
++                             size_t len)
+ {
+-	ssize_t res = 0;
+-	size_t copied = 0;
+-
+-	while (len) {
+-		if (src->flags & FUSE_BUF_FD_SEEK) {
+-			res = pread(src->fd, (char *)dst->mem + dst_off, len,
+-				     src->pos + src_off);
+-		} else {
+-			res = read(src->fd, (char *)dst->mem + dst_off, len);
+-		}
+-		if (res == -1) {
+-			if (!copied)
+-				return -errno;
+-			break;
+-		}
+-		if (res == 0)
+-			break;
+-
+-		copied += res;
+-		if (!(src->flags & FUSE_BUF_FD_RETRY))
+-			break;
+-
+-		dst_off += res;
+-		src_off += res;
+-		len -= res;
+-	}
+-
+-	return copied;
++    ssize_t res = 0;
++    size_t copied = 0;
++
++    while (len) {
++        if (src->flags & FUSE_BUF_FD_SEEK) {
++            res = pread(src->fd, (char *)dst->mem + dst_off, len,
++                        src->pos + src_off);
++        } else {
++            res = read(src->fd, (char *)dst->mem + dst_off, len);
++        }
++        if (res == -1) {
++            if (!copied) {
++                return -errno;
++            }
++            break;
++        }
++        if (res == 0) {
++            break;
++        }
++
++        copied += res;
++        if (!(src->flags & FUSE_BUF_FD_RETRY)) {
++            break;
++        }
++
++        dst_off += res;
++        src_off += res;
++        len -= res;
++    }
++
++    return copied;
+ }
+ 
+ static ssize_t fuse_buf_fd_to_fd(const struct fuse_buf *dst, size_t dst_off,
+-				 const struct fuse_buf *src, size_t src_off,
+-				 size_t len)
++                                 const struct fuse_buf *src, size_t src_off,
++                                 size_t len)
+ {
+-	char buf[4096];
+-	struct fuse_buf tmp = {
+-		.size = sizeof(buf),
+-		.flags = 0,
+-	};
+-	ssize_t res;
+-	size_t copied = 0;
+-
+-	tmp.mem = buf;
+-
+-	while (len) {
+-		size_t this_len = min_size(tmp.size, len);
+-		size_t read_len;
+-
+-		res = fuse_buf_read(&tmp, 0, src, src_off, this_len);
+-		if (res < 0) {
+-			if (!copied)
+-				return res;
+-			break;
+-		}
+-		if (res == 0)
+-			break;
+-
+-		read_len = res;
+-		res = fuse_buf_write(dst, dst_off, &tmp, 0, read_len);
+-		if (res < 0) {
+-			if (!copied)
+-				return res;
+-			break;
+-		}
+-		if (res == 0)
+-			break;
+-
+-		copied += res;
+-
+-		if (res < this_len)
+-			break;
+-
+-		dst_off += res;
+-		src_off += res;
+-		len -= res;
+-	}
+-
+-	return copied;
++    char buf[4096];
++    struct fuse_buf tmp = {
++        .size = sizeof(buf),
++        .flags = 0,
++    };
++    ssize_t res;
++    size_t copied = 0;
++
++    tmp.mem = buf;
++
++    while (len) {
++        size_t this_len = min_size(tmp.size, len);
++        size_t read_len;
++
++        res = fuse_buf_read(&tmp, 0, src, src_off, this_len);
++        if (res < 0) {
++            if (!copied) {
++                return res;
++            }
++            break;
++        }
++        if (res == 0) {
++            break;
++        }
++
++        read_len = res;
++        res = fuse_buf_write(dst, dst_off, &tmp, 0, read_len);
++        if (res < 0) {
++            if (!copied) {
++                return res;
++            }
++            break;
++        }
++        if (res == 0) {
++            break;
++        }
++
++        copied += res;
++
++        if (res < this_len) {
++            break;
++        }
++
++        dst_off += res;
++        src_off += res;
++        len -= res;
++    }
++
++    return copied;
+ }
+ 
+ static ssize_t fuse_buf_copy_one(const struct fuse_buf *dst, size_t dst_off,
+-				 const struct fuse_buf *src, size_t src_off,
+-				 size_t len, enum fuse_buf_copy_flags flags)
++                                 const struct fuse_buf *src, size_t src_off,
++                                 size_t len, enum fuse_buf_copy_flags flags)
+ {
+-	int src_is_fd = src->flags & FUSE_BUF_IS_FD;
+-	int dst_is_fd = dst->flags & FUSE_BUF_IS_FD;
+-
+-	if (!src_is_fd && !dst_is_fd) {
+-		char *dstmem = (char *)dst->mem + dst_off;
+-		char *srcmem = (char *)src->mem + src_off;
+-
+-		if (dstmem != srcmem) {
+-			if (dstmem + len <= srcmem || srcmem + len <= dstmem)
+-				memcpy(dstmem, srcmem, len);
+-			else
+-				memmove(dstmem, srcmem, len);
+-		}
+-
+-		return len;
+-	} else if (!src_is_fd) {
+-		return fuse_buf_write(dst, dst_off, src, src_off, len);
+-	} else if (!dst_is_fd) {
+-		return fuse_buf_read(dst, dst_off, src, src_off, len);
+-	} else {
+-		return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
+-	}
++    int src_is_fd = src->flags & FUSE_BUF_IS_FD;
++    int dst_is_fd = dst->flags & FUSE_BUF_IS_FD;
++
++    if (!src_is_fd && !dst_is_fd) {
++        char *dstmem = (char *)dst->mem + dst_off;
++        char *srcmem = (char *)src->mem + src_off;
++
++        if (dstmem != srcmem) {
++            if (dstmem + len <= srcmem || srcmem + len <= dstmem) {
++                memcpy(dstmem, srcmem, len);
++            } else {
++                memmove(dstmem, srcmem, len);
++            }
++        }
++
++        return len;
++    } else if (!src_is_fd) {
++        return fuse_buf_write(dst, dst_off, src, src_off, len);
++    } else if (!dst_is_fd) {
++        return fuse_buf_read(dst, dst_off, src, src_off, len);
++    } else {
++        return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
++    }
+ }
+ 
+ static const struct fuse_buf *fuse_bufvec_current(struct fuse_bufvec *bufv)
+ {
+-	if (bufv->idx < bufv->count)
+-		return &bufv->buf[bufv->idx];
+-	else
+-		return NULL;
++    if (bufv->idx < bufv->count) {
++        return &bufv->buf[bufv->idx];
++    } else {
++        return NULL;
++    }
+ }
+ 
+ static int fuse_bufvec_advance(struct fuse_bufvec *bufv, size_t len)
+ {
+-	const struct fuse_buf *buf = fuse_bufvec_current(bufv);
+-
+-	bufv->off += len;
+-	assert(bufv->off <= buf->size);
+-	if (bufv->off == buf->size) {
+-		assert(bufv->idx < bufv->count);
+-		bufv->idx++;
+-		if (bufv->idx == bufv->count)
+-			return 0;
+-		bufv->off = 0;
+-	}
+-	return 1;
++    const struct fuse_buf *buf = fuse_bufvec_current(bufv);
++
++    bufv->off += len;
++    assert(bufv->off <= buf->size);
++    if (bufv->off == buf->size) {
++        assert(bufv->idx < bufv->count);
++        bufv->idx++;
++        if (bufv->idx == bufv->count) {
++            return 0;
++        }
++        bufv->off = 0;
++    }
++    return 1;
+ }
+ 
+ ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv,
+-		      enum fuse_buf_copy_flags flags)
++                      enum fuse_buf_copy_flags flags)
+ {
+-	size_t copied = 0;
+-
+-	if (dstv == srcv)
+-		return fuse_buf_size(dstv);
+-
+-	for (;;) {
+-		const struct fuse_buf *src = fuse_bufvec_current(srcv);
+-		const struct fuse_buf *dst = fuse_bufvec_current(dstv);
+-		size_t src_len;
+-		size_t dst_len;
+-		size_t len;
+-		ssize_t res;
+-
+-		if (src == NULL || dst == NULL)
+-			break;
+-
+-		src_len = src->size - srcv->off;
+-		dst_len = dst->size - dstv->off;
+-		len = min_size(src_len, dst_len);
+-
+-		res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len, flags);
+-		if (res < 0) {
+-			if (!copied)
+-				return res;
+-			break;
+-		}
+-		copied += res;
+-
+-		if (!fuse_bufvec_advance(srcv, res) ||
+-		    !fuse_bufvec_advance(dstv, res))
+-			break;
+-
+-		if (res < len)
+-			break;
+-	}
+-
+-	return copied;
++    size_t copied = 0;
++
++    if (dstv == srcv) {
++        return fuse_buf_size(dstv);
++    }
++
++    for (;;) {
++        const struct fuse_buf *src = fuse_bufvec_current(srcv);
++        const struct fuse_buf *dst = fuse_bufvec_current(dstv);
++        size_t src_len;
++        size_t dst_len;
++        size_t len;
++        ssize_t res;
++
++        if (src == NULL || dst == NULL) {
++            break;
++        }
++
++        src_len = src->size - srcv->off;
++        dst_len = dst->size - dstv->off;
++        len = min_size(src_len, dst_len);
++
++        res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len, flags);
++        if (res < 0) {
++            if (!copied) {
++                return res;
++            }
++            break;
++        }
++        copied += res;
++
++        if (!fuse_bufvec_advance(srcv, res) ||
++            !fuse_bufvec_advance(dstv, res)) {
++            break;
++        }
++
++        if (res < len) {
++            break;
++        }
++    }
++
++    return copied;
+ }
+diff --git a/tools/virtiofsd/fuse.h b/tools/virtiofsd/fuse.h
+index 3202fba6bb..7a4c713559 100644
+--- a/tools/virtiofsd/fuse.h
++++ b/tools/virtiofsd/fuse.h
+@@ -1,15 +1,15 @@
+ /*
+-  FUSE: Filesystem in Userspace
+-  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+-
+-  This program can be distributed under the terms of the GNU LGPLv2.
+-  See the file COPYING.LIB.
+-*/
++ * FUSE: Filesystem in Userspace
++ * Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++ *
++ * This program can be distributed under the terms of the GNU LGPLv2.
++ * See the file COPYING.LIB.
++ */
+ 
+ #ifndef FUSE_H_
+ #define FUSE_H_
+ 
+-/** @file
++/*
+  *
+  * This file defines the library interface of FUSE
+  *
+@@ -19,15 +19,15 @@
+ #include "fuse_common.h"
+ 
+ #include <fcntl.h>
+-#include <time.h>
+-#include <sys/types.h>
+ #include <sys/stat.h>
+ #include <sys/statvfs.h>
++#include <sys/types.h>
+ #include <sys/uio.h>
++#include <time.h>
+ 
+-/* ----------------------------------------------------------- *
+- * Basic FUSE API					       *
+- * ----------------------------------------------------------- */
++/*
++ * Basic FUSE API
++ */
+ 
+ /** Handle for a FUSE filesystem */
+ struct fuse;
+@@ -36,38 +36,39 @@ struct fuse;
+  * Readdir flags, passed to ->readdir()
+  */
+ enum fuse_readdir_flags {
+-	/**
+-	 * "Plus" mode.
+-	 *
+-	 * The kernel wants to prefill the inode cache during readdir.  The
+-	 * filesystem may honour this by filling in the attributes and setting
+-	 * FUSE_FILL_DIR_FLAGS for the filler function.  The filesystem may also
+-	 * just ignore this flag completely.
+-	 */
+-	FUSE_READDIR_PLUS = (1 << 0),
++    /**
++     * "Plus" mode.
++     *
++     * The kernel wants to prefill the inode cache during readdir.  The
++     * filesystem may honour this by filling in the attributes and setting
++     * FUSE_FILL_DIR_FLAGS for the filler function.  The filesystem may also
++     * just ignore this flag completely.
++     */
++    FUSE_READDIR_PLUS = (1 << 0),
+ };
+ 
+ enum fuse_fill_dir_flags {
+-	/**
+-	 * "Plus" mode: all file attributes are valid
+-	 *
+-	 * The attributes are used by the kernel to prefill the inode cache
+-	 * during a readdir.
+-	 *
+-	 * It is okay to set FUSE_FILL_DIR_PLUS if FUSE_READDIR_PLUS is not set
+-	 * and vice versa.
+-	 */
+-	FUSE_FILL_DIR_PLUS = (1 << 1),
++    /**
++     * "Plus" mode: all file attributes are valid
++     *
++     * The attributes are used by the kernel to prefill the inode cache
++     * during a readdir.
++     *
++     * It is okay to set FUSE_FILL_DIR_PLUS if FUSE_READDIR_PLUS is not set
++     * and vice versa.
++     */
++    FUSE_FILL_DIR_PLUS = (1 << 1),
+ };
+ 
+-/** Function to add an entry in a readdir() operation
++/**
++ * Function to add an entry in a readdir() operation
+  *
+  * The *off* parameter can be any non-zero value that enables the
+  * filesystem to identify the current point in the directory
+  * stream. It does not need to be the actual physical position. A
+  * value of zero is reserved to indicate that seeking in directories
+  * is not supported.
+- * 
++ *
+  * @param buf the buffer passed to the readdir() operation
+  * @param name the file name of the directory entry
+  * @param stat file attributes, can be NULL
+@@ -75,9 +76,9 @@ enum fuse_fill_dir_flags {
+  * @param flags fill flags
+  * @return 1 if buffer is full, zero otherwise
+  */
+-typedef int (*fuse_fill_dir_t) (void *buf, const char *name,
+-				const struct stat *stbuf, off_t off,
+-				enum fuse_fill_dir_flags flags);
++typedef int (*fuse_fill_dir_t)(void *buf, const char *name,
++                               const struct stat *stbuf, off_t off,
++                               enum fuse_fill_dir_flags flags);
+ /**
+  * Configuration of the high-level API
+  *
+@@ -87,186 +88,186 @@ typedef int (*fuse_fill_dir_t) (void *buf, const char *name,
+  * file system implementation.
+  */
+ struct fuse_config {
+-	/**
+-	 * If `set_gid` is non-zero, the st_gid attribute of each file
+-	 * is overwritten with the value of `gid`.
+-	 */
+-	int set_gid;
+-	unsigned int gid;
+-
+-	/**
+-	 * If `set_uid` is non-zero, the st_uid attribute of each file
+-	 * is overwritten with the value of `uid`.
+-	 */
+-	int set_uid;
+-	unsigned int uid;
+-
+-	/**
+-	 * If `set_mode` is non-zero, the any permissions bits set in
+-	 * `umask` are unset in the st_mode attribute of each file.
+-	 */
+-	int set_mode;
+-	unsigned int umask;
+-
+-	/**
+-	 * The timeout in seconds for which name lookups will be
+-	 * cached.
+-	 */
+-	double entry_timeout;
+-
+-	/**
+-	 * The timeout in seconds for which a negative lookup will be
+-	 * cached. This means, that if file did not exist (lookup
+-	 * retuned ENOENT), the lookup will only be redone after the
+-	 * timeout, and the file/directory will be assumed to not
+-	 * exist until then. A value of zero means that negative
+-	 * lookups are not cached.
+-	 */
+-	double negative_timeout;
+-
+-	/**
+-	 * The timeout in seconds for which file/directory attributes
+-	 * (as returned by e.g. the `getattr` handler) are cached.
+-	 */
+-	double attr_timeout;
+-
+-	/**
+-	 * Allow requests to be interrupted
+-	 */
+-	int intr;
+-
+-	/**
+-	 * Specify which signal number to send to the filesystem when
+-	 * a request is interrupted.  The default is hardcoded to
+-	 * USR1.
+-	 */
+-	int intr_signal;
+-
+-	/**
+-	 * Normally, FUSE assigns inodes to paths only for as long as
+-	 * the kernel is aware of them. With this option inodes are
+-	 * instead remembered for at least this many seconds.  This
+-	 * will require more memory, but may be necessary when using
+-	 * applications that make use of inode numbers.
+-	 *
+-	 * A number of -1 means that inodes will be remembered for the
+-	 * entire life-time of the file-system process.
+-	 */
+-	int remember;
+-
+-	/**
+-	 * The default behavior is that if an open file is deleted,
+-	 * the file is renamed to a hidden file (.fuse_hiddenXXX), and
+-	 * only removed when the file is finally released.  This
+-	 * relieves the filesystem implementation of having to deal
+-	 * with this problem. This option disables the hiding
+-	 * behavior, and files are removed immediately in an unlink
+-	 * operation (or in a rename operation which overwrites an
+-	 * existing file).
+-	 *
+-	 * It is recommended that you not use the hard_remove
+-	 * option. When hard_remove is set, the following libc
+-	 * functions fail on unlinked files (returning errno of
+-	 * ENOENT): read(2), write(2), fsync(2), close(2), f*xattr(2),
+-	 * ftruncate(2), fstat(2), fchmod(2), fchown(2)
+-	 */
+-	int hard_remove;
+-
+-	/**
+-	 * Honor the st_ino field in the functions getattr() and
+-	 * fill_dir(). This value is used to fill in the st_ino field
+-	 * in the stat(2), lstat(2), fstat(2) functions and the d_ino
+-	 * field in the readdir(2) function. The filesystem does not
+-	 * have to guarantee uniqueness, however some applications
+-	 * rely on this value being unique for the whole filesystem.
+-	 *
+-	 * Note that this does *not* affect the inode that libfuse 
+-	 * and the kernel use internally (also called the "nodeid").
+-	 */
+-	int use_ino;
+-
+-	/**
+-	 * If use_ino option is not given, still try to fill in the
+-	 * d_ino field in readdir(2). If the name was previously
+-	 * looked up, and is still in the cache, the inode number
+-	 * found there will be used.  Otherwise it will be set to -1.
+-	 * If use_ino option is given, this option is ignored.
+-	 */
+-	int readdir_ino;
+-
+-	/**
+-	 * This option disables the use of page cache (file content cache)
+-	 * in the kernel for this filesystem. This has several affects:
+-	 *
+-	 * 1. Each read(2) or write(2) system call will initiate one
+-	 *    or more read or write operations, data will not be
+-	 *    cached in the kernel.
+-	 *
+-	 * 2. The return value of the read() and write() system calls
+-	 *    will correspond to the return values of the read and
+-	 *    write operations. This is useful for example if the
+-	 *    file size is not known in advance (before reading it).
+-	 *
+-	 * Internally, enabling this option causes fuse to set the
+-	 * `direct_io` field of `struct fuse_file_info` - overwriting
+-	 * any value that was put there by the file system.
+-	 */
+-	int direct_io;
+-
+-	/**
+-	 * This option disables flushing the cache of the file
+-	 * contents on every open(2).  This should only be enabled on
+-	 * filesystems where the file data is never changed
+-	 * externally (not through the mounted FUSE filesystem).  Thus
+-	 * it is not suitable for network filesystems and other
+-	 * intermediate filesystems.
+-	 *
+-	 * NOTE: if this option is not specified (and neither
+-	 * direct_io) data is still cached after the open(2), so a
+-	 * read(2) system call will not always initiate a read
+-	 * operation.
+-	 *
+-	 * Internally, enabling this option causes fuse to set the
+-	 * `keep_cache` field of `struct fuse_file_info` - overwriting
+-	 * any value that was put there by the file system.
+-	 */
+-	int kernel_cache;
+-
+-	/**
+-	 * This option is an alternative to `kernel_cache`. Instead of
+-	 * unconditionally keeping cached data, the cached data is
+-	 * invalidated on open(2) if if the modification time or the
+-	 * size of the file has changed since it was last opened.
+-	 */
+-	int auto_cache;
+-
+-	/**
+-	 * The timeout in seconds for which file attributes are cached
+-	 * for the purpose of checking if auto_cache should flush the
+-	 * file data on open.
+-	 */
+-	int ac_attr_timeout_set;
+-	double ac_attr_timeout;
+-
+-	/**
+-	 * If this option is given the file-system handlers for the
+-	 * following operations will not receive path information:
+-	 * read, write, flush, release, fsync, readdir, releasedir,
+-	 * fsyncdir, lock, ioctl and poll.
+-	 *
+-	 * For the truncate, getattr, chmod, chown and utimens
+-	 * operations the path will be provided only if the struct
+-	 * fuse_file_info argument is NULL.
+-	 */
+-	int nullpath_ok;
+-
+-	/**
+-	 * The remaining options are used by libfuse internally and
+-	 * should not be touched.
+-	 */
+-	int show_help;
+-	char *modules;
+-	int debug;
++    /**
++     * If `set_gid` is non-zero, the st_gid attribute of each file
++     * is overwritten with the value of `gid`.
++     */
++    int set_gid;
++    unsigned int gid;
++
++    /**
++     * If `set_uid` is non-zero, the st_uid attribute of each file
++     * is overwritten with the value of `uid`.
++     */
++    int set_uid;
++    unsigned int uid;
++
++    /**
++     * If `set_mode` is non-zero, the any permissions bits set in
++     * `umask` are unset in the st_mode attribute of each file.
++     */
++    int set_mode;
++    unsigned int umask;
++
++    /**
++     * The timeout in seconds for which name lookups will be
++     * cached.
++     */
++    double entry_timeout;
++
++    /**
++     * The timeout in seconds for which a negative lookup will be
++     * cached. This means, that if file did not exist (lookup
++     * retuned ENOENT), the lookup will only be redone after the
++     * timeout, and the file/directory will be assumed to not
++     * exist until then. A value of zero means that negative
++     * lookups are not cached.
++     */
++    double negative_timeout;
++
++    /**
++     * The timeout in seconds for which file/directory attributes
++     * (as returned by e.g. the `getattr` handler) are cached.
++     */
++    double attr_timeout;
++
++    /**
++     * Allow requests to be interrupted
++     */
++    int intr;
++
++    /**
++     * Specify which signal number to send to the filesystem when
++     * a request is interrupted.  The default is hardcoded to
++     * USR1.
++     */
++    int intr_signal;
++
++    /**
++     * Normally, FUSE assigns inodes to paths only for as long as
++     * the kernel is aware of them. With this option inodes are
++     * instead remembered for at least this many seconds.  This
++     * will require more memory, but may be necessary when using
++     * applications that make use of inode numbers.
++     *
++     * A number of -1 means that inodes will be remembered for the
++     * entire life-time of the file-system process.
++     */
++    int remember;
++
++    /**
++     * The default behavior is that if an open file is deleted,
++     * the file is renamed to a hidden file (.fuse_hiddenXXX), and
++     * only removed when the file is finally released.  This
++     * relieves the filesystem implementation of having to deal
++     * with this problem. This option disables the hiding
++     * behavior, and files are removed immediately in an unlink
++     * operation (or in a rename operation which overwrites an
++     * existing file).
++     *
++     * It is recommended that you not use the hard_remove
++     * option. When hard_remove is set, the following libc
++     * functions fail on unlinked files (returning errno of
++     * ENOENT): read(2), write(2), fsync(2), close(2), f*xattr(2),
++     * ftruncate(2), fstat(2), fchmod(2), fchown(2)
++     */
++    int hard_remove;
++
++    /**
++     * Honor the st_ino field in the functions getattr() and
++     * fill_dir(). This value is used to fill in the st_ino field
++     * in the stat(2), lstat(2), fstat(2) functions and the d_ino
++     * field in the readdir(2) function. The filesystem does not
++     * have to guarantee uniqueness, however some applications
++     * rely on this value being unique for the whole filesystem.
++     *
++     * Note that this does *not* affect the inode that libfuse
++     * and the kernel use internally (also called the "nodeid").
++     */
++    int use_ino;
++
++    /**
++     * If use_ino option is not given, still try to fill in the
++     * d_ino field in readdir(2). If the name was previously
++     * looked up, and is still in the cache, the inode number
++     * found there will be used.  Otherwise it will be set to -1.
++     * If use_ino option is given, this option is ignored.
++     */
++    int readdir_ino;
++
++    /**
++     * This option disables the use of page cache (file content cache)
++     * in the kernel for this filesystem. This has several affects:
++     *
++     * 1. Each read(2) or write(2) system call will initiate one
++     *    or more read or write operations, data will not be
++     *    cached in the kernel.
++     *
++     * 2. The return value of the read() and write() system calls
++     *    will correspond to the return values of the read and
++     *    write operations. This is useful for example if the
++     *    file size is not known in advance (before reading it).
++     *
++     * Internally, enabling this option causes fuse to set the
++     * `direct_io` field of `struct fuse_file_info` - overwriting
++     * any value that was put there by the file system.
++     */
++    int direct_io;
++
++    /**
++     * This option disables flushing the cache of the file
++     * contents on every open(2).  This should only be enabled on
++     * filesystems where the file data is never changed
++     * externally (not through the mounted FUSE filesystem).  Thus
++     * it is not suitable for network filesystems and other
++     * intermediate filesystems.
++     *
++     * NOTE: if this option is not specified (and neither
++     * direct_io) data is still cached after the open(2), so a
++     * read(2) system call will not always initiate a read
++     * operation.
++     *
++     * Internally, enabling this option causes fuse to set the
++     * `keep_cache` field of `struct fuse_file_info` - overwriting
++     * any value that was put there by the file system.
++     */
++    int kernel_cache;
++
++    /**
++     * This option is an alternative to `kernel_cache`. Instead of
++     * unconditionally keeping cached data, the cached data is
++     * invalidated on open(2) if if the modification time or the
++     * size of the file has changed since it was last opened.
++     */
++    int auto_cache;
++
++    /**
++     * The timeout in seconds for which file attributes are cached
++     * for the purpose of checking if auto_cache should flush the
++     * file data on open.
++     */
++    int ac_attr_timeout_set;
++    double ac_attr_timeout;
++
++    /**
++     * If this option is given the file-system handlers for the
++     * following operations will not receive path information:
++     * read, write, flush, release, fsync, readdir, releasedir,
++     * fsyncdir, lock, ioctl and poll.
++     *
++     * For the truncate, getattr, chmod, chown and utimens
++     * operations the path will be provided only if the struct
++     * fuse_file_info argument is NULL.
++     */
++    int nullpath_ok;
++
++    /**
++     * The remaining options are used by libfuse internally and
++     * should not be touched.
++     */
++    int show_help;
++    char *modules;
++    int debug;
+ };
+ 
+ 
+@@ -293,515 +294,535 @@ struct fuse_config {
+  * Almost all operations take a path which can be of any length.
+  */
+ struct fuse_operations {
+-	/** Get file attributes.
+-	 *
+-	 * Similar to stat().  The 'st_dev' and 'st_blksize' fields are
+-	 * ignored. The 'st_ino' field is ignored except if the 'use_ino'
+-	 * mount option is given. In that case it is passed to userspace,
+-	 * but libfuse and the kernel will still assign a different
+-	 * inode for internal use (called the "nodeid").
+-	 *
+-	 * `fi` will always be NULL if the file is not currently open, but
+-	 * may also be NULL if the file is open.
+-	 */
+-	int (*getattr) (const char *, struct stat *, struct fuse_file_info *fi);
+-
+-	/** Read the target of a symbolic link
+-	 *
+-	 * The buffer should be filled with a null terminated string.  The
+-	 * buffer size argument includes the space for the terminating
+-	 * null character.	If the linkname is too long to fit in the
+-	 * buffer, it should be truncated.	The return value should be 0
+-	 * for success.
+-	 */
+-	int (*readlink) (const char *, char *, size_t);
+-
+-	/** Create a file node
+-	 *
+-	 * This is called for creation of all non-directory, non-symlink
+-	 * nodes.  If the filesystem defines a create() method, then for
+-	 * regular files that will be called instead.
+-	 */
+-	int (*mknod) (const char *, mode_t, dev_t);
+-
+-	/** Create a directory
+-	 *
+-	 * Note that the mode argument may not have the type specification
+-	 * bits set, i.e. S_ISDIR(mode) can be false.  To obtain the
+-	 * correct directory type bits use  mode|S_IFDIR
+-	 * */
+-	int (*mkdir) (const char *, mode_t);
+-
+-	/** Remove a file */
+-	int (*unlink) (const char *);
+-
+-	/** Remove a directory */
+-	int (*rmdir) (const char *);
+-
+-	/** Create a symbolic link */
+-	int (*symlink) (const char *, const char *);
+-
+-	/** Rename a file
+-	 *
+-	 * *flags* may be `RENAME_EXCHANGE` or `RENAME_NOREPLACE`. If
+-	 * RENAME_NOREPLACE is specified, the filesystem must not
+-	 * overwrite *newname* if it exists and return an error
+-	 * instead. If `RENAME_EXCHANGE` is specified, the filesystem
+-	 * must atomically exchange the two files, i.e. both must
+-	 * exist and neither may be deleted.
+-	 */
+-	int (*rename) (const char *, const char *, unsigned int flags);
+-
+-	/** Create a hard link to a file */
+-	int (*link) (const char *, const char *);
+-
+-	/** Change the permission bits of a file
+-	 *
+-	 * `fi` will always be NULL if the file is not currenlty open, but
+-	 * may also be NULL if the file is open.
+-	 */
+-	int (*chmod) (const char *, mode_t, struct fuse_file_info *fi);
+-
+-	/** Change the owner and group of a file
+-	 *
+-	 * `fi` will always be NULL if the file is not currenlty open, but
+-	 * may also be NULL if the file is open.
+-	 *
+-	 * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
+-	 * expected to reset the setuid and setgid bits.
+-	 */
+-	int (*chown) (const char *, uid_t, gid_t, struct fuse_file_info *fi);
+-
+-	/** Change the size of a file
+-	 *
+-	 * `fi` will always be NULL if the file is not currenlty open, but
+-	 * may also be NULL if the file is open.
+-	 *
+-	 * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
+-	 * expected to reset the setuid and setgid bits.
+-	 */
+-	int (*truncate) (const char *, off_t, struct fuse_file_info *fi);
+-
+-	/** Open a file
+-	 *
+-	 * Open flags are available in fi->flags. The following rules
+-	 * apply.
+-	 *
+-	 *  - Creation (O_CREAT, O_EXCL, O_NOCTTY) flags will be
+-	 *    filtered out / handled by the kernel.
+-	 *
+-	 *  - Access modes (O_RDONLY, O_WRONLY, O_RDWR, O_EXEC, O_SEARCH)
+-	 *    should be used by the filesystem to check if the operation is
+-	 *    permitted.  If the ``-o default_permissions`` mount option is
+-	 *    given, this check is already done by the kernel before calling
+-	 *    open() and may thus be omitted by the filesystem.
+-	 *
+-	 *  - When writeback caching is enabled, the kernel may send
+-	 *    read requests even for files opened with O_WRONLY. The
+-	 *    filesystem should be prepared to handle this.
+-	 *
+-	 *  - When writeback caching is disabled, the filesystem is
+-	 *    expected to properly handle the O_APPEND flag and ensure
+-	 *    that each write is appending to the end of the file.
+-	 * 
+-         *  - When writeback caching is enabled, the kernel will
+-	 *    handle O_APPEND. However, unless all changes to the file
+-	 *    come through the kernel this will not work reliably. The
+-	 *    filesystem should thus either ignore the O_APPEND flag
+-	 *    (and let the kernel handle it), or return an error
+-	 *    (indicating that reliably O_APPEND is not available).
+-	 *
+-	 * Filesystem may store an arbitrary file handle (pointer,
+-	 * index, etc) in fi->fh, and use this in other all other file
+-	 * operations (read, write, flush, release, fsync).
+-	 *
+-	 * Filesystem may also implement stateless file I/O and not store
+-	 * anything in fi->fh.
+-	 *
+-	 * There are also some flags (direct_io, keep_cache) which the
+-	 * filesystem may set in fi, to change the way the file is opened.
+-	 * See fuse_file_info structure in <fuse_common.h> for more details.
+-	 *
+-	 * If this request is answered with an error code of ENOSYS
+-	 * and FUSE_CAP_NO_OPEN_SUPPORT is set in
+-	 * `fuse_conn_info.capable`, this is treated as success and
+-	 * future calls to open will also succeed without being send
+-	 * to the filesystem process.
+-	 *
+-	 */
+-	int (*open) (const char *, struct fuse_file_info *);
+-
+-	/** Read data from an open file
+-	 *
+-	 * Read should return exactly the number of bytes requested except
+-	 * on EOF or error, otherwise the rest of the data will be
+-	 * substituted with zeroes.	 An exception to this is when the
+-	 * 'direct_io' mount option is specified, in which case the return
+-	 * value of the read system call will reflect the return value of
+-	 * this operation.
+-	 */
+-	int (*read) (const char *, char *, size_t, off_t,
+-		     struct fuse_file_info *);
+-
+-	/** Write data to an open file
+-	 *
+-	 * Write should return exactly the number of bytes requested
+-	 * except on error.	 An exception to this is when the 'direct_io'
+-	 * mount option is specified (see read operation).
+-	 *
+-	 * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
+-	 * expected to reset the setuid and setgid bits.
+-	 */
+-	int (*write) (const char *, const char *, size_t, off_t,
+-		      struct fuse_file_info *);
+-
+-	/** Get file system statistics
+-	 *
+-	 * The 'f_favail', 'f_fsid' and 'f_flag' fields are ignored
+-	 */
+-	int (*statfs) (const char *, struct statvfs *);
+-
+-	/** Possibly flush cached data
+-	 *
+-	 * BIG NOTE: This is not equivalent to fsync().  It's not a
+-	 * request to sync dirty data.
+-	 *
+-	 * Flush is called on each close() of a file descriptor, as opposed to
+-	 * release which is called on the close of the last file descriptor for
+-	 * a file.  Under Linux, errors returned by flush() will be passed to 
+-	 * userspace as errors from close(), so flush() is a good place to write
+-	 * back any cached dirty data. However, many applications ignore errors 
+-	 * on close(), and on non-Linux systems, close() may succeed even if flush()
+-	 * returns an error. For these reasons, filesystems should not assume
+-	 * that errors returned by flush will ever be noticed or even
+-	 * delivered.
+-	 *
+-	 * NOTE: The flush() method may be called more than once for each
+-	 * open().  This happens if more than one file descriptor refers to an
+-	 * open file handle, e.g. due to dup(), dup2() or fork() calls.  It is
+-	 * not possible to determine if a flush is final, so each flush should
+-	 * be treated equally.  Multiple write-flush sequences are relatively
+-	 * rare, so this shouldn't be a problem.
+-	 *
+-	 * Filesystems shouldn't assume that flush will be called at any
+-	 * particular point.  It may be called more times than expected, or not
+-	 * at all.
+-	 *
+-	 * [close]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html
+-	 */
+-	int (*flush) (const char *, struct fuse_file_info *);
+-
+-	/** Release an open file
+-	 *
+-	 * Release is called when there are no more references to an open
+-	 * file: all file descriptors are closed and all memory mappings
+-	 * are unmapped.
+-	 *
+-	 * For every open() call there will be exactly one release() call
+-	 * with the same flags and file handle.  It is possible to
+-	 * have a file opened more than once, in which case only the last
+-	 * release will mean, that no more reads/writes will happen on the
+-	 * file.  The return value of release is ignored.
+-	 */
+-	int (*release) (const char *, struct fuse_file_info *);
+-
+-	/** Synchronize file contents
+-	 *
+-	 * If the datasync parameter is non-zero, then only the user data
+-	 * should be flushed, not the meta data.
+-	 */
+-	int (*fsync) (const char *, int, struct fuse_file_info *);
+-
+-	/** Set extended attributes */
+-	int (*setxattr) (const char *, const char *, const char *, size_t, int);
+-
+-	/** Get extended attributes */
+-	int (*getxattr) (const char *, const char *, char *, size_t);
+-
+-	/** List extended attributes */
+-	int (*listxattr) (const char *, char *, size_t);
+-
+-	/** Remove extended attributes */
+-	int (*removexattr) (const char *, const char *);
+-
+-	/** Open directory
+-	 *
+-	 * Unless the 'default_permissions' mount option is given,
+-	 * this method should check if opendir is permitted for this
+-	 * directory. Optionally opendir may also return an arbitrary
+-	 * filehandle in the fuse_file_info structure, which will be
+-	 * passed to readdir, releasedir and fsyncdir.
+-	 */
+-	int (*opendir) (const char *, struct fuse_file_info *);
+-
+-	/** Read directory
+-	 *
+-	 * The filesystem may choose between two modes of operation:
+-	 *
+-	 * 1) The readdir implementation ignores the offset parameter, and
+-	 * passes zero to the filler function's offset.  The filler
+-	 * function will not return '1' (unless an error happens), so the
+-	 * whole directory is read in a single readdir operation.
+-	 *
+-	 * 2) The readdir implementation keeps track of the offsets of the
+-	 * directory entries.  It uses the offset parameter and always
+-	 * passes non-zero offset to the filler function.  When the buffer
+-	 * is full (or an error happens) the filler function will return
+-	 * '1'.
+-	 */
+-	int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
+-			struct fuse_file_info *, enum fuse_readdir_flags);
+-
+-	/** Release directory
+-	 */
+-	int (*releasedir) (const char *, struct fuse_file_info *);
+-
+-	/** Synchronize directory contents
+-	 *
+-	 * If the datasync parameter is non-zero, then only the user data
+-	 * should be flushed, not the meta data
+-	 */
+-	int (*fsyncdir) (const char *, int, struct fuse_file_info *);
+-
+-	/**
+-	 * Initialize filesystem
+-	 *
+-	 * The return value will passed in the `private_data` field of
+-	 * `struct fuse_context` to all file operations, and as a
+-	 * parameter to the destroy() method. It overrides the initial
+-	 * value provided to fuse_main() / fuse_new().
+-	 */
+-	void *(*init) (struct fuse_conn_info *conn,
+-		       struct fuse_config *cfg);
+-
+-	/**
+-	 * Clean up filesystem
+-	 *
+-	 * Called on filesystem exit.
+-	 */
+-	void (*destroy) (void *private_data);
+-
+-	/**
+-	 * Check file access permissions
+-	 *
+-	 * This will be called for the access() system call.  If the
+-	 * 'default_permissions' mount option is given, this method is not
+-	 * called.
+-	 *
+-	 * This method is not called under Linux kernel versions 2.4.x
+-	 */
+-	int (*access) (const char *, int);
+-
+-	/**
+-	 * Create and open a file
+-	 *
+-	 * If the file does not exist, first create it with the specified
+-	 * mode, and then open it.
+-	 *
+-	 * If this method is not implemented or under Linux kernel
+-	 * versions earlier than 2.6.15, the mknod() and open() methods
+-	 * will be called instead.
+-	 */
+-	int (*create) (const char *, mode_t, struct fuse_file_info *);
+-
+-	/**
+-	 * Perform POSIX file locking operation
+-	 *
+-	 * The cmd argument will be either F_GETLK, F_SETLK or F_SETLKW.
+-	 *
+-	 * For the meaning of fields in 'struct flock' see the man page
+-	 * for fcntl(2).  The l_whence field will always be set to
+-	 * SEEK_SET.
+-	 *
+-	 * For checking lock ownership, the 'fuse_file_info->owner'
+-	 * argument must be used.
+-	 *
+-	 * For F_GETLK operation, the library will first check currently
+-	 * held locks, and if a conflicting lock is found it will return
+-	 * information without calling this method.	 This ensures, that
+-	 * for local locks the l_pid field is correctly filled in.	The
+-	 * results may not be accurate in case of race conditions and in
+-	 * the presence of hard links, but it's unlikely that an
+-	 * application would rely on accurate GETLK results in these
+-	 * cases.  If a conflicting lock is not found, this method will be
+-	 * called, and the filesystem may fill out l_pid by a meaningful
+-	 * value, or it may leave this field zero.
+-	 *
+-	 * For F_SETLK and F_SETLKW the l_pid field will be set to the pid
+-	 * of the process performing the locking operation.
+-	 *
+-	 * Note: if this method is not implemented, the kernel will still
+-	 * allow file locking to work locally.  Hence it is only
+-	 * interesting for network filesystems and similar.
+-	 */
+-	int (*lock) (const char *, struct fuse_file_info *, int cmd,
+-		     struct flock *);
+-
+-	/**
+-	 * Change the access and modification times of a file with
+-	 * nanosecond resolution
+-	 *
+-	 * This supersedes the old utime() interface.  New applications
+-	 * should use this.
+-	 *
+-	 * `fi` will always be NULL if the file is not currenlty open, but
+-	 * may also be NULL if the file is open.
+-	 *
+-	 * See the utimensat(2) man page for details.
+-	 */
+-	 int (*utimens) (const char *, const struct timespec tv[2],
+-			 struct fuse_file_info *fi);
+-
+-	/**
+-	 * Map block index within file to block index within device
+-	 *
+-	 * Note: This makes sense only for block device backed filesystems
+-	 * mounted with the 'blkdev' option
+-	 */
+-	int (*bmap) (const char *, size_t blocksize, uint64_t *idx);
+-
+-	/**
+-	 * Ioctl
+-	 *
+-	 * flags will have FUSE_IOCTL_COMPAT set for 32bit ioctls in
+-	 * 64bit environment.  The size and direction of data is
+-	 * determined by _IOC_*() decoding of cmd.  For _IOC_NONE,
+-	 * data will be NULL, for _IOC_WRITE data is out area, for
+-	 * _IOC_READ in area and if both are set in/out area.  In all
+-	 * non-NULL cases, the area is of _IOC_SIZE(cmd) bytes.
+-	 *
+-	 * If flags has FUSE_IOCTL_DIR then the fuse_file_info refers to a
+-	 * directory file handle.
+-	 *
+-	 * Note : the unsigned long request submitted by the application
+-	 * is truncated to 32 bits.
+-	 */
+-	int (*ioctl) (const char *, unsigned int cmd, void *arg,
+-		      struct fuse_file_info *, unsigned int flags, void *data);
+-
+-	/**
+-	 * Poll for IO readiness events
+-	 *
+-	 * Note: If ph is non-NULL, the client should notify
+-	 * when IO readiness events occur by calling
+-	 * fuse_notify_poll() with the specified ph.
+-	 *
+-	 * Regardless of the number of times poll with a non-NULL ph
+-	 * is received, single notification is enough to clear all.
+-	 * Notifying more times incurs overhead but doesn't harm
+-	 * correctness.
+-	 *
+-	 * The callee is responsible for destroying ph with
+-	 * fuse_pollhandle_destroy() when no longer in use.
+-	 */
+-	int (*poll) (const char *, struct fuse_file_info *,
+-		     struct fuse_pollhandle *ph, unsigned *reventsp);
+-
+-	/** Write contents of buffer to an open file
+-	 *
+-	 * Similar to the write() method, but data is supplied in a
+-	 * generic buffer.  Use fuse_buf_copy() to transfer data to
+-	 * the destination.
+-	 *
+-	 * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
+-	 * expected to reset the setuid and setgid bits.
+-	 */
+-	int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off,
+-			  struct fuse_file_info *);
+-
+-	/** Store data from an open file in a buffer
+-	 *
+-	 * Similar to the read() method, but data is stored and
+-	 * returned in a generic buffer.
+-	 *
+-	 * No actual copying of data has to take place, the source
+-	 * file descriptor may simply be stored in the buffer for
+-	 * later data transfer.
+-	 *
+-	 * The buffer must be allocated dynamically and stored at the
+-	 * location pointed to by bufp.  If the buffer contains memory
+-	 * regions, they too must be allocated using malloc().  The
+-	 * allocated memory will be freed by the caller.
+-	 */
+-	int (*read_buf) (const char *, struct fuse_bufvec **bufp,
+-			 size_t size, off_t off, struct fuse_file_info *);
+-	/**
+-	 * Perform BSD file locking operation
+-	 *
+-	 * The op argument will be either LOCK_SH, LOCK_EX or LOCK_UN
+-	 *
+-	 * Nonblocking requests will be indicated by ORing LOCK_NB to
+-	 * the above operations
+-	 *
+-	 * For more information see the flock(2) manual page.
+-	 *
+-	 * Additionally fi->owner will be set to a value unique to
+-	 * this open file.  This same value will be supplied to
+-	 * ->release() when the file is released.
+-	 *
+-	 * Note: if this method is not implemented, the kernel will still
+-	 * allow file locking to work locally.  Hence it is only
+-	 * interesting for network filesystems and similar.
+-	 */
+-	int (*flock) (const char *, struct fuse_file_info *, int op);
+-
+-	/**
+-	 * Allocates space for an open file
+-	 *
+-	 * This function ensures that required space is allocated for specified
+-	 * file.  If this function returns success then any subsequent write
+-	 * request to specified range is guaranteed not to fail because of lack
+-	 * of space on the file system media.
+-	 */
+-	int (*fallocate) (const char *, int, off_t, off_t,
+-			  struct fuse_file_info *);
+-
+-	/**
+-	 * Copy a range of data from one file to another
+-	 *
+-	 * Performs an optimized copy between two file descriptors without the
+-	 * additional cost of transferring data through the FUSE kernel module
+-	 * to user space (glibc) and then back into the FUSE filesystem again.
+-	 *
+-	 * In case this method is not implemented, glibc falls back to reading
+-	 * data from the source and writing to the destination. Effectively
+-	 * doing an inefficient copy of the data.
+-	 */
+-	ssize_t (*copy_file_range) (const char *path_in,
+-				    struct fuse_file_info *fi_in,
+-				    off_t offset_in, const char *path_out,
+-				    struct fuse_file_info *fi_out,
+-				    off_t offset_out, size_t size, int flags);
+-
+-	/**
+-	 * Find next data or hole after the specified offset
+-	 */
+-	off_t (*lseek) (const char *, off_t off, int whence, struct fuse_file_info *);
++    /**
++     * Get file attributes.
++     *
++     * Similar to stat().  The 'st_dev' and 'st_blksize' fields are
++     * ignored. The 'st_ino' field is ignored except if the 'use_ino'
++     * mount option is given. In that case it is passed to userspace,
++     * but libfuse and the kernel will still assign a different
++     * inode for internal use (called the "nodeid").
++     *
++     * `fi` will always be NULL if the file is not currently open, but
++     * may also be NULL if the file is open.
++     */
++    int (*getattr)(const char *, struct stat *, struct fuse_file_info *fi);
++
++    /**
++     * Read the target of a symbolic link
++     *
++     * The buffer should be filled with a null terminated string.  The
++     * buffer size argument includes the space for the terminating
++     * null character. If the linkname is too long to fit in the
++     * buffer, it should be truncated. The return value should be 0
++     * for success.
++     */
++    int (*readlink)(const char *, char *, size_t);
++
++    /**
++     * Create a file node
++     *
++     * This is called for creation of all non-directory, non-symlink
++     * nodes.  If the filesystem defines a create() method, then for
++     * regular files that will be called instead.
++     */
++    int (*mknod)(const char *, mode_t, dev_t);
++
++    /**
++     * Create a directory
++     *
++     * Note that the mode argument may not have the type specification
++     * bits set, i.e. S_ISDIR(mode) can be false.  To obtain the
++     * correct directory type bits use  mode|S_IFDIR
++     */
++    int (*mkdir)(const char *, mode_t);
++
++    /** Remove a file */
++    int (*unlink)(const char *);
++
++    /** Remove a directory */
++    int (*rmdir)(const char *);
++
++    /** Create a symbolic link */
++    int (*symlink)(const char *, const char *);
++
++    /**
++     * Rename a file
++     *
++     * *flags* may be `RENAME_EXCHANGE` or `RENAME_NOREPLACE`. If
++     * RENAME_NOREPLACE is specified, the filesystem must not
++     * overwrite *newname* if it exists and return an error
++     * instead. If `RENAME_EXCHANGE` is specified, the filesystem
++     * must atomically exchange the two files, i.e. both must
++     * exist and neither may be deleted.
++     */
++    int (*rename)(const char *, const char *, unsigned int flags);
++
++    /** Create a hard link to a file */
++    int (*link)(const char *, const char *);
++
++    /**
++     * Change the permission bits of a file
++     *
++     * `fi` will always be NULL if the file is not currenlty open, but
++     * may also be NULL if the file is open.
++     */
++    int (*chmod)(const char *, mode_t, struct fuse_file_info *fi);
++
++    /**
++     * Change the owner and group of a file
++     *
++     * `fi` will always be NULL if the file is not currenlty open, but
++     * may also be NULL if the file is open.
++     *
++     * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
++     * expected to reset the setuid and setgid bits.
++     */
++    int (*chown)(const char *, uid_t, gid_t, struct fuse_file_info *fi);
++
++    /**
++     * Change the size of a file
++     *
++     * `fi` will always be NULL if the file is not currenlty open, but
++     * may also be NULL if the file is open.
++     *
++     * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
++     * expected to reset the setuid and setgid bits.
++     */
++    int (*truncate)(const char *, off_t, struct fuse_file_info *fi);
++
++    /**
++     * Open a file
++     *
++     * Open flags are available in fi->flags. The following rules
++     * apply.
++     *
++     *  - Creation (O_CREAT, O_EXCL, O_NOCTTY) flags will be
++     *    filtered out / handled by the kernel.
++     *
++     *  - Access modes (O_RDONLY, O_WRONLY, O_RDWR, O_EXEC, O_SEARCH)
++     *    should be used by the filesystem to check if the operation is
++     *    permitted.  If the ``-o default_permissions`` mount option is
++     *    given, this check is already done by the kernel before calling
++     *    open() and may thus be omitted by the filesystem.
++     *
++     *  - When writeback caching is enabled, the kernel may send
++     *    read requests even for files opened with O_WRONLY. The
++     *    filesystem should be prepared to handle this.
++     *
++     *  - When writeback caching is disabled, the filesystem is
++     *    expected to properly handle the O_APPEND flag and ensure
++     *    that each write is appending to the end of the file.
++     *
++     *  - When writeback caching is enabled, the kernel will
++     *    handle O_APPEND. However, unless all changes to the file
++     *    come through the kernel this will not work reliably. The
++     *    filesystem should thus either ignore the O_APPEND flag
++     *    (and let the kernel handle it), or return an error
++     *    (indicating that reliably O_APPEND is not available).
++     *
++     * Filesystem may store an arbitrary file handle (pointer,
++     * index, etc) in fi->fh, and use this in other all other file
++     * operations (read, write, flush, release, fsync).
++     *
++     * Filesystem may also implement stateless file I/O and not store
++     * anything in fi->fh.
++     *
++     * There are also some flags (direct_io, keep_cache) which the
++     * filesystem may set in fi, to change the way the file is opened.
++     * See fuse_file_info structure in <fuse_common.h> for more details.
++     *
++     * If this request is answered with an error code of ENOSYS
++     * and FUSE_CAP_NO_OPEN_SUPPORT is set in
++     * `fuse_conn_info.capable`, this is treated as success and
++     * future calls to open will also succeed without being send
++     * to the filesystem process.
++     *
++     */
++    int (*open)(const char *, struct fuse_file_info *);
++
++    /**
++     * Read data from an open file
++     *
++     * Read should return exactly the number of bytes requested except
++     * on EOF or error, otherwise the rest of the data will be
++     * substituted with zeroes.  An exception to this is when the
++     * 'direct_io' mount option is specified, in which case the return
++     * value of the read system call will reflect the return value of
++     * this operation.
++     */
++    int (*read)(const char *, char *, size_t, off_t, struct fuse_file_info *);
++
++    /**
++     * Write data to an open file
++     *
++     * Write should return exactly the number of bytes requested
++     * except on error.  An exception to this is when the 'direct_io'
++     * mount option is specified (see read operation).
++     *
++     * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
++     * expected to reset the setuid and setgid bits.
++     */
++    int (*write)(const char *, const char *, size_t, off_t,
++                 struct fuse_file_info *);
++
++    /**
++     * Get file system statistics
++     *
++     * The 'f_favail', 'f_fsid' and 'f_flag' fields are ignored
++     */
++    int (*statfs)(const char *, struct statvfs *);
++
++    /**
++     * Possibly flush cached data
++     *
++     * BIG NOTE: This is not equivalent to fsync().  It's not a
++     * request to sync dirty data.
++     *
++     * Flush is called on each close() of a file descriptor, as opposed to
++     * release which is called on the close of the last file descriptor for
++     * a file.  Under Linux, errors returned by flush() will be passed to
++     * userspace as errors from close(), so flush() is a good place to write
++     * back any cached dirty data. However, many applications ignore errors
++     * on close(), and on non-Linux systems, close() may succeed even if flush()
++     * returns an error. For these reasons, filesystems should not assume
++     * that errors returned by flush will ever be noticed or even
++     * delivered.
++     *
++     * NOTE: The flush() method may be called more than once for each
++     * open().  This happens if more than one file descriptor refers to an
++     * open file handle, e.g. due to dup(), dup2() or fork() calls.  It is
++     * not possible to determine if a flush is final, so each flush should
++     * be treated equally.  Multiple write-flush sequences are relatively
++     * rare, so this shouldn't be a problem.
++     *
++     * Filesystems shouldn't assume that flush will be called at any
++     * particular point.  It may be called more times than expected, or not
++     * at all.
++     *
++     * [close]:
++     * http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html
++     */
++    int (*flush)(const char *, struct fuse_file_info *);
++
++    /**
++     * Release an open file
++     *
++     * Release is called when there are no more references to an open
++     * file: all file descriptors are closed and all memory mappings
++     * are unmapped.
++     *
++     * For every open() call there will be exactly one release() call
++     * with the same flags and file handle.  It is possible to
++     * have a file opened more than once, in which case only the last
++     * release will mean, that no more reads/writes will happen on the
++     * file.  The return value of release is ignored.
++     */
++    int (*release)(const char *, struct fuse_file_info *);
++
++    /*
++     * Synchronize file contents
++     *
++     * If the datasync parameter is non-zero, then only the user data
++     * should be flushed, not the meta data.
++     */
++    int (*fsync)(const char *, int, struct fuse_file_info *);
++
++    /** Set extended attributes */
++    int (*setxattr)(const char *, const char *, const char *, size_t, int);
++
++    /** Get extended attributes */
++    int (*getxattr)(const char *, const char *, char *, size_t);
++
++    /** List extended attributes */
++    int (*listxattr)(const char *, char *, size_t);
++
++    /** Remove extended attributes */
++    int (*removexattr)(const char *, const char *);
++
++    /*
++     * Open directory
++     *
++     * Unless the 'default_permissions' mount option is given,
++     * this method should check if opendir is permitted for this
++     * directory. Optionally opendir may also return an arbitrary
++     * filehandle in the fuse_file_info structure, which will be
++     * passed to readdir, releasedir and fsyncdir.
++     */
++    int (*opendir)(const char *, struct fuse_file_info *);
++
++    /*
++     * Read directory
++     *
++     * The filesystem may choose between two modes of operation:
++     *
++     * 1) The readdir implementation ignores the offset parameter, and
++     * passes zero to the filler function's offset.  The filler
++     * function will not return '1' (unless an error happens), so the
++     * whole directory is read in a single readdir operation.
++     *
++     * 2) The readdir implementation keeps track of the offsets of the
++     * directory entries.  It uses the offset parameter and always
++     * passes non-zero offset to the filler function.  When the buffer
++     * is full (or an error happens) the filler function will return
++     * '1'.
++     */
++    int (*readdir)(const char *, void *, fuse_fill_dir_t, off_t,
++                   struct fuse_file_info *, enum fuse_readdir_flags);
++
++    /**
++     *  Release directory
++     */
++    int (*releasedir)(const char *, struct fuse_file_info *);
++
++    /**
++     * Synchronize directory contents
++     *
++     * If the datasync parameter is non-zero, then only the user data
++     * should be flushed, not the meta data
++     */
++    int (*fsyncdir)(const char *, int, struct fuse_file_info *);
++
++    /**
++     * Initialize filesystem
++     *
++     * The return value will passed in the `private_data` field of
++     * `struct fuse_context` to all file operations, and as a
++     * parameter to the destroy() method. It overrides the initial
++     * value provided to fuse_main() / fuse_new().
++     */
++    void *(*init)(struct fuse_conn_info *conn, struct fuse_config *cfg);
++
++    /**
++     * Clean up filesystem
++     *
++     * Called on filesystem exit.
++     */
++    void (*destroy)(void *private_data);
++
++    /**
++     * Check file access permissions
++     *
++     * This will be called for the access() system call.  If the
++     * 'default_permissions' mount option is given, this method is not
++     * called.
++     *
++     * This method is not called under Linux kernel versions 2.4.x
++     */
++    int (*access)(const char *, int);
++
++    /**
++     * Create and open a file
++     *
++     * If the file does not exist, first create it with the specified
++     * mode, and then open it.
++     *
++     * If this method is not implemented or under Linux kernel
++     * versions earlier than 2.6.15, the mknod() and open() methods
++     * will be called instead.
++     */
++    int (*create)(const char *, mode_t, struct fuse_file_info *);
++
++    /**
++     * Perform POSIX file locking operation
++     *
++     * The cmd argument will be either F_GETLK, F_SETLK or F_SETLKW.
++     *
++     * For the meaning of fields in 'struct flock' see the man page
++     * for fcntl(2).  The l_whence field will always be set to
++     * SEEK_SET.
++     *
++     * For checking lock ownership, the 'fuse_file_info->owner'
++     * argument must be used.
++     *
++     * For F_GETLK operation, the library will first check currently
++     * held locks, and if a conflicting lock is found it will return
++     * information without calling this method.  This ensures, that
++     * for local locks the l_pid field is correctly filled in. The
++     * results may not be accurate in case of race conditions and in
++     * the presence of hard links, but it's unlikely that an
++     * application would rely on accurate GETLK results in these
++     * cases.  If a conflicting lock is not found, this method will be
++     * called, and the filesystem may fill out l_pid by a meaningful
++     * value, or it may leave this field zero.
++     *
++     * For F_SETLK and F_SETLKW the l_pid field will be set to the pid
++     * of the process performing the locking operation.
++     *
++     * Note: if this method is not implemented, the kernel will still
++     * allow file locking to work locally.  Hence it is only
++     * interesting for network filesystems and similar.
++     */
++    int (*lock)(const char *, struct fuse_file_info *, int cmd, struct flock *);
++
++    /**
++     * Change the access and modification times of a file with
++     * nanosecond resolution
++     *
++     * This supersedes the old utime() interface.  New applications
++     * should use this.
++     *
++     * `fi` will always be NULL if the file is not currenlty open, but
++     * may also be NULL if the file is open.
++     *
++     * See the utimensat(2) man page for details.
++     */
++    int (*utimens)(const char *, const struct timespec tv[2],
++                   struct fuse_file_info *fi);
++
++    /**
++     * Map block index within file to block index within device
++     *
++     * Note: This makes sense only for block device backed filesystems
++     * mounted with the 'blkdev' option
++     */
++    int (*bmap)(const char *, size_t blocksize, uint64_t *idx);
++
++    /**
++     * Ioctl
++     *
++     * flags will have FUSE_IOCTL_COMPAT set for 32bit ioctls in
++     * 64bit environment.  The size and direction of data is
++     * determined by _IOC_*() decoding of cmd.  For _IOC_NONE,
++     * data will be NULL, for _IOC_WRITE data is out area, for
++     * _IOC_READ in area and if both are set in/out area.  In all
++     * non-NULL cases, the area is of _IOC_SIZE(cmd) bytes.
++     *
++     * If flags has FUSE_IOCTL_DIR then the fuse_file_info refers to a
++     * directory file handle.
++     *
++     * Note : the unsigned long request submitted by the application
++     * is truncated to 32 bits.
++     */
++    int (*ioctl)(const char *, unsigned int cmd, void *arg,
++                 struct fuse_file_info *, unsigned int flags, void *data);
++
++    /**
++     * Poll for IO readiness events
++     *
++     * Note: If ph is non-NULL, the client should notify
++     * when IO readiness events occur by calling
++     * fuse_notify_poll() with the specified ph.
++     *
++     * Regardless of the number of times poll with a non-NULL ph
++     * is received, single notification is enough to clear all.
++     * Notifying more times incurs overhead but doesn't harm
++     * correctness.
++     *
++     * The callee is responsible for destroying ph with
++     * fuse_pollhandle_destroy() when no longer in use.
++     */
++    int (*poll)(const char *, struct fuse_file_info *,
++                struct fuse_pollhandle *ph, unsigned *reventsp);
++
++    /*
++     * Write contents of buffer to an open file
++     *
++     * Similar to the write() method, but data is supplied in a
++     * generic buffer.  Use fuse_buf_copy() to transfer data to
++     * the destination.
++     *
++     * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
++     * expected to reset the setuid and setgid bits.
++     */
++    int (*write_buf)(const char *, struct fuse_bufvec *buf, off_t off,
++                     struct fuse_file_info *);
++
++    /*
++     *  Store data from an open file in a buffer
++     *
++     * Similar to the read() method, but data is stored and
++     * returned in a generic buffer.
++     *
++     * No actual copying of data has to take place, the source
++     * file descriptor may simply be stored in the buffer for
++     * later data transfer.
++     *
++     * The buffer must be allocated dynamically and stored at the
++     * location pointed to by bufp.  If the buffer contains memory
++     * regions, they too must be allocated using malloc().  The
++     * allocated memory will be freed by the caller.
++     */
++    int (*read_buf)(const char *, struct fuse_bufvec **bufp, size_t size,
++                    off_t off, struct fuse_file_info *);
++    /**
++     * Perform BSD file locking operation
++     *
++     * The op argument will be either LOCK_SH, LOCK_EX or LOCK_UN
++     *
++     * Nonblocking requests will be indicated by ORing LOCK_NB to
++     * the above operations
++     *
++     * For more information see the flock(2) manual page.
++     *
++     * Additionally fi->owner will be set to a value unique to
++     * this open file.  This same value will be supplied to
++     * ->release() when the file is released.
++     *
++     * Note: if this method is not implemented, the kernel will still
++     * allow file locking to work locally.  Hence it is only
++     * interesting for network filesystems and similar.
++     */
++    int (*flock)(const char *, struct fuse_file_info *, int op);
++
++    /**
++     * Allocates space for an open file
++     *
++     * This function ensures that required space is allocated for specified
++     * file.  If this function returns success then any subsequent write
++     * request to specified range is guaranteed not to fail because of lack
++     * of space on the file system media.
++     */
++    int (*fallocate)(const char *, int, off_t, off_t, struct fuse_file_info *);
++
++    /**
++     * Copy a range of data from one file to another
++     *
++     * Performs an optimized copy between two file descriptors without the
++     * additional cost of transferring data through the FUSE kernel module
++     * to user space (glibc) and then back into the FUSE filesystem again.
++     *
++     * In case this method is not implemented, glibc falls back to reading
++     * data from the source and writing to the destination. Effectively
++     * doing an inefficient copy of the data.
++     */
++    ssize_t (*copy_file_range)(const char *path_in,
++                               struct fuse_file_info *fi_in, off_t offset_in,
++                               const char *path_out,
++                               struct fuse_file_info *fi_out, off_t offset_out,
++                               size_t size, int flags);
++
++    /**
++     * Find next data or hole after the specified offset
++     */
++    off_t (*lseek)(const char *, off_t off, int whence,
++                   struct fuse_file_info *);
+ };
+ 
+-/** Extra context that may be needed by some filesystems
++/*
++ * Extra context that may be needed by some filesystems
+  *
+  * The uid, gid and pid fields are not filled in case of a writepage
+  * operation.
+  */
+ struct fuse_context {
+-	/** Pointer to the fuse object */
+-	struct fuse *fuse;
++    /** Pointer to the fuse object */
++    struct fuse *fuse;
+ 
+-	/** User ID of the calling process */
+-	uid_t uid;
++    /** User ID of the calling process */
++    uid_t uid;
+ 
+-	/** Group ID of the calling process */
+-	gid_t gid;
++    /** Group ID of the calling process */
++    gid_t gid;
+ 
+-	/** Process ID of the calling thread */
+-	pid_t pid;
++    /** Process ID of the calling thread */
++    pid_t pid;
+ 
+-	/** Private filesystem data */
+-	void *private_data;
++    /** Private filesystem data */
++    void *private_data;
+ 
+-	/** Umask of the calling process */
+-	mode_t umask;
++    /** Umask of the calling process */
++    mode_t umask;
+ };
+ 
+ /**
+@@ -859,15 +880,15 @@ struct fuse_context {
+  * Example usage, see hello.c
+  */
+ /*
+-  int fuse_main(int argc, char *argv[], const struct fuse_operations *op,
+-  void *private_data);
+-*/
+-#define fuse_main(argc, argv, op, private_data)				\
+-	fuse_main_real(argc, argv, op, sizeof(*(op)), private_data)
++ * int fuse_main(int argc, char *argv[], const struct fuse_operations *op,
++ * void *private_data);
++ */
++#define fuse_main(argc, argv, op, private_data) \
++    fuse_main_real(argc, argv, op, sizeof(*(op)), private_data)
+ 
+-/* ----------------------------------------------------------- *
+- * More detailed API					       *
+- * ----------------------------------------------------------- */
++/*
++ * More detailed API
++ */
+ 
+ /**
+  * Print available options (high- and low-level) to stdout.  This is
+@@ -910,12 +931,13 @@ void fuse_lib_help(struct fuse_args *args);
+  * @return the created FUSE handle
+  */
+ #if FUSE_USE_VERSION == 30
+-struct fuse *fuse_new_30(struct fuse_args *args, const struct fuse_operations *op,
+-			 size_t op_size, void *private_data);
++struct fuse *fuse_new_30(struct fuse_args *args,
++                         const struct fuse_operations *op, size_t op_size,
++                         void *private_data);
+ #define fuse_new(args, op, size, data) fuse_new_30(args, op, size, data)
+ #else
+ struct fuse *fuse_new(struct fuse_args *args, const struct fuse_operations *op,
+-		      size_t op_size, void *private_data);
++                      size_t op_size, void *private_data);
+ #endif
+ 
+ /**
+@@ -940,7 +962,7 @@ void fuse_unmount(struct fuse *f);
+ /**
+  * Destroy the FUSE handle.
+  *
+- * NOTE: This function does not unmount the filesystem.	 If this is
++ * NOTE: This function does not unmount the filesystem.  If this is
+  * needed, call fuse_unmount() before calling this function.
+  *
+  * @param f the FUSE handle
+@@ -1030,7 +1052,7 @@ int fuse_invalidate_path(struct fuse *f, const char *path);
+  * Do not call this directly, use fuse_main()
+  */
+ int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
+-		   size_t op_size, void *private_data);
++                   size_t op_size, void *private_data);
+ 
+ /**
+  * Start the cleanup thread when using option "remember".
+@@ -1081,89 +1103,87 @@ struct fuse_fs;
+  */
+ 
+ int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf,
+-		    struct fuse_file_info *fi);
+-int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath,
+-		   const char *newpath, unsigned int flags);
++                    struct fuse_file_info *fi);
++int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath, const char *newpath,
++                   unsigned int flags);
+ int fuse_fs_unlink(struct fuse_fs *fs, const char *path);
+ int fuse_fs_rmdir(struct fuse_fs *fs, const char *path);
+-int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname,
+-		    const char *path);
++int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname, const char *path);
+ int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath);
+-int fuse_fs_release(struct fuse_fs *fs,	 const char *path,
+-		    struct fuse_file_info *fi);
++int fuse_fs_release(struct fuse_fs *fs, const char *path,
++                    struct fuse_file_info *fi);
+ int fuse_fs_open(struct fuse_fs *fs, const char *path,
+-		 struct fuse_file_info *fi);
++                 struct fuse_file_info *fi);
+ int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
+-		 off_t off, struct fuse_file_info *fi);
++                 off_t off, struct fuse_file_info *fi);
+ int fuse_fs_read_buf(struct fuse_fs *fs, const char *path,
+-		     struct fuse_bufvec **bufp, size_t size, off_t off,
+-		     struct fuse_file_info *fi);
++                     struct fuse_bufvec **bufp, size_t size, off_t off,
++                     struct fuse_file_info *fi);
+ int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf,
+-		  size_t size, off_t off, struct fuse_file_info *fi);
++                  size_t size, off_t off, struct fuse_file_info *fi);
+ int fuse_fs_write_buf(struct fuse_fs *fs, const char *path,
+-		      struct fuse_bufvec *buf, off_t off,
+-		      struct fuse_file_info *fi);
++                      struct fuse_bufvec *buf, off_t off,
++                      struct fuse_file_info *fi);
+ int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
+-		  struct fuse_file_info *fi);
++                  struct fuse_file_info *fi);
+ int fuse_fs_flush(struct fuse_fs *fs, const char *path,
+-		  struct fuse_file_info *fi);
++                  struct fuse_file_info *fi);
+ int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf);
+ int fuse_fs_opendir(struct fuse_fs *fs, const char *path,
+-		    struct fuse_file_info *fi);
++                    struct fuse_file_info *fi);
+ int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf,
+-		    fuse_fill_dir_t filler, off_t off,
+-		    struct fuse_file_info *fi, enum fuse_readdir_flags flags);
++                    fuse_fill_dir_t filler, off_t off,
++                    struct fuse_file_info *fi, enum fuse_readdir_flags flags);
+ int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync,
+-		     struct fuse_file_info *fi);
++                     struct fuse_file_info *fi);
+ int fuse_fs_releasedir(struct fuse_fs *fs, const char *path,
+-		       struct fuse_file_info *fi);
++                       struct fuse_file_info *fi);
+ int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
+-		   struct fuse_file_info *fi);
++                   struct fuse_file_info *fi);
+ int fuse_fs_lock(struct fuse_fs *fs, const char *path,
+-		 struct fuse_file_info *fi, int cmd, struct flock *lock);
++                 struct fuse_file_info *fi, int cmd, struct flock *lock);
+ int fuse_fs_flock(struct fuse_fs *fs, const char *path,
+-		  struct fuse_file_info *fi, int op);
++                  struct fuse_file_info *fi, int op);
+ int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode,
+-		  struct fuse_file_info *fi);
++                  struct fuse_file_info *fi);
+ int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid,
+-		  struct fuse_file_info *fi);
++                  struct fuse_file_info *fi);
+ int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size,
+-		     struct fuse_file_info *fi);
++                     struct fuse_file_info *fi);
+ int fuse_fs_utimens(struct fuse_fs *fs, const char *path,
+-		    const struct timespec tv[2], struct fuse_file_info *fi);
++                    const struct timespec tv[2], struct fuse_file_info *fi);
+ int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask);
+ int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf,
+-		     size_t len);
++                     size_t len);
+ int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode,
+-		  dev_t rdev);
++                  dev_t rdev);
+ int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode);
+ int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name,
+-		     const char *value, size_t size, int flags);
++                     const char *value, size_t size, int flags);
+ int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name,
+-		     char *value, size_t size);
++                     char *value, size_t size);
+ int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list,
+-		      size_t size);
+-int fuse_fs_removexattr(struct fuse_fs *fs, const char *path,
+-			const char *name);
++                      size_t size);
++int fuse_fs_removexattr(struct fuse_fs *fs, const char *path, const char *name);
+ int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
+-		 uint64_t *idx);
++                 uint64_t *idx);
+ int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, unsigned int cmd,
+-		  void *arg, struct fuse_file_info *fi, unsigned int flags,
+-		  void *data);
++                  void *arg, struct fuse_file_info *fi, unsigned int flags,
++                  void *data);
+ int fuse_fs_poll(struct fuse_fs *fs, const char *path,
+-		 struct fuse_file_info *fi, struct fuse_pollhandle *ph,
+-		 unsigned *reventsp);
++                 struct fuse_file_info *fi, struct fuse_pollhandle *ph,
++                 unsigned *reventsp);
+ int fuse_fs_fallocate(struct fuse_fs *fs, const char *path, int mode,
+-		 off_t offset, off_t length, struct fuse_file_info *fi);
++                      off_t offset, off_t length, struct fuse_file_info *fi);
+ ssize_t fuse_fs_copy_file_range(struct fuse_fs *fs, const char *path_in,
+-				struct fuse_file_info *fi_in, off_t off_in,
+-				const char *path_out,
+-				struct fuse_file_info *fi_out, off_t off_out,
+-				size_t len, int flags);
++                                struct fuse_file_info *fi_in, off_t off_in,
++                                const char *path_out,
++                                struct fuse_file_info *fi_out, off_t off_out,
++                                size_t len, int flags);
+ off_t fuse_fs_lseek(struct fuse_fs *fs, const char *path, off_t off, int whence,
+-		    struct fuse_file_info *fi);
++                    struct fuse_file_info *fi);
+ void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn,
+-		struct fuse_config *cfg);
++                  struct fuse_config *cfg);
+ void fuse_fs_destroy(struct fuse_fs *fs);
+ 
+ int fuse_notify_poll(struct fuse_pollhandle *ph);
+@@ -1182,7 +1202,7 @@ int fuse_notify_poll(struct fuse_pollhandle *ph);
+  * @return a new filesystem object
+  */
+ struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
+-			    void *private_data);
++                            void *private_data);
+ 
+ /**
+  * Factory for creating filesystem objects
+@@ -1199,7 +1219,7 @@ struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
+  * @return the new filesystem object
+  */
+ typedef struct fuse_fs *(*fuse_module_factory_t)(struct fuse_args *args,
+-						 struct fuse_fs *fs[]);
++                                                 struct fuse_fs *fs[]);
+ /**
+  * Register filesystem module
+  *
+@@ -1211,7 +1231,7 @@ typedef struct fuse_fs *(*fuse_module_factory_t)(struct fuse_args *args,
+  * @param factory_ the factory function for this filesystem module
+  */
+ #define FUSE_REGISTER_MODULE(name_, factory_) \
+-	fuse_module_factory_t fuse_module_ ## name_ ## _factory = factory_
++    fuse_module_factory_t fuse_module_##name_##_factory = factory_
+ 
+ /** Get session from fuse object */
+ struct fuse_session *fuse_get_session(struct fuse *f);
+diff --git a/tools/virtiofsd/fuse_common.h b/tools/virtiofsd/fuse_common.h
+index bf8f8cc865..bd9bf861f0 100644
+--- a/tools/virtiofsd/fuse_common.h
++++ b/tools/virtiofsd/fuse_common.h
+@@ -1,21 +1,23 @@
+-/*  FUSE: Filesystem in Userspace
+-  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+-
+-  This program can be distributed under the terms of the GNU LGPLv2.
+-  See the file COPYING.LIB.
+-*/
++/*
++ * FUSE: Filesystem in Userspace
++ * Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++ *
++ * This program can be distributed under the terms of the GNU LGPLv2.
++ * See the file COPYING.LIB.
++ */
+ 
+ /** @file */
+ 
+ #if !defined(FUSE_H_) && !defined(FUSE_LOWLEVEL_H_)
+-#error "Never include <fuse_common.h> directly; use <fuse.h> or <fuse_lowlevel.h> instead."
++#error \
++    "Never include <fuse_common.h> directly; use <fuse.h> or <fuse_lowlevel.h> instead."
+ #endif
+ 
+ #ifndef FUSE_COMMON_H_
+ #define FUSE_COMMON_H_
+ 
+-#include "fuse_opt.h"
+ #include "fuse_log.h"
++#include "fuse_opt.h"
+ #include <stdint.h>
+ #include <sys/types.h>
+ 
+@@ -25,7 +27,7 @@
+ /** Minor version of FUSE library interface */
+ #define FUSE_MINOR_VERSION 2
+ 
+-#define FUSE_MAKE_VERSION(maj, min)  ((maj) * 10 + (min))
++#define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min))
+ #define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION)
+ 
+ /**
+@@ -38,67 +40,83 @@
+  * descriptors can share a single file handle.
+  */
+ struct fuse_file_info {
+-	/** Open flags.	 Available in open() and release() */
+-	int flags;
+-
+-	/** In case of a write operation indicates if this was caused
+-	    by a delayed write from the page cache. If so, then the
+-	    context's pid, uid, and gid fields will not be valid, and
+-	    the *fh* value may not match the *fh* value that would
+-	    have been sent with the corresponding individual write
+-	    requests if write caching had been disabled. */
+-	unsigned int writepage : 1;
+-
+-	/** Can be filled in by open, to use direct I/O on this file. */
+-	unsigned int direct_io : 1;
+-
+-	/** Can be filled in by open. It signals the kernel that any
+-	    currently cached file data (ie., data that the filesystem
+-	    provided the last time the file was open) need not be
+-	    invalidated. Has no effect when set in other contexts (in
+-	    particular it does nothing when set by opendir()). */
+-	unsigned int keep_cache : 1;
+-
+-	/** Indicates a flush operation.  Set in flush operation, also
+-	    maybe set in highlevel lock operation and lowlevel release
+-	    operation. */
+-	unsigned int flush : 1;
+-
+-	/** Can be filled in by open, to indicate that the file is not
+-	    seekable. */
+-	unsigned int nonseekable : 1;
+-
+-	/* Indicates that flock locks for this file should be
+-	   released.  If set, lock_owner shall contain a valid value.
+-	   May only be set in ->release(). */
+-	unsigned int flock_release : 1;
+-
+-	/** Can be filled in by opendir. It signals the kernel to
+-	    enable caching of entries returned by readdir().  Has no
+-	    effect when set in other contexts (in particular it does
+-	    nothing when set by open()). */
+-	unsigned int cache_readdir : 1;
+-
+-	/** Padding.  Reserved for future use*/
+-	unsigned int padding : 25;
+-	unsigned int padding2 : 32;
+-
+-	/** File handle id.  May be filled in by filesystem in create,
+-	 * open, and opendir().  Available in most other file operations on the
+-	 * same file handle. */
+-	uint64_t fh;
+-
+-	/** Lock owner id.  Available in locking operations and flush */
+-	uint64_t lock_owner;
+-
+-	/** Requested poll events.  Available in ->poll.  Only set on kernels
+-	    which support it.  If unsupported, this field is set to zero. */
+-	uint32_t poll_events;
++    /** Open flags. Available in open() and release() */
++    int flags;
++
++    /*
++     * In case of a write operation indicates if this was caused
++     * by a delayed write from the page cache. If so, then the
++     * context's pid, uid, and gid fields will not be valid, and
++     * the *fh* value may not match the *fh* value that would
++     * have been sent with the corresponding individual write
++     * requests if write caching had been disabled.
++     */
++    unsigned int writepage:1;
++
++    /** Can be filled in by open, to use direct I/O on this file. */
++    unsigned int direct_io:1;
++
++    /*
++     *  Can be filled in by open. It signals the kernel that any
++     *  currently cached file data (ie., data that the filesystem
++     *  provided the last time the file was open) need not be
++     *  invalidated. Has no effect when set in other contexts (in
++     *  particular it does nothing when set by opendir()).
++     */
++    unsigned int keep_cache:1;
++
++    /*
++     *  Indicates a flush operation.  Set in flush operation, also
++     *  maybe set in highlevel lock operation and lowlevel release
++     *  operation.
++     */
++    unsigned int flush:1;
++
++    /*
++     *  Can be filled in by open, to indicate that the file is not
++     *  seekable.
++     */
++    unsigned int nonseekable:1;
++
++    /*
++     * Indicates that flock locks for this file should be
++     * released.  If set, lock_owner shall contain a valid value.
++     * May only be set in ->release().
++     */
++    unsigned int flock_release:1;
++
++    /*
++     *  Can be filled in by opendir. It signals the kernel to
++     *  enable caching of entries returned by readdir().  Has no
++     *  effect when set in other contexts (in particular it does
++     *  nothing when set by open()).
++     */
++    unsigned int cache_readdir:1;
++
++    /** Padding.  Reserved for future use*/
++    unsigned int padding:25;
++    unsigned int padding2:32;
++
++    /*
++     *  File handle id.  May be filled in by filesystem in create,
++     * open, and opendir().  Available in most other file operations on the
++     * same file handle.
++     */
++    uint64_t fh;
++
++    /** Lock owner id.  Available in locking operations and flush */
++    uint64_t lock_owner;
++
++    /*
++     * Requested poll events.  Available in ->poll.  Only set on kernels
++     * which support it.  If unsupported, this field is set to zero.
++     */
++    uint32_t poll_events;
+ };
+ 
+-/**************************************************************************
+- * Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want' *
+- **************************************************************************/
++/*
++ * Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want'
++ */
+ 
+ /**
+  * Indicates that the filesystem supports asynchronous read requests.
+@@ -110,7 +128,7 @@ struct fuse_file_info {
+  *
+  * This feature is enabled by default when supported by the kernel.
+  */
+-#define FUSE_CAP_ASYNC_READ		(1 << 0)
++#define FUSE_CAP_ASYNC_READ (1 << 0)
+ 
+ /**
+  * Indicates that the filesystem supports "remote" locking.
+@@ -118,7 +136,7 @@ struct fuse_file_info {
+  * This feature is enabled by default when supported by the kernel,
+  * and if getlk() and setlk() handlers are implemented.
+  */
+-#define FUSE_CAP_POSIX_LOCKS		(1 << 1)
++#define FUSE_CAP_POSIX_LOCKS (1 << 1)
+ 
+ /**
+  * Indicates that the filesystem supports the O_TRUNC open flag.  If
+@@ -127,14 +145,14 @@ struct fuse_file_info {
+  *
+  * This feature is enabled by default when supported by the kernel.
+  */
+-#define FUSE_CAP_ATOMIC_O_TRUNC		(1 << 3)
++#define FUSE_CAP_ATOMIC_O_TRUNC (1 << 3)
+ 
+ /**
+  * Indicates that the filesystem supports lookups of "." and "..".
+  *
+  * This feature is disabled by default.
+  */
+-#define FUSE_CAP_EXPORT_SUPPORT		(1 << 4)
++#define FUSE_CAP_EXPORT_SUPPORT (1 << 4)
+ 
+ /**
+  * Indicates that the kernel should not apply the umask to the
+@@ -142,7 +160,7 @@ struct fuse_file_info {
+  *
+  * This feature is disabled by default.
+  */
+-#define FUSE_CAP_DONT_MASK		(1 << 6)
++#define FUSE_CAP_DONT_MASK (1 << 6)
+ 
+ /**
+  * Indicates that libfuse should try to use splice() when writing to
+@@ -150,7 +168,7 @@ struct fuse_file_info {
+  *
+  * This feature is disabled by default.
+  */
+-#define FUSE_CAP_SPLICE_WRITE		(1 << 7)
++#define FUSE_CAP_SPLICE_WRITE (1 << 7)
+ 
+ /**
+  * Indicates that libfuse should try to move pages instead of copying when
+@@ -158,7 +176,7 @@ struct fuse_file_info {
+  *
+  * This feature is disabled by default.
+  */
+-#define FUSE_CAP_SPLICE_MOVE		(1 << 8)
++#define FUSE_CAP_SPLICE_MOVE (1 << 8)
+ 
+ /**
+  * Indicates that libfuse should try to use splice() when reading from
+@@ -167,7 +185,7 @@ struct fuse_file_info {
+  * This feature is enabled by default when supported by the kernel and
+  * if the filesystem implements a write_buf() handler.
+  */
+-#define FUSE_CAP_SPLICE_READ		(1 << 9)
++#define FUSE_CAP_SPLICE_READ (1 << 9)
+ 
+ /**
+  * If set, the calls to flock(2) will be emulated using POSIX locks and must
+@@ -180,14 +198,14 @@ struct fuse_file_info {
+  * This feature is enabled by default when supported by the kernel and
+  * if the filesystem implements a flock() handler.
+  */
+-#define FUSE_CAP_FLOCK_LOCKS		(1 << 10)
++#define FUSE_CAP_FLOCK_LOCKS (1 << 10)
+ 
+ /**
+  * Indicates that the filesystem supports ioctl's on directories.
+  *
+  * This feature is enabled by default when supported by the kernel.
+  */
+-#define FUSE_CAP_IOCTL_DIR		(1 << 11)
++#define FUSE_CAP_IOCTL_DIR (1 << 11)
+ 
+ /**
+  * Traditionally, while a file is open the FUSE kernel module only
+@@ -209,7 +227,7 @@ struct fuse_file_info {
+  *
+  * This feature is enabled by default when supported by the kernel.
+  */
+-#define FUSE_CAP_AUTO_INVAL_DATA	(1 << 12)
++#define FUSE_CAP_AUTO_INVAL_DATA (1 << 12)
+ 
+ /**
+  * Indicates that the filesystem supports readdirplus.
+@@ -217,7 +235,7 @@ struct fuse_file_info {
+  * This feature is enabled by default when supported by the kernel and if the
+  * filesystem implements a readdirplus() handler.
+  */
+-#define FUSE_CAP_READDIRPLUS		(1 << 13)
++#define FUSE_CAP_READDIRPLUS (1 << 13)
+ 
+ /**
+  * Indicates that the filesystem supports adaptive readdirplus.
+@@ -245,7 +263,7 @@ struct fuse_file_info {
+  * if the filesystem implements both a readdirplus() and a readdir()
+  * handler.
+  */
+-#define FUSE_CAP_READDIRPLUS_AUTO	(1 << 14)
++#define FUSE_CAP_READDIRPLUS_AUTO (1 << 14)
+ 
+ /**
+  * Indicates that the filesystem supports asynchronous direct I/O submission.
+@@ -256,7 +274,7 @@ struct fuse_file_info {
+  *
+  * This feature is enabled by default when supported by the kernel.
+  */
+-#define FUSE_CAP_ASYNC_DIO		(1 << 15)
++#define FUSE_CAP_ASYNC_DIO (1 << 15)
+ 
+ /**
+  * Indicates that writeback caching should be enabled. This means that
+@@ -265,7 +283,7 @@ struct fuse_file_info {
+  *
+  * This feature is disabled by default.
+  */
+-#define FUSE_CAP_WRITEBACK_CACHE	(1 << 16)
++#define FUSE_CAP_WRITEBACK_CACHE (1 << 16)
+ 
+ /**
+  * Indicates support for zero-message opens. If this flag is set in
+@@ -278,7 +296,7 @@ struct fuse_file_info {
+  * Setting (or unsetting) this flag in the `want` field has *no
+  * effect*.
+  */
+-#define FUSE_CAP_NO_OPEN_SUPPORT	(1 << 17)
++#define FUSE_CAP_NO_OPEN_SUPPORT (1 << 17)
+ 
+ /**
+  * Indicates support for parallel directory operations. If this flag
+@@ -288,7 +306,7 @@ struct fuse_file_info {
+  *
+  * This feature is enabled by default when supported by the kernel.
+  */
+-#define FUSE_CAP_PARALLEL_DIROPS        (1 << 18)
++#define FUSE_CAP_PARALLEL_DIROPS (1 << 18)
+ 
+ /**
+  * Indicates support for POSIX ACLs.
+@@ -307,7 +325,7 @@ struct fuse_file_info {
+  *
+  * This feature is disabled by default.
+  */
+-#define FUSE_CAP_POSIX_ACL              (1 << 19)
++#define FUSE_CAP_POSIX_ACL (1 << 19)
+ 
+ /**
+  * Indicates that the filesystem is responsible for unsetting
+@@ -316,7 +334,7 @@ struct fuse_file_info {
+  *
+  * This feature is enabled by default when supported by the kernel.
+  */
+-#define FUSE_CAP_HANDLE_KILLPRIV         (1 << 20)
++#define FUSE_CAP_HANDLE_KILLPRIV (1 << 20)
+ 
+ /**
+  * Indicates support for zero-message opendirs. If this flag is set in
+@@ -328,7 +346,7 @@ struct fuse_file_info {
+  *
+  * Setting (or unsetting) this flag in the `want` field has *no effect*.
+  */
+-#define FUSE_CAP_NO_OPENDIR_SUPPORT    (1 << 24)
++#define FUSE_CAP_NO_OPENDIR_SUPPORT (1 << 24)
+ 
+ /**
+  * Ioctl flags
+@@ -340,12 +358,12 @@ struct fuse_file_info {
+  *
+  * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs
+  */
+-#define FUSE_IOCTL_COMPAT	(1 << 0)
+-#define FUSE_IOCTL_UNRESTRICTED	(1 << 1)
+-#define FUSE_IOCTL_RETRY	(1 << 2)
+-#define FUSE_IOCTL_DIR		(1 << 4)
++#define FUSE_IOCTL_COMPAT (1 << 0)
++#define FUSE_IOCTL_UNRESTRICTED (1 << 1)
++#define FUSE_IOCTL_RETRY (1 << 2)
++#define FUSE_IOCTL_DIR (1 << 4)
+ 
+-#define FUSE_IOCTL_MAX_IOV	256
++#define FUSE_IOCTL_MAX_IOV 256
+ 
+ /**
+  * Connection information, passed to the ->init() method
+@@ -355,114 +373,114 @@ struct fuse_file_info {
+  * value must usually be smaller than the indicated value.
+  */
+ struct fuse_conn_info {
+-	/**
+-	 * Major version of the protocol (read-only)
+-	 */
+-	unsigned proto_major;
+-
+-	/**
+-	 * Minor version of the protocol (read-only)
+-	 */
+-	unsigned proto_minor;
+-
+-	/**
+-	 * Maximum size of the write buffer
+-	 */
+-	unsigned max_write;
+-
+-	/**
+-	 * Maximum size of read requests. A value of zero indicates no
+-	 * limit. However, even if the filesystem does not specify a
+-	 * limit, the maximum size of read requests will still be
+-	 * limited by the kernel.
+-	 *
+-	 * NOTE: For the time being, the maximum size of read requests
+-	 * must be set both here *and* passed to fuse_session_new()
+-	 * using the ``-o max_read=<n>`` mount option. At some point
+-	 * in the future, specifying the mount option will no longer
+-	 * be necessary.
+-	 */
+-	unsigned max_read;
+-
+-	/**
+-	 * Maximum readahead
+-	 */
+-	unsigned max_readahead;
+-
+-	/**
+-	 * Capability flags that the kernel supports (read-only)
+-	 */
+-	unsigned capable;
+-
+-	/**
+-	 * Capability flags that the filesystem wants to enable.
+-	 *
+-	 * libfuse attempts to initialize this field with
+-	 * reasonable default values before calling the init() handler.
+-	 */
+-	unsigned want;
+-
+-	/**
+-	 * Maximum number of pending "background" requests. A
+-	 * background request is any type of request for which the
+-	 * total number is not limited by other means. As of kernel
+-	 * 4.8, only two types of requests fall into this category:
+-	 *
+-	 *   1. Read-ahead requests
+-	 *   2. Asynchronous direct I/O requests
+-	 *
+-	 * Read-ahead requests are generated (if max_readahead is
+-	 * non-zero) by the kernel to preemptively fill its caches
+-	 * when it anticipates that userspace will soon read more
+-	 * data.
+-	 *
+-	 * Asynchronous direct I/O requests are generated if
+-	 * FUSE_CAP_ASYNC_DIO is enabled and userspace submits a large
+-	 * direct I/O request. In this case the kernel will internally
+-	 * split it up into multiple smaller requests and submit them
+-	 * to the filesystem concurrently.
+-	 *
+-	 * Note that the following requests are *not* background
+-	 * requests: writeback requests (limited by the kernel's
+-	 * flusher algorithm), regular (i.e., synchronous and
+-	 * buffered) userspace read/write requests (limited to one per
+-	 * thread), asynchronous read requests (Linux's io_submit(2)
+-	 * call actually blocks, so these are also limited to one per
+-	 * thread).
+-	 */
+-	unsigned max_background;
+-
+-	/**
+-	 * Kernel congestion threshold parameter. If the number of pending
+-	 * background requests exceeds this number, the FUSE kernel module will
+-	 * mark the filesystem as "congested". This instructs the kernel to
+-	 * expect that queued requests will take some time to complete, and to
+-	 * adjust its algorithms accordingly (e.g. by putting a waiting thread
+-	 * to sleep instead of using a busy-loop).
+-	 */
+-	unsigned congestion_threshold;
+-
+-	/**
+-	 * When FUSE_CAP_WRITEBACK_CACHE is enabled, the kernel is responsible
+-	 * for updating mtime and ctime when write requests are received. The
+-	 * updated values are passed to the filesystem with setattr() requests.
+-	 * However, if the filesystem does not support the full resolution of
+-	 * the kernel timestamps (nanoseconds), the mtime and ctime values used
+-	 * by kernel and filesystem will differ (and result in an apparent
+-	 * change of times after a cache flush).
+-	 *
+-	 * To prevent this problem, this variable can be used to inform the
+-	 * kernel about the timestamp granularity supported by the file-system.
+-	 * The value should be power of 10.  The default is 1, i.e. full
+-	 * nano-second resolution. Filesystems supporting only second resolution
+-	 * should set this to 1000000000.
+-	 */
+-	unsigned time_gran;
+-
+-	/**
+-	 * For future use.
+-	 */
+-	unsigned reserved[22];
++    /**
++     * Major version of the protocol (read-only)
++     */
++    unsigned proto_major;
++
++    /**
++     * Minor version of the protocol (read-only)
++     */
++    unsigned proto_minor;
++
++    /**
++     * Maximum size of the write buffer
++     */
++    unsigned max_write;
++
++    /**
++     * Maximum size of read requests. A value of zero indicates no
++     * limit. However, even if the filesystem does not specify a
++     * limit, the maximum size of read requests will still be
++     * limited by the kernel.
++     *
++     * NOTE: For the time being, the maximum size of read requests
++     * must be set both here *and* passed to fuse_session_new()
++     * using the ``-o max_read=<n>`` mount option. At some point
++     * in the future, specifying the mount option will no longer
++     * be necessary.
++     */
++    unsigned max_read;
++
++    /**
++     * Maximum readahead
++     */
++    unsigned max_readahead;
++
++    /**
++     * Capability flags that the kernel supports (read-only)
++     */
++    unsigned capable;
++
++    /**
++     * Capability flags that the filesystem wants to enable.
++     *
++     * libfuse attempts to initialize this field with
++     * reasonable default values before calling the init() handler.
++     */
++    unsigned want;
++
++    /**
++     * Maximum number of pending "background" requests. A
++     * background request is any type of request for which the
++     * total number is not limited by other means. As of kernel
++     * 4.8, only two types of requests fall into this category:
++     *
++     *   1. Read-ahead requests
++     *   2. Asynchronous direct I/O requests
++     *
++     * Read-ahead requests are generated (if max_readahead is
++     * non-zero) by the kernel to preemptively fill its caches
++     * when it anticipates that userspace will soon read more
++     * data.
++     *
++     * Asynchronous direct I/O requests are generated if
++     * FUSE_CAP_ASYNC_DIO is enabled and userspace submits a large
++     * direct I/O request. In this case the kernel will internally
++     * split it up into multiple smaller requests and submit them
++     * to the filesystem concurrently.
++     *
++     * Note that the following requests are *not* background
++     * requests: writeback requests (limited by the kernel's
++     * flusher algorithm), regular (i.e., synchronous and
++     * buffered) userspace read/write requests (limited to one per
++     * thread), asynchronous read requests (Linux's io_submit(2)
++     * call actually blocks, so these are also limited to one per
++     * thread).
++     */
++    unsigned max_background;
++
++    /**
++     * Kernel congestion threshold parameter. If the number of pending
++     * background requests exceeds this number, the FUSE kernel module will
++     * mark the filesystem as "congested". This instructs the kernel to
++     * expect that queued requests will take some time to complete, and to
++     * adjust its algorithms accordingly (e.g. by putting a waiting thread
++     * to sleep instead of using a busy-loop).
++     */
++    unsigned congestion_threshold;
++
++    /**
++     * When FUSE_CAP_WRITEBACK_CACHE is enabled, the kernel is responsible
++     * for updating mtime and ctime when write requests are received. The
++     * updated values are passed to the filesystem with setattr() requests.
++     * However, if the filesystem does not support the full resolution of
++     * the kernel timestamps (nanoseconds), the mtime and ctime values used
++     * by kernel and filesystem will differ (and result in an apparent
++     * change of times after a cache flush).
++     *
++     * To prevent this problem, this variable can be used to inform the
++     * kernel about the timestamp granularity supported by the file-system.
++     * The value should be power of 10.  The default is 1, i.e. full
++     * nano-second resolution. Filesystems supporting only second resolution
++     * should set this to 1000000000.
++     */
++    unsigned time_gran;
++
++    /**
++     * For future use.
++     */
++    unsigned reserved[22];
+ };
+ 
+ struct fuse_session;
+@@ -489,21 +507,20 @@ struct fuse_conn_info_opts;
+  *   -o async_read          sets FUSE_CAP_ASYNC_READ in conn->want
+  *   -o sync_read           unsets FUSE_CAP_ASYNC_READ in conn->want
+  *   -o atomic_o_trunc      sets FUSE_CAP_ATOMIC_O_TRUNC in conn->want
+- *   -o no_remote_lock      Equivalent to -o no_remote_flock,no_remote_posix_lock
+- *   -o no_remote_flock     Unsets FUSE_CAP_FLOCK_LOCKS in conn->want
+- *   -o no_remote_posix_lock  Unsets FUSE_CAP_POSIX_LOCKS in conn->want
+- *   -o [no_]splice_write     (un-)sets FUSE_CAP_SPLICE_WRITE in conn->want
+- *   -o [no_]splice_move      (un-)sets FUSE_CAP_SPLICE_MOVE in conn->want
+- *   -o [no_]splice_read      (un-)sets FUSE_CAP_SPLICE_READ in conn->want
+- *   -o [no_]auto_inval_data  (un-)sets FUSE_CAP_AUTO_INVAL_DATA in conn->want
+- *   -o readdirplus=no        unsets FUSE_CAP_READDIRPLUS in conn->want
+- *   -o readdirplus=yes       sets FUSE_CAP_READDIRPLUS and unsets
+- *                            FUSE_CAP_READDIRPLUS_AUTO in conn->want
+- *   -o readdirplus=auto      sets FUSE_CAP_READDIRPLUS and
+- *                            FUSE_CAP_READDIRPLUS_AUTO in conn->want
+- *   -o [no_]async_dio        (un-)sets FUSE_CAP_ASYNC_DIO in conn->want
+- *   -o [no_]writeback_cache  (un-)sets FUSE_CAP_WRITEBACK_CACHE in conn->want
+- *   -o time_gran=N           sets conn->time_gran
++ *   -o no_remote_lock      Equivalent to -o
++ *no_remote_flock,no_remote_posix_lock -o no_remote_flock     Unsets
++ *FUSE_CAP_FLOCK_LOCKS in conn->want -o no_remote_posix_lock  Unsets
++ *FUSE_CAP_POSIX_LOCKS in conn->want -o [no_]splice_write     (un-)sets
++ *FUSE_CAP_SPLICE_WRITE in conn->want -o [no_]splice_move      (un-)sets
++ *FUSE_CAP_SPLICE_MOVE in conn->want -o [no_]splice_read      (un-)sets
++ *FUSE_CAP_SPLICE_READ in conn->want -o [no_]auto_inval_data  (un-)sets
++ *FUSE_CAP_AUTO_INVAL_DATA in conn->want -o readdirplus=no        unsets
++ *FUSE_CAP_READDIRPLUS in conn->want -o readdirplus=yes       sets
++ *FUSE_CAP_READDIRPLUS and unsets FUSE_CAP_READDIRPLUS_AUTO in conn->want -o
++ *readdirplus=auto      sets FUSE_CAP_READDIRPLUS and FUSE_CAP_READDIRPLUS_AUTO
++ *in conn->want -o [no_]async_dio        (un-)sets FUSE_CAP_ASYNC_DIO in
++ *conn->want -o [no_]writeback_cache  (un-)sets FUSE_CAP_WRITEBACK_CACHE in
++ *conn->want -o time_gran=N           sets conn->time_gran
+  *
+  * Known options will be removed from *args*, unknown options will be
+  * passed through unchanged.
+@@ -511,7 +528,7 @@ struct fuse_conn_info_opts;
+  * @param args argument vector (input+output)
+  * @return parsed options
+  **/
+-struct fuse_conn_info_opts* fuse_parse_conn_info_opts(struct fuse_args *args);
++struct fuse_conn_info_opts *fuse_parse_conn_info_opts(struct fuse_args *args);
+ 
+ /**
+  * This function applies the (parsed) parameters in *opts* to the
+@@ -521,7 +538,7 @@ struct fuse_conn_info_opts* fuse_parse_conn_info_opts(struct fuse_args *args);
+  * option has been explicitly set.
+  */
+ void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts,
+-			  struct fuse_conn_info *conn);
++                               struct fuse_conn_info *conn);
+ 
+ /**
+  * Go into the background
+@@ -552,81 +569,81 @@ const char *fuse_pkgversion(void);
+  */
+ void fuse_pollhandle_destroy(struct fuse_pollhandle *ph);
+ 
+-/* ----------------------------------------------------------- *
+- * Data buffer						       *
+- * ----------------------------------------------------------- */
++/*
++ * Data buffer
++ */
+ 
+ /**
+  * Buffer flags
+  */
+ enum fuse_buf_flags {
+-	/**
+-	 * Buffer contains a file descriptor
+-	 *
+-	 * If this flag is set, the .fd field is valid, otherwise the
+-	 * .mem fields is valid.
+-	 */
+-	FUSE_BUF_IS_FD		= (1 << 1),
+-
+-	/**
+-	 * Seek on the file descriptor
+-	 *
+-	 * If this flag is set then the .pos field is valid and is
+-	 * used to seek to the given offset before performing
+-	 * operation on file descriptor.
+-	 */
+-	FUSE_BUF_FD_SEEK	= (1 << 2),
+-
+-	/**
+-	 * Retry operation on file descriptor
+-	 *
+-	 * If this flag is set then retry operation on file descriptor
+-	 * until .size bytes have been copied or an error or EOF is
+-	 * detected.
+-	 */
+-	FUSE_BUF_FD_RETRY	= (1 << 3),
++    /**
++     * Buffer contains a file descriptor
++     *
++     * If this flag is set, the .fd field is valid, otherwise the
++     * .mem fields is valid.
++     */
++    FUSE_BUF_IS_FD = (1 << 1),
++
++    /**
++     * Seek on the file descriptor
++     *
++     * If this flag is set then the .pos field is valid and is
++     * used to seek to the given offset before performing
++     * operation on file descriptor.
++     */
++    FUSE_BUF_FD_SEEK = (1 << 2),
++
++    /**
++     * Retry operation on file descriptor
++     *
++     * If this flag is set then retry operation on file descriptor
++     * until .size bytes have been copied or an error or EOF is
++     * detected.
++     */
++    FUSE_BUF_FD_RETRY = (1 << 3),
+ };
+ 
+ /**
+  * Buffer copy flags
+  */
+ enum fuse_buf_copy_flags {
+-	/**
+-	 * Don't use splice(2)
+-	 *
+-	 * Always fall back to using read and write instead of
+-	 * splice(2) to copy data from one file descriptor to another.
+-	 *
+-	 * If this flag is not set, then only fall back if splice is
+-	 * unavailable.
+-	 */
+-	FUSE_BUF_NO_SPLICE	= (1 << 1),
+-
+-	/**
+-	 * Force splice
+-	 *
+-	 * Always use splice(2) to copy data from one file descriptor
+-	 * to another.  If splice is not available, return -EINVAL.
+-	 */
+-	FUSE_BUF_FORCE_SPLICE	= (1 << 2),
+-
+-	/**
+-	 * Try to move data with splice.
+-	 *
+-	 * If splice is used, try to move pages from the source to the
+-	 * destination instead of copying.  See documentation of
+-	 * SPLICE_F_MOVE in splice(2) man page.
+-	 */
+-	FUSE_BUF_SPLICE_MOVE	= (1 << 3),
+-
+-	/**
+-	 * Don't block on the pipe when copying data with splice
+-	 *
+-	 * Makes the operations on the pipe non-blocking (if the pipe
+-	 * is full or empty).  See SPLICE_F_NONBLOCK in the splice(2)
+-	 * man page.
+-	 */
+-	FUSE_BUF_SPLICE_NONBLOCK= (1 << 4),
++    /**
++     * Don't use splice(2)
++     *
++     * Always fall back to using read and write instead of
++     * splice(2) to copy data from one file descriptor to another.
++     *
++     * If this flag is not set, then only fall back if splice is
++     * unavailable.
++     */
++    FUSE_BUF_NO_SPLICE = (1 << 1),
++
++    /**
++     * Force splice
++     *
++     * Always use splice(2) to copy data from one file descriptor
++     * to another.  If splice is not available, return -EINVAL.
++     */
++    FUSE_BUF_FORCE_SPLICE = (1 << 2),
++
++    /**
++     * Try to move data with splice.
++     *
++     * If splice is used, try to move pages from the source to the
++     * destination instead of copying.  See documentation of
++     * SPLICE_F_MOVE in splice(2) man page.
++     */
++    FUSE_BUF_SPLICE_MOVE = (1 << 3),
++
++    /**
++     * Don't block on the pipe when copying data with splice
++     *
++     * Makes the operations on the pipe non-blocking (if the pipe
++     * is full or empty).  See SPLICE_F_NONBLOCK in the splice(2)
++     * man page.
++     */
++    FUSE_BUF_SPLICE_NONBLOCK = (1 << 4),
+ };
+ 
+ /**
+@@ -636,36 +653,36 @@ enum fuse_buf_copy_flags {
+  * be supplied as a memory pointer or as a file descriptor
+  */
+ struct fuse_buf {
+-	/**
+-	 * Size of data in bytes
+-	 */
+-	size_t size;
+-
+-	/**
+-	 * Buffer flags
+-	 */
+-	enum fuse_buf_flags flags;
+-
+-	/**
+-	 * Memory pointer
+-	 *
+-	 * Used unless FUSE_BUF_IS_FD flag is set.
+-	 */
+-	void *mem;
+-
+-	/**
+-	 * File descriptor
+-	 *
+-	 * Used if FUSE_BUF_IS_FD flag is set.
+-	 */
+-	int fd;
+-
+-	/**
+-	 * File position
+-	 *
+-	 * Used if FUSE_BUF_FD_SEEK flag is set.
+-	 */
+-	off_t pos;
++    /**
++     * Size of data in bytes
++     */
++    size_t size;
++
++    /**
++     * Buffer flags
++     */
++    enum fuse_buf_flags flags;
++
++    /**
++     * Memory pointer
++     *
++     * Used unless FUSE_BUF_IS_FD flag is set.
++     */
++    void *mem;
++
++    /**
++     * File descriptor
++     *
++     * Used if FUSE_BUF_IS_FD flag is set.
++     */
++    int fd;
++
++    /**
++     * File position
++     *
++     * Used if FUSE_BUF_FD_SEEK flag is set.
++     */
++    off_t pos;
+ };
+ 
+ /**
+@@ -677,41 +694,39 @@ struct fuse_buf {
+  * Allocate dynamically to add more than one buffer.
+  */
+ struct fuse_bufvec {
+-	/**
+-	 * Number of buffers in the array
+-	 */
+-	size_t count;
+-
+-	/**
+-	 * Index of current buffer within the array
+-	 */
+-	size_t idx;
+-
+-	/**
+-	 * Current offset within the current buffer
+-	 */
+-	size_t off;
+-
+-	/**
+-	 * Array of buffers
+-	 */
+-	struct fuse_buf buf[1];
++    /**
++     * Number of buffers in the array
++     */
++    size_t count;
++
++    /**
++     * Index of current buffer within the array
++     */
++    size_t idx;
++
++    /**
++     * Current offset within the current buffer
++     */
++    size_t off;
++
++    /**
++     * Array of buffers
++     */
++    struct fuse_buf buf[1];
+ };
+ 
+ /* Initialize bufvec with a single buffer of given size */
+-#define FUSE_BUFVEC_INIT(size__)				\
+-	((struct fuse_bufvec) {					\
+-		/* .count= */ 1,				\
+-		/* .idx =  */ 0,				\
+-		/* .off =  */ 0,				\
+-		/* .buf =  */ { /* [0] = */ {			\
+-			/* .size =  */ (size__),		\
+-			/* .flags = */ (enum fuse_buf_flags) 0,	\
+-			/* .mem =   */ NULL,			\
+-			/* .fd =    */ -1,			\
+-			/* .pos =   */ 0,			\
+-		} }						\
+-	} )
++#define FUSE_BUFVEC_INIT(size__)                                      \
++    ((struct fuse_bufvec){ /* .count= */ 1,                           \
++                           /* .idx =  */ 0,                           \
++                           /* .off =  */ 0, /* .buf =  */             \
++                           { /* [0] = */ {                            \
++                               /* .size =  */ (size__),               \
++                               /* .flags = */ (enum fuse_buf_flags)0, \
++                               /* .mem =   */ NULL,                   \
++                               /* .fd =    */ -1,                     \
++                               /* .pos =   */ 0,                      \
++                           } } })
+ 
+ /**
+  * Get total size of data in a fuse buffer vector
+@@ -730,16 +745,16 @@ size_t fuse_buf_size(const struct fuse_bufvec *bufv);
+  * @return actual number of bytes copied or -errno on error
+  */
+ ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src,
+-		      enum fuse_buf_copy_flags flags);
++                      enum fuse_buf_copy_flags flags);
+ 
+-/* ----------------------------------------------------------- *
+- * Signal handling					       *
+- * ----------------------------------------------------------- */
++/*
++ * Signal handling
++ */
+ 
+ /**
+  * Exit session on HUP, TERM and INT signals and ignore PIPE signal
+  *
+- * Stores session in a global variable.	 May only be called once per
++ * Stores session in a global variable. May only be called once per
+  * process until fuse_remove_signal_handlers() is called.
+  *
+  * Once either of the POSIX signals arrives, the signal handler calls
+@@ -766,12 +781,12 @@ int fuse_set_signal_handlers(struct fuse_session *se);
+  */
+ void fuse_remove_signal_handlers(struct fuse_session *se);
+ 
+-/* ----------------------------------------------------------- *
+- * Compatibility stuff					       *
+- * ----------------------------------------------------------- */
++/*
++ * Compatibility stuff
++ */
+ 
+ #if !defined(FUSE_USE_VERSION) || FUSE_USE_VERSION < 30
+-#  error only API version 30 or greater is supported
++#error only API version 30 or greater is supported
+ #endif
+ 
+ 
+@@ -781,11 +796,14 @@ void fuse_remove_signal_handlers(struct fuse_session *se);
+  * On 32bit systems please add -D_FILE_OFFSET_BITS=64 to your compile flags!
+  */
+ 
+-#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && !defined __cplusplus
++#if defined(__GNUC__) &&                                      \
++    (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && \
++    !defined __cplusplus
+ _Static_assert(sizeof(off_t) == 8, "fuse: off_t must be 64bit");
+ #else
+-struct _fuse_off_t_must_be_64bit_dummy_struct \
+-	{ unsigned _fuse_off_t_must_be_64bit:((sizeof(off_t) == 8) ? 1 : -1); };
++struct _fuse_off_t_must_be_64bit_dummy_struct {
++    unsigned _fuse_off_t_must_be_64bit:((sizeof(off_t) == 8) ? 1 : -1);
++};
+ #endif
+ 
+ #endif /* FUSE_COMMON_H_ */
+diff --git a/tools/virtiofsd/fuse_i.h b/tools/virtiofsd/fuse_i.h
+index b39522e3ca..e63cb58388 100644
+--- a/tools/virtiofsd/fuse_i.h
++++ b/tools/virtiofsd/fuse_i.h
+@@ -1,71 +1,71 @@
+ /*
+-  FUSE: Filesystem in Userspace
+-  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+-
+-  This program can be distributed under the terms of the GNU LGPLv2.
+-  See the file COPYING.LIB
+-*/
++ * FUSE: Filesystem in Userspace
++ * Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++ *
++ * This program can be distributed under the terms of the GNU LGPLv2.
++ * See the file COPYING.LIB
++ */
+ 
+ #include "fuse.h"
+ #include "fuse_lowlevel.h"
+ 
+ struct fuse_req {
+-	struct fuse_session *se;
+-	uint64_t unique;
+-	int ctr;
+-	pthread_mutex_t lock;
+-	struct fuse_ctx ctx;
+-	struct fuse_chan *ch;
+-	int interrupted;
+-	unsigned int ioctl_64bit : 1;
+-	union {
+-		struct {
+-			uint64_t unique;
+-		} i;
+-		struct {
+-			fuse_interrupt_func_t func;
+-			void *data;
+-		} ni;
+-	} u;
+-	struct fuse_req *next;
+-	struct fuse_req *prev;
++    struct fuse_session *se;
++    uint64_t unique;
++    int ctr;
++    pthread_mutex_t lock;
++    struct fuse_ctx ctx;
++    struct fuse_chan *ch;
++    int interrupted;
++    unsigned int ioctl_64bit:1;
++    union {
++        struct {
++            uint64_t unique;
++        } i;
++        struct {
++            fuse_interrupt_func_t func;
++            void *data;
++        } ni;
++    } u;
++    struct fuse_req *next;
++    struct fuse_req *prev;
+ };
+ 
+ struct fuse_notify_req {
+-	uint64_t unique;
+-	void (*reply)(struct fuse_notify_req *, fuse_req_t, fuse_ino_t,
+-		      const void *, const struct fuse_buf *);
+-	struct fuse_notify_req *next;
+-	struct fuse_notify_req *prev;
++    uint64_t unique;
++    void (*reply)(struct fuse_notify_req *, fuse_req_t, fuse_ino_t,
++                  const void *, const struct fuse_buf *);
++    struct fuse_notify_req *next;
++    struct fuse_notify_req *prev;
+ };
+ 
+ struct fuse_session {
+-	char *mountpoint;
+-	volatile int exited;
+-	int fd;
+-	int debug;
+-	int deny_others;
+-	struct fuse_lowlevel_ops op;
+-	int got_init;
+-	struct cuse_data *cuse_data;
+-	void *userdata;
+-	uid_t owner;
+-	struct fuse_conn_info conn;
+-	struct fuse_req list;
+-	struct fuse_req interrupts;
+-	pthread_mutex_t lock;
+-	int got_destroy;
+-	int broken_splice_nonblock;
+-	uint64_t notify_ctr;
+-	struct fuse_notify_req notify_list;
+-	size_t bufsize;
+-	int error;
++    char *mountpoint;
++    volatile int exited;
++    int fd;
++    int debug;
++    int deny_others;
++    struct fuse_lowlevel_ops op;
++    int got_init;
++    struct cuse_data *cuse_data;
++    void *userdata;
++    uid_t owner;
++    struct fuse_conn_info conn;
++    struct fuse_req list;
++    struct fuse_req interrupts;
++    pthread_mutex_t lock;
++    int got_destroy;
++    int broken_splice_nonblock;
++    uint64_t notify_ctr;
++    struct fuse_notify_req notify_list;
++    size_t bufsize;
++    int error;
+ };
+ 
+ struct fuse_chan {
+-	pthread_mutex_t lock;
+-	int ctr;
+-	int fd;
++    pthread_mutex_t lock;
++    int ctr;
++    int fd;
+ };
+ 
+ /**
+@@ -76,19 +76,20 @@ struct fuse_chan {
+  *
+  */
+ struct fuse_module {
+-	char *name;
+-	fuse_module_factory_t factory;
+-	struct fuse_module *next;
+-	struct fusemod_so *so;
+-	int ctr;
++    char *name;
++    fuse_module_factory_t factory;
++    struct fuse_module *next;
++    struct fusemod_so *so;
++    int ctr;
+ };
+ 
+ int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
+-			       int count);
++                               int count);
+ void fuse_free_req(fuse_req_t req);
+ 
+ void fuse_session_process_buf_int(struct fuse_session *se,
+-				  const struct fuse_buf *buf, struct fuse_chan *ch);
++                                  const struct fuse_buf *buf,
++                                  struct fuse_chan *ch);
+ 
+ 
+ #define FUSE_MAX_MAX_PAGES 256
+diff --git a/tools/virtiofsd/fuse_log.c b/tools/virtiofsd/fuse_log.c
+index 0d268ab014..11345f9ec8 100644
+--- a/tools/virtiofsd/fuse_log.c
++++ b/tools/virtiofsd/fuse_log.c
+@@ -1,40 +1,40 @@
+ /*
+-  FUSE: Filesystem in Userspace
+-  Copyright (C) 2019  Red Hat, Inc.
+-
+-  Logging API.
+-
+-  This program can be distributed under the terms of the GNU LGPLv2.
+-  See the file COPYING.LIB
+-*/
++ * FUSE: Filesystem in Userspace
++ * Copyright (C) 2019  Red Hat, Inc.
++ *
++ * Logging API.
++ *
++ * This program can be distributed under the terms of the GNU LGPLv2.
++ * See the file COPYING.LIB
++ */
+ 
+ #include "fuse_log.h"
+ 
+ #include <stdarg.h>
+ #include <stdio.h>
+ 
+-static void default_log_func(
+-		__attribute__(( unused )) enum fuse_log_level level,
+-		const char *fmt, va_list ap)
++static void default_log_func(__attribute__((unused)) enum fuse_log_level level,
++                             const char *fmt, va_list ap)
+ {
+-	vfprintf(stderr, fmt, ap);
++    vfprintf(stderr, fmt, ap);
+ }
+ 
+ static fuse_log_func_t log_func = default_log_func;
+ 
+ void fuse_set_log_func(fuse_log_func_t func)
+ {
+-	if (!func)
+-		func = default_log_func;
++    if (!func) {
++        func = default_log_func;
++    }
+ 
+-	log_func = func;
++    log_func = func;
+ }
+ 
+ void fuse_log(enum fuse_log_level level, const char *fmt, ...)
+ {
+-	va_list ap;
++    va_list ap;
+ 
+-	va_start(ap, fmt);
+-	log_func(level, fmt, ap);
+-	va_end(ap);
++    va_start(ap, fmt);
++    log_func(level, fmt, ap);
++    va_end(ap);
+ }
+diff --git a/tools/virtiofsd/fuse_log.h b/tools/virtiofsd/fuse_log.h
+index 0af700da6b..bf6c11ff11 100644
+--- a/tools/virtiofsd/fuse_log.h
++++ b/tools/virtiofsd/fuse_log.h
+@@ -1,10 +1,10 @@
+ /*
+-  FUSE: Filesystem in Userspace
+-  Copyright (C) 2019  Red Hat, Inc.
+-
+-  This program can be distributed under the terms of the GNU LGPLv2.
+-  See the file COPYING.LIB.
+-*/
++ * FUSE: Filesystem in Userspace
++ * Copyright (C) 2019  Red Hat, Inc.
++ *
++ * This program can be distributed under the terms of the GNU LGPLv2.
++ * See the file COPYING.LIB.
++ */
+ 
+ #ifndef FUSE_LOG_H_
+ #define FUSE_LOG_H_
+@@ -22,14 +22,14 @@
+  * These levels correspond to syslog(2) log levels since they are widely used.
+  */
+ enum fuse_log_level {
+-	FUSE_LOG_EMERG,
+-	FUSE_LOG_ALERT,
+-	FUSE_LOG_CRIT,
+-	FUSE_LOG_ERR,
+-	FUSE_LOG_WARNING,
+-	FUSE_LOG_NOTICE,
+-	FUSE_LOG_INFO,
+-	FUSE_LOG_DEBUG
++    FUSE_LOG_EMERG,
++    FUSE_LOG_ALERT,
++    FUSE_LOG_CRIT,
++    FUSE_LOG_ERR,
++    FUSE_LOG_WARNING,
++    FUSE_LOG_NOTICE,
++    FUSE_LOG_INFO,
++    FUSE_LOG_DEBUG
+ };
+ 
+ /**
+@@ -45,8 +45,8 @@ enum fuse_log_level {
+  * @param fmt sprintf-style format string including newline
+  * @param ap format string arguments
+  */
+-typedef void (*fuse_log_func_t)(enum fuse_log_level level,
+-				const char *fmt, va_list ap);
++typedef void (*fuse_log_func_t)(enum fuse_log_level level, const char *fmt,
++                                va_list ap);
+ 
+ /**
+  * Install a custom log handler function.
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index e6fa247924..5c9cb52f2a 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -1,2380 +1,2515 @@
+ /*
+-  FUSE: Filesystem in Userspace
+-  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+-
+-  Implementation of (most of) the low-level FUSE API. The session loop
+-  functions are implemented in separate files.
+-
+-  This program can be distributed under the terms of the GNU LGPLv2.
+-  See the file COPYING.LIB
+-*/
++ * FUSE: Filesystem in Userspace
++ * Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++ *
++ * Implementation of (most of) the low-level FUSE API. The session loop
++ * functions are implemented in separate files.
++ *
++ * This program can be distributed under the terms of the GNU LGPLv2.
++ * See the file COPYING.LIB
++ */
+ 
+ #define _GNU_SOURCE
+ 
+ #include "config.h"
+ #include "fuse_i.h"
+ #include "fuse_kernel.h"
+-#include "fuse_opt.h"
+ #include "fuse_misc.h"
++#include "fuse_opt.h"
+ 
++#include <assert.h>
++#include <errno.h>
++#include <limits.h>
++#include <stddef.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+-#include <stddef.h>
+ #include <string.h>
+-#include <unistd.h>
+-#include <limits.h>
+-#include <errno.h>
+-#include <assert.h>
+ #include <sys/file.h>
+-
++#include <unistd.h>
+ 
+ 
+ #define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
+ #define OFFSET_MAX 0x7fffffffffffffffLL
+ 
+-#define container_of(ptr, type, member) ({				\
+-			const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+-			(type *)( (char *)__mptr - offsetof(type,member) );})
++#define container_of(ptr, type, member)                    \
++    ({                                                     \
++        const typeof(((type *)0)->member) *__mptr = (ptr); \
++        (type *)((char *)__mptr - offsetof(type, member)); \
++    })
+ 
+ struct fuse_pollhandle {
+-	uint64_t kh;
+-	struct fuse_session *se;
++    uint64_t kh;
++    struct fuse_session *se;
+ };
+ 
+ static size_t pagesize;
+ 
+ static __attribute__((constructor)) void fuse_ll_init_pagesize(void)
+ {
+-	pagesize = getpagesize();
++    pagesize = getpagesize();
+ }
+ 
+ static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
+ {
+-	attr->ino	= stbuf->st_ino;
+-	attr->mode	= stbuf->st_mode;
+-	attr->nlink	= stbuf->st_nlink;
+-	attr->uid	= stbuf->st_uid;
+-	attr->gid	= stbuf->st_gid;
+-	attr->rdev	= stbuf->st_rdev;
+-	attr->size	= stbuf->st_size;
+-	attr->blksize	= stbuf->st_blksize;
+-	attr->blocks	= stbuf->st_blocks;
+-	attr->atime	= stbuf->st_atime;
+-	attr->mtime	= stbuf->st_mtime;
+-	attr->ctime	= stbuf->st_ctime;
+-	attr->atimensec = ST_ATIM_NSEC(stbuf);
+-	attr->mtimensec = ST_MTIM_NSEC(stbuf);
+-	attr->ctimensec = ST_CTIM_NSEC(stbuf);
++    attr->ino = stbuf->st_ino;
++    attr->mode = stbuf->st_mode;
++    attr->nlink = stbuf->st_nlink;
++    attr->uid = stbuf->st_uid;
++    attr->gid = stbuf->st_gid;
++    attr->rdev = stbuf->st_rdev;
++    attr->size = stbuf->st_size;
++    attr->blksize = stbuf->st_blksize;
++    attr->blocks = stbuf->st_blocks;
++    attr->atime = stbuf->st_atime;
++    attr->mtime = stbuf->st_mtime;
++    attr->ctime = stbuf->st_ctime;
++    attr->atimensec = ST_ATIM_NSEC(stbuf);
++    attr->mtimensec = ST_MTIM_NSEC(stbuf);
++    attr->ctimensec = ST_CTIM_NSEC(stbuf);
+ }
+ 
+ static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
+ {
+-	stbuf->st_mode	       = attr->mode;
+-	stbuf->st_uid	       = attr->uid;
+-	stbuf->st_gid	       = attr->gid;
+-	stbuf->st_size	       = attr->size;
+-	stbuf->st_atime	       = attr->atime;
+-	stbuf->st_mtime	       = attr->mtime;
+-	stbuf->st_ctime        = attr->ctime;
+-	ST_ATIM_NSEC_SET(stbuf, attr->atimensec);
+-	ST_MTIM_NSEC_SET(stbuf, attr->mtimensec);
+-	ST_CTIM_NSEC_SET(stbuf, attr->ctimensec);
++    stbuf->st_mode = attr->mode;
++    stbuf->st_uid = attr->uid;
++    stbuf->st_gid = attr->gid;
++    stbuf->st_size = attr->size;
++    stbuf->st_atime = attr->atime;
++    stbuf->st_mtime = attr->mtime;
++    stbuf->st_ctime = attr->ctime;
++    ST_ATIM_NSEC_SET(stbuf, attr->atimensec);
++    ST_MTIM_NSEC_SET(stbuf, attr->mtimensec);
++    ST_CTIM_NSEC_SET(stbuf, attr->ctimensec);
+ }
+ 
+-static	size_t iov_length(const struct iovec *iov, size_t count)
++static size_t iov_length(const struct iovec *iov, size_t count)
+ {
+-	size_t seg;
+-	size_t ret = 0;
++    size_t seg;
++    size_t ret = 0;
+ 
+-	for (seg = 0; seg < count; seg++)
+-		ret += iov[seg].iov_len;
+-	return ret;
++    for (seg = 0; seg < count; seg++) {
++        ret += iov[seg].iov_len;
++    }
++    return ret;
+ }
+ 
+ static void list_init_req(struct fuse_req *req)
+ {
+-	req->next = req;
+-	req->prev = req;
++    req->next = req;
++    req->prev = req;
+ }
+ 
+ static void list_del_req(struct fuse_req *req)
+ {
+-	struct fuse_req *prev = req->prev;
+-	struct fuse_req *next = req->next;
+-	prev->next = next;
+-	next->prev = prev;
++    struct fuse_req *prev = req->prev;
++    struct fuse_req *next = req->next;
++    prev->next = next;
++    next->prev = prev;
+ }
+ 
+ static void list_add_req(struct fuse_req *req, struct fuse_req *next)
+ {
+-	struct fuse_req *prev = next->prev;
+-	req->next = next;
+-	req->prev = prev;
+-	prev->next = req;
+-	next->prev = req;
++    struct fuse_req *prev = next->prev;
++    req->next = next;
++    req->prev = prev;
++    prev->next = req;
++    next->prev = req;
+ }
+ 
+ static void destroy_req(fuse_req_t req)
+ {
+-	pthread_mutex_destroy(&req->lock);
+-	free(req);
++    pthread_mutex_destroy(&req->lock);
++    free(req);
+ }
+ 
+ void fuse_free_req(fuse_req_t req)
+ {
+-	int ctr;
+-	struct fuse_session *se = req->se;
++    int ctr;
++    struct fuse_session *se = req->se;
+ 
+-	pthread_mutex_lock(&se->lock);
+-	req->u.ni.func = NULL;
+-	req->u.ni.data = NULL;
+-	list_del_req(req);
+-	ctr = --req->ctr;
+-	req->ch = NULL;
+-	pthread_mutex_unlock(&se->lock);
+-	if (!ctr)
+-		destroy_req(req);
++    pthread_mutex_lock(&se->lock);
++    req->u.ni.func = NULL;
++    req->u.ni.data = NULL;
++    list_del_req(req);
++    ctr = --req->ctr;
++    req->ch = NULL;
++    pthread_mutex_unlock(&se->lock);
++    if (!ctr) {
++        destroy_req(req);
++    }
+ }
+ 
+ static struct fuse_req *fuse_ll_alloc_req(struct fuse_session *se)
+ {
+-	struct fuse_req *req;
++    struct fuse_req *req;
+ 
+-	req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req));
+-	if (req == NULL) {
+-		fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate request\n");
+-	} else {
+-		req->se = se;
+-		req->ctr = 1;
+-		list_init_req(req);
+-		fuse_mutex_init(&req->lock);
+-	}
++    req = (struct fuse_req *)calloc(1, sizeof(struct fuse_req));
++    if (req == NULL) {
++        fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate request\n");
++    } else {
++        req->se = se;
++        req->ctr = 1;
++        list_init_req(req);
++        fuse_mutex_init(&req->lock);
++    }
+ 
+-	return req;
++    return req;
+ }
+ 
+ /* Send data. If *ch* is NULL, send via session master fd */
+ static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
+-			 struct iovec *iov, int count)
++                         struct iovec *iov, int count)
+ {
+-	struct fuse_out_header *out = iov[0].iov_base;
++    struct fuse_out_header *out = iov[0].iov_base;
+ 
+-	out->len = iov_length(iov, count);
+-	if (se->debug) {
+-		if (out->unique == 0) {
+-			fuse_log(FUSE_LOG_DEBUG, "NOTIFY: code=%d length=%u\n",
+-				out->error, out->len);
+-		} else if (out->error) {
+-			fuse_log(FUSE_LOG_DEBUG,
+-				"   unique: %llu, error: %i (%s), outsize: %i\n",
+-				(unsigned long long) out->unique, out->error,
+-				strerror(-out->error), out->len);
+-		} else {
+-			fuse_log(FUSE_LOG_DEBUG,
+-				"   unique: %llu, success, outsize: %i\n",
+-				(unsigned long long) out->unique, out->len);
+-		}
+-	}
++    out->len = iov_length(iov, count);
++    if (se->debug) {
++        if (out->unique == 0) {
++            fuse_log(FUSE_LOG_DEBUG, "NOTIFY: code=%d length=%u\n", out->error,
++                     out->len);
++        } else if (out->error) {
++            fuse_log(FUSE_LOG_DEBUG,
++                     "   unique: %llu, error: %i (%s), outsize: %i\n",
++                     (unsigned long long)out->unique, out->error,
++                     strerror(-out->error), out->len);
++        } else {
++            fuse_log(FUSE_LOG_DEBUG, "   unique: %llu, success, outsize: %i\n",
++                     (unsigned long long)out->unique, out->len);
++        }
++    }
+ 
+-	abort(); /* virtio should have taken it before here */
+-	return 0;
++    abort(); /* virtio should have taken it before here */
++    return 0;
+ }
+ 
+ 
+ int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
+-			       int count)
++                               int count)
+ {
+-	struct fuse_out_header out;
++    struct fuse_out_header out;
+ 
+-	if (error <= -1000 || error > 0) {
+-		fuse_log(FUSE_LOG_ERR, "fuse: bad error value: %i\n",	error);
+-		error = -ERANGE;
+-	}
++    if (error <= -1000 || error > 0) {
++        fuse_log(FUSE_LOG_ERR, "fuse: bad error value: %i\n", error);
++        error = -ERANGE;
++    }
+ 
+-	out.unique = req->unique;
+-	out.error = error;
++    out.unique = req->unique;
++    out.error = error;
+ 
+-	iov[0].iov_base = &out;
+-	iov[0].iov_len = sizeof(struct fuse_out_header);
++    iov[0].iov_base = &out;
++    iov[0].iov_len = sizeof(struct fuse_out_header);
+ 
+-	return fuse_send_msg(req->se, req->ch, iov, count);
++    return fuse_send_msg(req->se, req->ch, iov, count);
+ }
+ 
+ static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov,
+-			  int count)
++                          int count)
+ {
+-	int res;
++    int res;
+ 
+-	res = fuse_send_reply_iov_nofree(req, error, iov, count);
+-	fuse_free_req(req);
+-	return res;
++    res = fuse_send_reply_iov_nofree(req, error, iov, count);
++    fuse_free_req(req);
++    return res;
+ }
+ 
+ static int send_reply(fuse_req_t req, int error, const void *arg,
+-		      size_t argsize)
++                      size_t argsize)
+ {
+-	struct iovec iov[2];
+-	int count = 1;
+-	if (argsize) {
+-		iov[1].iov_base = (void *) arg;
+-		iov[1].iov_len = argsize;
+-		count++;
+-	}
+-	return send_reply_iov(req, error, iov, count);
++    struct iovec iov[2];
++    int count = 1;
++    if (argsize) {
++        iov[1].iov_base = (void *)arg;
++        iov[1].iov_len = argsize;
++        count++;
++    }
++    return send_reply_iov(req, error, iov, count);
+ }
+ 
+ int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
+ {
+-	int res;
+-	struct iovec *padded_iov;
++    int res;
++    struct iovec *padded_iov;
+ 
+-	padded_iov = malloc((count + 1) * sizeof(struct iovec));
+-	if (padded_iov == NULL)
+-		return fuse_reply_err(req, ENOMEM);
++    padded_iov = malloc((count + 1) * sizeof(struct iovec));
++    if (padded_iov == NULL) {
++        return fuse_reply_err(req, ENOMEM);
++    }
+ 
+-	memcpy(padded_iov + 1, iov, count * sizeof(struct iovec));
+-	count++;
++    memcpy(padded_iov + 1, iov, count * sizeof(struct iovec));
++    count++;
+ 
+-	res = send_reply_iov(req, 0, padded_iov, count);
+-	free(padded_iov);
++    res = send_reply_iov(req, 0, padded_iov, count);
++    free(padded_iov);
+ 
+-	return res;
++    return res;
+ }
+ 
+ 
+-/* `buf` is allowed to be empty so that the proper size may be
+-   allocated by the caller */
++/*
++ * 'buf` is allowed to be empty so that the proper size may be
++ * allocated by the caller
++ */
+ size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
+-			 const char *name, const struct stat *stbuf, off_t off)
++                         const char *name, const struct stat *stbuf, off_t off)
+ {
+-	(void)req;
+-	size_t namelen;
+-	size_t entlen;
+-	size_t entlen_padded;
+-	struct fuse_dirent *dirent;
++    (void)req;
++    size_t namelen;
++    size_t entlen;
++    size_t entlen_padded;
++    struct fuse_dirent *dirent;
+ 
+-	namelen = strlen(name);
+-	entlen = FUSE_NAME_OFFSET + namelen;
+-	entlen_padded = FUSE_DIRENT_ALIGN(entlen);
++    namelen = strlen(name);
++    entlen = FUSE_NAME_OFFSET + namelen;
++    entlen_padded = FUSE_DIRENT_ALIGN(entlen);
+ 
+-	if ((buf == NULL) || (entlen_padded > bufsize))
+-	  return entlen_padded;
++    if ((buf == NULL) || (entlen_padded > bufsize)) {
++        return entlen_padded;
++    }
+ 
+-	dirent = (struct fuse_dirent*) buf;
+-	dirent->ino = stbuf->st_ino;
+-	dirent->off = off;
+-	dirent->namelen = namelen;
+-	dirent->type = (stbuf->st_mode & S_IFMT) >> 12;
+-	memcpy(dirent->name, name, namelen);
+-	memset(dirent->name + namelen, 0, entlen_padded - entlen);
++    dirent = (struct fuse_dirent *)buf;
++    dirent->ino = stbuf->st_ino;
++    dirent->off = off;
++    dirent->namelen = namelen;
++    dirent->type = (stbuf->st_mode & S_IFMT) >> 12;
++    memcpy(dirent->name, name, namelen);
++    memset(dirent->name + namelen, 0, entlen_padded - entlen);
+ 
+-	return entlen_padded;
++    return entlen_padded;
+ }
+ 
+ static void convert_statfs(const struct statvfs *stbuf,
+-			   struct fuse_kstatfs *kstatfs)
++                           struct fuse_kstatfs *kstatfs)
+ {
+-	kstatfs->bsize	 = stbuf->f_bsize;
+-	kstatfs->frsize	 = stbuf->f_frsize;
+-	kstatfs->blocks	 = stbuf->f_blocks;
+-	kstatfs->bfree	 = stbuf->f_bfree;
+-	kstatfs->bavail	 = stbuf->f_bavail;
+-	kstatfs->files	 = stbuf->f_files;
+-	kstatfs->ffree	 = stbuf->f_ffree;
+-	kstatfs->namelen = stbuf->f_namemax;
++    kstatfs->bsize = stbuf->f_bsize;
++    kstatfs->frsize = stbuf->f_frsize;
++    kstatfs->blocks = stbuf->f_blocks;
++    kstatfs->bfree = stbuf->f_bfree;
++    kstatfs->bavail = stbuf->f_bavail;
++    kstatfs->files = stbuf->f_files;
++    kstatfs->ffree = stbuf->f_ffree;
++    kstatfs->namelen = stbuf->f_namemax;
+ }
+ 
+ static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
+ {
+-	return send_reply(req, 0, arg, argsize);
++    return send_reply(req, 0, arg, argsize);
+ }
+ 
+ int fuse_reply_err(fuse_req_t req, int err)
+ {
+-	return send_reply(req, -err, NULL, 0);
++    return send_reply(req, -err, NULL, 0);
+ }
+ 
+ void fuse_reply_none(fuse_req_t req)
+ {
+-	fuse_free_req(req);
++    fuse_free_req(req);
+ }
+ 
+ static unsigned long calc_timeout_sec(double t)
+ {
+-	if (t > (double) ULONG_MAX)
+-		return ULONG_MAX;
+-	else if (t < 0.0)
+-		return 0;
+-	else
+-		return (unsigned long) t;
++    if (t > (double)ULONG_MAX) {
++        return ULONG_MAX;
++    } else if (t < 0.0) {
++        return 0;
++    } else {
++        return (unsigned long)t;
++    }
+ }
+ 
+ static unsigned int calc_timeout_nsec(double t)
+ {
+-	double f = t - (double) calc_timeout_sec(t);
+-	if (f < 0.0)
+-		return 0;
+-	else if (f >= 0.999999999)
+-		return 999999999;
+-	else
+-		return (unsigned int) (f * 1.0e9);
++    double f = t - (double)calc_timeout_sec(t);
++    if (f < 0.0) {
++        return 0;
++    } else if (f >= 0.999999999) {
++        return 999999999;
++    } else {
++        return (unsigned int)(f * 1.0e9);
++    }
+ }
+ 
+ static void fill_entry(struct fuse_entry_out *arg,
+-		       const struct fuse_entry_param *e)
++                       const struct fuse_entry_param *e)
+ {
+-	arg->nodeid = e->ino;
+-	arg->generation = e->generation;
+-	arg->entry_valid = calc_timeout_sec(e->entry_timeout);
+-	arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
+-	arg->attr_valid = calc_timeout_sec(e->attr_timeout);
+-	arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
+-	convert_stat(&e->attr, &arg->attr);
++    arg->nodeid = e->ino;
++    arg->generation = e->generation;
++    arg->entry_valid = calc_timeout_sec(e->entry_timeout);
++    arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
++    arg->attr_valid = calc_timeout_sec(e->attr_timeout);
++    arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
++    convert_stat(&e->attr, &arg->attr);
+ }
+ 
+-/* `buf` is allowed to be empty so that the proper size may be
+-   allocated by the caller */
++/*
++ * `buf` is allowed to be empty so that the proper size may be
++ * allocated by the caller
++ */
+ size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
+-			      const char *name,
+-			      const struct fuse_entry_param *e, off_t off)
+-{
+-	(void)req;
+-	size_t namelen;
+-	size_t entlen;
+-	size_t entlen_padded;
+-
+-	namelen = strlen(name);
+-	entlen = FUSE_NAME_OFFSET_DIRENTPLUS + namelen;
+-	entlen_padded = FUSE_DIRENT_ALIGN(entlen);
+-	if ((buf == NULL) || (entlen_padded > bufsize))
+-	  return entlen_padded;
+-
+-	struct fuse_direntplus *dp = (struct fuse_direntplus *) buf;
+-	memset(&dp->entry_out, 0, sizeof(dp->entry_out));
+-	fill_entry(&dp->entry_out, e);
+-
+-	struct fuse_dirent *dirent = &dp->dirent;
+-	dirent->ino = e->attr.st_ino;
+-	dirent->off = off;
+-	dirent->namelen = namelen;
+-	dirent->type = (e->attr.st_mode & S_IFMT) >> 12;
+-	memcpy(dirent->name, name, namelen);
+-	memset(dirent->name + namelen, 0, entlen_padded - entlen);
+-
+-	return entlen_padded;
+-}
+-
+-static void fill_open(struct fuse_open_out *arg,
+-		      const struct fuse_file_info *f)
+-{
+-	arg->fh = f->fh;
+-	if (f->direct_io)
+-		arg->open_flags |= FOPEN_DIRECT_IO;
+-	if (f->keep_cache)
+-		arg->open_flags |= FOPEN_KEEP_CACHE;
+-	if (f->cache_readdir)
+-		arg->open_flags |= FOPEN_CACHE_DIR;
+-	if (f->nonseekable)
+-		arg->open_flags |= FOPEN_NONSEEKABLE;
++                              const char *name,
++                              const struct fuse_entry_param *e, off_t off)
++{
++    (void)req;
++    size_t namelen;
++    size_t entlen;
++    size_t entlen_padded;
++
++    namelen = strlen(name);
++    entlen = FUSE_NAME_OFFSET_DIRENTPLUS + namelen;
++    entlen_padded = FUSE_DIRENT_ALIGN(entlen);
++    if ((buf == NULL) || (entlen_padded > bufsize)) {
++        return entlen_padded;
++    }
++
++    struct fuse_direntplus *dp = (struct fuse_direntplus *)buf;
++    memset(&dp->entry_out, 0, sizeof(dp->entry_out));
++    fill_entry(&dp->entry_out, e);
++
++    struct fuse_dirent *dirent = &dp->dirent;
++    dirent->ino = e->attr.st_ino;
++    dirent->off = off;
++    dirent->namelen = namelen;
++    dirent->type = (e->attr.st_mode & S_IFMT) >> 12;
++    memcpy(dirent->name, name, namelen);
++    memset(dirent->name + namelen, 0, entlen_padded - entlen);
++
++    return entlen_padded;
++}
++
++static void fill_open(struct fuse_open_out *arg, const struct fuse_file_info *f)
++{
++    arg->fh = f->fh;
++    if (f->direct_io) {
++        arg->open_flags |= FOPEN_DIRECT_IO;
++    }
++    if (f->keep_cache) {
++        arg->open_flags |= FOPEN_KEEP_CACHE;
++    }
++    if (f->cache_readdir) {
++        arg->open_flags |= FOPEN_CACHE_DIR;
++    }
++    if (f->nonseekable) {
++        arg->open_flags |= FOPEN_NONSEEKABLE;
++    }
+ }
+ 
+ int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
+ {
+-	struct fuse_entry_out arg;
+-	size_t size = req->se->conn.proto_minor < 9 ?
+-		FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg);
++    struct fuse_entry_out arg;
++    size_t size = req->se->conn.proto_minor < 9 ? FUSE_COMPAT_ENTRY_OUT_SIZE :
++                                                  sizeof(arg);
+ 
+-	/* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
+-	   negative entry */
+-	if (!e->ino && req->se->conn.proto_minor < 4)
+-		return fuse_reply_err(req, ENOENT);
++    /*
++     * before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
++     * negative entry
++     */
++    if (!e->ino && req->se->conn.proto_minor < 4) {
++        return fuse_reply_err(req, ENOENT);
++    }
+ 
+-	memset(&arg, 0, sizeof(arg));
+-	fill_entry(&arg, e);
+-	return send_reply_ok(req, &arg, size);
++    memset(&arg, 0, sizeof(arg));
++    fill_entry(&arg, e);
++    return send_reply_ok(req, &arg, size);
+ }
+ 
+ int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
+-		      const struct fuse_file_info *f)
++                      const struct fuse_file_info *f)
+ {
+-	char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)];
+-	size_t entrysize = req->se->conn.proto_minor < 9 ?
+-		FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(struct fuse_entry_out);
+-	struct fuse_entry_out *earg = (struct fuse_entry_out *) buf;
+-	struct fuse_open_out *oarg = (struct fuse_open_out *) (buf + entrysize);
++    char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)];
++    size_t entrysize = req->se->conn.proto_minor < 9 ?
++                           FUSE_COMPAT_ENTRY_OUT_SIZE :
++                           sizeof(struct fuse_entry_out);
++    struct fuse_entry_out *earg = (struct fuse_entry_out *)buf;
++    struct fuse_open_out *oarg = (struct fuse_open_out *)(buf + entrysize);
+ 
+-	memset(buf, 0, sizeof(buf));
+-	fill_entry(earg, e);
+-	fill_open(oarg, f);
+-	return send_reply_ok(req, buf,
+-			     entrysize + sizeof(struct fuse_open_out));
++    memset(buf, 0, sizeof(buf));
++    fill_entry(earg, e);
++    fill_open(oarg, f);
++    return send_reply_ok(req, buf, entrysize + sizeof(struct fuse_open_out));
+ }
+ 
+ int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
+-		    double attr_timeout)
++                    double attr_timeout)
+ {
+-	struct fuse_attr_out arg;
+-	size_t size = req->se->conn.proto_minor < 9 ?
+-		FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg);
++    struct fuse_attr_out arg;
++    size_t size =
++        req->se->conn.proto_minor < 9 ? FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg);
+ 
+-	memset(&arg, 0, sizeof(arg));
+-	arg.attr_valid = calc_timeout_sec(attr_timeout);
+-	arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
+-	convert_stat(attr, &arg.attr);
++    memset(&arg, 0, sizeof(arg));
++    arg.attr_valid = calc_timeout_sec(attr_timeout);
++    arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
++    convert_stat(attr, &arg.attr);
+ 
+-	return send_reply_ok(req, &arg, size);
++    return send_reply_ok(req, &arg, size);
+ }
+ 
+ int fuse_reply_readlink(fuse_req_t req, const char *linkname)
+ {
+-	return send_reply_ok(req, linkname, strlen(linkname));
++    return send_reply_ok(req, linkname, strlen(linkname));
+ }
+ 
+ int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
+ {
+-	struct fuse_open_out arg;
++    struct fuse_open_out arg;
+ 
+-	memset(&arg, 0, sizeof(arg));
+-	fill_open(&arg, f);
+-	return send_reply_ok(req, &arg, sizeof(arg));
++    memset(&arg, 0, sizeof(arg));
++    fill_open(&arg, f);
++    return send_reply_ok(req, &arg, sizeof(arg));
+ }
+ 
+ int fuse_reply_write(fuse_req_t req, size_t count)
+ {
+-	struct fuse_write_out arg;
++    struct fuse_write_out arg;
+ 
+-	memset(&arg, 0, sizeof(arg));
+-	arg.size = count;
++    memset(&arg, 0, sizeof(arg));
++    arg.size = count;
+ 
+-	return send_reply_ok(req, &arg, sizeof(arg));
++    return send_reply_ok(req, &arg, sizeof(arg));
+ }
+ 
+ int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
+ {
+-	return send_reply_ok(req, buf, size);
++    return send_reply_ok(req, buf, size);
+ }
+ 
+ static int fuse_send_data_iov_fallback(struct fuse_session *se,
+-				       struct fuse_chan *ch,
+-				       struct iovec *iov, int iov_count,
+-				       struct fuse_bufvec *buf,
+-				       size_t len)
++                                       struct fuse_chan *ch, struct iovec *iov,
++                                       int iov_count, struct fuse_bufvec *buf,
++                                       size_t len)
+ {
+-	/* Optimize common case */
+-	if (buf->count == 1 && buf->idx == 0 && buf->off == 0 &&
+-	    !(buf->buf[0].flags & FUSE_BUF_IS_FD)) {
+-		/* FIXME: also avoid memory copy if there are multiple buffers
+-		   but none of them contain an fd */
++    /* Optimize common case */
++    if (buf->count == 1 && buf->idx == 0 && buf->off == 0 &&
++        !(buf->buf[0].flags & FUSE_BUF_IS_FD)) {
++        /*
++         * FIXME: also avoid memory copy if there are multiple buffers
++         * but none of them contain an fd
++         */
+ 
+-		iov[iov_count].iov_base = buf->buf[0].mem;
+-		iov[iov_count].iov_len = len;
+-		iov_count++;
+-		return fuse_send_msg(se, ch, iov, iov_count);
+-	}
++        iov[iov_count].iov_base = buf->buf[0].mem;
++        iov[iov_count].iov_len = len;
++        iov_count++;
++        return fuse_send_msg(se, ch, iov, iov_count);
++    }
+ 
+-	abort(); /* Will have taken vhost path */
+-	return 0;
++    abort(); /* Will have taken vhost path */
++    return 0;
+ }
+ 
+ static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
+-			       struct iovec *iov, int iov_count,
+-			       struct fuse_bufvec *buf, unsigned int flags)
++                              struct iovec *iov, int iov_count,
++                              struct fuse_bufvec *buf, unsigned int flags)
+ {
+-	size_t len = fuse_buf_size(buf);
+-	(void) flags;
++    size_t len = fuse_buf_size(buf);
++    (void)flags;
+ 
+-	return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
++    return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
+ }
+ 
+ int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
+-		    enum fuse_buf_copy_flags flags)
++                    enum fuse_buf_copy_flags flags)
+ {
+-	struct iovec iov[2];
+-	struct fuse_out_header out;
+-	int res;
++    struct iovec iov[2];
++    struct fuse_out_header out;
++    int res;
+ 
+-	iov[0].iov_base = &out;
+-	iov[0].iov_len = sizeof(struct fuse_out_header);
++    iov[0].iov_base = &out;
++    iov[0].iov_len = sizeof(struct fuse_out_header);
+ 
+-	out.unique = req->unique;
+-	out.error = 0;
++    out.unique = req->unique;
++    out.error = 0;
+ 
+-	res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags);
+-	if (res <= 0) {
+-		fuse_free_req(req);
+-		return res;
+-	} else {
+-		return fuse_reply_err(req, res);
+-	}
++    res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags);
++    if (res <= 0) {
++        fuse_free_req(req);
++        return res;
++    } else {
++        return fuse_reply_err(req, res);
++    }
+ }
+ 
+ int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
+ {
+-	struct fuse_statfs_out arg;
+-	size_t size = req->se->conn.proto_minor < 4 ?
+-		FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
++    struct fuse_statfs_out arg;
++    size_t size =
++        req->se->conn.proto_minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
+ 
+-	memset(&arg, 0, sizeof(arg));
+-	convert_statfs(stbuf, &arg.st);
++    memset(&arg, 0, sizeof(arg));
++    convert_statfs(stbuf, &arg.st);
+ 
+-	return send_reply_ok(req, &arg, size);
++    return send_reply_ok(req, &arg, size);
+ }
+ 
+ int fuse_reply_xattr(fuse_req_t req, size_t count)
+ {
+-	struct fuse_getxattr_out arg;
++    struct fuse_getxattr_out arg;
+ 
+-	memset(&arg, 0, sizeof(arg));
+-	arg.size = count;
++    memset(&arg, 0, sizeof(arg));
++    arg.size = count;
+ 
+-	return send_reply_ok(req, &arg, sizeof(arg));
++    return send_reply_ok(req, &arg, sizeof(arg));
+ }
+ 
+ int fuse_reply_lock(fuse_req_t req, const struct flock *lock)
+ {
+-	struct fuse_lk_out arg;
++    struct fuse_lk_out arg;
+ 
+-	memset(&arg, 0, sizeof(arg));
+-	arg.lk.type = lock->l_type;
+-	if (lock->l_type != F_UNLCK) {
+-		arg.lk.start = lock->l_start;
+-		if (lock->l_len == 0)
+-			arg.lk.end = OFFSET_MAX;
+-		else
+-			arg.lk.end = lock->l_start + lock->l_len - 1;
+-	}
+-	arg.lk.pid = lock->l_pid;
+-	return send_reply_ok(req, &arg, sizeof(arg));
++    memset(&arg, 0, sizeof(arg));
++    arg.lk.type = lock->l_type;
++    if (lock->l_type != F_UNLCK) {
++        arg.lk.start = lock->l_start;
++        if (lock->l_len == 0) {
++            arg.lk.end = OFFSET_MAX;
++        } else {
++            arg.lk.end = lock->l_start + lock->l_len - 1;
++        }
++    }
++    arg.lk.pid = lock->l_pid;
++    return send_reply_ok(req, &arg, sizeof(arg));
+ }
+ 
+ int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
+ {
+-	struct fuse_bmap_out arg;
++    struct fuse_bmap_out arg;
+ 
+-	memset(&arg, 0, sizeof(arg));
+-	arg.block = idx;
++    memset(&arg, 0, sizeof(arg));
++    arg.block = idx;
+ 
+-	return send_reply_ok(req, &arg, sizeof(arg));
++    return send_reply_ok(req, &arg, sizeof(arg));
+ }
+ 
+ static struct fuse_ioctl_iovec *fuse_ioctl_iovec_copy(const struct iovec *iov,
+-						      size_t count)
+-{
+-	struct fuse_ioctl_iovec *fiov;
+-	size_t i;
+-
+-	fiov = malloc(sizeof(fiov[0]) * count);
+-	if (!fiov)
+-		return NULL;
+-
+-	for (i = 0; i < count; i++) {
+-		fiov[i].base = (uintptr_t) iov[i].iov_base;
+-		fiov[i].len = iov[i].iov_len;
+-	}
+-
+-	return fiov;
+-}
+-
+-int fuse_reply_ioctl_retry(fuse_req_t req,
+-			   const struct iovec *in_iov, size_t in_count,
+-			   const struct iovec *out_iov, size_t out_count)
+-{
+-	struct fuse_ioctl_out arg;
+-	struct fuse_ioctl_iovec *in_fiov = NULL;
+-	struct fuse_ioctl_iovec *out_fiov = NULL;
+-	struct iovec iov[4];
+-	size_t count = 1;
+-	int res;
+-
+-	memset(&arg, 0, sizeof(arg));
+-	arg.flags |= FUSE_IOCTL_RETRY;
+-	arg.in_iovs = in_count;
+-	arg.out_iovs = out_count;
+-	iov[count].iov_base = &arg;
+-	iov[count].iov_len = sizeof(arg);
+-	count++;
+-
+-	if (req->se->conn.proto_minor < 16) {
+-		if (in_count) {
+-			iov[count].iov_base = (void *)in_iov;
+-			iov[count].iov_len = sizeof(in_iov[0]) * in_count;
+-			count++;
+-		}
+-
+-		if (out_count) {
+-			iov[count].iov_base = (void *)out_iov;
+-			iov[count].iov_len = sizeof(out_iov[0]) * out_count;
+-			count++;
+-		}
+-	} else {
+-		/* Can't handle non-compat 64bit ioctls on 32bit */
+-		if (sizeof(void *) == 4 && req->ioctl_64bit) {
+-			res = fuse_reply_err(req, EINVAL);
+-			goto out;
+-		}
+-
+-		if (in_count) {
+-			in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count);
+-			if (!in_fiov)
+-				goto enomem;
+-
+-			iov[count].iov_base = (void *)in_fiov;
+-			iov[count].iov_len = sizeof(in_fiov[0]) * in_count;
+-			count++;
+-		}
+-		if (out_count) {
+-			out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count);
+-			if (!out_fiov)
+-				goto enomem;
+-
+-			iov[count].iov_base = (void *)out_fiov;
+-			iov[count].iov_len = sizeof(out_fiov[0]) * out_count;
+-			count++;
+-		}
+-	}
+-
+-	res = send_reply_iov(req, 0, iov, count);
++                                                      size_t count)
++{
++    struct fuse_ioctl_iovec *fiov;
++    size_t i;
++
++    fiov = malloc(sizeof(fiov[0]) * count);
++    if (!fiov) {
++        return NULL;
++    }
++
++    for (i = 0; i < count; i++) {
++        fiov[i].base = (uintptr_t)iov[i].iov_base;
++        fiov[i].len = iov[i].iov_len;
++    }
++
++    return fiov;
++}
++
++int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov,
++                           size_t in_count, const struct iovec *out_iov,
++                           size_t out_count)
++{
++    struct fuse_ioctl_out arg;
++    struct fuse_ioctl_iovec *in_fiov = NULL;
++    struct fuse_ioctl_iovec *out_fiov = NULL;
++    struct iovec iov[4];
++    size_t count = 1;
++    int res;
++
++    memset(&arg, 0, sizeof(arg));
++    arg.flags |= FUSE_IOCTL_RETRY;
++    arg.in_iovs = in_count;
++    arg.out_iovs = out_count;
++    iov[count].iov_base = &arg;
++    iov[count].iov_len = sizeof(arg);
++    count++;
++
++    if (req->se->conn.proto_minor < 16) {
++        if (in_count) {
++            iov[count].iov_base = (void *)in_iov;
++            iov[count].iov_len = sizeof(in_iov[0]) * in_count;
++            count++;
++        }
++
++        if (out_count) {
++            iov[count].iov_base = (void *)out_iov;
++            iov[count].iov_len = sizeof(out_iov[0]) * out_count;
++            count++;
++        }
++    } else {
++        /* Can't handle non-compat 64bit ioctls on 32bit */
++        if (sizeof(void *) == 4 && req->ioctl_64bit) {
++            res = fuse_reply_err(req, EINVAL);
++            goto out;
++        }
++
++        if (in_count) {
++            in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count);
++            if (!in_fiov) {
++                goto enomem;
++            }
++
++            iov[count].iov_base = (void *)in_fiov;
++            iov[count].iov_len = sizeof(in_fiov[0]) * in_count;
++            count++;
++        }
++        if (out_count) {
++            out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count);
++            if (!out_fiov) {
++                goto enomem;
++            }
++
++            iov[count].iov_base = (void *)out_fiov;
++            iov[count].iov_len = sizeof(out_fiov[0]) * out_count;
++            count++;
++        }
++    }
++
++    res = send_reply_iov(req, 0, iov, count);
+ out:
+-	free(in_fiov);
+-	free(out_fiov);
++    free(in_fiov);
++    free(out_fiov);
+ 
+-	return res;
++    return res;
+ 
+ enomem:
+-	res = fuse_reply_err(req, ENOMEM);
+-	goto out;
++    res = fuse_reply_err(req, ENOMEM);
++    goto out;
+ }
+ 
+ int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
+ {
+-	struct fuse_ioctl_out arg;
+-	struct iovec iov[3];
+-	size_t count = 1;
++    struct fuse_ioctl_out arg;
++    struct iovec iov[3];
++    size_t count = 1;
+ 
+-	memset(&arg, 0, sizeof(arg));
+-	arg.result = result;
+-	iov[count].iov_base = &arg;
+-	iov[count].iov_len = sizeof(arg);
+-	count++;
++    memset(&arg, 0, sizeof(arg));
++    arg.result = result;
++    iov[count].iov_base = &arg;
++    iov[count].iov_len = sizeof(arg);
++    count++;
+ 
+-	if (size) {
+-		iov[count].iov_base = (char *) buf;
+-		iov[count].iov_len = size;
+-		count++;
+-	}
++    if (size) {
++        iov[count].iov_base = (char *)buf;
++        iov[count].iov_len = size;
++        count++;
++    }
+ 
+-	return send_reply_iov(req, 0, iov, count);
++    return send_reply_iov(req, 0, iov, count);
+ }
+ 
+ int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov,
+-			 int count)
++                         int count)
+ {
+-	struct iovec *padded_iov;
+-	struct fuse_ioctl_out arg;
+-	int res;
++    struct iovec *padded_iov;
++    struct fuse_ioctl_out arg;
++    int res;
+ 
+-	padded_iov = malloc((count + 2) * sizeof(struct iovec));
+-	if (padded_iov == NULL)
+-		return fuse_reply_err(req, ENOMEM);
++    padded_iov = malloc((count + 2) * sizeof(struct iovec));
++    if (padded_iov == NULL) {
++        return fuse_reply_err(req, ENOMEM);
++    }
+ 
+-	memset(&arg, 0, sizeof(arg));
+-	arg.result = result;
+-	padded_iov[1].iov_base = &arg;
+-	padded_iov[1].iov_len = sizeof(arg);
++    memset(&arg, 0, sizeof(arg));
++    arg.result = result;
++    padded_iov[1].iov_base = &arg;
++    padded_iov[1].iov_len = sizeof(arg);
+ 
+-	memcpy(&padded_iov[2], iov, count * sizeof(struct iovec));
++    memcpy(&padded_iov[2], iov, count * sizeof(struct iovec));
+ 
+-	res = send_reply_iov(req, 0, padded_iov, count + 2);
+-	free(padded_iov);
++    res = send_reply_iov(req, 0, padded_iov, count + 2);
++    free(padded_iov);
+ 
+-	return res;
++    return res;
+ }
+ 
+ int fuse_reply_poll(fuse_req_t req, unsigned revents)
+ {
+-	struct fuse_poll_out arg;
++    struct fuse_poll_out arg;
+ 
+-	memset(&arg, 0, sizeof(arg));
+-	arg.revents = revents;
++    memset(&arg, 0, sizeof(arg));
++    arg.revents = revents;
+ 
+-	return send_reply_ok(req, &arg, sizeof(arg));
++    return send_reply_ok(req, &arg, sizeof(arg));
+ }
+ 
+ int fuse_reply_lseek(fuse_req_t req, off_t off)
+ {
+-	struct fuse_lseek_out arg;
++    struct fuse_lseek_out arg;
+ 
+-	memset(&arg, 0, sizeof(arg));
+-	arg.offset = off;
++    memset(&arg, 0, sizeof(arg));
++    arg.offset = off;
+ 
+-	return send_reply_ok(req, &arg, sizeof(arg));
++    return send_reply_ok(req, &arg, sizeof(arg));
+ }
+ 
+ static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	char *name = (char *) inarg;
++    char *name = (char *)inarg;
+ 
+-	if (req->se->op.lookup)
+-		req->se->op.lookup(req, nodeid, name);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.lookup) {
++        req->se->op.lookup(req, nodeid, name);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_forget_in *arg = (struct fuse_forget_in *) inarg;
++    struct fuse_forget_in *arg = (struct fuse_forget_in *)inarg;
+ 
+-	if (req->se->op.forget)
+-		req->se->op.forget(req, nodeid, arg->nlookup);
+-	else
+-		fuse_reply_none(req);
++    if (req->se->op.forget) {
++        req->se->op.forget(req, nodeid, arg->nlookup);
++    } else {
++        fuse_reply_none(req);
++    }
+ }
+ 
+ static void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid,
+-			    const void *inarg)
++                            const void *inarg)
+ {
+-	struct fuse_batch_forget_in *arg = (void *) inarg;
+-	struct fuse_forget_one *param = (void *) PARAM(arg);
+-	unsigned int i;
++    struct fuse_batch_forget_in *arg = (void *)inarg;
++    struct fuse_forget_one *param = (void *)PARAM(arg);
++    unsigned int i;
+ 
+-	(void) nodeid;
++    (void)nodeid;
+ 
+-	if (req->se->op.forget_multi) {
+-		req->se->op.forget_multi(req, arg->count,
+-				     (struct fuse_forget_data *) param);
+-	} else if (req->se->op.forget) {
+-		for (i = 0; i < arg->count; i++) {
+-			struct fuse_forget_one *forget = &param[i];
+-			struct fuse_req *dummy_req;
++    if (req->se->op.forget_multi) {
++        req->se->op.forget_multi(req, arg->count,
++                                 (struct fuse_forget_data *)param);
++    } else if (req->se->op.forget) {
++        for (i = 0; i < arg->count; i++) {
++            struct fuse_forget_one *forget = &param[i];
++            struct fuse_req *dummy_req;
+ 
+-			dummy_req = fuse_ll_alloc_req(req->se);
+-			if (dummy_req == NULL)
+-				break;
++            dummy_req = fuse_ll_alloc_req(req->se);
++            if (dummy_req == NULL) {
++                break;
++            }
+ 
+-			dummy_req->unique = req->unique;
+-			dummy_req->ctx = req->ctx;
+-			dummy_req->ch = NULL;
++            dummy_req->unique = req->unique;
++            dummy_req->ctx = req->ctx;
++            dummy_req->ch = NULL;
+ 
+-			req->se->op.forget(dummy_req, forget->nodeid,
+-					  forget->nlookup);
+-		}
+-		fuse_reply_none(req);
+-	} else {
+-		fuse_reply_none(req);
+-	}
++            req->se->op.forget(dummy_req, forget->nodeid, forget->nlookup);
++        }
++        fuse_reply_none(req);
++    } else {
++        fuse_reply_none(req);
++    }
+ }
+ 
+ static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_file_info *fip = NULL;
+-	struct fuse_file_info fi;
++    struct fuse_file_info *fip = NULL;
++    struct fuse_file_info fi;
+ 
+-	if (req->se->conn.proto_minor >= 9) {
+-		struct fuse_getattr_in *arg = (struct fuse_getattr_in *) inarg;
++    if (req->se->conn.proto_minor >= 9) {
++        struct fuse_getattr_in *arg = (struct fuse_getattr_in *)inarg;
+ 
+-		if (arg->getattr_flags & FUSE_GETATTR_FH) {
+-			memset(&fi, 0, sizeof(fi));
+-			fi.fh = arg->fh;
+-			fip = &fi;
+-		}
+-	}
++        if (arg->getattr_flags & FUSE_GETATTR_FH) {
++            memset(&fi, 0, sizeof(fi));
++            fi.fh = arg->fh;
++            fip = &fi;
++        }
++    }
+ 
+-	if (req->se->op.getattr)
+-		req->se->op.getattr(req, nodeid, fip);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.getattr) {
++        req->se->op.getattr(req, nodeid, fip);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_setattr_in *arg = (struct fuse_setattr_in *) inarg;
+-
+-	if (req->se->op.setattr) {
+-		struct fuse_file_info *fi = NULL;
+-		struct fuse_file_info fi_store;
+-		struct stat stbuf;
+-		memset(&stbuf, 0, sizeof(stbuf));
+-		convert_attr(arg, &stbuf);
+-		if (arg->valid & FATTR_FH) {
+-			arg->valid &= ~FATTR_FH;
+-			memset(&fi_store, 0, sizeof(fi_store));
+-			fi = &fi_store;
+-			fi->fh = arg->fh;
+-		}
+-		arg->valid &=
+-			FUSE_SET_ATTR_MODE	|
+-			FUSE_SET_ATTR_UID	|
+-			FUSE_SET_ATTR_GID	|
+-			FUSE_SET_ATTR_SIZE	|
+-			FUSE_SET_ATTR_ATIME	|
+-			FUSE_SET_ATTR_MTIME	|
+-			FUSE_SET_ATTR_ATIME_NOW	|
+-			FUSE_SET_ATTR_MTIME_NOW |
+-			FUSE_SET_ATTR_CTIME;
+-
+-		req->se->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
+-	} else
+-		fuse_reply_err(req, ENOSYS);
++    struct fuse_setattr_in *arg = (struct fuse_setattr_in *)inarg;
++
++    if (req->se->op.setattr) {
++        struct fuse_file_info *fi = NULL;
++        struct fuse_file_info fi_store;
++        struct stat stbuf;
++        memset(&stbuf, 0, sizeof(stbuf));
++        convert_attr(arg, &stbuf);
++        if (arg->valid & FATTR_FH) {
++            arg->valid &= ~FATTR_FH;
++            memset(&fi_store, 0, sizeof(fi_store));
++            fi = &fi_store;
++            fi->fh = arg->fh;
++        }
++        arg->valid &= FUSE_SET_ATTR_MODE | FUSE_SET_ATTR_UID |
++                      FUSE_SET_ATTR_GID | FUSE_SET_ATTR_SIZE |
++                      FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME |
++                      FUSE_SET_ATTR_ATIME_NOW | FUSE_SET_ATTR_MTIME_NOW |
++                      FUSE_SET_ATTR_CTIME;
++
++        req->se->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_access_in *arg = (struct fuse_access_in *) inarg;
++    struct fuse_access_in *arg = (struct fuse_access_in *)inarg;
+ 
+-	if (req->se->op.access)
+-		req->se->op.access(req, nodeid, arg->mask);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.access) {
++        req->se->op.access(req, nodeid, arg->mask);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	(void) inarg;
++    (void)inarg;
+ 
+-	if (req->se->op.readlink)
+-		req->se->op.readlink(req, nodeid);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.readlink) {
++        req->se->op.readlink(req, nodeid);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg;
+-	char *name = PARAM(arg);
++    struct fuse_mknod_in *arg = (struct fuse_mknod_in *)inarg;
++    char *name = PARAM(arg);
+ 
+-	if (req->se->conn.proto_minor >= 12)
+-		req->ctx.umask = arg->umask;
+-	else
+-		name = (char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
++    if (req->se->conn.proto_minor >= 12) {
++        req->ctx.umask = arg->umask;
++    } else {
++        name = (char *)inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
++    }
+ 
+-	if (req->se->op.mknod)
+-		req->se->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.mknod) {
++        req->se->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg;
++    struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *)inarg;
+ 
+-	if (req->se->conn.proto_minor >= 12)
+-		req->ctx.umask = arg->umask;
++    if (req->se->conn.proto_minor >= 12) {
++        req->ctx.umask = arg->umask;
++    }
+ 
+-	if (req->se->op.mkdir)
+-		req->se->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.mkdir) {
++        req->se->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	char *name = (char *) inarg;
++    char *name = (char *)inarg;
+ 
+-	if (req->se->op.unlink)
+-		req->se->op.unlink(req, nodeid, name);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.unlink) {
++        req->se->op.unlink(req, nodeid, name);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	char *name = (char *) inarg;
++    char *name = (char *)inarg;
+ 
+-	if (req->se->op.rmdir)
+-		req->se->op.rmdir(req, nodeid, name);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.rmdir) {
++        req->se->op.rmdir(req, nodeid, name);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	char *name = (char *) inarg;
+-	char *linkname = ((char *) inarg) + strlen((char *) inarg) + 1;
++    char *name = (char *)inarg;
++    char *linkname = ((char *)inarg) + strlen((char *)inarg) + 1;
+ 
+-	if (req->se->op.symlink)
+-		req->se->op.symlink(req, linkname, nodeid, name);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.symlink) {
++        req->se->op.symlink(req, linkname, nodeid, name);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_rename_in *arg = (struct fuse_rename_in *) inarg;
+-	char *oldname = PARAM(arg);
+-	char *newname = oldname + strlen(oldname) + 1;
++    struct fuse_rename_in *arg = (struct fuse_rename_in *)inarg;
++    char *oldname = PARAM(arg);
++    char *newname = oldname + strlen(oldname) + 1;
+ 
+-	if (req->se->op.rename)
+-		req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
+-				  0);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.rename) {
++        req->se->op.rename(req, nodeid, oldname, arg->newdir, newname, 0);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_rename2(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_rename2_in *arg = (struct fuse_rename2_in *) inarg;
+-	char *oldname = PARAM(arg);
+-	char *newname = oldname + strlen(oldname) + 1;
++    struct fuse_rename2_in *arg = (struct fuse_rename2_in *)inarg;
++    char *oldname = PARAM(arg);
++    char *newname = oldname + strlen(oldname) + 1;
+ 
+-	if (req->se->op.rename)
+-		req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
+-				  arg->flags);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.rename) {
++        req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
++                           arg->flags);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_link_in *arg = (struct fuse_link_in *) inarg;
++    struct fuse_link_in *arg = (struct fuse_link_in *)inarg;
+ 
+-	if (req->se->op.link)
+-		req->se->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.link) {
++        req->se->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_create_in *arg = (struct fuse_create_in *) inarg;
++    struct fuse_create_in *arg = (struct fuse_create_in *)inarg;
+ 
+-	if (req->se->op.create) {
+-		struct fuse_file_info fi;
+-		char *name = PARAM(arg);
++    if (req->se->op.create) {
++        struct fuse_file_info fi;
++        char *name = PARAM(arg);
+ 
+-		memset(&fi, 0, sizeof(fi));
+-		fi.flags = arg->flags;
++        memset(&fi, 0, sizeof(fi));
++        fi.flags = arg->flags;
+ 
+-		if (req->se->conn.proto_minor >= 12)
+-			req->ctx.umask = arg->umask;
+-		else
+-			name = (char *) inarg + sizeof(struct fuse_open_in);
++        if (req->se->conn.proto_minor >= 12) {
++            req->ctx.umask = arg->umask;
++        } else {
++            name = (char *)inarg + sizeof(struct fuse_open_in);
++        }
+ 
+-		req->se->op.create(req, nodeid, name, arg->mode, &fi);
+-	} else
+-		fuse_reply_err(req, ENOSYS);
++        req->se->op.create(req, nodeid, name, arg->mode, &fi);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
+-	struct fuse_file_info fi;
++    struct fuse_open_in *arg = (struct fuse_open_in *)inarg;
++    struct fuse_file_info fi;
+ 
+-	memset(&fi, 0, sizeof(fi));
+-	fi.flags = arg->flags;
++    memset(&fi, 0, sizeof(fi));
++    fi.flags = arg->flags;
+ 
+-	if (req->se->op.open)
+-		req->se->op.open(req, nodeid, &fi);
+-	else
+-		fuse_reply_open(req, &fi);
++    if (req->se->op.open) {
++        req->se->op.open(req, nodeid, &fi);
++    } else {
++        fuse_reply_open(req, &fi);
++    }
+ }
+ 
+ static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
++    struct fuse_read_in *arg = (struct fuse_read_in *)inarg;
+ 
+-	if (req->se->op.read) {
+-		struct fuse_file_info fi;
++    if (req->se->op.read) {
++        struct fuse_file_info fi;
+ 
+-		memset(&fi, 0, sizeof(fi));
+-		fi.fh = arg->fh;
+-		if (req->se->conn.proto_minor >= 9) {
+-			fi.lock_owner = arg->lock_owner;
+-			fi.flags = arg->flags;
+-		}
+-		req->se->op.read(req, nodeid, arg->size, arg->offset, &fi);
+-	} else
+-		fuse_reply_err(req, ENOSYS);
++        memset(&fi, 0, sizeof(fi));
++        fi.fh = arg->fh;
++        if (req->se->conn.proto_minor >= 9) {
++            fi.lock_owner = arg->lock_owner;
++            fi.flags = arg->flags;
++        }
++        req->se->op.read(req, nodeid, arg->size, arg->offset, &fi);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
+-	struct fuse_file_info fi;
+-	char *param;
++    struct fuse_write_in *arg = (struct fuse_write_in *)inarg;
++    struct fuse_file_info fi;
++    char *param;
+ 
+-	memset(&fi, 0, sizeof(fi));
+-	fi.fh = arg->fh;
+-	fi.writepage = (arg->write_flags & FUSE_WRITE_CACHE) != 0;
++    memset(&fi, 0, sizeof(fi));
++    fi.fh = arg->fh;
++    fi.writepage = (arg->write_flags & FUSE_WRITE_CACHE) != 0;
+ 
+-	if (req->se->conn.proto_minor < 9) {
+-		param = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE;
+-	} else {
+-		fi.lock_owner = arg->lock_owner;
+-		fi.flags = arg->flags;
+-		param = PARAM(arg);
+-	}
++    if (req->se->conn.proto_minor < 9) {
++        param = ((char *)arg) + FUSE_COMPAT_WRITE_IN_SIZE;
++    } else {
++        fi.lock_owner = arg->lock_owner;
++        fi.flags = arg->flags;
++        param = PARAM(arg);
++    }
+ 
+-	if (req->se->op.write)
+-		req->se->op.write(req, nodeid, param, arg->size,
+-				 arg->offset, &fi);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.write) {
++        req->se->op.write(req, nodeid, param, arg->size, arg->offset, &fi);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid, const void *inarg,
+-			 const struct fuse_buf *ibuf)
+-{
+-	struct fuse_session *se = req->se;
+-	struct fuse_bufvec bufv = {
+-		.buf[0] = *ibuf,
+-		.count = 1,
+-	};
+-	struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
+-	struct fuse_file_info fi;
+-
+-	memset(&fi, 0, sizeof(fi));
+-	fi.fh = arg->fh;
+-	fi.writepage = arg->write_flags & FUSE_WRITE_CACHE;
+-
+-	if (se->conn.proto_minor < 9) {
+-		bufv.buf[0].mem = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE;
+-		bufv.buf[0].size -= sizeof(struct fuse_in_header) +
+-			FUSE_COMPAT_WRITE_IN_SIZE;
+-		assert(!(bufv.buf[0].flags & FUSE_BUF_IS_FD));
+-	} else {
+-		fi.lock_owner = arg->lock_owner;
+-		fi.flags = arg->flags;
+-		if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
+-			bufv.buf[0].mem = PARAM(arg);
+-
+-		bufv.buf[0].size -= sizeof(struct fuse_in_header) +
+-			sizeof(struct fuse_write_in);
+-	}
+-	if (bufv.buf[0].size < arg->size) {
+-		fuse_log(FUSE_LOG_ERR, "fuse: do_write_buf: buffer size too small\n");
+-		fuse_reply_err(req, EIO);
+-		return;
+-	}
+-	bufv.buf[0].size = arg->size;
+-
+-	se->op.write_buf(req, nodeid, &bufv, arg->offset, &fi);
++                         const struct fuse_buf *ibuf)
++{
++    struct fuse_session *se = req->se;
++    struct fuse_bufvec bufv = {
++        .buf[0] = *ibuf,
++        .count = 1,
++    };
++    struct fuse_write_in *arg = (struct fuse_write_in *)inarg;
++    struct fuse_file_info fi;
++
++    memset(&fi, 0, sizeof(fi));
++    fi.fh = arg->fh;
++    fi.writepage = arg->write_flags & FUSE_WRITE_CACHE;
++
++    if (se->conn.proto_minor < 9) {
++        bufv.buf[0].mem = ((char *)arg) + FUSE_COMPAT_WRITE_IN_SIZE;
++        bufv.buf[0].size -=
++            sizeof(struct fuse_in_header) + FUSE_COMPAT_WRITE_IN_SIZE;
++        assert(!(bufv.buf[0].flags & FUSE_BUF_IS_FD));
++    } else {
++        fi.lock_owner = arg->lock_owner;
++        fi.flags = arg->flags;
++        if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD)) {
++            bufv.buf[0].mem = PARAM(arg);
++        }
++
++        bufv.buf[0].size -=
++            sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in);
++    }
++    if (bufv.buf[0].size < arg->size) {
++        fuse_log(FUSE_LOG_ERR, "fuse: do_write_buf: buffer size too small\n");
++        fuse_reply_err(req, EIO);
++        return;
++    }
++    bufv.buf[0].size = arg->size;
++
++    se->op.write_buf(req, nodeid, &bufv, arg->offset, &fi);
+ }
+ 
+ static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_flush_in *arg = (struct fuse_flush_in *) inarg;
+-	struct fuse_file_info fi;
++    struct fuse_flush_in *arg = (struct fuse_flush_in *)inarg;
++    struct fuse_file_info fi;
+ 
+-	memset(&fi, 0, sizeof(fi));
+-	fi.fh = arg->fh;
+-	fi.flush = 1;
+-	if (req->se->conn.proto_minor >= 7)
+-		fi.lock_owner = arg->lock_owner;
++    memset(&fi, 0, sizeof(fi));
++    fi.fh = arg->fh;
++    fi.flush = 1;
++    if (req->se->conn.proto_minor >= 7) {
++        fi.lock_owner = arg->lock_owner;
++    }
+ 
+-	if (req->se->op.flush)
+-		req->se->op.flush(req, nodeid, &fi);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.flush) {
++        req->se->op.flush(req, nodeid, &fi);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
+-	struct fuse_file_info fi;
++    struct fuse_release_in *arg = (struct fuse_release_in *)inarg;
++    struct fuse_file_info fi;
+ 
+-	memset(&fi, 0, sizeof(fi));
+-	fi.flags = arg->flags;
+-	fi.fh = arg->fh;
+-	if (req->se->conn.proto_minor >= 8) {
+-		fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
+-		fi.lock_owner = arg->lock_owner;
+-	}
+-	if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) {
+-		fi.flock_release = 1;
+-		fi.lock_owner = arg->lock_owner;
+-	}
++    memset(&fi, 0, sizeof(fi));
++    fi.flags = arg->flags;
++    fi.fh = arg->fh;
++    if (req->se->conn.proto_minor >= 8) {
++        fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
++        fi.lock_owner = arg->lock_owner;
++    }
++    if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) {
++        fi.flock_release = 1;
++        fi.lock_owner = arg->lock_owner;
++    }
+ 
+-	if (req->se->op.release)
+-		req->se->op.release(req, nodeid, &fi);
+-	else
+-		fuse_reply_err(req, 0);
++    if (req->se->op.release) {
++        req->se->op.release(req, nodeid, &fi);
++    } else {
++        fuse_reply_err(req, 0);
++    }
+ }
+ 
+ static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
+-	struct fuse_file_info fi;
+-	int datasync = arg->fsync_flags & 1;
++    struct fuse_fsync_in *arg = (struct fuse_fsync_in *)inarg;
++    struct fuse_file_info fi;
++    int datasync = arg->fsync_flags & 1;
+ 
+-	memset(&fi, 0, sizeof(fi));
+-	fi.fh = arg->fh;
++    memset(&fi, 0, sizeof(fi));
++    fi.fh = arg->fh;
+ 
+-	if (req->se->op.fsync)
+-		req->se->op.fsync(req, nodeid, datasync, &fi);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.fsync) {
++        req->se->op.fsync(req, nodeid, datasync, &fi);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
+-	struct fuse_file_info fi;
++    struct fuse_open_in *arg = (struct fuse_open_in *)inarg;
++    struct fuse_file_info fi;
+ 
+-	memset(&fi, 0, sizeof(fi));
+-	fi.flags = arg->flags;
++    memset(&fi, 0, sizeof(fi));
++    fi.flags = arg->flags;
+ 
+-	if (req->se->op.opendir)
+-		req->se->op.opendir(req, nodeid, &fi);
+-	else
+-		fuse_reply_open(req, &fi);
++    if (req->se->op.opendir) {
++        req->se->op.opendir(req, nodeid, &fi);
++    } else {
++        fuse_reply_open(req, &fi);
++    }
+ }
+ 
+ static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
+-	struct fuse_file_info fi;
++    struct fuse_read_in *arg = (struct fuse_read_in *)inarg;
++    struct fuse_file_info fi;
+ 
+-	memset(&fi, 0, sizeof(fi));
+-	fi.fh = arg->fh;
++    memset(&fi, 0, sizeof(fi));
++    fi.fh = arg->fh;
+ 
+-	if (req->se->op.readdir)
+-		req->se->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.readdir) {
++        req->se->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_readdirplus(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
+-	struct fuse_file_info fi;
++    struct fuse_read_in *arg = (struct fuse_read_in *)inarg;
++    struct fuse_file_info fi;
+ 
+-	memset(&fi, 0, sizeof(fi));
+-	fi.fh = arg->fh;
++    memset(&fi, 0, sizeof(fi));
++    fi.fh = arg->fh;
+ 
+-	if (req->se->op.readdirplus)
+-		req->se->op.readdirplus(req, nodeid, arg->size, arg->offset, &fi);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.readdirplus) {
++        req->se->op.readdirplus(req, nodeid, arg->size, arg->offset, &fi);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
+-	struct fuse_file_info fi;
++    struct fuse_release_in *arg = (struct fuse_release_in *)inarg;
++    struct fuse_file_info fi;
+ 
+-	memset(&fi, 0, sizeof(fi));
+-	fi.flags = arg->flags;
+-	fi.fh = arg->fh;
++    memset(&fi, 0, sizeof(fi));
++    fi.flags = arg->flags;
++    fi.fh = arg->fh;
+ 
+-	if (req->se->op.releasedir)
+-		req->se->op.releasedir(req, nodeid, &fi);
+-	else
+-		fuse_reply_err(req, 0);
++    if (req->se->op.releasedir) {
++        req->se->op.releasedir(req, nodeid, &fi);
++    } else {
++        fuse_reply_err(req, 0);
++    }
+ }
+ 
+ static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
+-	struct fuse_file_info fi;
+-	int datasync = arg->fsync_flags & 1;
++    struct fuse_fsync_in *arg = (struct fuse_fsync_in *)inarg;
++    struct fuse_file_info fi;
++    int datasync = arg->fsync_flags & 1;
+ 
+-	memset(&fi, 0, sizeof(fi));
+-	fi.fh = arg->fh;
++    memset(&fi, 0, sizeof(fi));
++    fi.fh = arg->fh;
+ 
+-	if (req->se->op.fsyncdir)
+-		req->se->op.fsyncdir(req, nodeid, datasync, &fi);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.fsyncdir) {
++        req->se->op.fsyncdir(req, nodeid, datasync, &fi);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	(void) nodeid;
+-	(void) inarg;
++    (void)nodeid;
++    (void)inarg;
+ 
+-	if (req->se->op.statfs)
+-		req->se->op.statfs(req, nodeid);
+-	else {
+-		struct statvfs buf = {
+-			.f_namemax = 255,
+-			.f_bsize = 512,
+-		};
+-		fuse_reply_statfs(req, &buf);
+-	}
++    if (req->se->op.statfs) {
++        req->se->op.statfs(req, nodeid);
++    } else {
++        struct statvfs buf = {
++            .f_namemax = 255,
++            .f_bsize = 512,
++        };
++        fuse_reply_statfs(req, &buf);
++    }
+ }
+ 
+ static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg;
+-	char *name = PARAM(arg);
+-	char *value = name + strlen(name) + 1;
++    struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *)inarg;
++    char *name = PARAM(arg);
++    char *value = name + strlen(name) + 1;
+ 
+-	if (req->se->op.setxattr)
+-		req->se->op.setxattr(req, nodeid, name, value, arg->size,
+-				    arg->flags);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.setxattr) {
++        req->se->op.setxattr(req, nodeid, name, value, arg->size, arg->flags);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
++    struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *)inarg;
+ 
+-	if (req->se->op.getxattr)
+-		req->se->op.getxattr(req, nodeid, PARAM(arg), arg->size);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.getxattr) {
++        req->se->op.getxattr(req, nodeid, PARAM(arg), arg->size);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
++    struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *)inarg;
+ 
+-	if (req->se->op.listxattr)
+-		req->se->op.listxattr(req, nodeid, arg->size);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.listxattr) {
++        req->se->op.listxattr(req, nodeid, arg->size);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	char *name = (char *) inarg;
++    char *name = (char *)inarg;
+ 
+-	if (req->se->op.removexattr)
+-		req->se->op.removexattr(req, nodeid, name);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.removexattr) {
++        req->se->op.removexattr(req, nodeid, name);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void convert_fuse_file_lock(struct fuse_file_lock *fl,
+-				   struct flock *flock)
++                                   struct flock *flock)
+ {
+-	memset(flock, 0, sizeof(struct flock));
+-	flock->l_type = fl->type;
+-	flock->l_whence = SEEK_SET;
+-	flock->l_start = fl->start;
+-	if (fl->end == OFFSET_MAX)
+-		flock->l_len = 0;
+-	else
+-		flock->l_len = fl->end - fl->start + 1;
+-	flock->l_pid = fl->pid;
++    memset(flock, 0, sizeof(struct flock));
++    flock->l_type = fl->type;
++    flock->l_whence = SEEK_SET;
++    flock->l_start = fl->start;
++    if (fl->end == OFFSET_MAX) {
++        flock->l_len = 0;
++    } else {
++        flock->l_len = fl->end - fl->start + 1;
++    }
++    flock->l_pid = fl->pid;
+ }
+ 
+ static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg;
+-	struct fuse_file_info fi;
+-	struct flock flock;
++    struct fuse_lk_in *arg = (struct fuse_lk_in *)inarg;
++    struct fuse_file_info fi;
++    struct flock flock;
+ 
+-	memset(&fi, 0, sizeof(fi));
+-	fi.fh = arg->fh;
+-	fi.lock_owner = arg->owner;
++    memset(&fi, 0, sizeof(fi));
++    fi.fh = arg->fh;
++    fi.lock_owner = arg->owner;
+ 
+-	convert_fuse_file_lock(&arg->lk, &flock);
+-	if (req->se->op.getlk)
+-		req->se->op.getlk(req, nodeid, &fi, &flock);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    convert_fuse_file_lock(&arg->lk, &flock);
++    if (req->se->op.getlk) {
++        req->se->op.getlk(req, nodeid, &fi, &flock);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid,
+-			    const void *inarg, int sleep)
+-{
+-	struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg;
+-	struct fuse_file_info fi;
+-	struct flock flock;
+-
+-	memset(&fi, 0, sizeof(fi));
+-	fi.fh = arg->fh;
+-	fi.lock_owner = arg->owner;
+-
+-	if (arg->lk_flags & FUSE_LK_FLOCK) {
+-		int op = 0;
+-
+-		switch (arg->lk.type) {
+-		case F_RDLCK:
+-			op = LOCK_SH;
+-			break;
+-		case F_WRLCK:
+-			op = LOCK_EX;
+-			break;
+-		case F_UNLCK:
+-			op = LOCK_UN;
+-			break;
+-		}
+-		if (!sleep)
+-			op |= LOCK_NB;
+-
+-		if (req->se->op.flock)
+-			req->se->op.flock(req, nodeid, &fi, op);
+-		else
+-			fuse_reply_err(req, ENOSYS);
+-	} else {
+-		convert_fuse_file_lock(&arg->lk, &flock);
+-		if (req->se->op.setlk)
+-			req->se->op.setlk(req, nodeid, &fi, &flock, sleep);
+-		else
+-			fuse_reply_err(req, ENOSYS);
+-	}
++                            const void *inarg, int sleep)
++{
++    struct fuse_lk_in *arg = (struct fuse_lk_in *)inarg;
++    struct fuse_file_info fi;
++    struct flock flock;
++
++    memset(&fi, 0, sizeof(fi));
++    fi.fh = arg->fh;
++    fi.lock_owner = arg->owner;
++
++    if (arg->lk_flags & FUSE_LK_FLOCK) {
++        int op = 0;
++
++        switch (arg->lk.type) {
++        case F_RDLCK:
++            op = LOCK_SH;
++            break;
++        case F_WRLCK:
++            op = LOCK_EX;
++            break;
++        case F_UNLCK:
++            op = LOCK_UN;
++            break;
++        }
++        if (!sleep) {
++            op |= LOCK_NB;
++        }
++
++        if (req->se->op.flock) {
++            req->se->op.flock(req, nodeid, &fi, op);
++        } else {
++            fuse_reply_err(req, ENOSYS);
++        }
++    } else {
++        convert_fuse_file_lock(&arg->lk, &flock);
++        if (req->se->op.setlk) {
++            req->se->op.setlk(req, nodeid, &fi, &flock, sleep);
++        } else {
++            fuse_reply_err(req, ENOSYS);
++        }
++    }
+ }
+ 
+ static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	do_setlk_common(req, nodeid, inarg, 0);
++    do_setlk_common(req, nodeid, inarg, 0);
+ }
+ 
+ static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	do_setlk_common(req, nodeid, inarg, 1);
++    do_setlk_common(req, nodeid, inarg, 1);
+ }
+ 
+ static int find_interrupted(struct fuse_session *se, struct fuse_req *req)
+ {
+-	struct fuse_req *curr;
+-
+-	for (curr = se->list.next; curr != &se->list; curr = curr->next) {
+-		if (curr->unique == req->u.i.unique) {
+-			fuse_interrupt_func_t func;
+-			void *data;
+-
+-			curr->ctr++;
+-			pthread_mutex_unlock(&se->lock);
+-
+-			/* Ugh, ugly locking */
+-			pthread_mutex_lock(&curr->lock);
+-			pthread_mutex_lock(&se->lock);
+-			curr->interrupted = 1;
+-			func = curr->u.ni.func;
+-			data = curr->u.ni.data;
+-			pthread_mutex_unlock(&se->lock);
+-			if (func)
+-				func(curr, data);
+-			pthread_mutex_unlock(&curr->lock);
+-
+-			pthread_mutex_lock(&se->lock);
+-			curr->ctr--;
+-			if (!curr->ctr)
+-				destroy_req(curr);
+-
+-			return 1;
+-		}
+-	}
+-	for (curr = se->interrupts.next; curr != &se->interrupts;
+-	     curr = curr->next) {
+-		if (curr->u.i.unique == req->u.i.unique)
+-			return 1;
+-	}
+-	return 0;
++    struct fuse_req *curr;
++
++    for (curr = se->list.next; curr != &se->list; curr = curr->next) {
++        if (curr->unique == req->u.i.unique) {
++            fuse_interrupt_func_t func;
++            void *data;
++
++            curr->ctr++;
++            pthread_mutex_unlock(&se->lock);
++
++            /* Ugh, ugly locking */
++            pthread_mutex_lock(&curr->lock);
++            pthread_mutex_lock(&se->lock);
++            curr->interrupted = 1;
++            func = curr->u.ni.func;
++            data = curr->u.ni.data;
++            pthread_mutex_unlock(&se->lock);
++            if (func) {
++                func(curr, data);
++            }
++            pthread_mutex_unlock(&curr->lock);
++
++            pthread_mutex_lock(&se->lock);
++            curr->ctr--;
++            if (!curr->ctr) {
++                destroy_req(curr);
++            }
++
++            return 1;
++        }
++    }
++    for (curr = se->interrupts.next; curr != &se->interrupts;
++         curr = curr->next) {
++        if (curr->u.i.unique == req->u.i.unique) {
++            return 1;
++        }
++    }
++    return 0;
+ }
+ 
+ static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *) inarg;
+-	struct fuse_session *se = req->se;
++    struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *)inarg;
++    struct fuse_session *se = req->se;
+ 
+-	(void) nodeid;
+-	if (se->debug)
+-		fuse_log(FUSE_LOG_DEBUG, "INTERRUPT: %llu\n",
+-			(unsigned long long) arg->unique);
++    (void)nodeid;
++    if (se->debug) {
++        fuse_log(FUSE_LOG_DEBUG, "INTERRUPT: %llu\n",
++                 (unsigned long long)arg->unique);
++    }
+ 
+-	req->u.i.unique = arg->unique;
++    req->u.i.unique = arg->unique;
+ 
+-	pthread_mutex_lock(&se->lock);
+-	if (find_interrupted(se, req))
+-		destroy_req(req);
+-	else
+-		list_add_req(req, &se->interrupts);
+-	pthread_mutex_unlock(&se->lock);
++    pthread_mutex_lock(&se->lock);
++    if (find_interrupted(se, req)) {
++        destroy_req(req);
++    } else {
++        list_add_req(req, &se->interrupts);
++    }
++    pthread_mutex_unlock(&se->lock);
+ }
+ 
+ static struct fuse_req *check_interrupt(struct fuse_session *se,
+-					struct fuse_req *req)
+-{
+-	struct fuse_req *curr;
+-
+-	for (curr = se->interrupts.next; curr != &se->interrupts;
+-	     curr = curr->next) {
+-		if (curr->u.i.unique == req->unique) {
+-			req->interrupted = 1;
+-			list_del_req(curr);
+-			free(curr);
+-			return NULL;
+-		}
+-	}
+-	curr = se->interrupts.next;
+-	if (curr != &se->interrupts) {
+-		list_del_req(curr);
+-		list_init_req(curr);
+-		return curr;
+-	} else
+-		return NULL;
++                                        struct fuse_req *req)
++{
++    struct fuse_req *curr;
++
++    for (curr = se->interrupts.next; curr != &se->interrupts;
++         curr = curr->next) {
++        if (curr->u.i.unique == req->unique) {
++            req->interrupted = 1;
++            list_del_req(curr);
++            free(curr);
++            return NULL;
++        }
++    }
++    curr = se->interrupts.next;
++    if (curr != &se->interrupts) {
++        list_del_req(curr);
++        list_init_req(curr);
++        return curr;
++    } else {
++        return NULL;
++    }
+ }
+ 
+ static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_bmap_in *arg = (struct fuse_bmap_in *) inarg;
++    struct fuse_bmap_in *arg = (struct fuse_bmap_in *)inarg;
+ 
+-	if (req->se->op.bmap)
+-		req->se->op.bmap(req, nodeid, arg->blocksize, arg->block);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.bmap) {
++        req->se->op.bmap(req, nodeid, arg->blocksize, arg->block);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_ioctl_in *arg = (struct fuse_ioctl_in *) inarg;
+-	unsigned int flags = arg->flags;
+-	void *in_buf = arg->in_size ? PARAM(arg) : NULL;
+-	struct fuse_file_info fi;
++    struct fuse_ioctl_in *arg = (struct fuse_ioctl_in *)inarg;
++    unsigned int flags = arg->flags;
++    void *in_buf = arg->in_size ? PARAM(arg) : NULL;
++    struct fuse_file_info fi;
+ 
+-	if (flags & FUSE_IOCTL_DIR &&
+-	    !(req->se->conn.want & FUSE_CAP_IOCTL_DIR)) {
+-		fuse_reply_err(req, ENOTTY);
+-		return;
+-	}
++    if (flags & FUSE_IOCTL_DIR && !(req->se->conn.want & FUSE_CAP_IOCTL_DIR)) {
++        fuse_reply_err(req, ENOTTY);
++        return;
++    }
+ 
+-	memset(&fi, 0, sizeof(fi));
+-	fi.fh = arg->fh;
++    memset(&fi, 0, sizeof(fi));
++    fi.fh = arg->fh;
+ 
+-	if (sizeof(void *) == 4 && req->se->conn.proto_minor >= 16 &&
+-	    !(flags & FUSE_IOCTL_32BIT)) {
+-		req->ioctl_64bit = 1;
+-	}
++    if (sizeof(void *) == 4 && req->se->conn.proto_minor >= 16 &&
++        !(flags & FUSE_IOCTL_32BIT)) {
++        req->ioctl_64bit = 1;
++    }
+ 
+-	if (req->se->op.ioctl)
+-		req->se->op.ioctl(req, nodeid, arg->cmd,
+-				 (void *)(uintptr_t)arg->arg, &fi, flags,
+-				 in_buf, arg->in_size, arg->out_size);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.ioctl) {
++        req->se->op.ioctl(req, nodeid, arg->cmd, (void *)(uintptr_t)arg->arg,
++                          &fi, flags, in_buf, arg->in_size, arg->out_size);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
+ {
+-	free(ph);
++    free(ph);
+ }
+ 
+ static void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_poll_in *arg = (struct fuse_poll_in *) inarg;
+-	struct fuse_file_info fi;
++    struct fuse_poll_in *arg = (struct fuse_poll_in *)inarg;
++    struct fuse_file_info fi;
+ 
+-	memset(&fi, 0, sizeof(fi));
+-	fi.fh = arg->fh;
+-	fi.poll_events = arg->events;
++    memset(&fi, 0, sizeof(fi));
++    fi.fh = arg->fh;
++    fi.poll_events = arg->events;
+ 
+-	if (req->se->op.poll) {
+-		struct fuse_pollhandle *ph = NULL;
++    if (req->se->op.poll) {
++        struct fuse_pollhandle *ph = NULL;
+ 
+-		if (arg->flags & FUSE_POLL_SCHEDULE_NOTIFY) {
+-			ph = malloc(sizeof(struct fuse_pollhandle));
+-			if (ph == NULL) {
+-				fuse_reply_err(req, ENOMEM);
+-				return;
+-			}
+-			ph->kh = arg->kh;
+-			ph->se = req->se;
+-		}
++        if (arg->flags & FUSE_POLL_SCHEDULE_NOTIFY) {
++            ph = malloc(sizeof(struct fuse_pollhandle));
++            if (ph == NULL) {
++                fuse_reply_err(req, ENOMEM);
++                return;
++            }
++            ph->kh = arg->kh;
++            ph->se = req->se;
++        }
+ 
+-		req->se->op.poll(req, nodeid, &fi, ph);
+-	} else {
+-		fuse_reply_err(req, ENOSYS);
+-	}
++        req->se->op.poll(req, nodeid, &fi, ph);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_fallocate(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_fallocate_in *arg = (struct fuse_fallocate_in *) inarg;
+-	struct fuse_file_info fi;
++    struct fuse_fallocate_in *arg = (struct fuse_fallocate_in *)inarg;
++    struct fuse_file_info fi;
+ 
+-	memset(&fi, 0, sizeof(fi));
+-	fi.fh = arg->fh;
++    memset(&fi, 0, sizeof(fi));
++    fi.fh = arg->fh;
+ 
+-	if (req->se->op.fallocate)
+-		req->se->op.fallocate(req, nodeid, arg->mode, arg->offset, arg->length, &fi);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.fallocate) {
++        req->se->op.fallocate(req, nodeid, arg->mode, arg->offset, arg->length,
++                              &fi);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+-static void do_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in, const void *inarg)
++static void do_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in,
++                               const void *inarg)
+ {
+-	struct fuse_copy_file_range_in *arg = (struct fuse_copy_file_range_in *) inarg;
+-	struct fuse_file_info fi_in, fi_out;
++    struct fuse_copy_file_range_in *arg =
++        (struct fuse_copy_file_range_in *)inarg;
++    struct fuse_file_info fi_in, fi_out;
+ 
+-	memset(&fi_in, 0, sizeof(fi_in));
+-	fi_in.fh = arg->fh_in;
++    memset(&fi_in, 0, sizeof(fi_in));
++    fi_in.fh = arg->fh_in;
+ 
+-	memset(&fi_out, 0, sizeof(fi_out));
+-	fi_out.fh = arg->fh_out;
++    memset(&fi_out, 0, sizeof(fi_out));
++    fi_out.fh = arg->fh_out;
+ 
+ 
+-	if (req->se->op.copy_file_range)
+-		req->se->op.copy_file_range(req, nodeid_in, arg->off_in,
+-					    &fi_in, arg->nodeid_out,
+-					    arg->off_out, &fi_out, arg->len,
+-					    arg->flags);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.copy_file_range) {
++        req->se->op.copy_file_range(req, nodeid_in, arg->off_in, &fi_in,
++                                    arg->nodeid_out, arg->off_out, &fi_out,
++                                    arg->len, arg->flags);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_lseek(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_lseek_in *arg = (struct fuse_lseek_in *) inarg;
+-	struct fuse_file_info fi;
++    struct fuse_lseek_in *arg = (struct fuse_lseek_in *)inarg;
++    struct fuse_file_info fi;
+ 
+-	memset(&fi, 0, sizeof(fi));
+-	fi.fh = arg->fh;
++    memset(&fi, 0, sizeof(fi));
++    fi.fh = arg->fh;
+ 
+-	if (req->se->op.lseek)
+-		req->se->op.lseek(req, nodeid, arg->offset, arg->whence, &fi);
+-	else
+-		fuse_reply_err(req, ENOSYS);
++    if (req->se->op.lseek) {
++        req->se->op.lseek(req, nodeid, arg->offset, arg->whence, &fi);
++    } else {
++        fuse_reply_err(req, ENOSYS);
++    }
+ }
+ 
+ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
+-	struct fuse_init_out outarg;
+-	struct fuse_session *se = req->se;
+-	size_t bufsize = se->bufsize;
+-	size_t outargsize = sizeof(outarg);
+-
+-	(void) nodeid;
+-	if (se->debug) {
+-		fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor);
+-		if (arg->major == 7 && arg->minor >= 6) {
+-			fuse_log(FUSE_LOG_DEBUG, "flags=0x%08x\n", arg->flags);
+-			fuse_log(FUSE_LOG_DEBUG, "max_readahead=0x%08x\n",
+-				arg->max_readahead);
+-		}
+-	}
+-	se->conn.proto_major = arg->major;
+-	se->conn.proto_minor = arg->minor;
+-	se->conn.capable = 0;
+-	se->conn.want = 0;
+-
+-	memset(&outarg, 0, sizeof(outarg));
+-	outarg.major = FUSE_KERNEL_VERSION;
+-	outarg.minor = FUSE_KERNEL_MINOR_VERSION;
+-
+-	if (arg->major < 7) {
+-		fuse_log(FUSE_LOG_ERR, "fuse: unsupported protocol version: %u.%u\n",
+-			arg->major, arg->minor);
+-		fuse_reply_err(req, EPROTO);
+-		return;
+-	}
+-
+-	if (arg->major > 7) {
+-		/* Wait for a second INIT request with a 7.X version */
+-		send_reply_ok(req, &outarg, sizeof(outarg));
+-		return;
+-	}
+-
+-	if (arg->minor >= 6) {
+-		if (arg->max_readahead < se->conn.max_readahead)
+-			se->conn.max_readahead = arg->max_readahead;
+-		if (arg->flags & FUSE_ASYNC_READ)
+-			se->conn.capable |= FUSE_CAP_ASYNC_READ;
+-		if (arg->flags & FUSE_POSIX_LOCKS)
+-			se->conn.capable |= FUSE_CAP_POSIX_LOCKS;
+-		if (arg->flags & FUSE_ATOMIC_O_TRUNC)
+-			se->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC;
+-		if (arg->flags & FUSE_EXPORT_SUPPORT)
+-			se->conn.capable |= FUSE_CAP_EXPORT_SUPPORT;
+-		if (arg->flags & FUSE_DONT_MASK)
+-			se->conn.capable |= FUSE_CAP_DONT_MASK;
+-		if (arg->flags & FUSE_FLOCK_LOCKS)
+-			se->conn.capable |= FUSE_CAP_FLOCK_LOCKS;
+-		if (arg->flags & FUSE_AUTO_INVAL_DATA)
+-			se->conn.capable |= FUSE_CAP_AUTO_INVAL_DATA;
+-		if (arg->flags & FUSE_DO_READDIRPLUS)
+-			se->conn.capable |= FUSE_CAP_READDIRPLUS;
+-		if (arg->flags & FUSE_READDIRPLUS_AUTO)
+-			se->conn.capable |= FUSE_CAP_READDIRPLUS_AUTO;
+-		if (arg->flags & FUSE_ASYNC_DIO)
+-			se->conn.capable |= FUSE_CAP_ASYNC_DIO;
+-		if (arg->flags & FUSE_WRITEBACK_CACHE)
+-			se->conn.capable |= FUSE_CAP_WRITEBACK_CACHE;
+-		if (arg->flags & FUSE_NO_OPEN_SUPPORT)
+-			se->conn.capable |= FUSE_CAP_NO_OPEN_SUPPORT;
+-		if (arg->flags & FUSE_PARALLEL_DIROPS)
+-			se->conn.capable |= FUSE_CAP_PARALLEL_DIROPS;
+-		if (arg->flags & FUSE_POSIX_ACL)
+-			se->conn.capable |= FUSE_CAP_POSIX_ACL;
+-		if (arg->flags & FUSE_HANDLE_KILLPRIV)
+-			se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV;
+-		if (arg->flags & FUSE_NO_OPENDIR_SUPPORT)
+-			se->conn.capable |= FUSE_CAP_NO_OPENDIR_SUPPORT;
+-		if (!(arg->flags & FUSE_MAX_PAGES)) {
+-			size_t max_bufsize =
+-				FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize()
+-				+ FUSE_BUFFER_HEADER_SIZE;
+-			if (bufsize > max_bufsize) {
+-				bufsize = max_bufsize;
+-			}
+-		}
+-	} else {
+-		se->conn.max_readahead = 0;
+-	}
+-
+-	if (se->conn.proto_minor >= 14) {
++    struct fuse_init_in *arg = (struct fuse_init_in *)inarg;
++    struct fuse_init_out outarg;
++    struct fuse_session *se = req->se;
++    size_t bufsize = se->bufsize;
++    size_t outargsize = sizeof(outarg);
++
++    (void)nodeid;
++    if (se->debug) {
++        fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor);
++        if (arg->major == 7 && arg->minor >= 6) {
++            fuse_log(FUSE_LOG_DEBUG, "flags=0x%08x\n", arg->flags);
++            fuse_log(FUSE_LOG_DEBUG, "max_readahead=0x%08x\n",
++                     arg->max_readahead);
++        }
++    }
++    se->conn.proto_major = arg->major;
++    se->conn.proto_minor = arg->minor;
++    se->conn.capable = 0;
++    se->conn.want = 0;
++
++    memset(&outarg, 0, sizeof(outarg));
++    outarg.major = FUSE_KERNEL_VERSION;
++    outarg.minor = FUSE_KERNEL_MINOR_VERSION;
++
++    if (arg->major < 7) {
++        fuse_log(FUSE_LOG_ERR, "fuse: unsupported protocol version: %u.%u\n",
++                 arg->major, arg->minor);
++        fuse_reply_err(req, EPROTO);
++        return;
++    }
++
++    if (arg->major > 7) {
++        /* Wait for a second INIT request with a 7.X version */
++        send_reply_ok(req, &outarg, sizeof(outarg));
++        return;
++    }
++
++    if (arg->minor >= 6) {
++        if (arg->max_readahead < se->conn.max_readahead) {
++            se->conn.max_readahead = arg->max_readahead;
++        }
++        if (arg->flags & FUSE_ASYNC_READ) {
++            se->conn.capable |= FUSE_CAP_ASYNC_READ;
++        }
++        if (arg->flags & FUSE_POSIX_LOCKS) {
++            se->conn.capable |= FUSE_CAP_POSIX_LOCKS;
++        }
++        if (arg->flags & FUSE_ATOMIC_O_TRUNC) {
++            se->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC;
++        }
++        if (arg->flags & FUSE_EXPORT_SUPPORT) {
++            se->conn.capable |= FUSE_CAP_EXPORT_SUPPORT;
++        }
++        if (arg->flags & FUSE_DONT_MASK) {
++            se->conn.capable |= FUSE_CAP_DONT_MASK;
++        }
++        if (arg->flags & FUSE_FLOCK_LOCKS) {
++            se->conn.capable |= FUSE_CAP_FLOCK_LOCKS;
++        }
++        if (arg->flags & FUSE_AUTO_INVAL_DATA) {
++            se->conn.capable |= FUSE_CAP_AUTO_INVAL_DATA;
++        }
++        if (arg->flags & FUSE_DO_READDIRPLUS) {
++            se->conn.capable |= FUSE_CAP_READDIRPLUS;
++        }
++        if (arg->flags & FUSE_READDIRPLUS_AUTO) {
++            se->conn.capable |= FUSE_CAP_READDIRPLUS_AUTO;
++        }
++        if (arg->flags & FUSE_ASYNC_DIO) {
++            se->conn.capable |= FUSE_CAP_ASYNC_DIO;
++        }
++        if (arg->flags & FUSE_WRITEBACK_CACHE) {
++            se->conn.capable |= FUSE_CAP_WRITEBACK_CACHE;
++        }
++        if (arg->flags & FUSE_NO_OPEN_SUPPORT) {
++            se->conn.capable |= FUSE_CAP_NO_OPEN_SUPPORT;
++        }
++        if (arg->flags & FUSE_PARALLEL_DIROPS) {
++            se->conn.capable |= FUSE_CAP_PARALLEL_DIROPS;
++        }
++        if (arg->flags & FUSE_POSIX_ACL) {
++            se->conn.capable |= FUSE_CAP_POSIX_ACL;
++        }
++        if (arg->flags & FUSE_HANDLE_KILLPRIV) {
++            se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV;
++        }
++        if (arg->flags & FUSE_NO_OPENDIR_SUPPORT) {
++            se->conn.capable |= FUSE_CAP_NO_OPENDIR_SUPPORT;
++        }
++        if (!(arg->flags & FUSE_MAX_PAGES)) {
++            size_t max_bufsize =
++                FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize() +
++                FUSE_BUFFER_HEADER_SIZE;
++            if (bufsize > max_bufsize) {
++                bufsize = max_bufsize;
++            }
++        }
++    } else {
++        se->conn.max_readahead = 0;
++    }
++
++    if (se->conn.proto_minor >= 14) {
+ #ifdef HAVE_SPLICE
+ #ifdef HAVE_VMSPLICE
+-		se->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE;
++        se->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE;
+ #endif
+-		se->conn.capable |= FUSE_CAP_SPLICE_READ;
++        se->conn.capable |= FUSE_CAP_SPLICE_READ;
+ #endif
+-	}
+-	if (se->conn.proto_minor >= 18)
+-		se->conn.capable |= FUSE_CAP_IOCTL_DIR;
+-
+-	/* Default settings for modern filesystems.
+-	 *
+-	 * Most of these capabilities were disabled by default in
+-	 * libfuse2 for backwards compatibility reasons. In libfuse3,
+-	 * we can finally enable them by default (as long as they're
+-	 * supported by the kernel).
+-	 */
+-#define LL_SET_DEFAULT(cond, cap) \
+-	if ((cond) && (se->conn.capable & (cap))) \
+-		se->conn.want |= (cap)
+-	LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_READ);
+-	LL_SET_DEFAULT(1, FUSE_CAP_PARALLEL_DIROPS);
+-	LL_SET_DEFAULT(1, FUSE_CAP_AUTO_INVAL_DATA);
+-	LL_SET_DEFAULT(1, FUSE_CAP_HANDLE_KILLPRIV);
+-	LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_DIO);
+-	LL_SET_DEFAULT(1, FUSE_CAP_IOCTL_DIR);
+-	LL_SET_DEFAULT(1, FUSE_CAP_ATOMIC_O_TRUNC);
+-	LL_SET_DEFAULT(se->op.write_buf, FUSE_CAP_SPLICE_READ);
+-	LL_SET_DEFAULT(se->op.getlk && se->op.setlk,
+-		       FUSE_CAP_POSIX_LOCKS);
+-	LL_SET_DEFAULT(se->op.flock, FUSE_CAP_FLOCK_LOCKS);
+-	LL_SET_DEFAULT(se->op.readdirplus, FUSE_CAP_READDIRPLUS);
+-	LL_SET_DEFAULT(se->op.readdirplus && se->op.readdir,
+-		       FUSE_CAP_READDIRPLUS_AUTO);
+-	se->conn.time_gran = 1;
+-	
+-	if (bufsize < FUSE_MIN_READ_BUFFER) {
+-		fuse_log(FUSE_LOG_ERR, "fuse: warning: buffer size too small: %zu\n",
+-			bufsize);
+-		bufsize = FUSE_MIN_READ_BUFFER;
+-	}
+-	se->bufsize = bufsize;
+-
+-	if (se->conn.max_write > bufsize - FUSE_BUFFER_HEADER_SIZE)
+-		se->conn.max_write = bufsize - FUSE_BUFFER_HEADER_SIZE;
+-
+-	se->got_init = 1;
+-	if (se->op.init)
+-		se->op.init(se->userdata, &se->conn);
+-
+-	if (se->conn.want & (~se->conn.capable)) {
+-		fuse_log(FUSE_LOG_ERR, "fuse: error: filesystem requested capabilities "
+-			"0x%x that are not supported by kernel, aborting.\n",
+-			se->conn.want & (~se->conn.capable));
+-		fuse_reply_err(req, EPROTO);
+-		se->error = -EPROTO;
+-		fuse_session_exit(se);
+-		return;
+-	}
+-
+-	if (se->conn.max_write < bufsize - FUSE_BUFFER_HEADER_SIZE) {
+-		se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
+-	}
+-	if (arg->flags & FUSE_MAX_PAGES) {
+-		outarg.flags |= FUSE_MAX_PAGES;
+-		outarg.max_pages = (se->conn.max_write - 1) / getpagesize() + 1;
+-	}
+-
+-	/* Always enable big writes, this is superseded
+-	   by the max_write option */
+-	outarg.flags |= FUSE_BIG_WRITES;
+-
+-	if (se->conn.want & FUSE_CAP_ASYNC_READ)
+-		outarg.flags |= FUSE_ASYNC_READ;
+-	if (se->conn.want & FUSE_CAP_POSIX_LOCKS)
+-		outarg.flags |= FUSE_POSIX_LOCKS;
+-	if (se->conn.want & FUSE_CAP_ATOMIC_O_TRUNC)
+-		outarg.flags |= FUSE_ATOMIC_O_TRUNC;
+-	if (se->conn.want & FUSE_CAP_EXPORT_SUPPORT)
+-		outarg.flags |= FUSE_EXPORT_SUPPORT;
+-	if (se->conn.want & FUSE_CAP_DONT_MASK)
+-		outarg.flags |= FUSE_DONT_MASK;
+-	if (se->conn.want & FUSE_CAP_FLOCK_LOCKS)
+-		outarg.flags |= FUSE_FLOCK_LOCKS;
+-	if (se->conn.want & FUSE_CAP_AUTO_INVAL_DATA)
+-		outarg.flags |= FUSE_AUTO_INVAL_DATA;
+-	if (se->conn.want & FUSE_CAP_READDIRPLUS)
+-		outarg.flags |= FUSE_DO_READDIRPLUS;
+-	if (se->conn.want & FUSE_CAP_READDIRPLUS_AUTO)
+-		outarg.flags |= FUSE_READDIRPLUS_AUTO;
+-	if (se->conn.want & FUSE_CAP_ASYNC_DIO)
+-		outarg.flags |= FUSE_ASYNC_DIO;
+-	if (se->conn.want & FUSE_CAP_WRITEBACK_CACHE)
+-		outarg.flags |= FUSE_WRITEBACK_CACHE;
+-	if (se->conn.want & FUSE_CAP_POSIX_ACL)
+-		outarg.flags |= FUSE_POSIX_ACL;
+-	outarg.max_readahead = se->conn.max_readahead;
+-	outarg.max_write = se->conn.max_write;
+-	if (se->conn.proto_minor >= 13) {
+-		if (se->conn.max_background >= (1 << 16))
+-			se->conn.max_background = (1 << 16) - 1;
+-		if (se->conn.congestion_threshold > se->conn.max_background)
+-			se->conn.congestion_threshold = se->conn.max_background;
+-		if (!se->conn.congestion_threshold) {
+-			se->conn.congestion_threshold =
+-				se->conn.max_background * 3 / 4;
+-		}
+-
+-		outarg.max_background = se->conn.max_background;
+-		outarg.congestion_threshold = se->conn.congestion_threshold;
+-	}
+-	if (se->conn.proto_minor >= 23)
+-		outarg.time_gran = se->conn.time_gran;
+-
+-	if (se->debug) {
+-		fuse_log(FUSE_LOG_DEBUG, "   INIT: %u.%u\n", outarg.major, outarg.minor);
+-		fuse_log(FUSE_LOG_DEBUG, "   flags=0x%08x\n", outarg.flags);
+-		fuse_log(FUSE_LOG_DEBUG, "   max_readahead=0x%08x\n",
+-			outarg.max_readahead);
+-		fuse_log(FUSE_LOG_DEBUG, "   max_write=0x%08x\n", outarg.max_write);
+-		fuse_log(FUSE_LOG_DEBUG, "   max_background=%i\n",
+-			outarg.max_background);
+-		fuse_log(FUSE_LOG_DEBUG, "   congestion_threshold=%i\n",
+-			outarg.congestion_threshold);
+-		fuse_log(FUSE_LOG_DEBUG, "   time_gran=%u\n",
+-			outarg.time_gran);
+-	}
+-	if (arg->minor < 5)
+-		outargsize = FUSE_COMPAT_INIT_OUT_SIZE;
+-	else if (arg->minor < 23)
+-		outargsize = FUSE_COMPAT_22_INIT_OUT_SIZE;
+-
+-	send_reply_ok(req, &outarg, outargsize);
++    }
++    if (se->conn.proto_minor >= 18) {
++        se->conn.capable |= FUSE_CAP_IOCTL_DIR;
++    }
++
++    /*
++     * Default settings for modern filesystems.
++     *
++     * Most of these capabilities were disabled by default in
++     * libfuse2 for backwards compatibility reasons. In libfuse3,
++     * we can finally enable them by default (as long as they're
++     * supported by the kernel).
++     */
++#define LL_SET_DEFAULT(cond, cap)             \
++    if ((cond) && (se->conn.capable & (cap))) \
++        se->conn.want |= (cap)
++    LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_READ);
++    LL_SET_DEFAULT(1, FUSE_CAP_PARALLEL_DIROPS);
++    LL_SET_DEFAULT(1, FUSE_CAP_AUTO_INVAL_DATA);
++    LL_SET_DEFAULT(1, FUSE_CAP_HANDLE_KILLPRIV);
++    LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_DIO);
++    LL_SET_DEFAULT(1, FUSE_CAP_IOCTL_DIR);
++    LL_SET_DEFAULT(1, FUSE_CAP_ATOMIC_O_TRUNC);
++    LL_SET_DEFAULT(se->op.write_buf, FUSE_CAP_SPLICE_READ);
++    LL_SET_DEFAULT(se->op.getlk && se->op.setlk, FUSE_CAP_POSIX_LOCKS);
++    LL_SET_DEFAULT(se->op.flock, FUSE_CAP_FLOCK_LOCKS);
++    LL_SET_DEFAULT(se->op.readdirplus, FUSE_CAP_READDIRPLUS);
++    LL_SET_DEFAULT(se->op.readdirplus && se->op.readdir,
++                   FUSE_CAP_READDIRPLUS_AUTO);
++    se->conn.time_gran = 1;
++
++    if (bufsize < FUSE_MIN_READ_BUFFER) {
++        fuse_log(FUSE_LOG_ERR, "fuse: warning: buffer size too small: %zu\n",
++                 bufsize);
++        bufsize = FUSE_MIN_READ_BUFFER;
++    }
++    se->bufsize = bufsize;
++
++    if (se->conn.max_write > bufsize - FUSE_BUFFER_HEADER_SIZE) {
++        se->conn.max_write = bufsize - FUSE_BUFFER_HEADER_SIZE;
++    }
++
++    se->got_init = 1;
++    if (se->op.init) {
++        se->op.init(se->userdata, &se->conn);
++    }
++
++    if (se->conn.want & (~se->conn.capable)) {
++        fuse_log(FUSE_LOG_ERR,
++                 "fuse: error: filesystem requested capabilities "
++                 "0x%x that are not supported by kernel, aborting.\n",
++                 se->conn.want & (~se->conn.capable));
++        fuse_reply_err(req, EPROTO);
++        se->error = -EPROTO;
++        fuse_session_exit(se);
++        return;
++    }
++
++    if (se->conn.max_write < bufsize - FUSE_BUFFER_HEADER_SIZE) {
++        se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
++    }
++    if (arg->flags & FUSE_MAX_PAGES) {
++        outarg.flags |= FUSE_MAX_PAGES;
++        outarg.max_pages = (se->conn.max_write - 1) / getpagesize() + 1;
++    }
++
++    /*
++     * Always enable big writes, this is superseded
++     * by the max_write option
++     */
++    outarg.flags |= FUSE_BIG_WRITES;
++
++    if (se->conn.want & FUSE_CAP_ASYNC_READ) {
++        outarg.flags |= FUSE_ASYNC_READ;
++    }
++    if (se->conn.want & FUSE_CAP_POSIX_LOCKS) {
++        outarg.flags |= FUSE_POSIX_LOCKS;
++    }
++    if (se->conn.want & FUSE_CAP_ATOMIC_O_TRUNC) {
++        outarg.flags |= FUSE_ATOMIC_O_TRUNC;
++    }
++    if (se->conn.want & FUSE_CAP_EXPORT_SUPPORT) {
++        outarg.flags |= FUSE_EXPORT_SUPPORT;
++    }
++    if (se->conn.want & FUSE_CAP_DONT_MASK) {
++        outarg.flags |= FUSE_DONT_MASK;
++    }
++    if (se->conn.want & FUSE_CAP_FLOCK_LOCKS) {
++        outarg.flags |= FUSE_FLOCK_LOCKS;
++    }
++    if (se->conn.want & FUSE_CAP_AUTO_INVAL_DATA) {
++        outarg.flags |= FUSE_AUTO_INVAL_DATA;
++    }
++    if (se->conn.want & FUSE_CAP_READDIRPLUS) {
++        outarg.flags |= FUSE_DO_READDIRPLUS;
++    }
++    if (se->conn.want & FUSE_CAP_READDIRPLUS_AUTO) {
++        outarg.flags |= FUSE_READDIRPLUS_AUTO;
++    }
++    if (se->conn.want & FUSE_CAP_ASYNC_DIO) {
++        outarg.flags |= FUSE_ASYNC_DIO;
++    }
++    if (se->conn.want & FUSE_CAP_WRITEBACK_CACHE) {
++        outarg.flags |= FUSE_WRITEBACK_CACHE;
++    }
++    if (se->conn.want & FUSE_CAP_POSIX_ACL) {
++        outarg.flags |= FUSE_POSIX_ACL;
++    }
++    outarg.max_readahead = se->conn.max_readahead;
++    outarg.max_write = se->conn.max_write;
++    if (se->conn.proto_minor >= 13) {
++        if (se->conn.max_background >= (1 << 16)) {
++            se->conn.max_background = (1 << 16) - 1;
++        }
++        if (se->conn.congestion_threshold > se->conn.max_background) {
++            se->conn.congestion_threshold = se->conn.max_background;
++        }
++        if (!se->conn.congestion_threshold) {
++            se->conn.congestion_threshold = se->conn.max_background * 3 / 4;
++        }
++
++        outarg.max_background = se->conn.max_background;
++        outarg.congestion_threshold = se->conn.congestion_threshold;
++    }
++    if (se->conn.proto_minor >= 23) {
++        outarg.time_gran = se->conn.time_gran;
++    }
++
++    if (se->debug) {
++        fuse_log(FUSE_LOG_DEBUG, "   INIT: %u.%u\n", outarg.major,
++                 outarg.minor);
++        fuse_log(FUSE_LOG_DEBUG, "   flags=0x%08x\n", outarg.flags);
++        fuse_log(FUSE_LOG_DEBUG, "   max_readahead=0x%08x\n",
++                 outarg.max_readahead);
++        fuse_log(FUSE_LOG_DEBUG, "   max_write=0x%08x\n", outarg.max_write);
++        fuse_log(FUSE_LOG_DEBUG, "   max_background=%i\n",
++                 outarg.max_background);
++        fuse_log(FUSE_LOG_DEBUG, "   congestion_threshold=%i\n",
++                 outarg.congestion_threshold);
++        fuse_log(FUSE_LOG_DEBUG, "   time_gran=%u\n", outarg.time_gran);
++    }
++    if (arg->minor < 5) {
++        outargsize = FUSE_COMPAT_INIT_OUT_SIZE;
++    } else if (arg->minor < 23) {
++        outargsize = FUSE_COMPAT_22_INIT_OUT_SIZE;
++    }
++
++    send_reply_ok(req, &outarg, outargsize);
+ }
+ 
+ static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+-	struct fuse_session *se = req->se;
++    struct fuse_session *se = req->se;
+ 
+-	(void) nodeid;
+-	(void) inarg;
++    (void)nodeid;
++    (void)inarg;
+ 
+-	se->got_destroy = 1;
+-	if (se->op.destroy)
+-		se->op.destroy(se->userdata);
++    se->got_destroy = 1;
++    if (se->op.destroy) {
++        se->op.destroy(se->userdata);
++    }
+ 
+-	send_reply_ok(req, NULL, 0);
++    send_reply_ok(req, NULL, 0);
+ }
+ 
+ static void list_del_nreq(struct fuse_notify_req *nreq)
+ {
+-	struct fuse_notify_req *prev = nreq->prev;
+-	struct fuse_notify_req *next = nreq->next;
+-	prev->next = next;
+-	next->prev = prev;
++    struct fuse_notify_req *prev = nreq->prev;
++    struct fuse_notify_req *next = nreq->next;
++    prev->next = next;
++    next->prev = prev;
+ }
+ 
+ static void list_add_nreq(struct fuse_notify_req *nreq,
+-			  struct fuse_notify_req *next)
++                          struct fuse_notify_req *next)
+ {
+-	struct fuse_notify_req *prev = next->prev;
+-	nreq->next = next;
+-	nreq->prev = prev;
+-	prev->next = nreq;
+-	next->prev = nreq;
++    struct fuse_notify_req *prev = next->prev;
++    nreq->next = next;
++    nreq->prev = prev;
++    prev->next = nreq;
++    next->prev = nreq;
+ }
+ 
+ static void list_init_nreq(struct fuse_notify_req *nreq)
+ {
+-	nreq->next = nreq;
+-	nreq->prev = nreq;
++    nreq->next = nreq;
++    nreq->prev = nreq;
+ }
+ 
+ static void do_notify_reply(fuse_req_t req, fuse_ino_t nodeid,
+-			    const void *inarg, const struct fuse_buf *buf)
++                            const void *inarg, const struct fuse_buf *buf)
+ {
+-	struct fuse_session *se = req->se;
+-	struct fuse_notify_req *nreq;
+-	struct fuse_notify_req *head;
++    struct fuse_session *se = req->se;
++    struct fuse_notify_req *nreq;
++    struct fuse_notify_req *head;
+ 
+-	pthread_mutex_lock(&se->lock);
+-	head = &se->notify_list;
+-	for (nreq = head->next; nreq != head; nreq = nreq->next) {
+-		if (nreq->unique == req->unique) {
+-			list_del_nreq(nreq);
+-			break;
+-		}
+-	}
+-	pthread_mutex_unlock(&se->lock);
++    pthread_mutex_lock(&se->lock);
++    head = &se->notify_list;
++    for (nreq = head->next; nreq != head; nreq = nreq->next) {
++        if (nreq->unique == req->unique) {
++            list_del_nreq(nreq);
++            break;
++        }
++    }
++    pthread_mutex_unlock(&se->lock);
+ 
+-	if (nreq != head)
+-		nreq->reply(nreq, req, nodeid, inarg, buf);
++    if (nreq != head) {
++        nreq->reply(nreq, req, nodeid, inarg, buf);
++    }
+ }
+ 
+ static int send_notify_iov(struct fuse_session *se, int notify_code,
+-			   struct iovec *iov, int count)
++                           struct iovec *iov, int count)
+ {
+-	struct fuse_out_header out;
++    struct fuse_out_header out;
+ 
+-	if (!se->got_init)
+-		return -ENOTCONN;
++    if (!se->got_init) {
++        return -ENOTCONN;
++    }
+ 
+-	out.unique = 0;
+-	out.error = notify_code;
+-	iov[0].iov_base = &out;
+-	iov[0].iov_len = sizeof(struct fuse_out_header);
++    out.unique = 0;
++    out.error = notify_code;
++    iov[0].iov_base = &out;
++    iov[0].iov_len = sizeof(struct fuse_out_header);
+ 
+-	return fuse_send_msg(se, NULL, iov, count);
++    return fuse_send_msg(se, NULL, iov, count);
+ }
+ 
+ int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
+ {
+-	if (ph != NULL) {
+-		struct fuse_notify_poll_wakeup_out outarg;
+-		struct iovec iov[2];
++    if (ph != NULL) {
++        struct fuse_notify_poll_wakeup_out outarg;
++        struct iovec iov[2];
+ 
+-		outarg.kh = ph->kh;
++        outarg.kh = ph->kh;
+ 
+-		iov[1].iov_base = &outarg;
+-		iov[1].iov_len = sizeof(outarg);
++        iov[1].iov_base = &outarg;
++        iov[1].iov_len = sizeof(outarg);
+ 
+-		return send_notify_iov(ph->se, FUSE_NOTIFY_POLL, iov, 2);
+-	} else {
+-		return 0;
+-	}
++        return send_notify_iov(ph->se, FUSE_NOTIFY_POLL, iov, 2);
++    } else {
++        return 0;
++    }
+ }
+ 
+ int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
+-				     off_t off, off_t len)
++                                     off_t off, off_t len)
+ {
+-	struct fuse_notify_inval_inode_out outarg;
+-	struct iovec iov[2];
++    struct fuse_notify_inval_inode_out outarg;
++    struct iovec iov[2];
++
++    if (!se) {
++        return -EINVAL;
++    }
+ 
+-	if (!se)
+-		return -EINVAL;
++    if (se->conn.proto_major < 6 || se->conn.proto_minor < 12) {
++        return -ENOSYS;
++    }
+ 
+-	if (se->conn.proto_major < 6 || se->conn.proto_minor < 12)
+-		return -ENOSYS;
+-	
+-	outarg.ino = ino;
+-	outarg.off = off;
+-	outarg.len = len;
++    outarg.ino = ino;
++    outarg.off = off;
++    outarg.len = len;
+ 
+-	iov[1].iov_base = &outarg;
+-	iov[1].iov_len = sizeof(outarg);
++    iov[1].iov_base = &outarg;
++    iov[1].iov_len = sizeof(outarg);
+ 
+-	return send_notify_iov(se, FUSE_NOTIFY_INVAL_INODE, iov, 2);
++    return send_notify_iov(se, FUSE_NOTIFY_INVAL_INODE, iov, 2);
+ }
+ 
+ int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
+-				     const char *name, size_t namelen)
++                                     const char *name, size_t namelen)
+ {
+-	struct fuse_notify_inval_entry_out outarg;
+-	struct iovec iov[3];
++    struct fuse_notify_inval_entry_out outarg;
++    struct iovec iov[3];
++
++    if (!se) {
++        return -EINVAL;
++    }
+ 
+-	if (!se)
+-		return -EINVAL;
+-	
+-	if (se->conn.proto_major < 6 || se->conn.proto_minor < 12)
+-		return -ENOSYS;
++    if (se->conn.proto_major < 6 || se->conn.proto_minor < 12) {
++        return -ENOSYS;
++    }
+ 
+-	outarg.parent = parent;
+-	outarg.namelen = namelen;
+-	outarg.padding = 0;
++    outarg.parent = parent;
++    outarg.namelen = namelen;
++    outarg.padding = 0;
+ 
+-	iov[1].iov_base = &outarg;
+-	iov[1].iov_len = sizeof(outarg);
+-	iov[2].iov_base = (void *)name;
+-	iov[2].iov_len = namelen + 1;
++    iov[1].iov_base = &outarg;
++    iov[1].iov_len = sizeof(outarg);
++    iov[2].iov_base = (void *)name;
++    iov[2].iov_len = namelen + 1;
+ 
+-	return send_notify_iov(se, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
++    return send_notify_iov(se, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
+ }
+ 
+-int fuse_lowlevel_notify_delete(struct fuse_session *se,
+-				fuse_ino_t parent, fuse_ino_t child,
+-				const char *name, size_t namelen)
++int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent,
++                                fuse_ino_t child, const char *name,
++                                size_t namelen)
+ {
+-	struct fuse_notify_delete_out outarg;
+-	struct iovec iov[3];
++    struct fuse_notify_delete_out outarg;
++    struct iovec iov[3];
+ 
+-	if (!se)
+-		return -EINVAL;
++    if (!se) {
++        return -EINVAL;
++    }
+ 
+-	if (se->conn.proto_major < 6 || se->conn.proto_minor < 18)
+-		return -ENOSYS;
++    if (se->conn.proto_major < 6 || se->conn.proto_minor < 18) {
++        return -ENOSYS;
++    }
+ 
+-	outarg.parent = parent;
+-	outarg.child = child;
+-	outarg.namelen = namelen;
+-	outarg.padding = 0;
++    outarg.parent = parent;
++    outarg.child = child;
++    outarg.namelen = namelen;
++    outarg.padding = 0;
+ 
+-	iov[1].iov_base = &outarg;
+-	iov[1].iov_len = sizeof(outarg);
+-	iov[2].iov_base = (void *)name;
+-	iov[2].iov_len = namelen + 1;
++    iov[1].iov_base = &outarg;
++    iov[1].iov_len = sizeof(outarg);
++    iov[2].iov_base = (void *)name;
++    iov[2].iov_len = namelen + 1;
+ 
+-	return send_notify_iov(se, FUSE_NOTIFY_DELETE, iov, 3);
++    return send_notify_iov(se, FUSE_NOTIFY_DELETE, iov, 3);
+ }
+ 
+ int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
+-			       off_t offset, struct fuse_bufvec *bufv,
+-			       enum fuse_buf_copy_flags flags)
++                               off_t offset, struct fuse_bufvec *bufv,
++                               enum fuse_buf_copy_flags flags)
+ {
+-	struct fuse_out_header out;
+-	struct fuse_notify_store_out outarg;
+-	struct iovec iov[3];
+-	size_t size = fuse_buf_size(bufv);
+-	int res;
++    struct fuse_out_header out;
++    struct fuse_notify_store_out outarg;
++    struct iovec iov[3];
++    size_t size = fuse_buf_size(bufv);
++    int res;
+ 
+-	if (!se)
+-		return -EINVAL;
++    if (!se) {
++        return -EINVAL;
++    }
+ 
+-	if (se->conn.proto_major < 6 || se->conn.proto_minor < 15)
+-		return -ENOSYS;
++    if (se->conn.proto_major < 6 || se->conn.proto_minor < 15) {
++        return -ENOSYS;
++    }
+ 
+-	out.unique = 0;
+-	out.error = FUSE_NOTIFY_STORE;
++    out.unique = 0;
++    out.error = FUSE_NOTIFY_STORE;
+ 
+-	outarg.nodeid = ino;
+-	outarg.offset = offset;
+-	outarg.size = size;
+-	outarg.padding = 0;
++    outarg.nodeid = ino;
++    outarg.offset = offset;
++    outarg.size = size;
++    outarg.padding = 0;
+ 
+-	iov[0].iov_base = &out;
+-	iov[0].iov_len = sizeof(out);
+-	iov[1].iov_base = &outarg;
+-	iov[1].iov_len = sizeof(outarg);
++    iov[0].iov_base = &out;
++    iov[0].iov_len = sizeof(out);
++    iov[1].iov_base = &outarg;
++    iov[1].iov_len = sizeof(outarg);
+ 
+-	res = fuse_send_data_iov(se, NULL, iov, 2, bufv, flags);
+-	if (res > 0)
+-		res = -res;
++    res = fuse_send_data_iov(se, NULL, iov, 2, bufv, flags);
++    if (res > 0) {
++        res = -res;
++    }
+ 
+-	return res;
++    return res;
+ }
+ 
+ struct fuse_retrieve_req {
+-	struct fuse_notify_req nreq;
+-	void *cookie;
++    struct fuse_notify_req nreq;
++    void *cookie;
+ };
+ 
+-static void fuse_ll_retrieve_reply(struct fuse_notify_req *nreq,
+-				   fuse_req_t req, fuse_ino_t ino,
+-				   const void *inarg,
+-				   const struct fuse_buf *ibuf)
+-{
+-	struct fuse_session *se = req->se;
+-	struct fuse_retrieve_req *rreq =
+-		container_of(nreq, struct fuse_retrieve_req, nreq);
+-	const struct fuse_notify_retrieve_in *arg = inarg;
+-	struct fuse_bufvec bufv = {
+-		.buf[0] = *ibuf,
+-		.count = 1,
+-	};
+-
+-	if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
+-		bufv.buf[0].mem = PARAM(arg);
+-
+-	bufv.buf[0].size -= sizeof(struct fuse_in_header) +
+-		sizeof(struct fuse_notify_retrieve_in);
+-
+-	if (bufv.buf[0].size < arg->size) {
+-		fuse_log(FUSE_LOG_ERR, "fuse: retrieve reply: buffer size too small\n");
+-		fuse_reply_none(req);
+-		goto out;
+-	}
+-	bufv.buf[0].size = arg->size;
+-
+-	if (se->op.retrieve_reply) {
+-		se->op.retrieve_reply(req, rreq->cookie, ino,
+-					  arg->offset, &bufv);
+-	} else {
+-		fuse_reply_none(req);
+-	}
++static void fuse_ll_retrieve_reply(struct fuse_notify_req *nreq, fuse_req_t req,
++                                   fuse_ino_t ino, const void *inarg,
++                                   const struct fuse_buf *ibuf)
++{
++    struct fuse_session *se = req->se;
++    struct fuse_retrieve_req *rreq =
++        container_of(nreq, struct fuse_retrieve_req, nreq);
++    const struct fuse_notify_retrieve_in *arg = inarg;
++    struct fuse_bufvec bufv = {
++        .buf[0] = *ibuf,
++        .count = 1,
++    };
++
++    if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD)) {
++        bufv.buf[0].mem = PARAM(arg);
++    }
++
++    bufv.buf[0].size -=
++        sizeof(struct fuse_in_header) + sizeof(struct fuse_notify_retrieve_in);
++
++    if (bufv.buf[0].size < arg->size) {
++        fuse_log(FUSE_LOG_ERR, "fuse: retrieve reply: buffer size too small\n");
++        fuse_reply_none(req);
++        goto out;
++    }
++    bufv.buf[0].size = arg->size;
++
++    if (se->op.retrieve_reply) {
++        se->op.retrieve_reply(req, rreq->cookie, ino, arg->offset, &bufv);
++    } else {
++        fuse_reply_none(req);
++    }
+ out:
+-	free(rreq);
++    free(rreq);
+ }
+ 
+ int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino,
+-				  size_t size, off_t offset, void *cookie)
++                                  size_t size, off_t offset, void *cookie)
+ {
+-	struct fuse_notify_retrieve_out outarg;
+-	struct iovec iov[2];
+-	struct fuse_retrieve_req *rreq;
+-	int err;
++    struct fuse_notify_retrieve_out outarg;
++    struct iovec iov[2];
++    struct fuse_retrieve_req *rreq;
++    int err;
+ 
+-	if (!se)
+-		return -EINVAL;
++    if (!se) {
++        return -EINVAL;
++    }
+ 
+-	if (se->conn.proto_major < 6 || se->conn.proto_minor < 15)
+-		return -ENOSYS;
++    if (se->conn.proto_major < 6 || se->conn.proto_minor < 15) {
++        return -ENOSYS;
++    }
+ 
+-	rreq = malloc(sizeof(*rreq));
+-	if (rreq == NULL)
+-		return -ENOMEM;
++    rreq = malloc(sizeof(*rreq));
++    if (rreq == NULL) {
++        return -ENOMEM;
++    }
+ 
+-	pthread_mutex_lock(&se->lock);
+-	rreq->cookie = cookie;
+-	rreq->nreq.unique = se->notify_ctr++;
+-	rreq->nreq.reply = fuse_ll_retrieve_reply;
+-	list_add_nreq(&rreq->nreq, &se->notify_list);
+-	pthread_mutex_unlock(&se->lock);
++    pthread_mutex_lock(&se->lock);
++    rreq->cookie = cookie;
++    rreq->nreq.unique = se->notify_ctr++;
++    rreq->nreq.reply = fuse_ll_retrieve_reply;
++    list_add_nreq(&rreq->nreq, &se->notify_list);
++    pthread_mutex_unlock(&se->lock);
+ 
+-	outarg.notify_unique = rreq->nreq.unique;
+-	outarg.nodeid = ino;
+-	outarg.offset = offset;
+-	outarg.size = size;
+-	outarg.padding = 0;
++    outarg.notify_unique = rreq->nreq.unique;
++    outarg.nodeid = ino;
++    outarg.offset = offset;
++    outarg.size = size;
++    outarg.padding = 0;
+ 
+-	iov[1].iov_base = &outarg;
+-	iov[1].iov_len = sizeof(outarg);
++    iov[1].iov_base = &outarg;
++    iov[1].iov_len = sizeof(outarg);
+ 
+-	err = send_notify_iov(se, FUSE_NOTIFY_RETRIEVE, iov, 2);
+-	if (err) {
+-		pthread_mutex_lock(&se->lock);
+-		list_del_nreq(&rreq->nreq);
+-		pthread_mutex_unlock(&se->lock);
+-		free(rreq);
+-	}
++    err = send_notify_iov(se, FUSE_NOTIFY_RETRIEVE, iov, 2);
++    if (err) {
++        pthread_mutex_lock(&se->lock);
++        list_del_nreq(&rreq->nreq);
++        pthread_mutex_unlock(&se->lock);
++        free(rreq);
++    }
+ 
+-	return err;
++    return err;
+ }
+ 
+ void *fuse_req_userdata(fuse_req_t req)
+ {
+-	return req->se->userdata;
++    return req->se->userdata;
+ }
+ 
+ const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
+ {
+-	return &req->ctx;
++    return &req->ctx;
+ }
+ 
+ void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
+-			     void *data)
++                             void *data)
+ {
+-	pthread_mutex_lock(&req->lock);
+-	pthread_mutex_lock(&req->se->lock);
+-	req->u.ni.func = func;
+-	req->u.ni.data = data;
+-	pthread_mutex_unlock(&req->se->lock);
+-	if (req->interrupted && func)
+-		func(req, data);
+-	pthread_mutex_unlock(&req->lock);
++    pthread_mutex_lock(&req->lock);
++    pthread_mutex_lock(&req->se->lock);
++    req->u.ni.func = func;
++    req->u.ni.data = data;
++    pthread_mutex_unlock(&req->se->lock);
++    if (req->interrupted && func) {
++        func(req, data);
++    }
++    pthread_mutex_unlock(&req->lock);
+ }
+ 
+ int fuse_req_interrupted(fuse_req_t req)
+ {
+-	int interrupted;
++    int interrupted;
+ 
+-	pthread_mutex_lock(&req->se->lock);
+-	interrupted = req->interrupted;
+-	pthread_mutex_unlock(&req->se->lock);
++    pthread_mutex_lock(&req->se->lock);
++    interrupted = req->interrupted;
++    pthread_mutex_unlock(&req->se->lock);
+ 
+-	return interrupted;
++    return interrupted;
+ }
+ 
+ static struct {
+-	void (*func)(fuse_req_t, fuse_ino_t, const void *);
+-	const char *name;
++    void (*func)(fuse_req_t, fuse_ino_t, const void *);
++    const char *name;
+ } fuse_ll_ops[] = {
+-	[FUSE_LOOKUP]	   = { do_lookup,      "LOOKUP"	     },
+-	[FUSE_FORGET]	   = { do_forget,      "FORGET"	     },
+-	[FUSE_GETATTR]	   = { do_getattr,     "GETATTR"     },
+-	[FUSE_SETATTR]	   = { do_setattr,     "SETATTR"     },
+-	[FUSE_READLINK]	   = { do_readlink,    "READLINK"    },
+-	[FUSE_SYMLINK]	   = { do_symlink,     "SYMLINK"     },
+-	[FUSE_MKNOD]	   = { do_mknod,       "MKNOD"	     },
+-	[FUSE_MKDIR]	   = { do_mkdir,       "MKDIR"	     },
+-	[FUSE_UNLINK]	   = { do_unlink,      "UNLINK"	     },
+-	[FUSE_RMDIR]	   = { do_rmdir,       "RMDIR"	     },
+-	[FUSE_RENAME]	   = { do_rename,      "RENAME"	     },
+-	[FUSE_LINK]	   = { do_link,	       "LINK"	     },
+-	[FUSE_OPEN]	   = { do_open,	       "OPEN"	     },
+-	[FUSE_READ]	   = { do_read,	       "READ"	     },
+-	[FUSE_WRITE]	   = { do_write,       "WRITE"	     },
+-	[FUSE_STATFS]	   = { do_statfs,      "STATFS"	     },
+-	[FUSE_RELEASE]	   = { do_release,     "RELEASE"     },
+-	[FUSE_FSYNC]	   = { do_fsync,       "FSYNC"	     },
+-	[FUSE_SETXATTR]	   = { do_setxattr,    "SETXATTR"    },
+-	[FUSE_GETXATTR]	   = { do_getxattr,    "GETXATTR"    },
+-	[FUSE_LISTXATTR]   = { do_listxattr,   "LISTXATTR"   },
+-	[FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" },
+-	[FUSE_FLUSH]	   = { do_flush,       "FLUSH"	     },
+-	[FUSE_INIT]	   = { do_init,	       "INIT"	     },
+-	[FUSE_OPENDIR]	   = { do_opendir,     "OPENDIR"     },
+-	[FUSE_READDIR]	   = { do_readdir,     "READDIR"     },
+-	[FUSE_RELEASEDIR]  = { do_releasedir,  "RELEASEDIR"  },
+-	[FUSE_FSYNCDIR]	   = { do_fsyncdir,    "FSYNCDIR"    },
+-	[FUSE_GETLK]	   = { do_getlk,       "GETLK"	     },
+-	[FUSE_SETLK]	   = { do_setlk,       "SETLK"	     },
+-	[FUSE_SETLKW]	   = { do_setlkw,      "SETLKW"	     },
+-	[FUSE_ACCESS]	   = { do_access,      "ACCESS"	     },
+-	[FUSE_CREATE]	   = { do_create,      "CREATE"	     },
+-	[FUSE_INTERRUPT]   = { do_interrupt,   "INTERRUPT"   },
+-	[FUSE_BMAP]	   = { do_bmap,	       "BMAP"	     },
+-	[FUSE_IOCTL]	   = { do_ioctl,       "IOCTL"	     },
+-	[FUSE_POLL]	   = { do_poll,        "POLL"	     },
+-	[FUSE_FALLOCATE]   = { do_fallocate,   "FALLOCATE"   },
+-	[FUSE_DESTROY]	   = { do_destroy,     "DESTROY"     },
+-	[FUSE_NOTIFY_REPLY] = { (void *) 1,    "NOTIFY_REPLY" },
+-	[FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" },
+-	[FUSE_READDIRPLUS] = { do_readdirplus,	"READDIRPLUS"},
+-	[FUSE_RENAME2]     = { do_rename2,      "RENAME2"    },
+-	[FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" },
+-	[FUSE_LSEEK]	   = { do_lseek,       "LSEEK"	     },
++    [FUSE_LOOKUP] = { do_lookup, "LOOKUP" },
++    [FUSE_FORGET] = { do_forget, "FORGET" },
++    [FUSE_GETATTR] = { do_getattr, "GETATTR" },
++    [FUSE_SETATTR] = { do_setattr, "SETATTR" },
++    [FUSE_READLINK] = { do_readlink, "READLINK" },
++    [FUSE_SYMLINK] = { do_symlink, "SYMLINK" },
++    [FUSE_MKNOD] = { do_mknod, "MKNOD" },
++    [FUSE_MKDIR] = { do_mkdir, "MKDIR" },
++    [FUSE_UNLINK] = { do_unlink, "UNLINK" },
++    [FUSE_RMDIR] = { do_rmdir, "RMDIR" },
++    [FUSE_RENAME] = { do_rename, "RENAME" },
++    [FUSE_LINK] = { do_link, "LINK" },
++    [FUSE_OPEN] = { do_open, "OPEN" },
++    [FUSE_READ] = { do_read, "READ" },
++    [FUSE_WRITE] = { do_write, "WRITE" },
++    [FUSE_STATFS] = { do_statfs, "STATFS" },
++    [FUSE_RELEASE] = { do_release, "RELEASE" },
++    [FUSE_FSYNC] = { do_fsync, "FSYNC" },
++    [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" },
++    [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" },
++    [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" },
++    [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" },
++    [FUSE_FLUSH] = { do_flush, "FLUSH" },
++    [FUSE_INIT] = { do_init, "INIT" },
++    [FUSE_OPENDIR] = { do_opendir, "OPENDIR" },
++    [FUSE_READDIR] = { do_readdir, "READDIR" },
++    [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" },
++    [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" },
++    [FUSE_GETLK] = { do_getlk, "GETLK" },
++    [FUSE_SETLK] = { do_setlk, "SETLK" },
++    [FUSE_SETLKW] = { do_setlkw, "SETLKW" },
++    [FUSE_ACCESS] = { do_access, "ACCESS" },
++    [FUSE_CREATE] = { do_create, "CREATE" },
++    [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" },
++    [FUSE_BMAP] = { do_bmap, "BMAP" },
++    [FUSE_IOCTL] = { do_ioctl, "IOCTL" },
++    [FUSE_POLL] = { do_poll, "POLL" },
++    [FUSE_FALLOCATE] = { do_fallocate, "FALLOCATE" },
++    [FUSE_DESTROY] = { do_destroy, "DESTROY" },
++    [FUSE_NOTIFY_REPLY] = { (void *)1, "NOTIFY_REPLY" },
++    [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" },
++    [FUSE_READDIRPLUS] = { do_readdirplus, "READDIRPLUS" },
++    [FUSE_RENAME2] = { do_rename2, "RENAME2" },
++    [FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" },
++    [FUSE_LSEEK] = { do_lseek, "LSEEK" },
+ };
+ 
+ #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
+ 
+ static const char *opname(enum fuse_opcode opcode)
+ {
+-	if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name)
+-		return "???";
+-	else
+-		return fuse_ll_ops[opcode].name;
++    if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name) {
++        return "???";
++    } else {
++        return fuse_ll_ops[opcode].name;
++    }
+ }
+ 
+ void fuse_session_process_buf(struct fuse_session *se,
+-			      const struct fuse_buf *buf)
++                              const struct fuse_buf *buf)
+ {
+-	fuse_session_process_buf_int(se, buf, NULL);
++    fuse_session_process_buf_int(se, buf, NULL);
+ }
+ 
+ void fuse_session_process_buf_int(struct fuse_session *se,
+-				  const struct fuse_buf *buf, struct fuse_chan *ch)
+-{
+-	struct fuse_in_header *in;
+-	const void *inarg;
+-	struct fuse_req *req;
+-	int err;
+-
+-	in = buf->mem;
+-
+-	if (se->debug) {
+-		fuse_log(FUSE_LOG_DEBUG,
+-			"unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n",
+-			(unsigned long long) in->unique,
+-			opname((enum fuse_opcode) in->opcode), in->opcode,
+-			(unsigned long long) in->nodeid, buf->size, in->pid);
+-	}
+-
+-	req = fuse_ll_alloc_req(se);
+-	if (req == NULL) {
+-		struct fuse_out_header out = {
+-			.unique = in->unique,
+-			.error = -ENOMEM,
+-		};
+-		struct iovec iov = {
+-			.iov_base = &out,
+-			.iov_len = sizeof(struct fuse_out_header),
+-		};
+-
+-		fuse_send_msg(se, ch, &iov, 1);
+-		return;
+-	}
+-
+-	req->unique = in->unique;
+-	req->ctx.uid = in->uid;
+-	req->ctx.gid = in->gid;
+-	req->ctx.pid = in->pid;
+-	req->ch = ch;
+-
+-	err = EIO;
+-	if (!se->got_init) {
+-		enum fuse_opcode expected;
+-
+-		expected = se->cuse_data ? CUSE_INIT : FUSE_INIT;
+-		if (in->opcode != expected)
+-			goto reply_err;
+-	} else if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT)
+-		goto reply_err;
+-
+-	err = EACCES;
+-	/* Implement -o allow_root */
+-	if (se->deny_others && in->uid != se->owner && in->uid != 0 &&
+-		 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
+-		 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
+-		 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
+-		 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR &&
+-		 in->opcode != FUSE_NOTIFY_REPLY &&
+-		 in->opcode != FUSE_READDIRPLUS)
+-		goto reply_err;
+-
+-	err = ENOSYS;
+-	if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func)
+-		goto reply_err;
+-	if (in->opcode != FUSE_INTERRUPT) {
+-		struct fuse_req *intr;
+-		pthread_mutex_lock(&se->lock);
+-		intr = check_interrupt(se, req);
+-		list_add_req(req, &se->list);
+-		pthread_mutex_unlock(&se->lock);
+-		if (intr)
+-			fuse_reply_err(intr, EAGAIN);
+-	}
+-
+-	inarg = (void *) &in[1];
+-	if (in->opcode == FUSE_WRITE && se->op.write_buf)
+-		do_write_buf(req, in->nodeid, inarg, buf);
+-	else if (in->opcode == FUSE_NOTIFY_REPLY)
+-		do_notify_reply(req, in->nodeid, inarg, buf);
+-	else
+-		fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
+-
+-	return;
++                                  const struct fuse_buf *buf,
++                                  struct fuse_chan *ch)
++{
++    struct fuse_in_header *in;
++    const void *inarg;
++    struct fuse_req *req;
++    int err;
++
++    in = buf->mem;
++
++    if (se->debug) {
++        fuse_log(FUSE_LOG_DEBUG,
++                 "unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, "
++                 "pid: %u\n",
++                 (unsigned long long)in->unique,
++                 opname((enum fuse_opcode)in->opcode), in->opcode,
++                 (unsigned long long)in->nodeid, buf->size, in->pid);
++    }
++
++    req = fuse_ll_alloc_req(se);
++    if (req == NULL) {
++        struct fuse_out_header out = {
++            .unique = in->unique,
++            .error = -ENOMEM,
++        };
++        struct iovec iov = {
++            .iov_base = &out,
++            .iov_len = sizeof(struct fuse_out_header),
++        };
++
++        fuse_send_msg(se, ch, &iov, 1);
++        return;
++    }
++
++    req->unique = in->unique;
++    req->ctx.uid = in->uid;
++    req->ctx.gid = in->gid;
++    req->ctx.pid = in->pid;
++    req->ch = ch;
++
++    err = EIO;
++    if (!se->got_init) {
++        enum fuse_opcode expected;
++
++        expected = se->cuse_data ? CUSE_INIT : FUSE_INIT;
++        if (in->opcode != expected) {
++            goto reply_err;
++        }
++    } else if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT) {
++        goto reply_err;
++    }
++
++    err = EACCES;
++    /* Implement -o allow_root */
++    if (se->deny_others && in->uid != se->owner && in->uid != 0 &&
++        in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
++        in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
++        in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
++        in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR &&
++        in->opcode != FUSE_NOTIFY_REPLY && in->opcode != FUSE_READDIRPLUS) {
++        goto reply_err;
++    }
++
++    err = ENOSYS;
++    if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func) {
++        goto reply_err;
++    }
++    if (in->opcode != FUSE_INTERRUPT) {
++        struct fuse_req *intr;
++        pthread_mutex_lock(&se->lock);
++        intr = check_interrupt(se, req);
++        list_add_req(req, &se->list);
++        pthread_mutex_unlock(&se->lock);
++        if (intr) {
++            fuse_reply_err(intr, EAGAIN);
++        }
++    }
++
++    inarg = (void *)&in[1];
++    if (in->opcode == FUSE_WRITE && se->op.write_buf) {
++        do_write_buf(req, in->nodeid, inarg, buf);
++    } else if (in->opcode == FUSE_NOTIFY_REPLY) {
++        do_notify_reply(req, in->nodeid, inarg, buf);
++    } else {
++        fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
++    }
++
++    return;
+ 
+ reply_err:
+-	fuse_reply_err(req, err);
++    fuse_reply_err(req, err);
+ }
+ 
+-#define LL_OPTION(n,o,v) \
+-	{ n, offsetof(struct fuse_session, o), v }
++#define LL_OPTION(n, o, v)                     \
++    {                                          \
++        n, offsetof(struct fuse_session, o), v \
++    }
+ 
+ static const struct fuse_opt fuse_ll_opts[] = {
+-	LL_OPTION("debug", debug, 1),
+-	LL_OPTION("-d", debug, 1),
+-	LL_OPTION("--debug", debug, 1),
+-	LL_OPTION("allow_root", deny_others, 1),
+-	FUSE_OPT_END
++    LL_OPTION("debug", debug, 1), LL_OPTION("-d", debug, 1),
++    LL_OPTION("--debug", debug, 1), LL_OPTION("allow_root", deny_others, 1),
++    FUSE_OPT_END
+ };
+ 
+ void fuse_lowlevel_version(void)
+ {
+-	printf("using FUSE kernel interface version %i.%i\n",
+-	       FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
++    printf("using FUSE kernel interface version %i.%i\n", FUSE_KERNEL_VERSION,
++           FUSE_KERNEL_MINOR_VERSION);
+ }
+ 
+ void fuse_lowlevel_help(void)
+ {
+-	/* These are not all options, but the ones that are
+-	   potentially of interest to an end-user */
+-	printf(
+-"    -o allow_root          allow access by root\n"
+-);
++    /*
++     * These are not all options, but the ones that are
++     * potentially of interest to an end-user
++     */
++    printf("    -o allow_root          allow access by root\n");
+ }
+ 
+ void fuse_session_destroy(struct fuse_session *se)
+ {
+-	if (se->got_init && !se->got_destroy) {
+-		if (se->op.destroy)
+-			se->op.destroy(se->userdata);
+-	}
+-	pthread_mutex_destroy(&se->lock);
+-	free(se->cuse_data);
+-	if (se->fd != -1)
+-		close(se->fd);
+-	free(se);
++    if (se->got_init && !se->got_destroy) {
++        if (se->op.destroy) {
++            se->op.destroy(se->userdata);
++        }
++    }
++    pthread_mutex_destroy(&se->lock);
++    free(se->cuse_data);
++    if (se->fd != -1) {
++        close(se->fd);
++    }
++    free(se);
+ }
+ 
+ 
+ struct fuse_session *fuse_session_new(struct fuse_args *args,
+-				      const struct fuse_lowlevel_ops *op,
+-				      size_t op_size, void *userdata)
+-{
+-	struct fuse_session *se;
+-
+-	if (sizeof(struct fuse_lowlevel_ops) < op_size) {
+-		fuse_log(FUSE_LOG_ERR, "fuse: warning: library too old, some operations may not work\n");
+-		op_size = sizeof(struct fuse_lowlevel_ops);
+-	}
+-
+-	if (args->argc == 0) {
+-		fuse_log(FUSE_LOG_ERR, "fuse: empty argv passed to fuse_session_new().\n");
+-		return NULL;
+-	}
+-
+-	se = (struct fuse_session *) calloc(1, sizeof(struct fuse_session));
+-	if (se == NULL) {
+-		fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse object\n");
+-		goto out1;
+-	}
+-	se->fd = -1;
+-	se->conn.max_write = UINT_MAX;
+-	se->conn.max_readahead = UINT_MAX;
+-
+-	/* Parse options */
+-	if(fuse_opt_parse(args, se, fuse_ll_opts, NULL) == -1)
+-		goto out2;
+-	if(args->argc == 1 &&
+-	   args->argv[0][0] == '-') {
+-		fuse_log(FUSE_LOG_ERR, "fuse: warning: argv[0] looks like an option, but "
+-			"will be ignored\n");
+-	} else if (args->argc != 1) {
+-		int i;
+-		fuse_log(FUSE_LOG_ERR, "fuse: unknown option(s): `");
+-		for(i = 1; i < args->argc-1; i++)
+-			fuse_log(FUSE_LOG_ERR, "%s ", args->argv[i]);
+-		fuse_log(FUSE_LOG_ERR, "%s'\n", args->argv[i]);
+-		goto out4;
+-	}
+-
+-	se->bufsize = FUSE_MAX_MAX_PAGES * getpagesize() +
+-		FUSE_BUFFER_HEADER_SIZE;
+-
+-	list_init_req(&se->list);
+-	list_init_req(&se->interrupts);
+-	list_init_nreq(&se->notify_list);
+-	se->notify_ctr = 1;
+-	fuse_mutex_init(&se->lock);
+-
+-	memcpy(&se->op, op, op_size);
+-	se->owner = getuid();
+-	se->userdata = userdata;
+-
+-	return se;
++                                      const struct fuse_lowlevel_ops *op,
++                                      size_t op_size, void *userdata)
++{
++    struct fuse_session *se;
++
++    if (sizeof(struct fuse_lowlevel_ops) < op_size) {
++        fuse_log(
++            FUSE_LOG_ERR,
++            "fuse: warning: library too old, some operations may not work\n");
++        op_size = sizeof(struct fuse_lowlevel_ops);
++    }
++
++    if (args->argc == 0) {
++        fuse_log(FUSE_LOG_ERR,
++                 "fuse: empty argv passed to fuse_session_new().\n");
++        return NULL;
++    }
++
++    se = (struct fuse_session *)calloc(1, sizeof(struct fuse_session));
++    if (se == NULL) {
++        fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse object\n");
++        goto out1;
++    }
++    se->fd = -1;
++    se->conn.max_write = UINT_MAX;
++    se->conn.max_readahead = UINT_MAX;
++
++    /* Parse options */
++    if (fuse_opt_parse(args, se, fuse_ll_opts, NULL) == -1) {
++        goto out2;
++    }
++    if (args->argc == 1 && args->argv[0][0] == '-') {
++        fuse_log(FUSE_LOG_ERR,
++                 "fuse: warning: argv[0] looks like an option, but "
++                 "will be ignored\n");
++    } else if (args->argc != 1) {
++        int i;
++        fuse_log(FUSE_LOG_ERR, "fuse: unknown option(s): `");
++        for (i = 1; i < args->argc - 1; i++) {
++            fuse_log(FUSE_LOG_ERR, "%s ", args->argv[i]);
++        }
++        fuse_log(FUSE_LOG_ERR, "%s'\n", args->argv[i]);
++        goto out4;
++    }
++
++    se->bufsize = FUSE_MAX_MAX_PAGES * getpagesize() + FUSE_BUFFER_HEADER_SIZE;
++
++    list_init_req(&se->list);
++    list_init_req(&se->interrupts);
++    list_init_nreq(&se->notify_list);
++    se->notify_ctr = 1;
++    fuse_mutex_init(&se->lock);
++
++    memcpy(&se->op, op, op_size);
++    se->owner = getuid();
++    se->userdata = userdata;
++
++    return se;
+ 
+ out4:
+-	fuse_opt_free_args(args);
++    fuse_opt_free_args(args);
+ out2:
+-	free(se);
++    free(se);
+ out1:
+-	return NULL;
++    return NULL;
+ }
+ 
+ int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
+ {
+-	int fd;
+-
+-	/*
+-	 * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
+-	 * would ensue.
+-	 */
+-	do {
+-		fd = open("/dev/null", O_RDWR);
+-		if (fd > 2)
+-			close(fd);
+-	} while (fd >= 0 && fd <= 2);
+-
+-	/*
+-	 * To allow FUSE daemons to run without privileges, the caller may open
+-	 * /dev/fuse before launching the file system and pass on the file
+-	 * descriptor by specifying /dev/fd/N as the mount point. Note that the
+-	 * parent process takes care of performing the mount in this case.
+-	 */
+-	fd = fuse_mnt_parse_fuse_fd(mountpoint);
+-	if (fd != -1) {
+-		if (fcntl(fd, F_GETFD) == -1) {
+-			fuse_log(FUSE_LOG_ERR,
+-				"fuse: Invalid file descriptor /dev/fd/%u\n",
+-				fd);
+-			return -1;
+-		}
+-		se->fd = fd;
+-		return 0;
+-	}
+-
+-	/* Open channel */
+-	fd = fuse_kern_mount(mountpoint, se->mo);
+-	if (fd == -1)
+-		return -1;
+-	se->fd = fd;
+-
+-	/* Save mountpoint */
+-	se->mountpoint = strdup(mountpoint);
+-	if (se->mountpoint == NULL)
+-		goto error_out;
+-
+-	return 0;
++    int fd;
++
++    /*
++     * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
++     * would ensue.
++     */
++    do {
++        fd = open("/dev/null", O_RDWR);
++        if (fd > 2) {
++            close(fd);
++        }
++    } while (fd >= 0 && fd <= 2);
++
++    /*
++     * To allow FUSE daemons to run without privileges, the caller may open
++     * /dev/fuse before launching the file system and pass on the file
++     * descriptor by specifying /dev/fd/N as the mount point. Note that the
++     * parent process takes care of performing the mount in this case.
++     */
++    fd = fuse_mnt_parse_fuse_fd(mountpoint);
++    if (fd != -1) {
++        if (fcntl(fd, F_GETFD) == -1) {
++            fuse_log(FUSE_LOG_ERR, "fuse: Invalid file descriptor /dev/fd/%u\n",
++                     fd);
++            return -1;
++        }
++        se->fd = fd;
++        return 0;
++    }
++
++    /* Open channel */
++    fd = fuse_kern_mount(mountpoint, se->mo);
++    if (fd == -1) {
++        return -1;
++    }
++    se->fd = fd;
++
++    /* Save mountpoint */
++    se->mountpoint = strdup(mountpoint);
++    if (se->mountpoint == NULL) {
++        goto error_out;
++    }
++
++    return 0;
+ 
+ error_out:
+-	fuse_kern_unmount(mountpoint, fd);
+-	return -1;
++    fuse_kern_unmount(mountpoint, fd);
++    return -1;
+ }
+ 
+ int fuse_session_fd(struct fuse_session *se)
+ {
+-	return se->fd;
++    return se->fd;
+ }
+ 
+ void fuse_session_unmount(struct fuse_session *se)
+@@ -2384,61 +2519,66 @@ void fuse_session_unmount(struct fuse_session *se)
+ #ifdef linux
+ int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
+ {
+-	char *buf;
+-	size_t bufsize = 1024;
+-	char path[128];
+-	int ret;
+-	int fd;
+-	unsigned long pid = req->ctx.pid;
+-	char *s;
++    char *buf;
++    size_t bufsize = 1024;
++    char path[128];
++    int ret;
++    int fd;
++    unsigned long pid = req->ctx.pid;
++    char *s;
+ 
+-	sprintf(path, "/proc/%lu/task/%lu/status", pid, pid);
++    sprintf(path, "/proc/%lu/task/%lu/status", pid, pid);
+ 
+ retry:
+-	buf = malloc(bufsize);
+-	if (buf == NULL)
+-		return -ENOMEM;
+-
+-	ret = -EIO;
+-	fd = open(path, O_RDONLY);
+-	if (fd == -1)
+-		goto out_free;
+-
+-	ret = read(fd, buf, bufsize);
+-	close(fd);
+-	if (ret < 0) {
+-		ret = -EIO;
+-		goto out_free;
+-	}
+-
+-	if ((size_t)ret == bufsize) {
+-		free(buf);
+-		bufsize *= 4;
+-		goto retry;
+-	}
+-
+-	ret = -EIO;
+-	s = strstr(buf, "\nGroups:");
+-	if (s == NULL)
+-		goto out_free;
+-
+-	s += 8;
+-	ret = 0;
+-	while (1) {
+-		char *end;
+-		unsigned long val = strtoul(s, &end, 0);
+-		if (end == s)
+-			break;
+-
+-		s = end;
+-		if (ret < size)
+-			list[ret] = val;
+-		ret++;
+-	}
++    buf = malloc(bufsize);
++    if (buf == NULL) {
++        return -ENOMEM;
++    }
++
++    ret = -EIO;
++    fd = open(path, O_RDONLY);
++    if (fd == -1) {
++        goto out_free;
++    }
++
++    ret = read(fd, buf, bufsize);
++    close(fd);
++    if (ret < 0) {
++        ret = -EIO;
++        goto out_free;
++    }
++
++    if ((size_t)ret == bufsize) {
++        free(buf);
++        bufsize *= 4;
++        goto retry;
++    }
++
++    ret = -EIO;
++    s = strstr(buf, "\nGroups:");
++    if (s == NULL) {
++        goto out_free;
++    }
++
++    s += 8;
++    ret = 0;
++    while (1) {
++        char *end;
++        unsigned long val = strtoul(s, &end, 0);
++        if (end == s) {
++            break;
++        }
++
++        s = end;
++        if (ret < size) {
++            list[ret] = val;
++        }
++        ret++;
++    }
+ 
+ out_free:
+-	free(buf);
+-	return ret;
++    free(buf);
++    return ret;
+ }
+ #else /* linux */
+ /*
+@@ -2446,23 +2586,25 @@ out_free:
+  */
+ int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
+ {
+-	(void) req; (void) size; (void) list;
+-	return -ENOSYS;
++    (void)req;
++    (void)size;
++    (void)list;
++    return -ENOSYS;
+ }
+ #endif
+ 
+ void fuse_session_exit(struct fuse_session *se)
+ {
+-	se->exited = 1;
++    se->exited = 1;
+ }
+ 
+ void fuse_session_reset(struct fuse_session *se)
+ {
+-	se->exited = 0;
+-	se->error = 0;
++    se->exited = 0;
++    se->error = 0;
+ }
+ 
+ int fuse_session_exited(struct fuse_session *se)
+ {
+-	return se->exited;
++    return se->exited;
+ }
+diff --git a/tools/virtiofsd/fuse_lowlevel.h b/tools/virtiofsd/fuse_lowlevel.h
+index 6b1adfcfd1..adb9054bb1 100644
+--- a/tools/virtiofsd/fuse_lowlevel.h
++++ b/tools/virtiofsd/fuse_lowlevel.h
+@@ -1,15 +1,16 @@
+ /*
+-  FUSE: Filesystem in Userspace
+-  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+-
+-  This program can be distributed under the terms of the GNU LGPLv2.
+-  See the file COPYING.LIB.
+-*/
++ * FUSE: Filesystem in Userspace
++ * Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++ *
++ * This program can be distributed under the terms of the GNU LGPLv2.
++ * See the file COPYING.LIB.
++ */
+ 
+ #ifndef FUSE_LOWLEVEL_H_
+ #define FUSE_LOWLEVEL_H_
+ 
+-/** @file
++/**
++ * @file
+  *
+  * Low level API
+  *
+@@ -24,16 +25,16 @@
+ 
+ #include "fuse_common.h"
+ 
+-#include <utime.h>
+ #include <fcntl.h>
+-#include <sys/types.h>
+ #include <sys/stat.h>
+ #include <sys/statvfs.h>
++#include <sys/types.h>
+ #include <sys/uio.h>
++#include <utime.h>
+ 
+-/* ----------------------------------------------------------- *
+- * Miscellaneous definitions				       *
+- * ----------------------------------------------------------- */
++/*
++ * Miscellaneous definitions
++ */
+ 
+ /** The node ID of the root inode */
+ #define FUSE_ROOT_ID 1
+@@ -53,47 +54,54 @@ struct fuse_session;
+ 
+ /** Directory entry parameters supplied to fuse_reply_entry() */
+ struct fuse_entry_param {
+-	/** Unique inode number
+-	 *
+-	 * In lookup, zero means negative entry (from version 2.5)
+-	 * Returning ENOENT also means negative entry, but by setting zero
+-	 * ino the kernel may cache negative entries for entry_timeout
+-	 * seconds.
+-	 */
+-	fuse_ino_t ino;
+-
+-	/** Generation number for this entry.
+-	 *
+-	 * If the file system will be exported over NFS, the
+-	 * ino/generation pairs need to be unique over the file
+-	 * system's lifetime (rather than just the mount time). So if
+-	 * the file system reuses an inode after it has been deleted,
+-	 * it must assign a new, previously unused generation number
+-	 * to the inode at the same time.
+-	 *
+-	 */
+-	uint64_t generation;
+-
+-	/** Inode attributes.
+-	 *
+-	 * Even if attr_timeout == 0, attr must be correct. For example,
+-	 * for open(), FUSE uses attr.st_size from lookup() to determine
+-	 * how many bytes to request. If this value is not correct,
+-	 * incorrect data will be returned.
+-	 */
+-	struct stat attr;
+-
+-	/** Validity timeout (in seconds) for inode attributes. If
+-	    attributes only change as a result of requests that come
+-	    through the kernel, this should be set to a very large
+-	    value. */
+-	double attr_timeout;
+-
+-	/** Validity timeout (in seconds) for the name. If directory
+-	    entries are changed/deleted only as a result of requests
+-	    that come through the kernel, this should be set to a very
+-	    large value. */
+-	double entry_timeout;
++    /**
++     * Unique inode number
++     *
++     * In lookup, zero means negative entry (from version 2.5)
++     * Returning ENOENT also means negative entry, but by setting zero
++     * ino the kernel may cache negative entries for entry_timeout
++     * seconds.
++     */
++    fuse_ino_t ino;
++
++    /**
++     * Generation number for this entry.
++     *
++     * If the file system will be exported over NFS, the
++     * ino/generation pairs need to be unique over the file
++     * system's lifetime (rather than just the mount time). So if
++     * the file system reuses an inode after it has been deleted,
++     * it must assign a new, previously unused generation number
++     * to the inode at the same time.
++     *
++     */
++    uint64_t generation;
++
++    /**
++     * Inode attributes.
++     *
++     * Even if attr_timeout == 0, attr must be correct. For example,
++     * for open(), FUSE uses attr.st_size from lookup() to determine
++     * how many bytes to request. If this value is not correct,
++     * incorrect data will be returned.
++     */
++    struct stat attr;
++
++    /**
++     * Validity timeout (in seconds) for inode attributes. If
++     *  attributes only change as a result of requests that come
++     *  through the kernel, this should be set to a very large
++     *  value.
++     */
++    double attr_timeout;
++
++    /**
++     * Validity timeout (in seconds) for the name. If directory
++     *  entries are changed/deleted only as a result of requests
++     *  that come through the kernel, this should be set to a very
++     *  large value.
++     */
++    double entry_timeout;
+ };
+ 
+ /**
+@@ -105,38 +113,38 @@ struct fuse_entry_param {
+  * there is no valid uid/pid/gid that could be reported.
+  */
+ struct fuse_ctx {
+-	/** User ID of the calling process */
+-	uid_t uid;
++    /** User ID of the calling process */
++    uid_t uid;
+ 
+-	/** Group ID of the calling process */
+-	gid_t gid;
++    /** Group ID of the calling process */
++    gid_t gid;
+ 
+-	/** Thread ID of the calling process */
+-	pid_t pid;
++    /** Thread ID of the calling process */
++    pid_t pid;
+ 
+-	/** Umask of the calling process */
+-	mode_t umask;
++    /** Umask of the calling process */
++    mode_t umask;
+ };
+ 
+ struct fuse_forget_data {
+-	fuse_ino_t ino;
+-	uint64_t nlookup;
++    fuse_ino_t ino;
++    uint64_t nlookup;
+ };
+ 
+ /* 'to_set' flags in setattr */
+-#define FUSE_SET_ATTR_MODE	(1 << 0)
+-#define FUSE_SET_ATTR_UID	(1 << 1)
+-#define FUSE_SET_ATTR_GID	(1 << 2)
+-#define FUSE_SET_ATTR_SIZE	(1 << 3)
+-#define FUSE_SET_ATTR_ATIME	(1 << 4)
+-#define FUSE_SET_ATTR_MTIME	(1 << 5)
+-#define FUSE_SET_ATTR_ATIME_NOW	(1 << 7)
+-#define FUSE_SET_ATTR_MTIME_NOW	(1 << 8)
+-#define FUSE_SET_ATTR_CTIME	(1 << 10)
+-
+-/* ----------------------------------------------------------- *
+- * Request methods and replies				       *
+- * ----------------------------------------------------------- */
++#define FUSE_SET_ATTR_MODE (1 << 0)
++#define FUSE_SET_ATTR_UID (1 << 1)
++#define FUSE_SET_ATTR_GID (1 << 2)
++#define FUSE_SET_ATTR_SIZE (1 << 3)
++#define FUSE_SET_ATTR_ATIME (1 << 4)
++#define FUSE_SET_ATTR_MTIME (1 << 5)
++#define FUSE_SET_ATTR_ATIME_NOW (1 << 7)
++#define FUSE_SET_ATTR_MTIME_NOW (1 << 8)
++#define FUSE_SET_ATTR_CTIME (1 << 10)
++
++/*
++ * Request methods and replies
++ */
+ 
+ /**
+  * Low level filesystem operations
+@@ -166,1075 +174,1069 @@ struct fuse_forget_data {
+  * this file will not be called.
+  */
+ struct fuse_lowlevel_ops {
+-	/**
+-	 * Initialize filesystem
+-	 *
+-	 * This function is called when libfuse establishes
+-	 * communication with the FUSE kernel module. The file system
+-	 * should use this module to inspect and/or modify the
+-	 * connection parameters provided in the `conn` structure.
+-	 *
+-	 * Note that some parameters may be overwritten by options
+-	 * passed to fuse_session_new() which take precedence over the
+-	 * values set in this handler.
+-	 *
+-	 * There's no reply to this function
+-	 *
+-	 * @param userdata the user data passed to fuse_session_new()
+-	 */
+-	void (*init) (void *userdata, struct fuse_conn_info *conn);
+-
+-	/**
+-	 * Clean up filesystem.
+-	 *
+-	 * Called on filesystem exit. When this method is called, the
+-	 * connection to the kernel may be gone already, so that eg. calls
+-	 * to fuse_lowlevel_notify_* will fail.
+-	 *
+-	 * There's no reply to this function
+-	 *
+-	 * @param userdata the user data passed to fuse_session_new()
+-	 */
+-	void (*destroy) (void *userdata);
+-
+-	/**
+-	 * Look up a directory entry by name and get its attributes.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_entry
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param parent inode number of the parent directory
+-	 * @param name the name to look up
+-	 */
+-	void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name);
+-
+-	/**
+-	 * Forget about an inode
+-	 *
+-	 * This function is called when the kernel removes an inode
+-	 * from its internal caches.
+-	 *
+-	 * The inode's lookup count increases by one for every call to
+-	 * fuse_reply_entry and fuse_reply_create. The nlookup parameter
+-	 * indicates by how much the lookup count should be decreased.
+-	 *
+-	 * Inodes with a non-zero lookup count may receive request from
+-	 * the kernel even after calls to unlink, rmdir or (when
+-	 * overwriting an existing file) rename. Filesystems must handle
+-	 * such requests properly and it is recommended to defer removal
+-	 * of the inode until the lookup count reaches zero. Calls to
+-	 * unlink, rmdir or rename will be followed closely by forget
+-	 * unless the file or directory is open, in which case the
+-	 * kernel issues forget only after the release or releasedir
+-	 * calls.
+-	 *
+-	 * Note that if a file system will be exported over NFS the
+-	 * inodes lifetime must extend even beyond forget. See the
+-	 * generation field in struct fuse_entry_param above.
+-	 *
+-	 * On unmount the lookup count for all inodes implicitly drops
+-	 * to zero. It is not guaranteed that the file system will
+-	 * receive corresponding forget messages for the affected
+-	 * inodes.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_none
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param nlookup the number of lookups to forget
+-	 */
+-	void (*forget) (fuse_req_t req, fuse_ino_t ino, uint64_t nlookup);
+-
+-	/**
+-	 * Get file attributes.
+-	 *
+-	 * If writeback caching is enabled, the kernel may have a
+-	 * better idea of a file's length than the FUSE file system
+-	 * (eg if there has been a write that extended the file size,
+-	 * but that has not yet been passed to the filesystem.n
+-	 *
+-	 * In this case, the st_size value provided by the file system
+-	 * will be ignored.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_attr
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param fi for future use, currently always NULL
+-	 */
+-	void (*getattr) (fuse_req_t req, fuse_ino_t ino,
+-			 struct fuse_file_info *fi);
+-
+-	/**
+-	 * Set file attributes
+-	 *
+-	 * In the 'attr' argument only members indicated by the 'to_set'
+-	 * bitmask contain valid values.  Other members contain undefined
+-	 * values.
+-	 *
+-	 * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
+-	 * expected to reset the setuid and setgid bits if the file
+-	 * size or owner is being changed.
+-	 *
+-	 * If the setattr was invoked from the ftruncate() system call
+-	 * under Linux kernel versions 2.6.15 or later, the fi->fh will
+-	 * contain the value set by the open method or will be undefined
+-	 * if the open method didn't set any value.  Otherwise (not
+-	 * ftruncate call, or kernel version earlier than 2.6.15) the fi
+-	 * parameter will be NULL.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_attr
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param attr the attributes
+-	 * @param to_set bit mask of attributes which should be set
+-	 * @param fi file information, or NULL
+-	 */
+-	void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+-			 int to_set, struct fuse_file_info *fi);
+-
+-	/**
+-	 * Read symbolic link
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_readlink
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 */
+-	void (*readlink) (fuse_req_t req, fuse_ino_t ino);
+-
+-	/**
+-	 * Create file node
+-	 *
+-	 * Create a regular file, character device, block device, fifo or
+-	 * socket node.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_entry
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param parent inode number of the parent directory
+-	 * @param name to create
+-	 * @param mode file type and mode with which to create the new file
+-	 * @param rdev the device number (only valid if created file is a device)
+-	 */
+-	void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name,
+-		       mode_t mode, dev_t rdev);
+-
+-	/**
+-	 * Create a directory
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_entry
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param parent inode number of the parent directory
+-	 * @param name to create
+-	 * @param mode with which to create the new file
+-	 */
+-	void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name,
+-		       mode_t mode);
+-
+-	/**
+-	 * Remove a file
+-	 *
+-	 * If the file's inode's lookup count is non-zero, the file
+-	 * system is expected to postpone any removal of the inode
+-	 * until the lookup count reaches zero (see description of the
+-	 * forget function).
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param parent inode number of the parent directory
+-	 * @param name to remove
+-	 */
+-	void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name);
+-
+-	/**
+-	 * Remove a directory
+-	 *
+-	 * If the directory's inode's lookup count is non-zero, the
+-	 * file system is expected to postpone any removal of the
+-	 * inode until the lookup count reaches zero (see description
+-	 * of the forget function).
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param parent inode number of the parent directory
+-	 * @param name to remove
+-	 */
+-	void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name);
+-
+-	/**
+-	 * Create a symbolic link
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_entry
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param link the contents of the symbolic link
+-	 * @param parent inode number of the parent directory
+-	 * @param name to create
+-	 */
+-	void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent,
+-			 const char *name);
+-
+-	/** Rename a file
+-	 *
+-	 * If the target exists it should be atomically replaced. If
+-	 * the target's inode's lookup count is non-zero, the file
+-	 * system is expected to postpone any removal of the inode
+-	 * until the lookup count reaches zero (see description of the
+-	 * forget function).
+-	 *
+-	 * If this request is answered with an error code of ENOSYS, this is
+-	 * treated as a permanent failure with error code EINVAL, i.e. all
+-	 * future bmap requests will fail with EINVAL without being
+-	 * send to the filesystem process.
+-	 *
+-	 * *flags* may be `RENAME_EXCHANGE` or `RENAME_NOREPLACE`. If
+-	 * RENAME_NOREPLACE is specified, the filesystem must not
+-	 * overwrite *newname* if it exists and return an error
+-	 * instead. If `RENAME_EXCHANGE` is specified, the filesystem
+-	 * must atomically exchange the two files, i.e. both must
+-	 * exist and neither may be deleted.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param parent inode number of the old parent directory
+-	 * @param name old name
+-	 * @param newparent inode number of the new parent directory
+-	 * @param newname new name
+-	 */
+-	void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name,
+-			fuse_ino_t newparent, const char *newname,
+-			unsigned int flags);
+-
+-	/**
+-	 * Create a hard link
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_entry
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the old inode number
+-	 * @param newparent inode number of the new parent directory
+-	 * @param newname new name to create
+-	 */
+-	void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
+-		      const char *newname);
+-
+-	/**
+-	 * Open a file
+-	 *
+-	 * Open flags are available in fi->flags. The following rules
+-	 * apply.
+-	 *
+-	 *  - Creation (O_CREAT, O_EXCL, O_NOCTTY) flags will be
+-	 *    filtered out / handled by the kernel.
+-	 *
+-	 *  - Access modes (O_RDONLY, O_WRONLY, O_RDWR) should be used
+-	 *    by the filesystem to check if the operation is
+-	 *    permitted.  If the ``-o default_permissions`` mount
+-	 *    option is given, this check is already done by the
+-	 *    kernel before calling open() and may thus be omitted by
+-	 *    the filesystem.
+-	 *
+-	 *  - When writeback caching is enabled, the kernel may send
+-	 *    read requests even for files opened with O_WRONLY. The
+-	 *    filesystem should be prepared to handle this.
+-	 *
+-	 *  - When writeback caching is disabled, the filesystem is
+-	 *    expected to properly handle the O_APPEND flag and ensure
+-	 *    that each write is appending to the end of the file.
+-	 * 
+-         *  - When writeback caching is enabled, the kernel will
+-	 *    handle O_APPEND. However, unless all changes to the file
+-	 *    come through the kernel this will not work reliably. The
+-	 *    filesystem should thus either ignore the O_APPEND flag
+-	 *    (and let the kernel handle it), or return an error
+-	 *    (indicating that reliably O_APPEND is not available).
+-	 *
+-	 * Filesystem may store an arbitrary file handle (pointer,
+-	 * index, etc) in fi->fh, and use this in other all other file
+-	 * operations (read, write, flush, release, fsync).
+-	 *
+-	 * Filesystem may also implement stateless file I/O and not store
+-	 * anything in fi->fh.
+-	 *
+-	 * There are also some flags (direct_io, keep_cache) which the
+-	 * filesystem may set in fi, to change the way the file is opened.
+-	 * See fuse_file_info structure in <fuse_common.h> for more details.
+-	 *
+-	 * If this request is answered with an error code of ENOSYS
+-	 * and FUSE_CAP_NO_OPEN_SUPPORT is set in
+-	 * `fuse_conn_info.capable`, this is treated as success and
+-	 * future calls to open and release will also succeed without being
+-	 * sent to the filesystem process.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_open
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param fi file information
+-	 */
+-	void (*open) (fuse_req_t req, fuse_ino_t ino,
+-		      struct fuse_file_info *fi);
+-
+-	/**
+-	 * Read data
+-	 *
+-	 * Read should send exactly the number of bytes requested except
+-	 * on EOF or error, otherwise the rest of the data will be
+-	 * substituted with zeroes.  An exception to this is when the file
+-	 * has been opened in 'direct_io' mode, in which case the return
+-	 * value of the read system call will reflect the return value of
+-	 * this operation.
+-	 *
+-	 * fi->fh will contain the value set by the open method, or will
+-	 * be undefined if the open method didn't set any value.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_buf
+-	 *   fuse_reply_iov
+-	 *   fuse_reply_data
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param size number of bytes to read
+-	 * @param off offset to read from
+-	 * @param fi file information
+-	 */
+-	void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
+-		      struct fuse_file_info *fi);
+-
+-	/**
+-	 * Write data
+-	 *
+-	 * Write should return exactly the number of bytes requested
+-	 * except on error.  An exception to this is when the file has
+-	 * been opened in 'direct_io' mode, in which case the return value
+-	 * of the write system call will reflect the return value of this
+-	 * operation.
+-	 *
+-	 * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
+-	 * expected to reset the setuid and setgid bits.
+-	 *
+-	 * fi->fh will contain the value set by the open method, or will
+-	 * be undefined if the open method didn't set any value.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_write
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param buf data to write
+-	 * @param size number of bytes to write
+-	 * @param off offset to write to
+-	 * @param fi file information
+-	 */
+-	void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf,
+-		       size_t size, off_t off, struct fuse_file_info *fi);
+-
+-	/**
+-	 * Flush method
+-	 *
+-	 * This is called on each close() of the opened file.
+-	 *
+-	 * Since file descriptors can be duplicated (dup, dup2, fork), for
+-	 * one open call there may be many flush calls.
+-	 *
+-	 * Filesystems shouldn't assume that flush will always be called
+-	 * after some writes, or that if will be called at all.
+-	 *
+-	 * fi->fh will contain the value set by the open method, or will
+-	 * be undefined if the open method didn't set any value.
+-	 *
+-	 * NOTE: the name of the method is misleading, since (unlike
+-	 * fsync) the filesystem is not forced to flush pending writes.
+-	 * One reason to flush data is if the filesystem wants to return
+-	 * write errors during close.  However, such use is non-portable
+-	 * because POSIX does not require [close] to wait for delayed I/O to
+-	 * complete.
+-	 *
+-	 * If the filesystem supports file locking operations (setlk,
+-	 * getlk) it should remove all locks belonging to 'fi->owner'.
+-	 *
+-	 * If this request is answered with an error code of ENOSYS,
+-	 * this is treated as success and future calls to flush() will
+-	 * succeed automatically without being send to the filesystem
+-	 * process.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param fi file information
+-	 *
+-	 * [close]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html
+-	 */
+-	void (*flush) (fuse_req_t req, fuse_ino_t ino,
+-		       struct fuse_file_info *fi);
+-
+-	/**
+-	 * Release an open file
+-	 *
+-	 * Release is called when there are no more references to an open
+-	 * file: all file descriptors are closed and all memory mappings
+-	 * are unmapped.
+-	 *
+-	 * For every open call there will be exactly one release call (unless
+-	 * the filesystem is force-unmounted).
+-	 *
+-	 * The filesystem may reply with an error, but error values are
+-	 * not returned to close() or munmap() which triggered the
+-	 * release.
+-	 *
+-	 * fi->fh will contain the value set by the open method, or will
+-	 * be undefined if the open method didn't set any value.
+-	 * fi->flags will contain the same flags as for open.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param fi file information
+-	 */
+-	void (*release) (fuse_req_t req, fuse_ino_t ino,
+-			 struct fuse_file_info *fi);
+-
+-	/**
+-	 * Synchronize file contents
+-	 *
+-	 * If the datasync parameter is non-zero, then only the user data
+-	 * should be flushed, not the meta data.
+-	 *
+-	 * If this request is answered with an error code of ENOSYS,
+-	 * this is treated as success and future calls to fsync() will
+-	 * succeed automatically without being send to the filesystem
+-	 * process.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param datasync flag indicating if only data should be flushed
+-	 * @param fi file information
+-	 */
+-	void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync,
+-		       struct fuse_file_info *fi);
+-
+-	/**
+-	 * Open a directory
+-	 *
+-	 * Filesystem may store an arbitrary file handle (pointer, index,
+-	 * etc) in fi->fh, and use this in other all other directory
+-	 * stream operations (readdir, releasedir, fsyncdir).
+-	 *
+-	 * If this request is answered with an error code of ENOSYS and
+-	 * FUSE_CAP_NO_OPENDIR_SUPPORT is set in `fuse_conn_info.capable`,
+-	 * this is treated as success and future calls to opendir and
+-	 * releasedir will also succeed without being sent to the filesystem
+-	 * process. In addition, the kernel will cache readdir results
+-	 * as if opendir returned FOPEN_KEEP_CACHE | FOPEN_CACHE_DIR.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_open
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param fi file information
+-	 */
+-	void (*opendir) (fuse_req_t req, fuse_ino_t ino,
+-			 struct fuse_file_info *fi);
+-
+-	/**
+-	 * Read directory
+-	 *
+-	 * Send a buffer filled using fuse_add_direntry(), with size not
+-	 * exceeding the requested size.  Send an empty buffer on end of
+-	 * stream.
+-	 *
+-	 * fi->fh will contain the value set by the opendir method, or
+-	 * will be undefined if the opendir method didn't set any value.
+-	 *
+-	 * Returning a directory entry from readdir() does not affect
+-	 * its lookup count.
+-	 *
+-         * If off_t is non-zero, then it will correspond to one of the off_t
+-	 * values that was previously returned by readdir() for the same
+-	 * directory handle. In this case, readdir() should skip over entries
+-	 * coming before the position defined by the off_t value. If entries
+-	 * are added or removed while the directory handle is open, they filesystem
+-	 * may still include the entries that have been removed, and may not
+-	 * report the entries that have been created. However, addition or
+-	 * removal of entries must never cause readdir() to skip over unrelated
+-	 * entries or to report them more than once. This means
+-	 * that off_t can not be a simple index that enumerates the entries
+-	 * that have been returned but must contain sufficient information to
+-	 * uniquely determine the next directory entry to return even when the
+-	 * set of entries is changing.
+-	 *
+-	 * The function does not have to report the '.' and '..'
+-	 * entries, but is allowed to do so. Note that, if readdir does
+-	 * not return '.' or '..', they will not be implicitly returned,
+-	 * and this behavior is observable by the caller.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_buf
+-	 *   fuse_reply_data
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param size maximum number of bytes to send
+-	 * @param off offset to continue reading the directory stream
+-	 * @param fi file information
+-	 */
+-	void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
+-			 struct fuse_file_info *fi);
+-
+-	/**
+-	 * Release an open directory
+-	 *
+-	 * For every opendir call there will be exactly one releasedir
+-	 * call (unless the filesystem is force-unmounted).
+-	 *
+-	 * fi->fh will contain the value set by the opendir method, or
+-	 * will be undefined if the opendir method didn't set any value.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param fi file information
+-	 */
+-	void (*releasedir) (fuse_req_t req, fuse_ino_t ino,
+-			    struct fuse_file_info *fi);
+-
+-	/**
+-	 * Synchronize directory contents
+-	 *
+-	 * If the datasync parameter is non-zero, then only the directory
+-	 * contents should be flushed, not the meta data.
+-	 *
+-	 * fi->fh will contain the value set by the opendir method, or
+-	 * will be undefined if the opendir method didn't set any value.
+-	 *
+-	 * If this request is answered with an error code of ENOSYS,
+-	 * this is treated as success and future calls to fsyncdir() will
+-	 * succeed automatically without being send to the filesystem
+-	 * process.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param datasync flag indicating if only data should be flushed
+-	 * @param fi file information
+-	 */
+-	void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync,
+-			  struct fuse_file_info *fi);
+-
+-	/**
+-	 * Get file system statistics
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_statfs
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number, zero means "undefined"
+-	 */
+-	void (*statfs) (fuse_req_t req, fuse_ino_t ino);
+-
+-	/**
+-	 * Set an extended attribute
+-	 *
+-	 * If this request is answered with an error code of ENOSYS, this is
+-	 * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
+-	 * future setxattr() requests will fail with EOPNOTSUPP without being
+-	 * send to the filesystem process.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_err
+-	 */
+-	void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
+-			  const char *value, size_t size, int flags);
+-
+-	/**
+-	 * Get an extended attribute
+-	 *
+-	 * If size is zero, the size of the value should be sent with
+-	 * fuse_reply_xattr.
+-	 *
+-	 * If the size is non-zero, and the value fits in the buffer, the
+-	 * value should be sent with fuse_reply_buf.
+-	 *
+-	 * If the size is too small for the value, the ERANGE error should
+-	 * be sent.
+-	 *
+-	 * If this request is answered with an error code of ENOSYS, this is
+-	 * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
+-	 * future getxattr() requests will fail with EOPNOTSUPP without being
+-	 * send to the filesystem process.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_buf
+-	 *   fuse_reply_data
+-	 *   fuse_reply_xattr
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param name of the extended attribute
+-	 * @param size maximum size of the value to send
+-	 */
+-	void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
+-			  size_t size);
+-
+-	/**
+-	 * List extended attribute names
+-	 *
+-	 * If size is zero, the total size of the attribute list should be
+-	 * sent with fuse_reply_xattr.
+-	 *
+-	 * If the size is non-zero, and the null character separated
+-	 * attribute list fits in the buffer, the list should be sent with
+-	 * fuse_reply_buf.
+-	 *
+-	 * If the size is too small for the list, the ERANGE error should
+-	 * be sent.
+-	 *
+-	 * If this request is answered with an error code of ENOSYS, this is
+-	 * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
+-	 * future listxattr() requests will fail with EOPNOTSUPP without being
+-	 * send to the filesystem process.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_buf
+-	 *   fuse_reply_data
+-	 *   fuse_reply_xattr
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param size maximum size of the list to send
+-	 */
+-	void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size);
+-
+-	/**
+-	 * Remove an extended attribute
+-	 *
+-	 * If this request is answered with an error code of ENOSYS, this is
+-	 * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
+-	 * future removexattr() requests will fail with EOPNOTSUPP without being
+-	 * send to the filesystem process.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param name of the extended attribute
+-	 */
+-	void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name);
+-
+-	/**
+-	 * Check file access permissions
+-	 *
+-	 * This will be called for the access() and chdir() system
+-	 * calls.  If the 'default_permissions' mount option is given,
+-	 * this method is not called.
+-	 *
+-	 * This method is not called under Linux kernel versions 2.4.x
+-	 *
+-	 * If this request is answered with an error code of ENOSYS, this is
+-	 * treated as a permanent success, i.e. this and all future access()
+-	 * requests will succeed without being send to the filesystem process.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param mask requested access mode
+-	 */
+-	void (*access) (fuse_req_t req, fuse_ino_t ino, int mask);
+-
+-	/**
+-	 * Create and open a file
+-	 *
+-	 * If the file does not exist, first create it with the specified
+-	 * mode, and then open it.
+-	 *
+-	 * See the description of the open handler for more
+-	 * information.
+-	 *
+-	 * If this method is not implemented or under Linux kernel
+-	 * versions earlier than 2.6.15, the mknod() and open() methods
+-	 * will be called instead.
+-	 *
+-	 * If this request is answered with an error code of ENOSYS, the handler
+-	 * is treated as not implemented (i.e., for this and future requests the
+-	 * mknod() and open() handlers will be called instead).
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_create
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param parent inode number of the parent directory
+-	 * @param name to create
+-	 * @param mode file type and mode with which to create the new file
+-	 * @param fi file information
+-	 */
+-	void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name,
+-			mode_t mode, struct fuse_file_info *fi);
+-
+-	/**
+-	 * Test for a POSIX file lock
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_lock
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param fi file information
+-	 * @param lock the region/type to test
+-	 */
+-	void (*getlk) (fuse_req_t req, fuse_ino_t ino,
+-		       struct fuse_file_info *fi, struct flock *lock);
+-
+-	/**
+-	 * Acquire, modify or release a POSIX file lock
+-	 *
+-	 * For POSIX threads (NPTL) there's a 1-1 relation between pid and
+-	 * owner, but otherwise this is not always the case.  For checking
+-	 * lock ownership, 'fi->owner' must be used.  The l_pid field in
+-	 * 'struct flock' should only be used to fill in this field in
+-	 * getlk().
+-	 *
+-	 * Note: if the locking methods are not implemented, the kernel
+-	 * will still allow file locking to work locally.  Hence these are
+-	 * only interesting for network filesystems and similar.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param fi file information
+-	 * @param lock the region/type to set
+-	 * @param sleep locking operation may sleep
+-	 */
+-	void (*setlk) (fuse_req_t req, fuse_ino_t ino,
+-		       struct fuse_file_info *fi,
+-		       struct flock *lock, int sleep);
+-
+-	/**
+-	 * Map block index within file to block index within device
+-	 *
+-	 * Note: This makes sense only for block device backed filesystems
+-	 * mounted with the 'blkdev' option
+-	 *
+-	 * If this request is answered with an error code of ENOSYS, this is
+-	 * treated as a permanent failure, i.e. all future bmap() requests will
+-	 * fail with the same error code without being send to the filesystem
+-	 * process.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_bmap
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param blocksize unit of block index
+-	 * @param idx block index within file
+-	 */
+-	void (*bmap) (fuse_req_t req, fuse_ino_t ino, size_t blocksize,
+-		      uint64_t idx);
+-
+-	/**
+-	 * Ioctl
+-	 *
+-	 * Note: For unrestricted ioctls (not allowed for FUSE
+-	 * servers), data in and out areas can be discovered by giving
+-	 * iovs and setting FUSE_IOCTL_RETRY in *flags*.  For
+-	 * restricted ioctls, kernel prepares in/out data area
+-	 * according to the information encoded in cmd.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_ioctl_retry
+-	 *   fuse_reply_ioctl
+-	 *   fuse_reply_ioctl_iov
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param cmd ioctl command
+-	 * @param arg ioctl argument
+-	 * @param fi file information
+-	 * @param flags for FUSE_IOCTL_* flags
+-	 * @param in_buf data fetched from the caller
+-	 * @param in_bufsz number of fetched bytes
+-	 * @param out_bufsz maximum size of output data
+-	 *
+-	 * Note : the unsigned long request submitted by the application
+-	 * is truncated to 32 bits.
+-	 */
+-	void (*ioctl) (fuse_req_t req, fuse_ino_t ino, unsigned int cmd,
+-		       void *arg, struct fuse_file_info *fi, unsigned flags,
+-		       const void *in_buf, size_t in_bufsz, size_t out_bufsz);
+-
+-	/**
+-	 * Poll for IO readiness
+-	 *
+-	 * Note: If ph is non-NULL, the client should notify
+-	 * when IO readiness events occur by calling
+-	 * fuse_lowlevel_notify_poll() with the specified ph.
+-	 *
+-	 * Regardless of the number of times poll with a non-NULL ph
+-	 * is received, single notification is enough to clear all.
+-	 * Notifying more times incurs overhead but doesn't harm
+-	 * correctness.
+-	 *
+-	 * The callee is responsible for destroying ph with
+-	 * fuse_pollhandle_destroy() when no longer in use.
+-	 *
+-	 * If this request is answered with an error code of ENOSYS, this is
+-	 * treated as success (with a kernel-defined default poll-mask) and
+-	 * future calls to pull() will succeed the same way without being send
+-	 * to the filesystem process.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_poll
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param fi file information
+-	 * @param ph poll handle to be used for notification
+-	 */
+-	void (*poll) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
+-		      struct fuse_pollhandle *ph);
+-
+-	/**
+-	 * Write data made available in a buffer
+-	 *
+-	 * This is a more generic version of the ->write() method.  If
+-	 * FUSE_CAP_SPLICE_READ is set in fuse_conn_info.want and the
+-	 * kernel supports splicing from the fuse device, then the
+-	 * data will be made available in pipe for supporting zero
+-	 * copy data transfer.
+-	 *
+-	 * buf->count is guaranteed to be one (and thus buf->idx is
+-	 * always zero). The write_buf handler must ensure that
+-	 * bufv->off is correctly updated (reflecting the number of
+-	 * bytes read from bufv->buf[0]).
+-	 *
+-	 * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
+-	 * expected to reset the setuid and setgid bits.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_write
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param bufv buffer containing the data
+-	 * @param off offset to write to
+-	 * @param fi file information
+-	 */
+-	void (*write_buf) (fuse_req_t req, fuse_ino_t ino,
+-			   struct fuse_bufvec *bufv, off_t off,
+-			   struct fuse_file_info *fi);
+-
+-	/**
+-	 * Callback function for the retrieve request
+-	 *
+-	 * Valid replies:
+-	 *	fuse_reply_none
+-	 *
+-	 * @param req request handle
+-	 * @param cookie user data supplied to fuse_lowlevel_notify_retrieve()
+-	 * @param ino the inode number supplied to fuse_lowlevel_notify_retrieve()
+-	 * @param offset the offset supplied to fuse_lowlevel_notify_retrieve()
+-	 * @param bufv the buffer containing the returned data
+-	 */
+-	void (*retrieve_reply) (fuse_req_t req, void *cookie, fuse_ino_t ino,
+-				off_t offset, struct fuse_bufvec *bufv);
+-
+-	/**
+-	 * Forget about multiple inodes
+-	 *
+-	 * See description of the forget function for more
+-	 * information.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_none
+-	 *
+-	 * @param req request handle
+-	 */
+-	void (*forget_multi) (fuse_req_t req, size_t count,
+-			      struct fuse_forget_data *forgets);
+-
+-	/**
+-	 * Acquire, modify or release a BSD file lock
+-	 *
+-	 * Note: if the locking methods are not implemented, the kernel
+-	 * will still allow file locking to work locally.  Hence these are
+-	 * only interesting for network filesystems and similar.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param fi file information
+-	 * @param op the locking operation, see flock(2)
+-	 */
+-	void (*flock) (fuse_req_t req, fuse_ino_t ino,
+-		       struct fuse_file_info *fi, int op);
+-
+-	/**
+-	 * Allocate requested space. If this function returns success then
+-	 * subsequent writes to the specified range shall not fail due to the lack
+-	 * of free space on the file system storage media.
+-	 *
+-	 * If this request is answered with an error code of ENOSYS, this is
+-	 * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
+-	 * future fallocate() requests will fail with EOPNOTSUPP without being
+-	 * send to the filesystem process.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param offset starting point for allocated region
+-	 * @param length size of allocated region
+-	 * @param mode determines the operation to be performed on the given range,
+-	 *             see fallocate(2)
+-	 */
+-	void (*fallocate) (fuse_req_t req, fuse_ino_t ino, int mode,
+-		       off_t offset, off_t length, struct fuse_file_info *fi);
+-
+-	/**
+-	 * Read directory with attributes
+-	 *
+-	 * Send a buffer filled using fuse_add_direntry_plus(), with size not
+-	 * exceeding the requested size.  Send an empty buffer on end of
+-	 * stream.
+-	 *
+-	 * fi->fh will contain the value set by the opendir method, or
+-	 * will be undefined if the opendir method didn't set any value.
+-	 *
+-	 * In contrast to readdir() (which does not affect the lookup counts),
+-	 * the lookup count of every entry returned by readdirplus(), except "."
+-	 * and "..", is incremented by one.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_buf
+-	 *   fuse_reply_data
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param size maximum number of bytes to send
+-	 * @param off offset to continue reading the directory stream
+-	 * @param fi file information
+-	 */
+-	void (*readdirplus) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
+-			 struct fuse_file_info *fi);
+-
+-	/**
+-	 * Copy a range of data from one file to another
+-	 *
+-	 * Performs an optimized copy between two file descriptors without the
+-	 * additional cost of transferring data through the FUSE kernel module
+-	 * to user space (glibc) and then back into the FUSE filesystem again.
+-	 *
+-	 * In case this method is not implemented, glibc falls back to reading
+-	 * data from the source and writing to the destination. Effectively
+-	 * doing an inefficient copy of the data.
+-	 *
+-	 * If this request is answered with an error code of ENOSYS, this is
+-	 * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
+-	 * future copy_file_range() requests will fail with EOPNOTSUPP without
+-	 * being send to the filesystem process.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_write
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino_in the inode number or the source file
+-	 * @param off_in starting point from were the data should be read
+-	 * @param fi_in file information of the source file
+-	 * @param ino_out the inode number or the destination file
+-	 * @param off_out starting point where the data should be written
+-	 * @param fi_out file information of the destination file
+-	 * @param len maximum size of the data to copy
+-	 * @param flags passed along with the copy_file_range() syscall
+-	 */
+-	void (*copy_file_range) (fuse_req_t req, fuse_ino_t ino_in,
+-				 off_t off_in, struct fuse_file_info *fi_in,
+-				 fuse_ino_t ino_out, off_t off_out,
+-				 struct fuse_file_info *fi_out, size_t len,
+-				 int flags);
+-
+-	/**
+-	 * Find next data or hole after the specified offset
+-	 *
+-	 * If this request is answered with an error code of ENOSYS, this is
+-	 * treated as a permanent failure, i.e. all future lseek() requests will
+-	 * fail with the same error code without being send to the filesystem
+-	 * process.
+-	 *
+-	 * Valid replies:
+-	 *   fuse_reply_lseek
+-	 *   fuse_reply_err
+-	 *
+-	 * @param req request handle
+-	 * @param ino the inode number
+-	 * @param off offset to start search from
+-	 * @param whence either SEEK_DATA or SEEK_HOLE
+-	 * @param fi file information
+-	 */
+-	void (*lseek) (fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
+-		       struct fuse_file_info *fi);
++    /**
++     * Initialize filesystem
++     *
++     * This function is called when libfuse establishes
++     * communication with the FUSE kernel module. The file system
++     * should use this module to inspect and/or modify the
++     * connection parameters provided in the `conn` structure.
++     *
++     * Note that some parameters may be overwritten by options
++     * passed to fuse_session_new() which take precedence over the
++     * values set in this handler.
++     *
++     * There's no reply to this function
++     *
++     * @param userdata the user data passed to fuse_session_new()
++     */
++    void (*init)(void *userdata, struct fuse_conn_info *conn);
++
++    /**
++     * Clean up filesystem.
++     *
++     * Called on filesystem exit. When this method is called, the
++     * connection to the kernel may be gone already, so that eg. calls
++     * to fuse_lowlevel_notify_* will fail.
++     *
++     * There's no reply to this function
++     *
++     * @param userdata the user data passed to fuse_session_new()
++     */
++    void (*destroy)(void *userdata);
++
++    /**
++     * Look up a directory entry by name and get its attributes.
++     *
++     * Valid replies:
++     *   fuse_reply_entry
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param parent inode number of the parent directory
++     * @param name the name to look up
++     */
++    void (*lookup)(fuse_req_t req, fuse_ino_t parent, const char *name);
++
++    /**
++     * Forget about an inode
++     *
++     * This function is called when the kernel removes an inode
++     * from its internal caches.
++     *
++     * The inode's lookup count increases by one for every call to
++     * fuse_reply_entry and fuse_reply_create. The nlookup parameter
++     * indicates by how much the lookup count should be decreased.
++     *
++     * Inodes with a non-zero lookup count may receive request from
++     * the kernel even after calls to unlink, rmdir or (when
++     * overwriting an existing file) rename. Filesystems must handle
++     * such requests properly and it is recommended to defer removal
++     * of the inode until the lookup count reaches zero. Calls to
++     * unlink, rmdir or rename will be followed closely by forget
++     * unless the file or directory is open, in which case the
++     * kernel issues forget only after the release or releasedir
++     * calls.
++     *
++     * Note that if a file system will be exported over NFS the
++     * inodes lifetime must extend even beyond forget. See the
++     * generation field in struct fuse_entry_param above.
++     *
++     * On unmount the lookup count for all inodes implicitly drops
++     * to zero. It is not guaranteed that the file system will
++     * receive corresponding forget messages for the affected
++     * inodes.
++     *
++     * Valid replies:
++     *   fuse_reply_none
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param nlookup the number of lookups to forget
++     */
++    void (*forget)(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup);
++
++    /**
++     * Get file attributes.
++     *
++     * If writeback caching is enabled, the kernel may have a
++     * better idea of a file's length than the FUSE file system
++     * (eg if there has been a write that extended the file size,
++     * but that has not yet been passed to the filesystem.n
++     *
++     * In this case, the st_size value provided by the file system
++     * will be ignored.
++     *
++     * Valid replies:
++     *   fuse_reply_attr
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param fi for future use, currently always NULL
++     */
++    void (*getattr)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
++
++    /**
++     * Set file attributes
++     *
++     * In the 'attr' argument only members indicated by the 'to_set'
++     * bitmask contain valid values.  Other members contain undefined
++     * values.
++     *
++     * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
++     * expected to reset the setuid and setgid bits if the file
++     * size or owner is being changed.
++     *
++     * If the setattr was invoked from the ftruncate() system call
++     * under Linux kernel versions 2.6.15 or later, the fi->fh will
++     * contain the value set by the open method or will be undefined
++     * if the open method didn't set any value.  Otherwise (not
++     * ftruncate call, or kernel version earlier than 2.6.15) the fi
++     * parameter will be NULL.
++     *
++     * Valid replies:
++     *   fuse_reply_attr
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param attr the attributes
++     * @param to_set bit mask of attributes which should be set
++     * @param fi file information, or NULL
++     */
++    void (*setattr)(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
++                    int to_set, struct fuse_file_info *fi);
++
++    /**
++     * Read symbolic link
++     *
++     * Valid replies:
++     *   fuse_reply_readlink
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     */
++    void (*readlink)(fuse_req_t req, fuse_ino_t ino);
++
++    /**
++     * Create file node
++     *
++     * Create a regular file, character device, block device, fifo or
++     * socket node.
++     *
++     * Valid replies:
++     *   fuse_reply_entry
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param parent inode number of the parent directory
++     * @param name to create
++     * @param mode file type and mode with which to create the new file
++     * @param rdev the device number (only valid if created file is a device)
++     */
++    void (*mknod)(fuse_req_t req, fuse_ino_t parent, const char *name,
++                  mode_t mode, dev_t rdev);
++
++    /**
++     * Create a directory
++     *
++     * Valid replies:
++     *   fuse_reply_entry
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param parent inode number of the parent directory
++     * @param name to create
++     * @param mode with which to create the new file
++     */
++    void (*mkdir)(fuse_req_t req, fuse_ino_t parent, const char *name,
++                  mode_t mode);
++
++    /**
++     * Remove a file
++     *
++     * If the file's inode's lookup count is non-zero, the file
++     * system is expected to postpone any removal of the inode
++     * until the lookup count reaches zero (see description of the
++     * forget function).
++     *
++     * Valid replies:
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param parent inode number of the parent directory
++     * @param name to remove
++     */
++    void (*unlink)(fuse_req_t req, fuse_ino_t parent, const char *name);
++
++    /**
++     * Remove a directory
++     *
++     * If the directory's inode's lookup count is non-zero, the
++     * file system is expected to postpone any removal of the
++     * inode until the lookup count reaches zero (see description
++     * of the forget function).
++     *
++     * Valid replies:
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param parent inode number of the parent directory
++     * @param name to remove
++     */
++    void (*rmdir)(fuse_req_t req, fuse_ino_t parent, const char *name);
++
++    /**
++     * Create a symbolic link
++     *
++     * Valid replies:
++     *   fuse_reply_entry
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param link the contents of the symbolic link
++     * @param parent inode number of the parent directory
++     * @param name to create
++     */
++    void (*symlink)(fuse_req_t req, const char *link, fuse_ino_t parent,
++                    const char *name);
++
++    /**
++     * Rename a file
++     *
++     * If the target exists it should be atomically replaced. If
++     * the target's inode's lookup count is non-zero, the file
++     * system is expected to postpone any removal of the inode
++     * until the lookup count reaches zero (see description of the
++     * forget function).
++     *
++     * If this request is answered with an error code of ENOSYS, this is
++     * treated as a permanent failure with error code EINVAL, i.e. all
++     * future bmap requests will fail with EINVAL without being
++     * send to the filesystem process.
++     *
++     * *flags* may be `RENAME_EXCHANGE` or `RENAME_NOREPLACE`. If
++     * RENAME_NOREPLACE is specified, the filesystem must not
++     * overwrite *newname* if it exists and return an error
++     * instead. If `RENAME_EXCHANGE` is specified, the filesystem
++     * must atomically exchange the two files, i.e. both must
++     * exist and neither may be deleted.
++     *
++     * Valid replies:
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param parent inode number of the old parent directory
++     * @param name old name
++     * @param newparent inode number of the new parent directory
++     * @param newname new name
++     */
++    void (*rename)(fuse_req_t req, fuse_ino_t parent, const char *name,
++                   fuse_ino_t newparent, const char *newname,
++                   unsigned int flags);
++
++    /**
++     * Create a hard link
++     *
++     * Valid replies:
++     *   fuse_reply_entry
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the old inode number
++     * @param newparent inode number of the new parent directory
++     * @param newname new name to create
++     */
++    void (*link)(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
++                 const char *newname);
++
++    /**
++     * Open a file
++     *
++     * Open flags are available in fi->flags. The following rules
++     * apply.
++     *
++     *  - Creation (O_CREAT, O_EXCL, O_NOCTTY) flags will be
++     *    filtered out / handled by the kernel.
++     *
++     *  - Access modes (O_RDONLY, O_WRONLY, O_RDWR) should be used
++     *    by the filesystem to check if the operation is
++     *    permitted.  If the ``-o default_permissions`` mount
++     *    option is given, this check is already done by the
++     *    kernel before calling open() and may thus be omitted by
++     *    the filesystem.
++     *
++     *  - When writeback caching is enabled, the kernel may send
++     *    read requests even for files opened with O_WRONLY. The
++     *    filesystem should be prepared to handle this.
++     *
++     *  - When writeback caching is disabled, the filesystem is
++     *    expected to properly handle the O_APPEND flag and ensure
++     *    that each write is appending to the end of the file.
++     *
++     *  - When writeback caching is enabled, the kernel will
++     *    handle O_APPEND. However, unless all changes to the file
++     *    come through the kernel this will not work reliably. The
++     *    filesystem should thus either ignore the O_APPEND flag
++     *    (and let the kernel handle it), or return an error
++     *    (indicating that reliably O_APPEND is not available).
++     *
++     * Filesystem may store an arbitrary file handle (pointer,
++     * index, etc) in fi->fh, and use this in other all other file
++     * operations (read, write, flush, release, fsync).
++     *
++     * Filesystem may also implement stateless file I/O and not store
++     * anything in fi->fh.
++     *
++     * There are also some flags (direct_io, keep_cache) which the
++     * filesystem may set in fi, to change the way the file is opened.
++     * See fuse_file_info structure in <fuse_common.h> for more details.
++     *
++     * If this request is answered with an error code of ENOSYS
++     * and FUSE_CAP_NO_OPEN_SUPPORT is set in
++     * `fuse_conn_info.capable`, this is treated as success and
++     * future calls to open and release will also succeed without being
++     * sent to the filesystem process.
++     *
++     * Valid replies:
++     *   fuse_reply_open
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param fi file information
++     */
++    void (*open)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
++
++    /**
++     * Read data
++     *
++     * Read should send exactly the number of bytes requested except
++     * on EOF or error, otherwise the rest of the data will be
++     * substituted with zeroes.  An exception to this is when the file
++     * has been opened in 'direct_io' mode, in which case the return
++     * value of the read system call will reflect the return value of
++     * this operation.
++     *
++     * fi->fh will contain the value set by the open method, or will
++     * be undefined if the open method didn't set any value.
++     *
++     * Valid replies:
++     *   fuse_reply_buf
++     *   fuse_reply_iov
++     *   fuse_reply_data
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param size number of bytes to read
++     * @param off offset to read from
++     * @param fi file information
++     */
++    void (*read)(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
++                 struct fuse_file_info *fi);
++
++    /**
++     * Write data
++     *
++     * Write should return exactly the number of bytes requested
++     * except on error.  An exception to this is when the file has
++     * been opened in 'direct_io' mode, in which case the return value
++     * of the write system call will reflect the return value of this
++     * operation.
++     *
++     * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
++     * expected to reset the setuid and setgid bits.
++     *
++     * fi->fh will contain the value set by the open method, or will
++     * be undefined if the open method didn't set any value.
++     *
++     * Valid replies:
++     *   fuse_reply_write
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param buf data to write
++     * @param size number of bytes to write
++     * @param off offset to write to
++     * @param fi file information
++     */
++    void (*write)(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size,
++                  off_t off, struct fuse_file_info *fi);
++
++    /**
++     * Flush method
++     *
++     * This is called on each close() of the opened file.
++     *
++     * Since file descriptors can be duplicated (dup, dup2, fork), for
++     * one open call there may be many flush calls.
++     *
++     * Filesystems shouldn't assume that flush will always be called
++     * after some writes, or that if will be called at all.
++     *
++     * fi->fh will contain the value set by the open method, or will
++     * be undefined if the open method didn't set any value.
++     *
++     * NOTE: the name of the method is misleading, since (unlike
++     * fsync) the filesystem is not forced to flush pending writes.
++     * One reason to flush data is if the filesystem wants to return
++     * write errors during close.  However, such use is non-portable
++     * because POSIX does not require [close] to wait for delayed I/O to
++     * complete.
++     *
++     * If the filesystem supports file locking operations (setlk,
++     * getlk) it should remove all locks belonging to 'fi->owner'.
++     *
++     * If this request is answered with an error code of ENOSYS,
++     * this is treated as success and future calls to flush() will
++     * succeed automatically without being send to the filesystem
++     * process.
++     *
++     * Valid replies:
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param fi file information
++     *
++     * [close]:
++     * http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html
++     */
++    void (*flush)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
++
++    /**
++     * Release an open file
++     *
++     * Release is called when there are no more references to an open
++     * file: all file descriptors are closed and all memory mappings
++     * are unmapped.
++     *
++     * For every open call there will be exactly one release call (unless
++     * the filesystem is force-unmounted).
++     *
++     * The filesystem may reply with an error, but error values are
++     * not returned to close() or munmap() which triggered the
++     * release.
++     *
++     * fi->fh will contain the value set by the open method, or will
++     * be undefined if the open method didn't set any value.
++     * fi->flags will contain the same flags as for open.
++     *
++     * Valid replies:
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param fi file information
++     */
++    void (*release)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
++
++    /**
++     * Synchronize file contents
++     *
++     * If the datasync parameter is non-zero, then only the user data
++     * should be flushed, not the meta data.
++     *
++     * If this request is answered with an error code of ENOSYS,
++     * this is treated as success and future calls to fsync() will
++     * succeed automatically without being send to the filesystem
++     * process.
++     *
++     * Valid replies:
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param datasync flag indicating if only data should be flushed
++     * @param fi file information
++     */
++    void (*fsync)(fuse_req_t req, fuse_ino_t ino, int datasync,
++                  struct fuse_file_info *fi);
++
++    /**
++     * Open a directory
++     *
++     * Filesystem may store an arbitrary file handle (pointer, index,
++     * etc) in fi->fh, and use this in other all other directory
++     * stream operations (readdir, releasedir, fsyncdir).
++     *
++     * If this request is answered with an error code of ENOSYS and
++     * FUSE_CAP_NO_OPENDIR_SUPPORT is set in `fuse_conn_info.capable`,
++     * this is treated as success and future calls to opendir and
++     * releasedir will also succeed without being sent to the filesystem
++     * process. In addition, the kernel will cache readdir results
++     * as if opendir returned FOPEN_KEEP_CACHE | FOPEN_CACHE_DIR.
++     *
++     * Valid replies:
++     *   fuse_reply_open
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param fi file information
++     */
++    void (*opendir)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
++
++    /**
++     * Read directory
++     *
++     * Send a buffer filled using fuse_add_direntry(), with size not
++     * exceeding the requested size.  Send an empty buffer on end of
++     * stream.
++     *
++     * fi->fh will contain the value set by the opendir method, or
++     * will be undefined if the opendir method didn't set any value.
++     *
++     * Returning a directory entry from readdir() does not affect
++     * its lookup count.
++     *
++     * If off_t is non-zero, then it will correspond to one of the off_t
++     * values that was previously returned by readdir() for the same
++     * directory handle. In this case, readdir() should skip over entries
++     * coming before the position defined by the off_t value. If entries
++     * are added or removed while the directory handle is open, they filesystem
++     * may still include the entries that have been removed, and may not
++     * report the entries that have been created. However, addition or
++     * removal of entries must never cause readdir() to skip over unrelated
++     * entries or to report them more than once. This means
++     * that off_t can not be a simple index that enumerates the entries
++     * that have been returned but must contain sufficient information to
++     * uniquely determine the next directory entry to return even when the
++     * set of entries is changing.
++     *
++     * The function does not have to report the '.' and '..'
++     * entries, but is allowed to do so. Note that, if readdir does
++     * not return '.' or '..', they will not be implicitly returned,
++     * and this behavior is observable by the caller.
++     *
++     * Valid replies:
++     *   fuse_reply_buf
++     *   fuse_reply_data
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param size maximum number of bytes to send
++     * @param off offset to continue reading the directory stream
++     * @param fi file information
++     */
++    void (*readdir)(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
++                    struct fuse_file_info *fi);
++
++    /**
++     * Release an open directory
++     *
++     * For every opendir call there will be exactly one releasedir
++     * call (unless the filesystem is force-unmounted).
++     *
++     * fi->fh will contain the value set by the opendir method, or
++     * will be undefined if the opendir method didn't set any value.
++     *
++     * Valid replies:
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param fi file information
++     */
++    void (*releasedir)(fuse_req_t req, fuse_ino_t ino,
++                       struct fuse_file_info *fi);
++
++    /**
++     * Synchronize directory contents
++     *
++     * If the datasync parameter is non-zero, then only the directory
++     * contents should be flushed, not the meta data.
++     *
++     * fi->fh will contain the value set by the opendir method, or
++     * will be undefined if the opendir method didn't set any value.
++     *
++     * If this request is answered with an error code of ENOSYS,
++     * this is treated as success and future calls to fsyncdir() will
++     * succeed automatically without being send to the filesystem
++     * process.
++     *
++     * Valid replies:
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param datasync flag indicating if only data should be flushed
++     * @param fi file information
++     */
++    void (*fsyncdir)(fuse_req_t req, fuse_ino_t ino, int datasync,
++                     struct fuse_file_info *fi);
++
++    /**
++     * Get file system statistics
++     *
++     * Valid replies:
++     *   fuse_reply_statfs
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number, zero means "undefined"
++     */
++    void (*statfs)(fuse_req_t req, fuse_ino_t ino);
++
++    /**
++     * Set an extended attribute
++     *
++     * If this request is answered with an error code of ENOSYS, this is
++     * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
++     * future setxattr() requests will fail with EOPNOTSUPP without being
++     * send to the filesystem process.
++     *
++     * Valid replies:
++     *   fuse_reply_err
++     */
++    void (*setxattr)(fuse_req_t req, fuse_ino_t ino, const char *name,
++                     const char *value, size_t size, int flags);
++
++    /**
++     * Get an extended attribute
++     *
++     * If size is zero, the size of the value should be sent with
++     * fuse_reply_xattr.
++     *
++     * If the size is non-zero, and the value fits in the buffer, the
++     * value should be sent with fuse_reply_buf.
++     *
++     * If the size is too small for the value, the ERANGE error should
++     * be sent.
++     *
++     * If this request is answered with an error code of ENOSYS, this is
++     * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
++     * future getxattr() requests will fail with EOPNOTSUPP without being
++     * send to the filesystem process.
++     *
++     * Valid replies:
++     *   fuse_reply_buf
++     *   fuse_reply_data
++     *   fuse_reply_xattr
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param name of the extended attribute
++     * @param size maximum size of the value to send
++     */
++    void (*getxattr)(fuse_req_t req, fuse_ino_t ino, const char *name,
++                     size_t size);
++
++    /**
++     * List extended attribute names
++     *
++     * If size is zero, the total size of the attribute list should be
++     * sent with fuse_reply_xattr.
++     *
++     * If the size is non-zero, and the null character separated
++     * attribute list fits in the buffer, the list should be sent with
++     * fuse_reply_buf.
++     *
++     * If the size is too small for the list, the ERANGE error should
++     * be sent.
++     *
++     * If this request is answered with an error code of ENOSYS, this is
++     * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
++     * future listxattr() requests will fail with EOPNOTSUPP without being
++     * send to the filesystem process.
++     *
++     * Valid replies:
++     *   fuse_reply_buf
++     *   fuse_reply_data
++     *   fuse_reply_xattr
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param size maximum size of the list to send
++     */
++    void (*listxattr)(fuse_req_t req, fuse_ino_t ino, size_t size);
++
++    /**
++     * Remove an extended attribute
++     *
++     * If this request is answered with an error code of ENOSYS, this is
++     * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
++     * future removexattr() requests will fail with EOPNOTSUPP without being
++     * send to the filesystem process.
++     *
++     * Valid replies:
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param name of the extended attribute
++     */
++    void (*removexattr)(fuse_req_t req, fuse_ino_t ino, const char *name);
++
++    /**
++     * Check file access permissions
++     *
++     * This will be called for the access() and chdir() system
++     * calls.  If the 'default_permissions' mount option is given,
++     * this method is not called.
++     *
++     * This method is not called under Linux kernel versions 2.4.x
++     *
++     * If this request is answered with an error code of ENOSYS, this is
++     * treated as a permanent success, i.e. this and all future access()
++     * requests will succeed without being send to the filesystem process.
++     *
++     * Valid replies:
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param mask requested access mode
++     */
++    void (*access)(fuse_req_t req, fuse_ino_t ino, int mask);
++
++    /**
++     * Create and open a file
++     *
++     * If the file does not exist, first create it with the specified
++     * mode, and then open it.
++     *
++     * See the description of the open handler for more
++     * information.
++     *
++     * If this method is not implemented or under Linux kernel
++     * versions earlier than 2.6.15, the mknod() and open() methods
++     * will be called instead.
++     *
++     * If this request is answered with an error code of ENOSYS, the handler
++     * is treated as not implemented (i.e., for this and future requests the
++     * mknod() and open() handlers will be called instead).
++     *
++     * Valid replies:
++     *   fuse_reply_create
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param parent inode number of the parent directory
++     * @param name to create
++     * @param mode file type and mode with which to create the new file
++     * @param fi file information
++     */
++    void (*create)(fuse_req_t req, fuse_ino_t parent, const char *name,
++                   mode_t mode, struct fuse_file_info *fi);
++
++    /**
++     * Test for a POSIX file lock
++     *
++     * Valid replies:
++     *   fuse_reply_lock
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param fi file information
++     * @param lock the region/type to test
++     */
++    void (*getlk)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
++                  struct flock *lock);
++
++    /**
++     * Acquire, modify or release a POSIX file lock
++     *
++     * For POSIX threads (NPTL) there's a 1-1 relation between pid and
++     * owner, but otherwise this is not always the case.  For checking
++     * lock ownership, 'fi->owner' must be used.  The l_pid field in
++     * 'struct flock' should only be used to fill in this field in
++     * getlk().
++     *
++     * Note: if the locking methods are not implemented, the kernel
++     * will still allow file locking to work locally.  Hence these are
++     * only interesting for network filesystems and similar.
++     *
++     * Valid replies:
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param fi file information
++     * @param lock the region/type to set
++     * @param sleep locking operation may sleep
++     */
++    void (*setlk)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
++                  struct flock *lock, int sleep);
++
++    /**
++     * Map block index within file to block index within device
++     *
++     * Note: This makes sense only for block device backed filesystems
++     * mounted with the 'blkdev' option
++     *
++     * If this request is answered with an error code of ENOSYS, this is
++     * treated as a permanent failure, i.e. all future bmap() requests will
++     * fail with the same error code without being send to the filesystem
++     * process.
++     *
++     * Valid replies:
++     *   fuse_reply_bmap
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param blocksize unit of block index
++     * @param idx block index within file
++     */
++    void (*bmap)(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
++                 uint64_t idx);
++
++    /**
++     * Ioctl
++     *
++     * Note: For unrestricted ioctls (not allowed for FUSE
++     * servers), data in and out areas can be discovered by giving
++     * iovs and setting FUSE_IOCTL_RETRY in *flags*.  For
++     * restricted ioctls, kernel prepares in/out data area
++     * according to the information encoded in cmd.
++     *
++     * Valid replies:
++     *   fuse_reply_ioctl_retry
++     *   fuse_reply_ioctl
++     *   fuse_reply_ioctl_iov
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param cmd ioctl command
++     * @param arg ioctl argument
++     * @param fi file information
++     * @param flags for FUSE_IOCTL_* flags
++     * @param in_buf data fetched from the caller
++     * @param in_bufsz number of fetched bytes
++     * @param out_bufsz maximum size of output data
++     *
++     * Note : the unsigned long request submitted by the application
++     * is truncated to 32 bits.
++     */
++    void (*ioctl)(fuse_req_t req, fuse_ino_t ino, unsigned int cmd, void *arg,
++                  struct fuse_file_info *fi, unsigned flags, const void *in_buf,
++                  size_t in_bufsz, size_t out_bufsz);
++
++    /**
++     * Poll for IO readiness
++     *
++     * Note: If ph is non-NULL, the client should notify
++     * when IO readiness events occur by calling
++     * fuse_lowlevel_notify_poll() with the specified ph.
++     *
++     * Regardless of the number of times poll with a non-NULL ph
++     * is received, single notification is enough to clear all.
++     * Notifying more times incurs overhead but doesn't harm
++     * correctness.
++     *
++     * The callee is responsible for destroying ph with
++     * fuse_pollhandle_destroy() when no longer in use.
++     *
++     * If this request is answered with an error code of ENOSYS, this is
++     * treated as success (with a kernel-defined default poll-mask) and
++     * future calls to pull() will succeed the same way without being send
++     * to the filesystem process.
++     *
++     * Valid replies:
++     *   fuse_reply_poll
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param fi file information
++     * @param ph poll handle to be used for notification
++     */
++    void (*poll)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
++                 struct fuse_pollhandle *ph);
++
++    /**
++     * Write data made available in a buffer
++     *
++     * This is a more generic version of the ->write() method.  If
++     * FUSE_CAP_SPLICE_READ is set in fuse_conn_info.want and the
++     * kernel supports splicing from the fuse device, then the
++     * data will be made available in pipe for supporting zero
++     * copy data transfer.
++     *
++     * buf->count is guaranteed to be one (and thus buf->idx is
++     * always zero). The write_buf handler must ensure that
++     * bufv->off is correctly updated (reflecting the number of
++     * bytes read from bufv->buf[0]).
++     *
++     * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
++     * expected to reset the setuid and setgid bits.
++     *
++     * Valid replies:
++     *   fuse_reply_write
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param bufv buffer containing the data
++     * @param off offset to write to
++     * @param fi file information
++     */
++    void (*write_buf)(fuse_req_t req, fuse_ino_t ino, struct fuse_bufvec *bufv,
++                      off_t off, struct fuse_file_info *fi);
++
++    /**
++     * Callback function for the retrieve request
++     *
++     * Valid replies:
++     *  fuse_reply_none
++     *
++     * @param req request handle
++     * @param cookie user data supplied to fuse_lowlevel_notify_retrieve()
++     * @param ino the inode number supplied to fuse_lowlevel_notify_retrieve()
++     * @param offset the offset supplied to fuse_lowlevel_notify_retrieve()
++     * @param bufv the buffer containing the returned data
++     */
++    void (*retrieve_reply)(fuse_req_t req, void *cookie, fuse_ino_t ino,
++                           off_t offset, struct fuse_bufvec *bufv);
++
++    /**
++     * Forget about multiple inodes
++     *
++     * See description of the forget function for more
++     * information.
++     *
++     * Valid replies:
++     *   fuse_reply_none
++     *
++     * @param req request handle
++     */
++    void (*forget_multi)(fuse_req_t req, size_t count,
++                         struct fuse_forget_data *forgets);
++
++    /**
++     * Acquire, modify or release a BSD file lock
++     *
++     * Note: if the locking methods are not implemented, the kernel
++     * will still allow file locking to work locally.  Hence these are
++     * only interesting for network filesystems and similar.
++     *
++     * Valid replies:
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param fi file information
++     * @param op the locking operation, see flock(2)
++     */
++    void (*flock)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
++                  int op);
++
++    /**
++     * Allocate requested space. If this function returns success then
++     * subsequent writes to the specified range shall not fail due to the lack
++     * of free space on the file system storage media.
++     *
++     * If this request is answered with an error code of ENOSYS, this is
++     * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
++     * future fallocate() requests will fail with EOPNOTSUPP without being
++     * send to the filesystem process.
++     *
++     * Valid replies:
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param offset starting point for allocated region
++     * @param length size of allocated region
++     * @param mode determines the operation to be performed on the given range,
++     *             see fallocate(2)
++     */
++    void (*fallocate)(fuse_req_t req, fuse_ino_t ino, int mode, off_t offset,
++                      off_t length, struct fuse_file_info *fi);
++
++    /**
++     * Read directory with attributes
++     *
++     * Send a buffer filled using fuse_add_direntry_plus(), with size not
++     * exceeding the requested size.  Send an empty buffer on end of
++     * stream.
++     *
++     * fi->fh will contain the value set by the opendir method, or
++     * will be undefined if the opendir method didn't set any value.
++     *
++     * In contrast to readdir() (which does not affect the lookup counts),
++     * the lookup count of every entry returned by readdirplus(), except "."
++     * and "..", is incremented by one.
++     *
++     * Valid replies:
++     *   fuse_reply_buf
++     *   fuse_reply_data
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param size maximum number of bytes to send
++     * @param off offset to continue reading the directory stream
++     * @param fi file information
++     */
++    void (*readdirplus)(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
++                        struct fuse_file_info *fi);
++
++    /**
++     * Copy a range of data from one file to another
++     *
++     * Performs an optimized copy between two file descriptors without the
++     * additional cost of transferring data through the FUSE kernel module
++     * to user space (glibc) and then back into the FUSE filesystem again.
++     *
++     * In case this method is not implemented, glibc falls back to reading
++     * data from the source and writing to the destination. Effectively
++     * doing an inefficient copy of the data.
++     *
++     * If this request is answered with an error code of ENOSYS, this is
++     * treated as a permanent failure with error code EOPNOTSUPP, i.e. all
++     * future copy_file_range() requests will fail with EOPNOTSUPP without
++     * being send to the filesystem process.
++     *
++     * Valid replies:
++     *   fuse_reply_write
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino_in the inode number or the source file
++     * @param off_in starting point from were the data should be read
++     * @param fi_in file information of the source file
++     * @param ino_out the inode number or the destination file
++     * @param off_out starting point where the data should be written
++     * @param fi_out file information of the destination file
++     * @param len maximum size of the data to copy
++     * @param flags passed along with the copy_file_range() syscall
++     */
++    void (*copy_file_range)(fuse_req_t req, fuse_ino_t ino_in, off_t off_in,
++                            struct fuse_file_info *fi_in, fuse_ino_t ino_out,
++                            off_t off_out, struct fuse_file_info *fi_out,
++                            size_t len, int flags);
++
++    /**
++     * Find next data or hole after the specified offset
++     *
++     * If this request is answered with an error code of ENOSYS, this is
++     * treated as a permanent failure, i.e. all future lseek() requests will
++     * fail with the same error code without being send to the filesystem
++     * process.
++     *
++     * Valid replies:
++     *   fuse_reply_lseek
++     *   fuse_reply_err
++     *
++     * @param req request handle
++     * @param ino the inode number
++     * @param off offset to start search from
++     * @param whence either SEEK_DATA or SEEK_HOLE
++     * @param fi file information
++     */
++    void (*lseek)(fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
++                  struct fuse_file_info *fi);
+ };
+ 
+ /**
+@@ -1305,7 +1307,7 @@ int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e);
+  * @return zero for success, -errno for failure to send reply
+  */
+ int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
+-		      const struct fuse_file_info *fi);
++                      const struct fuse_file_info *fi);
+ 
+ /**
+  * Reply with attributes
+@@ -1315,11 +1317,11 @@ int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
+  *
+  * @param req request handle
+  * @param attr the attributes
+- * @param attr_timeout	validity timeout (in seconds) for the attributes
++ * @param attr_timeout validity timeout (in seconds) for the attributes
+  * @return zero for success, -errno for failure to send reply
+  */
+ int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
+-		    double attr_timeout);
++                    double attr_timeout);
+ 
+ /**
+  * Reply with the contents of a symbolic link
+@@ -1417,7 +1419,7 @@ int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size);
+  * @return zero for success, -errno for failure to send reply
+  */
+ int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
+-		    enum fuse_buf_copy_flags flags);
++                    enum fuse_buf_copy_flags flags);
+ 
+ /**
+  * Reply with data vector
+@@ -1480,9 +1482,9 @@ int fuse_reply_lock(fuse_req_t req, const struct flock *lock);
+  */
+ int fuse_reply_bmap(fuse_req_t req, uint64_t idx);
+ 
+-/* ----------------------------------------------------------- *
+- * Filling a buffer in readdir				       *
+- * ----------------------------------------------------------- */
++/*
++ * Filling a buffer in readdir
++ */
+ 
+ /**
+  * Add a directory entry to the buffer
+@@ -1512,8 +1514,7 @@ int fuse_reply_bmap(fuse_req_t req, uint64_t idx);
+  * @return the space needed for the entry
+  */
+ size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
+-			 const char *name, const struct stat *stbuf,
+-			 off_t off);
++                         const char *name, const struct stat *stbuf, off_t off);
+ 
+ /**
+  * Add a directory entry to the buffer with the attributes
+@@ -1529,8 +1530,8 @@ size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
+  * @return the space needed for the entry
+  */
+ size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
+-			      const char *name,
+-			      const struct fuse_entry_param *e, off_t off);
++                              const char *name,
++                              const struct fuse_entry_param *e, off_t off);
+ 
+ /**
+  * Reply to ask for data fetch and output buffer preparation.  ioctl
+@@ -1547,9 +1548,9 @@ size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
+  * @param out_count number of entries in out_iov
+  * @return zero for success, -errno for failure to send reply
+  */
+-int fuse_reply_ioctl_retry(fuse_req_t req,
+-			   const struct iovec *in_iov, size_t in_count,
+-			   const struct iovec *out_iov, size_t out_count);
++int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov,
++                           size_t in_count, const struct iovec *out_iov,
++                           size_t out_count);
+ 
+ /**
+  * Reply to finish ioctl
+@@ -1576,7 +1577,7 @@ int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size);
+  * @param count the size of vector
+  */
+ int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov,
+-			 int count);
++                         int count);
+ 
+ /**
+  * Reply with poll result event mask
+@@ -1598,9 +1599,9 @@ int fuse_reply_poll(fuse_req_t req, unsigned revents);
+  */
+ int fuse_reply_lseek(fuse_req_t req, off_t off);
+ 
+-/* ----------------------------------------------------------- *
+- * Notification						       *
+- * ----------------------------------------------------------- */
++/*
++ * Notification
++ */
+ 
+ /**
+  * Notify IO readiness event
+@@ -1635,7 +1636,7 @@ int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph);
+  * @return zero for success, -errno for failure
+  */
+ int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
+-				     off_t off, off_t len);
++                                     off_t off, off_t len);
+ 
+ /**
+  * Notify to invalidate parent attributes and the dentry matching
+@@ -1663,7 +1664,7 @@ int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
+  * @return zero for success, -errno for failure
+  */
+ int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
+-				     const char *name, size_t namelen);
++                                     const char *name, size_t namelen);
+ 
+ /**
+  * This function behaves like fuse_lowlevel_notify_inval_entry() with
+@@ -1693,9 +1694,9 @@ int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
+  * @param namelen strlen() of file name
+  * @return zero for success, -errno for failure
+  */
+-int fuse_lowlevel_notify_delete(struct fuse_session *se,
+-				fuse_ino_t parent, fuse_ino_t child,
+-				const char *name, size_t namelen);
++int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent,
++                                fuse_ino_t child, const char *name,
++                                size_t namelen);
+ 
+ /**
+  * Store data to the kernel buffers
+@@ -1723,8 +1724,8 @@ int fuse_lowlevel_notify_delete(struct fuse_session *se,
+  * @return zero for success, -errno for failure
+  */
+ int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
+-			       off_t offset, struct fuse_bufvec *bufv,
+-			       enum fuse_buf_copy_flags flags);
++                               off_t offset, struct fuse_bufvec *bufv,
++                               enum fuse_buf_copy_flags flags);
+ /**
+  * Retrieve data from the kernel buffers
+  *
+@@ -1755,12 +1756,12 @@ int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
+  * @return zero for success, -errno for failure
+  */
+ int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino,
+-				  size_t size, off_t offset, void *cookie);
++                                  size_t size, off_t offset, void *cookie);
+ 
+ 
+-/* ----------------------------------------------------------- *
+- * Utility functions					       *
+- * ----------------------------------------------------------- */
++/*
++ * Utility functions
++ */
+ 
+ /**
+  * Get the userdata from the request
+@@ -1822,7 +1823,7 @@ typedef void (*fuse_interrupt_func_t)(fuse_req_t req, void *data);
+  * @param data user data passed to the callback function
+  */
+ void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
+-			     void *data);
++                             void *data);
+ 
+ /**
+  * Check if a request has already been interrupted
+@@ -1833,9 +1834,9 @@ void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
+ int fuse_req_interrupted(fuse_req_t req);
+ 
+ 
+-/* ----------------------------------------------------------- *
+- * Inquiry functions                                           *
+- * ----------------------------------------------------------- */
++/*
++ * Inquiry functions
++ */
+ 
+ /**
+  * Print low-level version information to stdout.
+@@ -1854,18 +1855,18 @@ void fuse_lowlevel_help(void);
+  */
+ void fuse_cmdline_help(void);
+ 
+-/* ----------------------------------------------------------- *
+- * Filesystem setup & teardown                                 *
+- * ----------------------------------------------------------- */
++/*
++ * Filesystem setup & teardown
++ */
+ 
+ struct fuse_cmdline_opts {
+-	int foreground;
+-	int debug;
+-	int nodefault_subtype;
+-	char *mountpoint;
+-	int show_version;
+-	int show_help;
+-	unsigned int max_idle_threads;
++    int foreground;
++    int debug;
++    int nodefault_subtype;
++    char *mountpoint;
++    int show_version;
++    int show_help;
++    unsigned int max_idle_threads;
+ };
+ 
+ /**
+@@ -1886,8 +1887,7 @@ struct fuse_cmdline_opts {
+  * @param opts output argument for parsed options
+  * @return 0 on success, -1 on failure
+  */
+-int fuse_parse_cmdline(struct fuse_args *args,
+-		       struct fuse_cmdline_opts *opts);
++int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts);
+ 
+ /**
+  * Create a low level session.
+@@ -1918,8 +1918,8 @@ int fuse_parse_cmdline(struct fuse_args *args,
+  * @return the fuse session on success, NULL on failure
+  **/
+ struct fuse_session *fuse_session_new(struct fuse_args *args,
+-				      const struct fuse_lowlevel_ops *op,
+-				      size_t op_size, void *userdata);
++                                      const struct fuse_lowlevel_ops *op,
++                                      size_t op_size, void *userdata);
+ 
+ /**
+  * Mount a FUSE file system.
+@@ -2014,9 +2014,9 @@ void fuse_session_unmount(struct fuse_session *se);
+  */
+ void fuse_session_destroy(struct fuse_session *se);
+ 
+-/* ----------------------------------------------------------- *
+- * Custom event loop support                                   *
+- * ----------------------------------------------------------- */
++/*
++ * Custom event loop support
++ */
+ 
+ /**
+  * Return file descriptor for communication with kernel.
+@@ -2043,7 +2043,7 @@ int fuse_session_fd(struct fuse_session *se);
+  * @param buf the fuse_buf containing the request
+  */
+ void fuse_session_process_buf(struct fuse_session *se,
+-			      const struct fuse_buf *buf);
++                              const struct fuse_buf *buf);
+ 
+ /**
+  * Read a raw request from the kernel into the supplied buffer.
+diff --git a/tools/virtiofsd/fuse_misc.h b/tools/virtiofsd/fuse_misc.h
+index 2f6663ed7d..f252baa752 100644
+--- a/tools/virtiofsd/fuse_misc.h
++++ b/tools/virtiofsd/fuse_misc.h
+@@ -1,18 +1,18 @@
+ /*
+-  FUSE: Filesystem in Userspace
+-  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+-
+-  This program can be distributed under the terms of the GNU LGPLv2.
+-  See the file COPYING.LIB
+-*/
++ * FUSE: Filesystem in Userspace
++ * Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++ *
++ * This program can be distributed under the terms of the GNU LGPLv2.
++ * See the file COPYING.LIB
++ */
+ 
+ #include <pthread.h>
+ 
+ /*
+-  Versioned symbols cannot be used in some cases because it
+-    - confuse the dynamic linker in uClibc
+-    - not supported on MacOSX (in MachO binary format)
+-*/
++ * Versioned symbols cannot be used in some cases because it
++ *   - confuse the dynamic linker in uClibc
++ *   - not supported on MacOSX (in MachO binary format)
++ */
+ #if (!defined(__UCLIBC__) && !defined(__APPLE__))
+ #define FUSE_SYMVER(x) __asm__(x)
+ #else
+@@ -25,11 +25,11 @@
+ /* Is this hack still needed? */
+ static inline void fuse_mutex_init(pthread_mutex_t *mut)
+ {
+-	pthread_mutexattr_t attr;
+-	pthread_mutexattr_init(&attr);
+-	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
+-	pthread_mutex_init(mut, &attr);
+-	pthread_mutexattr_destroy(&attr);
++    pthread_mutexattr_t attr;
++    pthread_mutexattr_init(&attr);
++    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
++    pthread_mutex_init(mut, &attr);
++    pthread_mutexattr_destroy(&attr);
+ }
+ #endif
+ 
+diff --git a/tools/virtiofsd/fuse_opt.c b/tools/virtiofsd/fuse_opt.c
+index 93066b926e..edd36f4a3b 100644
+--- a/tools/virtiofsd/fuse_opt.c
++++ b/tools/virtiofsd/fuse_opt.c
+@@ -1,423 +1,450 @@
+ /*
+-  FUSE: Filesystem in Userspace
+-  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+-
+-  Implementation of option parsing routines (dealing with `struct
+-  fuse_args`).
+-
+-  This program can be distributed under the terms of the GNU LGPLv2.
+-  See the file COPYING.LIB
+-*/
++ * FUSE: Filesystem in Userspace
++ * Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++ *
++ * Implementation of option parsing routines (dealing with `struct
++ * fuse_args`).
++ *
++ * This program can be distributed under the terms of the GNU LGPLv2.
++ * See the file COPYING.LIB
++ */
+ 
++#include "fuse_opt.h"
+ #include "config.h"
+ #include "fuse_i.h"
+-#include "fuse_opt.h"
+ #include "fuse_misc.h"
+ 
++#include <assert.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+-#include <assert.h>
+ 
+ struct fuse_opt_context {
+-	void *data;
+-	const struct fuse_opt *opt;
+-	fuse_opt_proc_t proc;
+-	int argctr;
+-	int argc;
+-	char **argv;
+-	struct fuse_args outargs;
+-	char *opts;
+-	int nonopt;
++    void *data;
++    const struct fuse_opt *opt;
++    fuse_opt_proc_t proc;
++    int argctr;
++    int argc;
++    char **argv;
++    struct fuse_args outargs;
++    char *opts;
++    int nonopt;
+ };
+ 
+ void fuse_opt_free_args(struct fuse_args *args)
+ {
+-	if (args) {
+-		if (args->argv && args->allocated) {
+-			int i;
+-			for (i = 0; i < args->argc; i++)
+-				free(args->argv[i]);
+-			free(args->argv);
+-		}
+-		args->argc = 0;
+-		args->argv = NULL;
+-		args->allocated = 0;
+-	}
++    if (args) {
++        if (args->argv && args->allocated) {
++            int i;
++            for (i = 0; i < args->argc; i++) {
++                free(args->argv[i]);
++            }
++            free(args->argv);
++        }
++        args->argc = 0;
++        args->argv = NULL;
++        args->allocated = 0;
++    }
+ }
+ 
+ static int alloc_failed(void)
+ {
+-	fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
+-	return -1;
++    fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
++    return -1;
+ }
+ 
+ int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
+ {
+-	char **newargv;
+-	char *newarg;
+-
+-	assert(!args->argv || args->allocated);
+-
+-	newarg = strdup(arg);
+-	if (!newarg)
+-		return alloc_failed();
+-
+-	newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *));
+-	if (!newargv) {
+-		free(newarg);
+-		return alloc_failed();
+-	}
+-
+-	args->argv = newargv;
+-	args->allocated = 1;
+-	args->argv[args->argc++] = newarg;
+-	args->argv[args->argc] = NULL;
+-	return 0;
++    char **newargv;
++    char *newarg;
++
++    assert(!args->argv || args->allocated);
++
++    newarg = strdup(arg);
++    if (!newarg) {
++        return alloc_failed();
++    }
++
++    newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *));
++    if (!newargv) {
++        free(newarg);
++        return alloc_failed();
++    }
++
++    args->argv = newargv;
++    args->allocated = 1;
++    args->argv[args->argc++] = newarg;
++    args->argv[args->argc] = NULL;
++    return 0;
+ }
+ 
+ static int fuse_opt_insert_arg_common(struct fuse_args *args, int pos,
+-				      const char *arg)
++                                      const char *arg)
+ {
+-	assert(pos <= args->argc);
+-	if (fuse_opt_add_arg(args, arg) == -1)
+-		return -1;
+-
+-	if (pos != args->argc - 1) {
+-		char *newarg = args->argv[args->argc - 1];
+-		memmove(&args->argv[pos + 1], &args->argv[pos],
+-			sizeof(char *) * (args->argc - pos - 1));
+-		args->argv[pos] = newarg;
+-	}
+-	return 0;
++    assert(pos <= args->argc);
++    if (fuse_opt_add_arg(args, arg) == -1) {
++        return -1;
++    }
++
++    if (pos != args->argc - 1) {
++        char *newarg = args->argv[args->argc - 1];
++        memmove(&args->argv[pos + 1], &args->argv[pos],
++                sizeof(char *) * (args->argc - pos - 1));
++        args->argv[pos] = newarg;
++    }
++    return 0;
+ }
+ 
+ int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
+ {
+-	return fuse_opt_insert_arg_common(args, pos, arg);
++    return fuse_opt_insert_arg_common(args, pos, arg);
+ }
+ 
+ static int next_arg(struct fuse_opt_context *ctx, const char *opt)
+ {
+-	if (ctx->argctr + 1 >= ctx->argc) {
+-		fuse_log(FUSE_LOG_ERR, "fuse: missing argument after `%s'\n", opt);
+-		return -1;
+-	}
+-	ctx->argctr++;
+-	return 0;
++    if (ctx->argctr + 1 >= ctx->argc) {
++        fuse_log(FUSE_LOG_ERR, "fuse: missing argument after `%s'\n", opt);
++        return -1;
++    }
++    ctx->argctr++;
++    return 0;
+ }
+ 
+ static int add_arg(struct fuse_opt_context *ctx, const char *arg)
+ {
+-	return fuse_opt_add_arg(&ctx->outargs, arg);
++    return fuse_opt_add_arg(&ctx->outargs, arg);
+ }
+ 
+ static int add_opt_common(char **opts, const char *opt, int esc)
+ {
+-	unsigned oldlen = *opts ? strlen(*opts) : 0;
+-	char *d = realloc(*opts, oldlen + 1 + strlen(opt) * 2 + 1);
+-
+-	if (!d)
+-		return alloc_failed();
+-
+-	*opts = d;
+-	if (oldlen) {
+-		d += oldlen;
+-		*d++ = ',';
+-	}
+-
+-	for (; *opt; opt++) {
+-		if (esc && (*opt == ',' || *opt == '\\'))
+-			*d++ = '\\';
+-		*d++ = *opt;
+-	}
+-	*d = '\0';
+-
+-	return 0;
++    unsigned oldlen = *opts ? strlen(*opts) : 0;
++    char *d = realloc(*opts, oldlen + 1 + strlen(opt) * 2 + 1);
++
++    if (!d) {
++        return alloc_failed();
++    }
++
++    *opts = d;
++    if (oldlen) {
++        d += oldlen;
++        *d++ = ',';
++    }
++
++    for (; *opt; opt++) {
++        if (esc && (*opt == ',' || *opt == '\\')) {
++            *d++ = '\\';
++        }
++        *d++ = *opt;
++    }
++    *d = '\0';
++
++    return 0;
+ }
+ 
+ int fuse_opt_add_opt(char **opts, const char *opt)
+ {
+-	return add_opt_common(opts, opt, 0);
++    return add_opt_common(opts, opt, 0);
+ }
+ 
+ int fuse_opt_add_opt_escaped(char **opts, const char *opt)
+ {
+-	return add_opt_common(opts, opt, 1);
++    return add_opt_common(opts, opt, 1);
+ }
+ 
+ static int add_opt(struct fuse_opt_context *ctx, const char *opt)
+ {
+-	return add_opt_common(&ctx->opts, opt, 1);
++    return add_opt_common(&ctx->opts, opt, 1);
+ }
+ 
+ static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key,
+-		     int iso)
++                     int iso)
+ {
+-	if (key == FUSE_OPT_KEY_DISCARD)
+-		return 0;
+-
+-	if (key != FUSE_OPT_KEY_KEEP && ctx->proc) {
+-		int res = ctx->proc(ctx->data, arg, key, &ctx->outargs);
+-		if (res == -1 || !res)
+-			return res;
+-	}
+-	if (iso)
+-		return add_opt(ctx, arg);
+-	else
+-		return add_arg(ctx, arg);
++    if (key == FUSE_OPT_KEY_DISCARD) {
++        return 0;
++    }
++
++    if (key != FUSE_OPT_KEY_KEEP && ctx->proc) {
++        int res = ctx->proc(ctx->data, arg, key, &ctx->outargs);
++        if (res == -1 || !res) {
++            return res;
++        }
++    }
++    if (iso) {
++        return add_opt(ctx, arg);
++    } else {
++        return add_arg(ctx, arg);
++    }
+ }
+ 
+ static int match_template(const char *t, const char *arg, unsigned *sepp)
+ {
+-	int arglen = strlen(arg);
+-	const char *sep = strchr(t, '=');
+-	sep = sep ? sep : strchr(t, ' ');
+-	if (sep && (!sep[1] || sep[1] == '%')) {
+-		int tlen = sep - t;
+-		if (sep[0] == '=')
+-			tlen ++;
+-		if (arglen >= tlen && strncmp(arg, t, tlen) == 0) {
+-			*sepp = sep - t;
+-			return 1;
+-		}
+-	}
+-	if (strcmp(t, arg) == 0) {
+-		*sepp = 0;
+-		return 1;
+-	}
+-	return 0;
++    int arglen = strlen(arg);
++    const char *sep = strchr(t, '=');
++    sep = sep ? sep : strchr(t, ' ');
++    if (sep && (!sep[1] || sep[1] == '%')) {
++        int tlen = sep - t;
++        if (sep[0] == '=') {
++            tlen++;
++        }
++        if (arglen >= tlen && strncmp(arg, t, tlen) == 0) {
++            *sepp = sep - t;
++            return 1;
++        }
++    }
++    if (strcmp(t, arg) == 0) {
++        *sepp = 0;
++        return 1;
++    }
++    return 0;
+ }
+ 
+ static const struct fuse_opt *find_opt(const struct fuse_opt *opt,
+-				       const char *arg, unsigned *sepp)
++                                       const char *arg, unsigned *sepp)
+ {
+-	for (; opt && opt->templ; opt++)
+-		if (match_template(opt->templ, arg, sepp))
+-			return opt;
+-	return NULL;
++    for (; opt && opt->templ; opt++) {
++        if (match_template(opt->templ, arg, sepp)) {
++            return opt;
++        }
++    }
++    return NULL;
+ }
+ 
+ int fuse_opt_match(const struct fuse_opt *opts, const char *opt)
+ {
+-	unsigned dummy;
+-	return find_opt(opts, opt, &dummy) ? 1 : 0;
++    unsigned dummy;
++    return find_opt(opts, opt, &dummy) ? 1 : 0;
+ }
+ 
+ static int process_opt_param(void *var, const char *format, const char *param,
+-			     const char *arg)
++                             const char *arg)
+ {
+-	assert(format[0] == '%');
+-	if (format[1] == 's') {
+-		char **s = var;
+-		char *copy = strdup(param);
+-		if (!copy)
+-			return alloc_failed();
+-
+-		free(*s);
+-		*s = copy;
+-	} else {
+-		if (sscanf(param, format, var) != 1) {
+-			fuse_log(FUSE_LOG_ERR, "fuse: invalid parameter in option `%s'\n", arg);
+-			return -1;
+-		}
+-	}
+-	return 0;
++    assert(format[0] == '%');
++    if (format[1] == 's') {
++        char **s = var;
++        char *copy = strdup(param);
++        if (!copy) {
++            return alloc_failed();
++        }
++
++        free(*s);
++        *s = copy;
++    } else {
++        if (sscanf(param, format, var) != 1) {
++            fuse_log(FUSE_LOG_ERR, "fuse: invalid parameter in option `%s'\n",
++                     arg);
++            return -1;
++        }
++    }
++    return 0;
+ }
+ 
+-static int process_opt(struct fuse_opt_context *ctx,
+-		       const struct fuse_opt *opt, unsigned sep,
+-		       const char *arg, int iso)
++static int process_opt(struct fuse_opt_context *ctx, const struct fuse_opt *opt,
++                       unsigned sep, const char *arg, int iso)
+ {
+-	if (opt->offset == -1U) {
+-		if (call_proc(ctx, arg, opt->value, iso) == -1)
+-			return -1;
+-	} else {
+-		void *var = (char *)ctx->data + opt->offset;
+-		if (sep && opt->templ[sep + 1]) {
+-			const char *param = arg + sep;
+-			if (opt->templ[sep] == '=')
+-				param ++;
+-			if (process_opt_param(var, opt->templ + sep + 1,
+-					      param, arg) == -1)
+-				return -1;
+-		} else
+-			*(int *)var = opt->value;
+-	}
+-	return 0;
++    if (opt->offset == -1U) {
++        if (call_proc(ctx, arg, opt->value, iso) == -1) {
++            return -1;
++        }
++    } else {
++        void *var = (char *)ctx->data + opt->offset;
++        if (sep && opt->templ[sep + 1]) {
++            const char *param = arg + sep;
++            if (opt->templ[sep] == '=') {
++                param++;
++            }
++            if (process_opt_param(var, opt->templ + sep + 1, param, arg) ==
++                -1) {
++                return -1;
++            }
++        } else {
++            *(int *)var = opt->value;
++        }
++    }
++    return 0;
+ }
+ 
+ static int process_opt_sep_arg(struct fuse_opt_context *ctx,
+-			       const struct fuse_opt *opt, unsigned sep,
+-			       const char *arg, int iso)
++                               const struct fuse_opt *opt, unsigned sep,
++                               const char *arg, int iso)
+ {
+-	int res;
+-	char *newarg;
+-	char *param;
+-
+-	if (next_arg(ctx, arg) == -1)
+-		return -1;
+-
+-	param = ctx->argv[ctx->argctr];
+-	newarg = malloc(sep + strlen(param) + 1);
+-	if (!newarg)
+-		return alloc_failed();
+-
+-	memcpy(newarg, arg, sep);
+-	strcpy(newarg + sep, param);
+-	res = process_opt(ctx, opt, sep, newarg, iso);
+-	free(newarg);
+-
+-	return res;
++    int res;
++    char *newarg;
++    char *param;
++
++    if (next_arg(ctx, arg) == -1) {
++        return -1;
++    }
++
++    param = ctx->argv[ctx->argctr];
++    newarg = malloc(sep + strlen(param) + 1);
++    if (!newarg) {
++        return alloc_failed();
++    }
++
++    memcpy(newarg, arg, sep);
++    strcpy(newarg + sep, param);
++    res = process_opt(ctx, opt, sep, newarg, iso);
++    free(newarg);
++
++    return res;
+ }
+ 
+ static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso)
+ {
+-	unsigned sep;
+-	const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep);
+-	if (opt) {
+-		for (; opt; opt = find_opt(opt + 1, arg, &sep)) {
+-			int res;
+-			if (sep && opt->templ[sep] == ' ' && !arg[sep])
+-				res = process_opt_sep_arg(ctx, opt, sep, arg,
+-							  iso);
+-			else
+-				res = process_opt(ctx, opt, sep, arg, iso);
+-			if (res == -1)
+-				return -1;
+-		}
+-		return 0;
+-	} else
+-		return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso);
++    unsigned sep;
++    const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep);
++    if (opt) {
++        for (; opt; opt = find_opt(opt + 1, arg, &sep)) {
++            int res;
++            if (sep && opt->templ[sep] == ' ' && !arg[sep]) {
++                res = process_opt_sep_arg(ctx, opt, sep, arg, iso);
++            } else {
++                res = process_opt(ctx, opt, sep, arg, iso);
++            }
++            if (res == -1) {
++                return -1;
++            }
++        }
++        return 0;
++    } else {
++        return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso);
++    }
+ }
+ 
+ static int process_real_option_group(struct fuse_opt_context *ctx, char *opts)
+ {
+-	char *s = opts;
+-	char *d = s;
+-	int end = 0;
+-
+-	while (!end) {
+-		if (*s == '\0')
+-			end = 1;
+-		if (*s == ',' || end) {
+-			int res;
+-
+-			*d = '\0';
+-			res = process_gopt(ctx, opts, 1);
+-			if (res == -1)
+-				return -1;
+-			d = opts;
+-		} else {
+-			if (s[0] == '\\' && s[1] != '\0') {
+-				s++;
+-				if (s[0] >= '0' && s[0] <= '3' &&
+-				    s[1] >= '0' && s[1] <= '7' &&
+-				    s[2] >= '0' && s[2] <= '7') {
+-					*d++ = (s[0] - '0') * 0100 +
+-						(s[1] - '0') * 0010 +
+-						(s[2] - '0');
+-					s += 2;
+-				} else {
+-					*d++ = *s;
+-				}
+-			} else {
+-				*d++ = *s;
+-			}
+-		}
+-		s++;
+-	}
+-
+-	return 0;
++    char *s = opts;
++    char *d = s;
++    int end = 0;
++
++    while (!end) {
++        if (*s == '\0') {
++            end = 1;
++        }
++        if (*s == ',' || end) {
++            int res;
++
++            *d = '\0';
++            res = process_gopt(ctx, opts, 1);
++            if (res == -1) {
++                return -1;
++            }
++            d = opts;
++        } else {
++            if (s[0] == '\\' && s[1] != '\0') {
++                s++;
++                if (s[0] >= '0' && s[0] <= '3' && s[1] >= '0' && s[1] <= '7' &&
++                    s[2] >= '0' && s[2] <= '7') {
++                    *d++ = (s[0] - '0') * 0100 + (s[1] - '0') * 0010 +
++                           (s[2] - '0');
++                    s += 2;
++                } else {
++                    *d++ = *s;
++                }
++            } else {
++                *d++ = *s;
++            }
++        }
++        s++;
++    }
++
++    return 0;
+ }
+ 
+ static int process_option_group(struct fuse_opt_context *ctx, const char *opts)
+ {
+-	int res;
+-	char *copy = strdup(opts);
+-
+-	if (!copy) {
+-		fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
+-		return -1;
+-	}
+-	res = process_real_option_group(ctx, copy);
+-	free(copy);
+-	return res;
++    int res;
++    char *copy = strdup(opts);
++
++    if (!copy) {
++        fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
++        return -1;
++    }
++    res = process_real_option_group(ctx, copy);
++    free(copy);
++    return res;
+ }
+ 
+ static int process_one(struct fuse_opt_context *ctx, const char *arg)
+ {
+-	if (ctx->nonopt || arg[0] != '-')
+-		return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0);
+-	else if (arg[1] == 'o') {
+-		if (arg[2])
+-			return process_option_group(ctx, arg + 2);
+-		else {
+-			if (next_arg(ctx, arg) == -1)
+-				return -1;
+-
+-			return process_option_group(ctx,
+-						    ctx->argv[ctx->argctr]);
+-		}
+-	} else if (arg[1] == '-' && !arg[2]) {
+-		if (add_arg(ctx, arg) == -1)
+-			return -1;
+-		ctx->nonopt = ctx->outargs.argc;
+-		return 0;
+-	} else
+-		return process_gopt(ctx, arg, 0);
++    if (ctx->nonopt || arg[0] != '-') {
++        return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0);
++    } else if (arg[1] == 'o') {
++        if (arg[2]) {
++            return process_option_group(ctx, arg + 2);
++        } else {
++            if (next_arg(ctx, arg) == -1) {
++                return -1;
++            }
++
++            return process_option_group(ctx, ctx->argv[ctx->argctr]);
++        }
++    } else if (arg[1] == '-' && !arg[2]) {
++        if (add_arg(ctx, arg) == -1) {
++            return -1;
++        }
++        ctx->nonopt = ctx->outargs.argc;
++        return 0;
++    } else {
++        return process_gopt(ctx, arg, 0);
++    }
+ }
+ 
+ static int opt_parse(struct fuse_opt_context *ctx)
+ {
+-	if (ctx->argc) {
+-		if (add_arg(ctx, ctx->argv[0]) == -1)
+-			return -1;
+-	}
+-
+-	for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++)
+-		if (process_one(ctx, ctx->argv[ctx->argctr]) == -1)
+-			return -1;
+-
+-	if (ctx->opts) {
+-		if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 ||
+-		    fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1)
+-			return -1;
+-	}
+-
+-	/* If option separator ("--") is the last argument, remove it */
+-	if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc &&
+-	    strcmp(ctx->outargs.argv[ctx->outargs.argc - 1], "--") == 0) {
+-		free(ctx->outargs.argv[ctx->outargs.argc - 1]);
+-		ctx->outargs.argv[--ctx->outargs.argc] = NULL;
+-	}
+-
+-	return 0;
++    if (ctx->argc) {
++        if (add_arg(ctx, ctx->argv[0]) == -1) {
++            return -1;
++        }
++    }
++
++    for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++) {
++        if (process_one(ctx, ctx->argv[ctx->argctr]) == -1) {
++            return -1;
++        }
++    }
++
++    if (ctx->opts) {
++        if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 ||
++            fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1) {
++            return -1;
++        }
++    }
++
++    /* If option separator ("--") is the last argument, remove it */
++    if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc &&
++        strcmp(ctx->outargs.argv[ctx->outargs.argc - 1], "--") == 0) {
++        free(ctx->outargs.argv[ctx->outargs.argc - 1]);
++        ctx->outargs.argv[--ctx->outargs.argc] = NULL;
++    }
++
++    return 0;
+ }
+ 
+ int fuse_opt_parse(struct fuse_args *args, void *data,
+-		   const struct fuse_opt opts[], fuse_opt_proc_t proc)
++                   const struct fuse_opt opts[], fuse_opt_proc_t proc)
+ {
+-	int res;
+-	struct fuse_opt_context ctx = {
+-		.data = data,
+-		.opt = opts,
+-		.proc = proc,
+-	};
+-
+-	if (!args || !args->argv || !args->argc)
+-		return 0;
+-
+-	ctx.argc = args->argc;
+-	ctx.argv = args->argv;
+-
+-	res = opt_parse(&ctx);
+-	if (res != -1) {
+-		struct fuse_args tmp = *args;
+-		*args = ctx.outargs;
+-		ctx.outargs = tmp;
+-	}
+-	free(ctx.opts);
+-	fuse_opt_free_args(&ctx.outargs);
+-	return res;
++    int res;
++    struct fuse_opt_context ctx = {
++        .data = data,
++        .opt = opts,
++        .proc = proc,
++    };
++
++    if (!args || !args->argv || !args->argc) {
++        return 0;
++    }
++
++    ctx.argc = args->argc;
++    ctx.argv = args->argv;
++
++    res = opt_parse(&ctx);
++    if (res != -1) {
++        struct fuse_args tmp = *args;
++        *args = ctx.outargs;
++        ctx.outargs = tmp;
++    }
++    free(ctx.opts);
++    fuse_opt_free_args(&ctx.outargs);
++    return res;
+ }
+diff --git a/tools/virtiofsd/fuse_opt.h b/tools/virtiofsd/fuse_opt.h
+index 69102555be..8f59b4d301 100644
+--- a/tools/virtiofsd/fuse_opt.h
++++ b/tools/virtiofsd/fuse_opt.h
+@@ -1,10 +1,10 @@
+ /*
+-  FUSE: Filesystem in Userspace
+-  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+-
+-  This program can be distributed under the terms of the GNU LGPLv2.
+-  See the file COPYING.LIB.
+-*/
++ * FUSE: Filesystem in Userspace
++ * Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++ *
++ * This program can be distributed under the terms of the GNU LGPLv2.
++ * See the file COPYING.LIB.
++ */
+ 
+ #ifndef FUSE_OPT_H_
+ #define FUSE_OPT_H_
+@@ -37,7 +37,7 @@
+  *
+  *  - 'offsetof(struct foo, member)'  actions i) and iii)
+  *
+- *  - -1			      action ii)
++ *  - -1                              action ii)
+  *
+  * The 'offsetof()' macro is defined in the <stddef.h> header.
+  *
+@@ -48,7 +48,7 @@
+  *
+  * The types of templates are:
+  *
+- * 1) "-x", "-foo", "--foo", "--foo-bar", etc.	These match only
++ * 1) "-x", "-foo", "--foo", "--foo-bar", etc. These match only
+  *   themselves.  Invalid values are "--" and anything beginning
+  *   with "-o"
+  *
+@@ -71,58 +71,67 @@
+  * freed.
+  */
+ struct fuse_opt {
+-	/** Matching template and optional parameter formatting */
+-	const char *templ;
++    /** Matching template and optional parameter formatting */
++    const char *templ;
+ 
+-	/**
+-	 * Offset of variable within 'data' parameter of fuse_opt_parse()
+-	 * or -1
+-	 */
+-	unsigned long offset;
++    /**
++     * Offset of variable within 'data' parameter of fuse_opt_parse()
++     * or -1
++     */
++    unsigned long offset;
+ 
+-	/**
+-	 * Value to set the variable to, or to be passed as 'key' to the
+-	 * processing function.	 Ignored if template has a format
+-	 */
+-	int value;
++    /**
++     * Value to set the variable to, or to be passed as 'key' to the
++     * processing function. Ignored if template has a format
++     */
++    int value;
+ };
+ 
+ /**
+- * Key option.	In case of a match, the processing function will be
++ * Key option. In case of a match, the processing function will be
+  * called with the specified key.
+  */
+-#define FUSE_OPT_KEY(templ, key) { templ, -1U, key }
++#define FUSE_OPT_KEY(templ, key) \
++    {                            \
++        templ, -1U, key          \
++    }
+ 
+ /**
+- * Last option.	 An array of 'struct fuse_opt' must end with a NULL
++ * Last option. An array of 'struct fuse_opt' must end with a NULL
+  * template value
+  */
+-#define FUSE_OPT_END { NULL, 0, 0 }
++#define FUSE_OPT_END \
++    {                \
++        NULL, 0, 0   \
++    }
+ 
+ /**
+  * Argument list
+  */
+ struct fuse_args {
+-	/** Argument count */
+-	int argc;
++    /** Argument count */
++    int argc;
+ 
+-	/** Argument vector.  NULL terminated */
+-	char **argv;
++    /** Argument vector.  NULL terminated */
++    char **argv;
+ 
+-	/** Is 'argv' allocated? */
+-	int allocated;
++    /** Is 'argv' allocated? */
++    int allocated;
+ };
+ 
+ /**
+  * Initializer for 'struct fuse_args'
+  */
+-#define FUSE_ARGS_INIT(argc, argv) { argc, argv, 0 }
++#define FUSE_ARGS_INIT(argc, argv) \
++    {                              \
++        argc, argv, 0              \
++    }
+ 
+ /**
+  * Key value passed to the processing function if an option did not
+  * match any template
+  */
+-#define FUSE_OPT_KEY_OPT     -1
++#define FUSE_OPT_KEY_OPT -1
+ 
+ /**
+  * Key value passed to the processing function for all non-options
+@@ -130,7 +139,7 @@ struct fuse_args {
+  * Non-options are the arguments beginning with a character other than
+  * '-' or all arguments after the special '--' option
+  */
+-#define FUSE_OPT_KEY_NONOPT  -2
++#define FUSE_OPT_KEY_NONOPT -2
+ 
+ /**
+  * Special key value for options to keep
+@@ -174,7 +183,7 @@ struct fuse_args {
+  * @return -1 on error, 0 if arg is to be discarded, 1 if arg should be kept
+  */
+ typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key,
+-			       struct fuse_args *outargs);
++                               struct fuse_args *outargs);
+ 
+ /**
+  * Option parsing function
+@@ -197,7 +206,7 @@ typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key,
+  * @return -1 on error, 0 on success
+  */
+ int fuse_opt_parse(struct fuse_args *args, void *data,
+-		   const struct fuse_opt opts[], fuse_opt_proc_t proc);
++                   const struct fuse_opt opts[], fuse_opt_proc_t proc);
+ 
+ /**
+  * Add an option to a comma separated option list
+diff --git a/tools/virtiofsd/fuse_signals.c b/tools/virtiofsd/fuse_signals.c
+index 4271947bd4..19d6791cb9 100644
+--- a/tools/virtiofsd/fuse_signals.c
++++ b/tools/virtiofsd/fuse_signals.c
+@@ -1,91 +1,95 @@
+ /*
+-  FUSE: Filesystem in Userspace
+-  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+-
+-  Utility functions for setting signal handlers.
+-
+-  This program can be distributed under the terms of the GNU LGPLv2.
+-  See the file COPYING.LIB
+-*/
++ * FUSE: Filesystem in Userspace
++ * Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++ *
++ * Utility functions for setting signal handlers.
++ *
++ * This program can be distributed under the terms of the GNU LGPLv2.
++ * See the file COPYING.LIB
++ */
+ 
+ #include "config.h"
+-#include "fuse_lowlevel.h"
+ #include "fuse_i.h"
++#include "fuse_lowlevel.h"
+ 
+-#include <stdio.h>
+-#include <string.h>
+ #include <signal.h>
++#include <stdio.h>
+ #include <stdlib.h>
++#include <string.h>
+ 
+ static struct fuse_session *fuse_instance;
+ 
+ static void exit_handler(int sig)
+ {
+-	if (fuse_instance) {
+-		fuse_session_exit(fuse_instance);
+-		if(sig <= 0) {
+-			fuse_log(FUSE_LOG_ERR, "assertion error: signal value <= 0\n");
+-			abort();
+-		}
+-		fuse_instance->error = sig;
+-	}
++    if (fuse_instance) {
++        fuse_session_exit(fuse_instance);
++        if (sig <= 0) {
++            fuse_log(FUSE_LOG_ERR, "assertion error: signal value <= 0\n");
++            abort();
++        }
++        fuse_instance->error = sig;
++    }
+ }
+ 
+ static void do_nothing(int sig)
+ {
+-	(void) sig;
++    (void)sig;
+ }
+ 
+ static int set_one_signal_handler(int sig, void (*handler)(int), int remove)
+ {
+-	struct sigaction sa;
+-	struct sigaction old_sa;
++    struct sigaction sa;
++    struct sigaction old_sa;
+ 
+-	memset(&sa, 0, sizeof(struct sigaction));
+-	sa.sa_handler = remove ? SIG_DFL : handler;
+-	sigemptyset(&(sa.sa_mask));
+-	sa.sa_flags = 0;
++    memset(&sa, 0, sizeof(struct sigaction));
++    sa.sa_handler = remove ? SIG_DFL : handler;
++    sigemptyset(&(sa.sa_mask));
++    sa.sa_flags = 0;
+ 
+-	if (sigaction(sig, NULL, &old_sa) == -1) {
+-		perror("fuse: cannot get old signal handler");
+-		return -1;
+-	}
++    if (sigaction(sig, NULL, &old_sa) == -1) {
++        perror("fuse: cannot get old signal handler");
++        return -1;
++    }
+ 
+-	if (old_sa.sa_handler == (remove ? handler : SIG_DFL) &&
+-	    sigaction(sig, &sa, NULL) == -1) {
+-		perror("fuse: cannot set signal handler");
+-		return -1;
+-	}
+-	return 0;
++    if (old_sa.sa_handler == (remove ? handler : SIG_DFL) &&
++        sigaction(sig, &sa, NULL) == -1) {
++        perror("fuse: cannot set signal handler");
++        return -1;
++    }
++    return 0;
+ }
+ 
+ int fuse_set_signal_handlers(struct fuse_session *se)
+ {
+-	/* If we used SIG_IGN instead of the do_nothing function,
+-	   then we would be unable to tell if we set SIG_IGN (and
+-	   thus should reset to SIG_DFL in fuse_remove_signal_handlers)
+-	   or if it was already set to SIG_IGN (and should be left
+-	   untouched. */
+-	if (set_one_signal_handler(SIGHUP, exit_handler, 0) == -1 ||
+-	    set_one_signal_handler(SIGINT, exit_handler, 0) == -1 ||
+-	    set_one_signal_handler(SIGTERM, exit_handler, 0) == -1 ||
+-	    set_one_signal_handler(SIGPIPE, do_nothing, 0) == -1)
+-		return -1;
++    /*
++     * If we used SIG_IGN instead of the do_nothing function,
++     * then we would be unable to tell if we set SIG_IGN (and
++     * thus should reset to SIG_DFL in fuse_remove_signal_handlers)
++     * or if it was already set to SIG_IGN (and should be left
++     * untouched.
++     */
++    if (set_one_signal_handler(SIGHUP, exit_handler, 0) == -1 ||
++        set_one_signal_handler(SIGINT, exit_handler, 0) == -1 ||
++        set_one_signal_handler(SIGTERM, exit_handler, 0) == -1 ||
++        set_one_signal_handler(SIGPIPE, do_nothing, 0) == -1) {
++        return -1;
++    }
+ 
+-	fuse_instance = se;
+-	return 0;
++    fuse_instance = se;
++    return 0;
+ }
+ 
+ void fuse_remove_signal_handlers(struct fuse_session *se)
+ {
+-	if (fuse_instance != se)
+-		fuse_log(FUSE_LOG_ERR,
+-			"fuse: fuse_remove_signal_handlers: unknown session\n");
+-	else
+-		fuse_instance = NULL;
++    if (fuse_instance != se) {
++        fuse_log(FUSE_LOG_ERR,
++                 "fuse: fuse_remove_signal_handlers: unknown session\n");
++    } else {
++        fuse_instance = NULL;
++    }
+ 
+-	set_one_signal_handler(SIGHUP, exit_handler, 1);
+-	set_one_signal_handler(SIGINT, exit_handler, 1);
+-	set_one_signal_handler(SIGTERM, exit_handler, 1);
+-	set_one_signal_handler(SIGPIPE, do_nothing, 1);
++    set_one_signal_handler(SIGHUP, exit_handler, 1);
++    set_one_signal_handler(SIGINT, exit_handler, 1);
++    set_one_signal_handler(SIGTERM, exit_handler, 1);
++    set_one_signal_handler(SIGPIPE, do_nothing, 1);
+ }
+diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
+index 5a2e64c6d0..5711dd2660 100644
+--- a/tools/virtiofsd/helper.c
++++ b/tools/virtiofsd/helper.c
+@@ -1,297 +1,309 @@
+ /*
+-  FUSE: Filesystem in Userspace
+-  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++ * FUSE: Filesystem in Userspace
++ * Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++ *
++ * Helper functions to create (simple) standalone programs. With the
++ * aid of these functions it should be possible to create full FUSE
++ * file system by implementing nothing but the request handlers.
+ 
+-  Helper functions to create (simple) standalone programs. With the
+-  aid of these functions it should be possible to create full FUSE
+-  file system by implementing nothing but the request handlers.
+-
+-  This program can be distributed under the terms of the GNU LGPLv2.
+-  See the file COPYING.LIB.
+-*/
++ * This program can be distributed under the terms of the GNU LGPLv2.
++ * See the file COPYING.LIB.
++ */
+ 
+ #include "config.h"
+ #include "fuse_i.h"
++#include "fuse_lowlevel.h"
+ #include "fuse_misc.h"
+ #include "fuse_opt.h"
+-#include "fuse_lowlevel.h"
+ #include "mount_util.h"
+ 
++#include <errno.h>
++#include <limits.h>
++#include <stddef.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+-#include <stddef.h>
+-#include <unistd.h>
+ #include <string.h>
+-#include <limits.h>
+-#include <errno.h>
+ #include <sys/param.h>
++#include <unistd.h>
+ 
+-#define FUSE_HELPER_OPT(t, p) \
+-	{ t, offsetof(struct fuse_cmdline_opts, p), 1 }
++#define FUSE_HELPER_OPT(t, p)                       \
++    {                                               \
++        t, offsetof(struct fuse_cmdline_opts, p), 1 \
++    }
+ 
+ static const struct fuse_opt fuse_helper_opts[] = {
+-	FUSE_HELPER_OPT("-h",		show_help),
+-	FUSE_HELPER_OPT("--help",	show_help),
+-	FUSE_HELPER_OPT("-V",		show_version),
+-	FUSE_HELPER_OPT("--version",	show_version),
+-	FUSE_HELPER_OPT("-d",		debug),
+-	FUSE_HELPER_OPT("debug",	debug),
+-	FUSE_HELPER_OPT("-d",		foreground),
+-	FUSE_HELPER_OPT("debug",	foreground),
+-	FUSE_OPT_KEY("-d",		FUSE_OPT_KEY_KEEP),
+-	FUSE_OPT_KEY("debug",		FUSE_OPT_KEY_KEEP),
+-	FUSE_HELPER_OPT("-f",		foreground),
+-	FUSE_HELPER_OPT("fsname=",	nodefault_subtype),
+-	FUSE_OPT_KEY("fsname=",		FUSE_OPT_KEY_KEEP),
+-	FUSE_HELPER_OPT("subtype=",	nodefault_subtype),
+-	FUSE_OPT_KEY("subtype=",	FUSE_OPT_KEY_KEEP),
+-	FUSE_HELPER_OPT("max_idle_threads=%u", max_idle_threads),
+-	FUSE_OPT_END
++    FUSE_HELPER_OPT("-h", show_help),
++    FUSE_HELPER_OPT("--help", show_help),
++    FUSE_HELPER_OPT("-V", show_version),
++    FUSE_HELPER_OPT("--version", show_version),
++    FUSE_HELPER_OPT("-d", debug),
++    FUSE_HELPER_OPT("debug", debug),
++    FUSE_HELPER_OPT("-d", foreground),
++    FUSE_HELPER_OPT("debug", foreground),
++    FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
++    FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
++    FUSE_HELPER_OPT("-f", foreground),
++    FUSE_HELPER_OPT("fsname=", nodefault_subtype),
++    FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP),
++    FUSE_HELPER_OPT("subtype=", nodefault_subtype),
++    FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP),
++    FUSE_HELPER_OPT("max_idle_threads=%u", max_idle_threads),
++    FUSE_OPT_END
+ };
+ 
+ struct fuse_conn_info_opts {
+-	int atomic_o_trunc;
+-	int no_remote_posix_lock;
+-	int no_remote_flock;
+-	int splice_write;
+-	int splice_move;
+-	int splice_read;
+-	int no_splice_write;
+-	int no_splice_move;
+-	int no_splice_read;
+-	int auto_inval_data;
+-	int no_auto_inval_data;
+-	int no_readdirplus;
+-	int no_readdirplus_auto;
+-	int async_dio;
+-	int no_async_dio;
+-	int writeback_cache;
+-	int no_writeback_cache;
+-	int async_read;
+-	int sync_read;
+-	unsigned max_write;
+-	unsigned max_readahead;
+-	unsigned max_background;
+-	unsigned congestion_threshold;
+-	unsigned time_gran;
+-	int set_max_write;
+-	int set_max_readahead;
+-	int set_max_background;
+-	int set_congestion_threshold;
+-	int set_time_gran;
++    int atomic_o_trunc;
++    int no_remote_posix_lock;
++    int no_remote_flock;
++    int splice_write;
++    int splice_move;
++    int splice_read;
++    int no_splice_write;
++    int no_splice_move;
++    int no_splice_read;
++    int auto_inval_data;
++    int no_auto_inval_data;
++    int no_readdirplus;
++    int no_readdirplus_auto;
++    int async_dio;
++    int no_async_dio;
++    int writeback_cache;
++    int no_writeback_cache;
++    int async_read;
++    int sync_read;
++    unsigned max_write;
++    unsigned max_readahead;
++    unsigned max_background;
++    unsigned congestion_threshold;
++    unsigned time_gran;
++    int set_max_write;
++    int set_max_readahead;
++    int set_max_background;
++    int set_congestion_threshold;
++    int set_time_gran;
+ };
+ 
+-#define CONN_OPTION(t, p, v)					\
+-	{ t, offsetof(struct fuse_conn_info_opts, p), v }
++#define CONN_OPTION(t, p, v)                          \
++    {                                                 \
++        t, offsetof(struct fuse_conn_info_opts, p), v \
++    }
+ static const struct fuse_opt conn_info_opt_spec[] = {
+-	CONN_OPTION("max_write=%u", max_write, 0),
+-	CONN_OPTION("max_write=", set_max_write, 1),
+-	CONN_OPTION("max_readahead=%u", max_readahead, 0),
+-	CONN_OPTION("max_readahead=", set_max_readahead, 1),
+-	CONN_OPTION("max_background=%u", max_background, 0),
+-	CONN_OPTION("max_background=", set_max_background, 1),
+-	CONN_OPTION("congestion_threshold=%u", congestion_threshold, 0),
+-	CONN_OPTION("congestion_threshold=", set_congestion_threshold, 1),
+-	CONN_OPTION("sync_read", sync_read, 1),
+-	CONN_OPTION("async_read", async_read, 1),
+-	CONN_OPTION("atomic_o_trunc", atomic_o_trunc, 1),
+-	CONN_OPTION("no_remote_lock", no_remote_posix_lock, 1),
+-	CONN_OPTION("no_remote_lock", no_remote_flock, 1),
+-	CONN_OPTION("no_remote_flock", no_remote_flock, 1),
+-	CONN_OPTION("no_remote_posix_lock", no_remote_posix_lock, 1),
+-	CONN_OPTION("splice_write", splice_write, 1),
+-	CONN_OPTION("no_splice_write", no_splice_write, 1),
+-	CONN_OPTION("splice_move", splice_move, 1),
+-	CONN_OPTION("no_splice_move", no_splice_move, 1),
+-	CONN_OPTION("splice_read", splice_read, 1),
+-	CONN_OPTION("no_splice_read", no_splice_read, 1),
+-	CONN_OPTION("auto_inval_data", auto_inval_data, 1),
+-	CONN_OPTION("no_auto_inval_data", no_auto_inval_data, 1),
+-	CONN_OPTION("readdirplus=no", no_readdirplus, 1),
+-	CONN_OPTION("readdirplus=yes", no_readdirplus, 0),
+-	CONN_OPTION("readdirplus=yes", no_readdirplus_auto, 1),
+-	CONN_OPTION("readdirplus=auto", no_readdirplus, 0),
+-	CONN_OPTION("readdirplus=auto", no_readdirplus_auto, 0),
+-	CONN_OPTION("async_dio", async_dio, 1),
+-	CONN_OPTION("no_async_dio", no_async_dio, 1),
+-	CONN_OPTION("writeback_cache", writeback_cache, 1),
+-	CONN_OPTION("no_writeback_cache", no_writeback_cache, 1),
+-	CONN_OPTION("time_gran=%u", time_gran, 0),
+-	CONN_OPTION("time_gran=", set_time_gran, 1),
+-	FUSE_OPT_END
++    CONN_OPTION("max_write=%u", max_write, 0),
++    CONN_OPTION("max_write=", set_max_write, 1),
++    CONN_OPTION("max_readahead=%u", max_readahead, 0),
++    CONN_OPTION("max_readahead=", set_max_readahead, 1),
++    CONN_OPTION("max_background=%u", max_background, 0),
++    CONN_OPTION("max_background=", set_max_background, 1),
++    CONN_OPTION("congestion_threshold=%u", congestion_threshold, 0),
++    CONN_OPTION("congestion_threshold=", set_congestion_threshold, 1),
++    CONN_OPTION("sync_read", sync_read, 1),
++    CONN_OPTION("async_read", async_read, 1),
++    CONN_OPTION("atomic_o_trunc", atomic_o_trunc, 1),
++    CONN_OPTION("no_remote_lock", no_remote_posix_lock, 1),
++    CONN_OPTION("no_remote_lock", no_remote_flock, 1),
++    CONN_OPTION("no_remote_flock", no_remote_flock, 1),
++    CONN_OPTION("no_remote_posix_lock", no_remote_posix_lock, 1),
++    CONN_OPTION("splice_write", splice_write, 1),
++    CONN_OPTION("no_splice_write", no_splice_write, 1),
++    CONN_OPTION("splice_move", splice_move, 1),
++    CONN_OPTION("no_splice_move", no_splice_move, 1),
++    CONN_OPTION("splice_read", splice_read, 1),
++    CONN_OPTION("no_splice_read", no_splice_read, 1),
++    CONN_OPTION("auto_inval_data", auto_inval_data, 1),
++    CONN_OPTION("no_auto_inval_data", no_auto_inval_data, 1),
++    CONN_OPTION("readdirplus=no", no_readdirplus, 1),
++    CONN_OPTION("readdirplus=yes", no_readdirplus, 0),
++    CONN_OPTION("readdirplus=yes", no_readdirplus_auto, 1),
++    CONN_OPTION("readdirplus=auto", no_readdirplus, 0),
++    CONN_OPTION("readdirplus=auto", no_readdirplus_auto, 0),
++    CONN_OPTION("async_dio", async_dio, 1),
++    CONN_OPTION("no_async_dio", no_async_dio, 1),
++    CONN_OPTION("writeback_cache", writeback_cache, 1),
++    CONN_OPTION("no_writeback_cache", no_writeback_cache, 1),
++    CONN_OPTION("time_gran=%u", time_gran, 0),
++    CONN_OPTION("time_gran=", set_time_gran, 1),
++    FUSE_OPT_END
+ };
+ 
+ 
+ void fuse_cmdline_help(void)
+ {
+-	printf("    -h   --help            print help\n"
+-	       "    -V   --version         print version\n"
+-	       "    -d   -o debug          enable debug output (implies -f)\n"
+-	       "    -f                     foreground operation\n"
+-	       "    -o max_idle_threads    the maximum number of idle worker threads\n"
+-	       "                           allowed (default: 10)\n");
++    printf(
++        "    -h   --help            print help\n"
++        "    -V   --version         print version\n"
++        "    -d   -o debug          enable debug output (implies -f)\n"
++        "    -f                     foreground operation\n"
++        "    -o max_idle_threads    the maximum number of idle worker threads\n"
++        "                           allowed (default: 10)\n");
+ }
+ 
+ static int fuse_helper_opt_proc(void *data, const char *arg, int key,
+-				struct fuse_args *outargs)
++                                struct fuse_args *outargs)
+ {
+-	(void) outargs;
+-	struct fuse_cmdline_opts *opts = data;
+-
+-	switch (key) {
+-	case FUSE_OPT_KEY_NONOPT:
+-		if (!opts->mountpoint) {
+-			if (fuse_mnt_parse_fuse_fd(arg) != -1) {
+-				return fuse_opt_add_opt(&opts->mountpoint, arg);
+-			}
+-
+-			char mountpoint[PATH_MAX] = "";
+-			if (realpath(arg, mountpoint) == NULL) {
+-				fuse_log(FUSE_LOG_ERR,
+-					"fuse: bad mount point `%s': %s\n",
+-					arg, strerror(errno));
+-				return -1;
+-			}
+-			return fuse_opt_add_opt(&opts->mountpoint, mountpoint);
+-		} else {
+-			fuse_log(FUSE_LOG_ERR, "fuse: invalid argument `%s'\n", arg);
+-			return -1;
+-		}
+-
+-	default:
+-		/* Pass through unknown options */
+-		return 1;
+-	}
++    (void)outargs;
++    struct fuse_cmdline_opts *opts = data;
++
++    switch (key) {
++    case FUSE_OPT_KEY_NONOPT:
++        if (!opts->mountpoint) {
++            if (fuse_mnt_parse_fuse_fd(arg) != -1) {
++                return fuse_opt_add_opt(&opts->mountpoint, arg);
++            }
++
++            char mountpoint[PATH_MAX] = "";
++            if (realpath(arg, mountpoint) == NULL) {
++                fuse_log(FUSE_LOG_ERR, "fuse: bad mount point `%s': %s\n", arg,
++                         strerror(errno));
++                return -1;
++            }
++            return fuse_opt_add_opt(&opts->mountpoint, mountpoint);
++        } else {
++            fuse_log(FUSE_LOG_ERR, "fuse: invalid argument `%s'\n", arg);
++            return -1;
++        }
++
++    default:
++        /* Pass through unknown options */
++        return 1;
++    }
+ }
+ 
+-int fuse_parse_cmdline(struct fuse_args *args,
+-		       struct fuse_cmdline_opts *opts)
++int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts)
+ {
+-	memset(opts, 0, sizeof(struct fuse_cmdline_opts));
++    memset(opts, 0, sizeof(struct fuse_cmdline_opts));
+ 
+-	opts->max_idle_threads = 10;
++    opts->max_idle_threads = 10;
+ 
+-	if (fuse_opt_parse(args, opts, fuse_helper_opts,
+-			   fuse_helper_opt_proc) == -1)
+-		return -1;
++    if (fuse_opt_parse(args, opts, fuse_helper_opts, fuse_helper_opt_proc) ==
++        -1) {
++        return -1;
++    }
+ 
+-	return 0;
++    return 0;
+ }
+ 
+ 
+ int fuse_daemonize(int foreground)
+ {
+-	if (!foreground) {
+-		int nullfd;
+-		int waiter[2];
+-		char completed;
+-
+-		if (pipe(waiter)) {
+-			perror("fuse_daemonize: pipe");
+-			return -1;
+-		}
+-
+-		/*
+-		 * demonize current process by forking it and killing the
+-		 * parent.  This makes current process as a child of 'init'.
+-		 */
+-		switch(fork()) {
+-		case -1:
+-			perror("fuse_daemonize: fork");
+-			return -1;
+-		case 0:
+-			break;
+-		default:
+-			(void) read(waiter[0], &completed, sizeof(completed));
+-			_exit(0);
+-		}
+-
+-		if (setsid() == -1) {
+-			perror("fuse_daemonize: setsid");
+-			return -1;
+-		}
+-
+-		(void) chdir("/");
+-
+-		nullfd = open("/dev/null", O_RDWR, 0);
+-		if (nullfd != -1) {
+-			(void) dup2(nullfd, 0);
+-			(void) dup2(nullfd, 1);
+-			(void) dup2(nullfd, 2);
+-			if (nullfd > 2)
+-				close(nullfd);
+-		}
+-
+-		/* Propagate completion of daemon initialization */
+-		completed = 1;
+-		(void) write(waiter[1], &completed, sizeof(completed));
+-		close(waiter[0]);
+-		close(waiter[1]);
+-	} else {
+-		(void) chdir("/");
+-	}
+-	return 0;
++    if (!foreground) {
++        int nullfd;
++        int waiter[2];
++        char completed;
++
++        if (pipe(waiter)) {
++            perror("fuse_daemonize: pipe");
++            return -1;
++        }
++
++        /*
++         * demonize current process by forking it and killing the
++         * parent.  This makes current process as a child of 'init'.
++         */
++        switch (fork()) {
++        case -1:
++            perror("fuse_daemonize: fork");
++            return -1;
++        case 0:
++            break;
++        default:
++            (void)read(waiter[0], &completed, sizeof(completed));
++            _exit(0);
++        }
++
++        if (setsid() == -1) {
++            perror("fuse_daemonize: setsid");
++            return -1;
++        }
++
++        (void)chdir("/");
++
++        nullfd = open("/dev/null", O_RDWR, 0);
++        if (nullfd != -1) {
++            (void)dup2(nullfd, 0);
++            (void)dup2(nullfd, 1);
++            (void)dup2(nullfd, 2);
++            if (nullfd > 2) {
++                close(nullfd);
++            }
++        }
++
++        /* Propagate completion of daemon initialization */
++        completed = 1;
++        (void)write(waiter[1], &completed, sizeof(completed));
++        close(waiter[0]);
++        close(waiter[1]);
++    } else {
++        (void)chdir("/");
++    }
++    return 0;
+ }
+ 
+ void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts,
+-			       struct fuse_conn_info *conn)
++                               struct fuse_conn_info *conn)
+ {
+-	if(opts->set_max_write)
+-		conn->max_write = opts->max_write;
+-	if(opts->set_max_background)
+-		conn->max_background = opts->max_background;
+-	if(opts->set_congestion_threshold)
+-		conn->congestion_threshold = opts->congestion_threshold;
+-	if(opts->set_time_gran)
+-		conn->time_gran = opts->time_gran;
+-	if(opts->set_max_readahead)
+-		conn->max_readahead = opts->max_readahead;
+-
+-#define LL_ENABLE(cond,cap) \
+-	if (cond) conn->want |= (cap)
+-#define LL_DISABLE(cond,cap) \
+-	if (cond) conn->want &= ~(cap)
+-
+-	LL_ENABLE(opts->splice_read, FUSE_CAP_SPLICE_READ);
+-	LL_DISABLE(opts->no_splice_read, FUSE_CAP_SPLICE_READ);
+-
+-	LL_ENABLE(opts->splice_write, FUSE_CAP_SPLICE_WRITE);
+-	LL_DISABLE(opts->no_splice_write, FUSE_CAP_SPLICE_WRITE);
+-
+-	LL_ENABLE(opts->splice_move, FUSE_CAP_SPLICE_MOVE);
+-	LL_DISABLE(opts->no_splice_move, FUSE_CAP_SPLICE_MOVE);
+-
+-	LL_ENABLE(opts->auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA);
+-	LL_DISABLE(opts->no_auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA);
+-
+-	LL_DISABLE(opts->no_readdirplus, FUSE_CAP_READDIRPLUS);
+-	LL_DISABLE(opts->no_readdirplus_auto, FUSE_CAP_READDIRPLUS_AUTO);
+-
+-	LL_ENABLE(opts->async_dio, FUSE_CAP_ASYNC_DIO);
+-	LL_DISABLE(opts->no_async_dio, FUSE_CAP_ASYNC_DIO);
+-
+-	LL_ENABLE(opts->writeback_cache, FUSE_CAP_WRITEBACK_CACHE);
+-	LL_DISABLE(opts->no_writeback_cache, FUSE_CAP_WRITEBACK_CACHE);
+-
+-	LL_ENABLE(opts->async_read, FUSE_CAP_ASYNC_READ);
+-	LL_DISABLE(opts->sync_read, FUSE_CAP_ASYNC_READ);
+-
+-	LL_DISABLE(opts->no_remote_posix_lock, FUSE_CAP_POSIX_LOCKS);
+-	LL_DISABLE(opts->no_remote_flock, FUSE_CAP_FLOCK_LOCKS);
++    if (opts->set_max_write) {
++        conn->max_write = opts->max_write;
++    }
++    if (opts->set_max_background) {
++        conn->max_background = opts->max_background;
++    }
++    if (opts->set_congestion_threshold) {
++        conn->congestion_threshold = opts->congestion_threshold;
++    }
++    if (opts->set_time_gran) {
++        conn->time_gran = opts->time_gran;
++    }
++    if (opts->set_max_readahead) {
++        conn->max_readahead = opts->max_readahead;
++    }
++
++#define LL_ENABLE(cond, cap) \
++    if (cond)                \
++        conn->want |= (cap)
++#define LL_DISABLE(cond, cap) \
++    if (cond)                 \
++        conn->want &= ~(cap)
++
++    LL_ENABLE(opts->splice_read, FUSE_CAP_SPLICE_READ);
++    LL_DISABLE(opts->no_splice_read, FUSE_CAP_SPLICE_READ);
++
++    LL_ENABLE(opts->splice_write, FUSE_CAP_SPLICE_WRITE);
++    LL_DISABLE(opts->no_splice_write, FUSE_CAP_SPLICE_WRITE);
++
++    LL_ENABLE(opts->splice_move, FUSE_CAP_SPLICE_MOVE);
++    LL_DISABLE(opts->no_splice_move, FUSE_CAP_SPLICE_MOVE);
++
++    LL_ENABLE(opts->auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA);
++    LL_DISABLE(opts->no_auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA);
++
++    LL_DISABLE(opts->no_readdirplus, FUSE_CAP_READDIRPLUS);
++    LL_DISABLE(opts->no_readdirplus_auto, FUSE_CAP_READDIRPLUS_AUTO);
++
++    LL_ENABLE(opts->async_dio, FUSE_CAP_ASYNC_DIO);
++    LL_DISABLE(opts->no_async_dio, FUSE_CAP_ASYNC_DIO);
++
++    LL_ENABLE(opts->writeback_cache, FUSE_CAP_WRITEBACK_CACHE);
++    LL_DISABLE(opts->no_writeback_cache, FUSE_CAP_WRITEBACK_CACHE);
++
++    LL_ENABLE(opts->async_read, FUSE_CAP_ASYNC_READ);
++    LL_DISABLE(opts->sync_read, FUSE_CAP_ASYNC_READ);
++
++    LL_DISABLE(opts->no_remote_posix_lock, FUSE_CAP_POSIX_LOCKS);
++    LL_DISABLE(opts->no_remote_flock, FUSE_CAP_FLOCK_LOCKS);
+ }
+ 
+-struct fuse_conn_info_opts* fuse_parse_conn_info_opts(struct fuse_args *args)
++struct fuse_conn_info_opts *fuse_parse_conn_info_opts(struct fuse_args *args)
+ {
+-	struct fuse_conn_info_opts *opts;
+-
+-	opts = calloc(1, sizeof(struct fuse_conn_info_opts));
+-	if(opts == NULL) {
+-		fuse_log(FUSE_LOG_ERR, "calloc failed\n");
+-		return NULL;
+-	}
+-	if(fuse_opt_parse(args, opts, conn_info_opt_spec, NULL) == -1) {
+-		free(opts);
+-		return NULL;
+-	}
+-	return opts;
++    struct fuse_conn_info_opts *opts;
++
++    opts = calloc(1, sizeof(struct fuse_conn_info_opts));
++    if (opts == NULL) {
++        fuse_log(FUSE_LOG_ERR, "calloc failed\n");
++        return NULL;
++    }
++    if (fuse_opt_parse(args, opts, conn_info_opt_spec, NULL) == -1) {
++        free(opts);
++        return NULL;
++    }
++    return opts;
+ }
+diff --git a/tools/virtiofsd/passthrough_helpers.h b/tools/virtiofsd/passthrough_helpers.h
+index 7c5f561fbc..0b98275ed5 100644
+--- a/tools/virtiofsd/passthrough_helpers.h
++++ b/tools/virtiofsd/passthrough_helpers.h
+@@ -28,23 +28,24 @@
+  * operation
+  */
+ static int mknod_wrapper(int dirfd, const char *path, const char *link,
+-	int mode, dev_t rdev)
++                         int mode, dev_t rdev)
+ {
+-	int res;
++    int res;
+ 
+-	if (S_ISREG(mode)) {
+-		res = openat(dirfd, path, O_CREAT | O_EXCL | O_WRONLY, mode);
+-		if (res >= 0)
+-			res = close(res);
+-	} else if (S_ISDIR(mode)) {
+-		res = mkdirat(dirfd, path, mode);
+-	} else if (S_ISLNK(mode) && link != NULL) {
+-		res = symlinkat(link, dirfd, path);
+-	} else if (S_ISFIFO(mode)) {
+-		res = mkfifoat(dirfd, path, mode);
+-	} else {
+-		res = mknodat(dirfd, path, mode, rdev);
+-	}
++    if (S_ISREG(mode)) {
++        res = openat(dirfd, path, O_CREAT | O_EXCL | O_WRONLY, mode);
++        if (res >= 0) {
++            res = close(res);
++        }
++    } else if (S_ISDIR(mode)) {
++        res = mkdirat(dirfd, path, mode);
++    } else if (S_ISLNK(mode) && link != NULL) {
++        res = symlinkat(link, dirfd, path);
++    } else if (S_ISFIFO(mode)) {
++        res = mkfifoat(dirfd, path, mode);
++    } else {
++        res = mknodat(dirfd, path, mode, rdev);
++    }
+ 
+-	return res;
++    return res;
+ }
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index e5f7115bc1..c5850ef803 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -1,12 +1,12 @@
+ /*
+-  FUSE: Filesystem in Userspace
+-  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+-
+-  This program can be distributed under the terms of the GNU GPLv2.
+-  See the file COPYING.
+-*/
++ * FUSE: Filesystem in Userspace
++ * Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
++ *
++ * This program can be distributed under the terms of the GNU GPLv2.
++ * See the file COPYING.
++ */
+ 
+-/** @file
++/*
+  *
+  * This file system mirrors the existing file system hierarchy of the
+  * system, starting at the root file system. This is implemented by
+@@ -28,7 +28,8 @@
+  *
+  * Compile with:
+  *
+- *     gcc -Wall passthrough_ll.c `pkg-config fuse3 --cflags --libs` -o passthrough_ll
++ *     gcc -Wall passthrough_ll.c `pkg-config fuse3 --cflags --libs` -o
++ * passthrough_ll
+  *
+  * ## Source code ##
+  * \include passthrough_ll.c
+@@ -39,1299 +40,1365 @@
+ 
+ #include "config.h"
+ 
+-#include <fuse_lowlevel.h>
+-#include <unistd.h>
+-#include <stdlib.h>
+-#include <stdio.h>
+-#include <stddef.h>
+-#include <stdbool.h>
+-#include <string.h>
+-#include <limits.h>
+-#include <dirent.h>
+ #include <assert.h>
++#include <dirent.h>
+ #include <errno.h>
++#include <fuse_lowlevel.h>
+ #include <inttypes.h>
++#include <limits.h>
+ #include <pthread.h>
++#include <stdbool.h>
++#include <stddef.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
+ #include <sys/file.h>
+ #include <sys/xattr.h>
++#include <unistd.h>
+ 
+ #include "passthrough_helpers.h"
+ 
+-/* We are re-using pointers to our `struct lo_inode` and `struct
+-   lo_dirp` elements as inodes. This means that we must be able to
+-   store uintptr_t values in a fuse_ino_t variable. The following
+-   incantation checks this condition at compile time. */
+-#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && !defined __cplusplus
++/*
++ * We are re-using pointers to our `struct lo_inode` and `struct
++ * lo_dirp` elements as inodes. This means that we must be able to
++ * store uintptr_t values in a fuse_ino_t variable. The following
++ * incantation checks this condition at compile time.
++ */
++#if defined(__GNUC__) &&                                      \
++    (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && \
++    !defined __cplusplus
+ _Static_assert(sizeof(fuse_ino_t) >= sizeof(uintptr_t),
+-	       "fuse_ino_t too small to hold uintptr_t values!");
++               "fuse_ino_t too small to hold uintptr_t values!");
+ #else
+-struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct \
+-	{ unsigned _uintptr_to_must_hold_fuse_ino_t:
+-			((sizeof(fuse_ino_t) >= sizeof(uintptr_t)) ? 1 : -1); };
++struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct {
++    unsigned _uintptr_to_must_hold_fuse_ino_t
++        : ((sizeof(fuse_ino_t) >= sizeof(uintptr_t)) ? 1 : -1);
++};
+ #endif
+ 
+ struct lo_inode {
+-	struct lo_inode *next; /* protected by lo->mutex */
+-	struct lo_inode *prev; /* protected by lo->mutex */
+-	int fd;
+-	bool is_symlink;
+-	ino_t ino;
+-	dev_t dev;
+-	uint64_t refcount; /* protected by lo->mutex */
++    struct lo_inode *next; /* protected by lo->mutex */
++    struct lo_inode *prev; /* protected by lo->mutex */
++    int fd;
++    bool is_symlink;
++    ino_t ino;
++    dev_t dev;
++    uint64_t refcount; /* protected by lo->mutex */
+ };
+ 
+ enum {
+-	CACHE_NEVER,
+-	CACHE_NORMAL,
+-	CACHE_ALWAYS,
++    CACHE_NEVER,
++    CACHE_NORMAL,
++    CACHE_ALWAYS,
+ };
+ 
+ struct lo_data {
+-	pthread_mutex_t mutex;
+-	int debug;
+-	int writeback;
+-	int flock;
+-	int xattr;
+-	const char *source;
+-	double timeout;
+-	int cache;
+-	int timeout_set;
+-	struct lo_inode root; /* protected by lo->mutex */
++    pthread_mutex_t mutex;
++    int debug;
++    int writeback;
++    int flock;
++    int xattr;
++    const char *source;
++    double timeout;
++    int cache;
++    int timeout_set;
++    struct lo_inode root; /* protected by lo->mutex */
+ };
+ 
+ static const struct fuse_opt lo_opts[] = {
+-	{ "writeback",
+-	  offsetof(struct lo_data, writeback), 1 },
+-	{ "no_writeback",
+-	  offsetof(struct lo_data, writeback), 0 },
+-	{ "source=%s",
+-	  offsetof(struct lo_data, source), 0 },
+-	{ "flock",
+-	  offsetof(struct lo_data, flock), 1 },
+-	{ "no_flock",
+-	  offsetof(struct lo_data, flock), 0 },
+-	{ "xattr",
+-	  offsetof(struct lo_data, xattr), 1 },
+-	{ "no_xattr",
+-	  offsetof(struct lo_data, xattr), 0 },
+-	{ "timeout=%lf",
+-	  offsetof(struct lo_data, timeout), 0 },
+-	{ "timeout=",
+-	  offsetof(struct lo_data, timeout_set), 1 },
+-	{ "cache=never",
+-	  offsetof(struct lo_data, cache), CACHE_NEVER },
+-	{ "cache=auto",
+-	  offsetof(struct lo_data, cache), CACHE_NORMAL },
+-	{ "cache=always",
+-	  offsetof(struct lo_data, cache), CACHE_ALWAYS },
+-
+-	FUSE_OPT_END
++    { "writeback", offsetof(struct lo_data, writeback), 1 },
++    { "no_writeback", offsetof(struct lo_data, writeback), 0 },
++    { "source=%s", offsetof(struct lo_data, source), 0 },
++    { "flock", offsetof(struct lo_data, flock), 1 },
++    { "no_flock", offsetof(struct lo_data, flock), 0 },
++    { "xattr", offsetof(struct lo_data, xattr), 1 },
++    { "no_xattr", offsetof(struct lo_data, xattr), 0 },
++    { "timeout=%lf", offsetof(struct lo_data, timeout), 0 },
++    { "timeout=", offsetof(struct lo_data, timeout_set), 1 },
++    { "cache=never", offsetof(struct lo_data, cache), CACHE_NEVER },
++    { "cache=auto", offsetof(struct lo_data, cache), CACHE_NORMAL },
++    { "cache=always", offsetof(struct lo_data, cache), CACHE_ALWAYS },
++
++    FUSE_OPT_END
+ };
+ 
+ static struct lo_data *lo_data(fuse_req_t req)
+ {
+-	return (struct lo_data *) fuse_req_userdata(req);
++    return (struct lo_data *)fuse_req_userdata(req);
+ }
+ 
+ static struct lo_inode *lo_inode(fuse_req_t req, fuse_ino_t ino)
+ {
+-	if (ino == FUSE_ROOT_ID)
+-		return &lo_data(req)->root;
+-	else
+-		return (struct lo_inode *) (uintptr_t) ino;
++    if (ino == FUSE_ROOT_ID) {
++        return &lo_data(req)->root;
++    } else {
++        return (struct lo_inode *)(uintptr_t)ino;
++    }
+ }
+ 
+ static int lo_fd(fuse_req_t req, fuse_ino_t ino)
+ {
+-	return lo_inode(req, ino)->fd;
++    return lo_inode(req, ino)->fd;
+ }
+ 
+ static bool lo_debug(fuse_req_t req)
+ {
+-	return lo_data(req)->debug != 0;
++    return lo_data(req)->debug != 0;
+ }
+ 
+-static void lo_init(void *userdata,
+-		    struct fuse_conn_info *conn)
++static void lo_init(void *userdata, struct fuse_conn_info *conn)
+ {
+-	struct lo_data *lo = (struct lo_data*) userdata;
+-
+-	if(conn->capable & FUSE_CAP_EXPORT_SUPPORT)
+-		conn->want |= FUSE_CAP_EXPORT_SUPPORT;
+-
+-	if (lo->writeback &&
+-	    conn->capable & FUSE_CAP_WRITEBACK_CACHE) {
+-		if (lo->debug)
+-			fuse_log(FUSE_LOG_DEBUG, "lo_init: activating writeback\n");
+-		conn->want |= FUSE_CAP_WRITEBACK_CACHE;
+-	}
+-	if (lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) {
+-		if (lo->debug)
+-			fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
+-		conn->want |= FUSE_CAP_FLOCK_LOCKS;
+-	}
++    struct lo_data *lo = (struct lo_data *)userdata;
++
++    if (conn->capable & FUSE_CAP_EXPORT_SUPPORT) {
++        conn->want |= FUSE_CAP_EXPORT_SUPPORT;
++    }
++
++    if (lo->writeback && conn->capable & FUSE_CAP_WRITEBACK_CACHE) {
++        if (lo->debug) {
++            fuse_log(FUSE_LOG_DEBUG, "lo_init: activating writeback\n");
++        }
++        conn->want |= FUSE_CAP_WRITEBACK_CACHE;
++    }
++    if (lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) {
++        if (lo->debug) {
++            fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
++        }
++        conn->want |= FUSE_CAP_FLOCK_LOCKS;
++    }
+ }
+ 
+ static void lo_getattr(fuse_req_t req, fuse_ino_t ino,
+-			     struct fuse_file_info *fi)
++                       struct fuse_file_info *fi)
+ {
+-	int res;
+-	struct stat buf;
+-	struct lo_data *lo = lo_data(req);
++    int res;
++    struct stat buf;
++    struct lo_data *lo = lo_data(req);
+ 
+-	(void) fi;
++    (void)fi;
+ 
+-	res = fstatat(lo_fd(req, ino), "", &buf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
+-	if (res == -1)
+-		return (void) fuse_reply_err(req, errno);
++    res =
++        fstatat(lo_fd(req, ino), "", &buf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
++    if (res == -1) {
++        return (void)fuse_reply_err(req, errno);
++    }
+ 
+-	fuse_reply_attr(req, &buf, lo->timeout);
++    fuse_reply_attr(req, &buf, lo->timeout);
+ }
+ 
+ static int utimensat_empty_nofollow(struct lo_inode *inode,
+-				    const struct timespec *tv)
++                                    const struct timespec *tv)
+ {
+-	int res;
+-	char procname[64];
+-
+-	if (inode->is_symlink) {
+-		res = utimensat(inode->fd, "", tv,
+-				AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
+-		if (res == -1 && errno == EINVAL) {
+-			/* Sorry, no race free way to set times on symlink. */
+-			errno = EPERM;
+-		}
+-		return res;
+-	}
+-	sprintf(procname, "/proc/self/fd/%i", inode->fd);
+-
+-	return utimensat(AT_FDCWD, procname, tv, 0);
++    int res;
++    char procname[64];
++
++    if (inode->is_symlink) {
++        res = utimensat(inode->fd, "", tv, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
++        if (res == -1 && errno == EINVAL) {
++            /* Sorry, no race free way to set times on symlink. */
++            errno = EPERM;
++        }
++        return res;
++    }
++    sprintf(procname, "/proc/self/fd/%i", inode->fd);
++
++    return utimensat(AT_FDCWD, procname, tv, 0);
+ }
+ 
+ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+-		       int valid, struct fuse_file_info *fi)
++                       int valid, struct fuse_file_info *fi)
+ {
+-	int saverr;
+-	char procname[64];
+-	struct lo_inode *inode = lo_inode(req, ino);
+-	int ifd = inode->fd;
+-	int res;
+-
+-	if (valid & FUSE_SET_ATTR_MODE) {
+-		if (fi) {
+-			res = fchmod(fi->fh, attr->st_mode);
+-		} else {
+-			sprintf(procname, "/proc/self/fd/%i", ifd);
+-			res = chmod(procname, attr->st_mode);
+-		}
+-		if (res == -1)
+-			goto out_err;
+-	}
+-	if (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) {
+-		uid_t uid = (valid & FUSE_SET_ATTR_UID) ?
+-			attr->st_uid : (uid_t) -1;
+-		gid_t gid = (valid & FUSE_SET_ATTR_GID) ?
+-			attr->st_gid : (gid_t) -1;
+-
+-		res = fchownat(ifd, "", uid, gid,
+-			       AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
+-		if (res == -1)
+-			goto out_err;
+-	}
+-	if (valid & FUSE_SET_ATTR_SIZE) {
+-		if (fi) {
+-			res = ftruncate(fi->fh, attr->st_size);
+-		} else {
+-			sprintf(procname, "/proc/self/fd/%i", ifd);
+-			res = truncate(procname, attr->st_size);
+-		}
+-		if (res == -1)
+-			goto out_err;
+-	}
+-	if (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
+-		struct timespec tv[2];
+-
+-		tv[0].tv_sec = 0;
+-		tv[1].tv_sec = 0;
+-		tv[0].tv_nsec = UTIME_OMIT;
+-		tv[1].tv_nsec = UTIME_OMIT;
+-
+-		if (valid & FUSE_SET_ATTR_ATIME_NOW)
+-			tv[0].tv_nsec = UTIME_NOW;
+-		else if (valid & FUSE_SET_ATTR_ATIME)
+-			tv[0] = attr->st_atim;
+-
+-		if (valid & FUSE_SET_ATTR_MTIME_NOW)
+-			tv[1].tv_nsec = UTIME_NOW;
+-		else if (valid & FUSE_SET_ATTR_MTIME)
+-			tv[1] = attr->st_mtim;
+-
+-		if (fi)
+-			res = futimens(fi->fh, tv);
+-		else
+-			res = utimensat_empty_nofollow(inode, tv);
+-		if (res == -1)
+-			goto out_err;
+-	}
+-
+-	return lo_getattr(req, ino, fi);
++    int saverr;
++    char procname[64];
++    struct lo_inode *inode = lo_inode(req, ino);
++    int ifd = inode->fd;
++    int res;
++
++    if (valid & FUSE_SET_ATTR_MODE) {
++        if (fi) {
++            res = fchmod(fi->fh, attr->st_mode);
++        } else {
++            sprintf(procname, "/proc/self/fd/%i", ifd);
++            res = chmod(procname, attr->st_mode);
++        }
++        if (res == -1) {
++            goto out_err;
++        }
++    }
++    if (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) {
++        uid_t uid = (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t)-1;
++        gid_t gid = (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t)-1;
++
++        res = fchownat(ifd, "", uid, gid, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
++        if (res == -1) {
++            goto out_err;
++        }
++    }
++    if (valid & FUSE_SET_ATTR_SIZE) {
++        if (fi) {
++            res = ftruncate(fi->fh, attr->st_size);
++        } else {
++            sprintf(procname, "/proc/self/fd/%i", ifd);
++            res = truncate(procname, attr->st_size);
++        }
++        if (res == -1) {
++            goto out_err;
++        }
++    }
++    if (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
++        struct timespec tv[2];
++
++        tv[0].tv_sec = 0;
++        tv[1].tv_sec = 0;
++        tv[0].tv_nsec = UTIME_OMIT;
++        tv[1].tv_nsec = UTIME_OMIT;
++
++        if (valid & FUSE_SET_ATTR_ATIME_NOW) {
++            tv[0].tv_nsec = UTIME_NOW;
++        } else if (valid & FUSE_SET_ATTR_ATIME) {
++            tv[0] = attr->st_atim;
++        }
++
++        if (valid & FUSE_SET_ATTR_MTIME_NOW) {
++            tv[1].tv_nsec = UTIME_NOW;
++        } else if (valid & FUSE_SET_ATTR_MTIME) {
++            tv[1] = attr->st_mtim;
++        }
++
++        if (fi) {
++            res = futimens(fi->fh, tv);
++        } else {
++            res = utimensat_empty_nofollow(inode, tv);
++        }
++        if (res == -1) {
++            goto out_err;
++        }
++    }
++
++    return lo_getattr(req, ino, fi);
+ 
+ out_err:
+-	saverr = errno;
+-	fuse_reply_err(req, saverr);
++    saverr = errno;
++    fuse_reply_err(req, saverr);
+ }
+ 
+ static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st)
+ {
+-	struct lo_inode *p;
+-	struct lo_inode *ret = NULL;
+-
+-	pthread_mutex_lock(&lo->mutex);
+-	for (p = lo->root.next; p != &lo->root; p = p->next) {
+-		if (p->ino == st->st_ino && p->dev == st->st_dev) {
+-			assert(p->refcount > 0);
+-			ret = p;
+-			ret->refcount++;
+-			break;
+-		}
+-	}
+-	pthread_mutex_unlock(&lo->mutex);
+-	return ret;
++    struct lo_inode *p;
++    struct lo_inode *ret = NULL;
++
++    pthread_mutex_lock(&lo->mutex);
++    for (p = lo->root.next; p != &lo->root; p = p->next) {
++        if (p->ino == st->st_ino && p->dev == st->st_dev) {
++            assert(p->refcount > 0);
++            ret = p;
++            ret->refcount++;
++            break;
++        }
++    }
++    pthread_mutex_unlock(&lo->mutex);
++    return ret;
+ }
+ 
+ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+-			 struct fuse_entry_param *e)
++                        struct fuse_entry_param *e)
+ {
+-	int newfd;
+-	int res;
+-	int saverr;
+-	struct lo_data *lo = lo_data(req);
+-	struct lo_inode *inode;
+-
+-	memset(e, 0, sizeof(*e));
+-	e->attr_timeout = lo->timeout;
+-	e->entry_timeout = lo->timeout;
+-
+-	newfd = openat(lo_fd(req, parent), name, O_PATH | O_NOFOLLOW);
+-	if (newfd == -1)
+-		goto out_err;
+-
+-	res = fstatat(newfd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
+-	if (res == -1)
+-		goto out_err;
+-
+-	inode = lo_find(lo_data(req), &e->attr);
+-	if (inode) {
+-		close(newfd);
+-		newfd = -1;
+-	} else {
+-		struct lo_inode *prev, *next;
+-
+-		saverr = ENOMEM;
+-		inode = calloc(1, sizeof(struct lo_inode));
+-		if (!inode)
+-			goto out_err;
+-
+-		inode->is_symlink = S_ISLNK(e->attr.st_mode);
+-		inode->refcount = 1;
+-		inode->fd = newfd;
+-		inode->ino = e->attr.st_ino;
+-		inode->dev = e->attr.st_dev;
+-
+-		pthread_mutex_lock(&lo->mutex);
+-		prev = &lo->root;
+-		next = prev->next;
+-		next->prev = inode;
+-		inode->next = next;
+-		inode->prev = prev;
+-		prev->next = inode;
+-		pthread_mutex_unlock(&lo->mutex);
+-	}
+-	e->ino = (uintptr_t) inode;
+-
+-	if (lo_debug(req))
+-		fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
+-			(unsigned long long) parent, name, (unsigned long long) e->ino);
+-
+-	return 0;
++    int newfd;
++    int res;
++    int saverr;
++    struct lo_data *lo = lo_data(req);
++    struct lo_inode *inode;
++
++    memset(e, 0, sizeof(*e));
++    e->attr_timeout = lo->timeout;
++    e->entry_timeout = lo->timeout;
++
++    newfd = openat(lo_fd(req, parent), name, O_PATH | O_NOFOLLOW);
++    if (newfd == -1) {
++        goto out_err;
++    }
++
++    res = fstatat(newfd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
++    if (res == -1) {
++        goto out_err;
++    }
++
++    inode = lo_find(lo_data(req), &e->attr);
++    if (inode) {
++        close(newfd);
++        newfd = -1;
++    } else {
++        struct lo_inode *prev, *next;
++
++        saverr = ENOMEM;
++        inode = calloc(1, sizeof(struct lo_inode));
++        if (!inode) {
++            goto out_err;
++        }
++
++        inode->is_symlink = S_ISLNK(e->attr.st_mode);
++        inode->refcount = 1;
++        inode->fd = newfd;
++        inode->ino = e->attr.st_ino;
++        inode->dev = e->attr.st_dev;
++
++        pthread_mutex_lock(&lo->mutex);
++        prev = &lo->root;
++        next = prev->next;
++        next->prev = inode;
++        inode->next = next;
++        inode->prev = prev;
++        prev->next = inode;
++        pthread_mutex_unlock(&lo->mutex);
++    }
++    e->ino = (uintptr_t)inode;
++
++    if (lo_debug(req)) {
++        fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
++                 (unsigned long long)parent, name, (unsigned long long)e->ino);
++    }
++
++    return 0;
+ 
+ out_err:
+-	saverr = errno;
+-	if (newfd != -1)
+-		close(newfd);
+-	return saverr;
++    saverr = errno;
++    if (newfd != -1) {
++        close(newfd);
++    }
++    return saverr;
+ }
+ 
+ static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
+ {
+-	struct fuse_entry_param e;
+-	int err;
+-
+-	if (lo_debug(req))
+-		fuse_log(FUSE_LOG_DEBUG, "lo_lookup(parent=%" PRIu64 ", name=%s)\n",
+-			parent, name);
+-
+-	err = lo_do_lookup(req, parent, name, &e);
+-	if (err)
+-		fuse_reply_err(req, err);
+-	else
+-		fuse_reply_entry(req, &e);
++    struct fuse_entry_param e;
++    int err;
++
++    if (lo_debug(req)) {
++        fuse_log(FUSE_LOG_DEBUG, "lo_lookup(parent=%" PRIu64 ", name=%s)\n",
++                 parent, name);
++    }
++
++    err = lo_do_lookup(req, parent, name, &e);
++    if (err) {
++        fuse_reply_err(req, err);
++    } else {
++        fuse_reply_entry(req, &e);
++    }
+ }
+ 
+ static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent,
+-			     const char *name, mode_t mode, dev_t rdev,
+-			     const char *link)
++                             const char *name, mode_t mode, dev_t rdev,
++                             const char *link)
+ {
+-	int res;
+-	int saverr;
+-	struct lo_inode *dir = lo_inode(req, parent);
+-	struct fuse_entry_param e;
++    int res;
++    int saverr;
++    struct lo_inode *dir = lo_inode(req, parent);
++    struct fuse_entry_param e;
+ 
+-	saverr = ENOMEM;
++    saverr = ENOMEM;
+ 
+-	res = mknod_wrapper(dir->fd, name, link, mode, rdev);
++    res = mknod_wrapper(dir->fd, name, link, mode, rdev);
+ 
+-	saverr = errno;
+-	if (res == -1)
+-		goto out;
++    saverr = errno;
++    if (res == -1) {
++        goto out;
++    }
+ 
+-	saverr = lo_do_lookup(req, parent, name, &e);
+-	if (saverr)
+-		goto out;
++    saverr = lo_do_lookup(req, parent, name, &e);
++    if (saverr) {
++        goto out;
++    }
+ 
+-	if (lo_debug(req))
+-		fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
+-			(unsigned long long) parent, name, (unsigned long long) e.ino);
++    if (lo_debug(req)) {
++        fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
++                 (unsigned long long)parent, name, (unsigned long long)e.ino);
++    }
+ 
+-	fuse_reply_entry(req, &e);
+-	return;
++    fuse_reply_entry(req, &e);
++    return;
+ 
+ out:
+-	fuse_reply_err(req, saverr);
++    fuse_reply_err(req, saverr);
+ }
+ 
+-static void lo_mknod(fuse_req_t req, fuse_ino_t parent,
+-		     const char *name, mode_t mode, dev_t rdev)
++static void lo_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
++                     mode_t mode, dev_t rdev)
+ {
+-	lo_mknod_symlink(req, parent, name, mode, rdev, NULL);
++    lo_mknod_symlink(req, parent, name, mode, rdev, NULL);
+ }
+ 
+ static void lo_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
+-		     mode_t mode)
++                     mode_t mode)
+ {
+-	lo_mknod_symlink(req, parent, name, S_IFDIR | mode, 0, NULL);
++    lo_mknod_symlink(req, parent, name, S_IFDIR | mode, 0, NULL);
+ }
+ 
+-static void lo_symlink(fuse_req_t req, const char *link,
+-		       fuse_ino_t parent, const char *name)
++static void lo_symlink(fuse_req_t req, const char *link, fuse_ino_t parent,
++                       const char *name)
+ {
+-	lo_mknod_symlink(req, parent, name, S_IFLNK, 0, link);
++    lo_mknod_symlink(req, parent, name, S_IFLNK, 0, link);
+ }
+ 
+ static int linkat_empty_nofollow(struct lo_inode *inode, int dfd,
+-				 const char *name)
++                                 const char *name)
+ {
+-	int res;
+-	char procname[64];
++    int res;
++    char procname[64];
+ 
+-	if (inode->is_symlink) {
+-		res = linkat(inode->fd, "", dfd, name, AT_EMPTY_PATH);
+-		if (res == -1 && (errno == ENOENT || errno == EINVAL)) {
+-			/* Sorry, no race free way to hard-link a symlink. */
+-			errno = EPERM;
+-		}
+-		return res;
+-	}
++    if (inode->is_symlink) {
++        res = linkat(inode->fd, "", dfd, name, AT_EMPTY_PATH);
++        if (res == -1 && (errno == ENOENT || errno == EINVAL)) {
++            /* Sorry, no race free way to hard-link a symlink. */
++            errno = EPERM;
++        }
++        return res;
++    }
+ 
+-	sprintf(procname, "/proc/self/fd/%i", inode->fd);
++    sprintf(procname, "/proc/self/fd/%i", inode->fd);
+ 
+-	return linkat(AT_FDCWD, procname, dfd, name, AT_SYMLINK_FOLLOW);
++    return linkat(AT_FDCWD, procname, dfd, name, AT_SYMLINK_FOLLOW);
+ }
+ 
+ static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
+-		    const char *name)
++                    const char *name)
+ {
+-	int res;
+-	struct lo_data *lo = lo_data(req);
+-	struct lo_inode *inode = lo_inode(req, ino);
+-	struct fuse_entry_param e;
+-	int saverr;
+-
+-	memset(&e, 0, sizeof(struct fuse_entry_param));
+-	e.attr_timeout = lo->timeout;
+-	e.entry_timeout = lo->timeout;
+-
+-	res = linkat_empty_nofollow(inode, lo_fd(req, parent), name);
+-	if (res == -1)
+-		goto out_err;
+-
+-	res = fstatat(inode->fd, "", &e.attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
+-	if (res == -1)
+-		goto out_err;
+-
+-	pthread_mutex_lock(&lo->mutex);
+-	inode->refcount++;
+-	pthread_mutex_unlock(&lo->mutex);
+-	e.ino = (uintptr_t) inode;
+-
+-	if (lo_debug(req))
+-		fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
+-			(unsigned long long) parent, name,
+-			(unsigned long long) e.ino);
+-
+-	fuse_reply_entry(req, &e);
+-	return;
++    int res;
++    struct lo_data *lo = lo_data(req);
++    struct lo_inode *inode = lo_inode(req, ino);
++    struct fuse_entry_param e;
++    int saverr;
++
++    memset(&e, 0, sizeof(struct fuse_entry_param));
++    e.attr_timeout = lo->timeout;
++    e.entry_timeout = lo->timeout;
++
++    res = linkat_empty_nofollow(inode, lo_fd(req, parent), name);
++    if (res == -1) {
++        goto out_err;
++    }
++
++    res = fstatat(inode->fd, "", &e.attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
++    if (res == -1) {
++        goto out_err;
++    }
++
++    pthread_mutex_lock(&lo->mutex);
++    inode->refcount++;
++    pthread_mutex_unlock(&lo->mutex);
++    e.ino = (uintptr_t)inode;
++
++    if (lo_debug(req)) {
++        fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
++                 (unsigned long long)parent, name, (unsigned long long)e.ino);
++    }
++
++    fuse_reply_entry(req, &e);
++    return;
+ 
+ out_err:
+-	saverr = errno;
+-	fuse_reply_err(req, saverr);
++    saverr = errno;
++    fuse_reply_err(req, saverr);
+ }
+ 
+ static void lo_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
+ {
+-	int res;
++    int res;
+ 
+-	res = unlinkat(lo_fd(req, parent), name, AT_REMOVEDIR);
++    res = unlinkat(lo_fd(req, parent), name, AT_REMOVEDIR);
+ 
+-	fuse_reply_err(req, res == -1 ? errno : 0);
++    fuse_reply_err(req, res == -1 ? errno : 0);
+ }
+ 
+ static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
+-		      fuse_ino_t newparent, const char *newname,
+-		      unsigned int flags)
++                      fuse_ino_t newparent, const char *newname,
++                      unsigned int flags)
+ {
+-	int res;
++    int res;
+ 
+-	if (flags) {
+-		fuse_reply_err(req, EINVAL);
+-		return;
+-	}
++    if (flags) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+ 
+-	res = renameat(lo_fd(req, parent), name,
+-			lo_fd(req, newparent), newname);
++    res = renameat(lo_fd(req, parent), name, lo_fd(req, newparent), newname);
+ 
+-	fuse_reply_err(req, res == -1 ? errno : 0);
++    fuse_reply_err(req, res == -1 ? errno : 0);
+ }
+ 
+ static void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
+ {
+-	int res;
++    int res;
+ 
+-	res = unlinkat(lo_fd(req, parent), name, 0);
++    res = unlinkat(lo_fd(req, parent), name, 0);
+ 
+-	fuse_reply_err(req, res == -1 ? errno : 0);
++    fuse_reply_err(req, res == -1 ? errno : 0);
+ }
+ 
+ static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n)
+ {
+-	if (!inode)
+-		return;
+-
+-	pthread_mutex_lock(&lo->mutex);
+-	assert(inode->refcount >= n);
+-	inode->refcount -= n;
+-	if (!inode->refcount) {
+-		struct lo_inode *prev, *next;
+-
+-		prev = inode->prev;
+-		next = inode->next;
+-		next->prev = prev;
+-		prev->next = next;
+-
+-		pthread_mutex_unlock(&lo->mutex);
+-		close(inode->fd);
+-		free(inode);
+-
+-	} else {
+-		pthread_mutex_unlock(&lo->mutex);
+-	}
++    if (!inode) {
++        return;
++    }
++
++    pthread_mutex_lock(&lo->mutex);
++    assert(inode->refcount >= n);
++    inode->refcount -= n;
++    if (!inode->refcount) {
++        struct lo_inode *prev, *next;
++
++        prev = inode->prev;
++        next = inode->next;
++        next->prev = prev;
++        prev->next = next;
++
++        pthread_mutex_unlock(&lo->mutex);
++        close(inode->fd);
++        free(inode);
++
++    } else {
++        pthread_mutex_unlock(&lo->mutex);
++    }
+ }
+ 
+ static void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
+ {
+-	struct lo_data *lo = lo_data(req);
+-	struct lo_inode *inode = lo_inode(req, ino);
++    struct lo_data *lo = lo_data(req);
++    struct lo_inode *inode = lo_inode(req, ino);
+ 
+-	if (lo_debug(req)) {
+-		fuse_log(FUSE_LOG_DEBUG, "  forget %lli %lli -%lli\n",
+-			(unsigned long long) ino,
+-			(unsigned long long) inode->refcount,
+-			(unsigned long long) nlookup);
+-	}
++    if (lo_debug(req)) {
++        fuse_log(FUSE_LOG_DEBUG, "  forget %lli %lli -%lli\n",
++                 (unsigned long long)ino, (unsigned long long)inode->refcount,
++                 (unsigned long long)nlookup);
++    }
+ 
+-	unref_inode(lo, inode, nlookup);
++    unref_inode(lo, inode, nlookup);
+ }
+ 
+ static void lo_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
+ {
+-	lo_forget_one(req, ino, nlookup);
+-	fuse_reply_none(req);
++    lo_forget_one(req, ino, nlookup);
++    fuse_reply_none(req);
+ }
+ 
+ static void lo_forget_multi(fuse_req_t req, size_t count,
+-				struct fuse_forget_data *forgets)
++                            struct fuse_forget_data *forgets)
+ {
+-	int i;
++    int i;
+ 
+-	for (i = 0; i < count; i++)
+-		lo_forget_one(req, forgets[i].ino, forgets[i].nlookup);
+-	fuse_reply_none(req);
++    for (i = 0; i < count; i++) {
++        lo_forget_one(req, forgets[i].ino, forgets[i].nlookup);
++    }
++    fuse_reply_none(req);
+ }
+ 
+ static void lo_readlink(fuse_req_t req, fuse_ino_t ino)
+ {
+-	char buf[PATH_MAX + 1];
+-	int res;
++    char buf[PATH_MAX + 1];
++    int res;
+ 
+-	res = readlinkat(lo_fd(req, ino), "", buf, sizeof(buf));
+-	if (res == -1)
+-		return (void) fuse_reply_err(req, errno);
++    res = readlinkat(lo_fd(req, ino), "", buf, sizeof(buf));
++    if (res == -1) {
++        return (void)fuse_reply_err(req, errno);
++    }
+ 
+-	if (res == sizeof(buf))
+-		return (void) fuse_reply_err(req, ENAMETOOLONG);
++    if (res == sizeof(buf)) {
++        return (void)fuse_reply_err(req, ENAMETOOLONG);
++    }
+ 
+-	buf[res] = '\0';
++    buf[res] = '\0';
+ 
+-	fuse_reply_readlink(req, buf);
++    fuse_reply_readlink(req, buf);
+ }
+ 
+ struct lo_dirp {
+-	DIR *dp;
+-	struct dirent *entry;
+-	off_t offset;
++    DIR *dp;
++    struct dirent *entry;
++    off_t offset;
+ };
+ 
+ static struct lo_dirp *lo_dirp(struct fuse_file_info *fi)
+ {
+-	return (struct lo_dirp *) (uintptr_t) fi->fh;
++    return (struct lo_dirp *)(uintptr_t)fi->fh;
+ }
+ 
+-static void lo_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
++static void lo_opendir(fuse_req_t req, fuse_ino_t ino,
++                       struct fuse_file_info *fi)
+ {
+-	int error = ENOMEM;
+-	struct lo_data *lo = lo_data(req);
+-	struct lo_dirp *d;
+-	int fd;
+-
+-	d = calloc(1, sizeof(struct lo_dirp));
+-	if (d == NULL)
+-		goto out_err;
+-
+-	fd = openat(lo_fd(req, ino), ".", O_RDONLY);
+-	if (fd == -1)
+-		goto out_errno;
+-
+-	d->dp = fdopendir(fd);
+-	if (d->dp == NULL)
+-		goto out_errno;
+-
+-	d->offset = 0;
+-	d->entry = NULL;
+-
+-	fi->fh = (uintptr_t) d;
+-	if (lo->cache == CACHE_ALWAYS)
+-		fi->keep_cache = 1;
+-	fuse_reply_open(req, fi);
+-	return;
++    int error = ENOMEM;
++    struct lo_data *lo = lo_data(req);
++    struct lo_dirp *d;
++    int fd;
++
++    d = calloc(1, sizeof(struct lo_dirp));
++    if (d == NULL) {
++        goto out_err;
++    }
++
++    fd = openat(lo_fd(req, ino), ".", O_RDONLY);
++    if (fd == -1) {
++        goto out_errno;
++    }
++
++    d->dp = fdopendir(fd);
++    if (d->dp == NULL) {
++        goto out_errno;
++    }
++
++    d->offset = 0;
++    d->entry = NULL;
++
++    fi->fh = (uintptr_t)d;
++    if (lo->cache == CACHE_ALWAYS) {
++        fi->keep_cache = 1;
++    }
++    fuse_reply_open(req, fi);
++    return;
+ 
+ out_errno:
+-	error = errno;
++    error = errno;
+ out_err:
+-	if (d) {
+-		if (fd != -1)
+-			close(fd);
+-		free(d);
+-	}
+-	fuse_reply_err(req, error);
++    if (d) {
++        if (fd != -1) {
++            close(fd);
++        }
++        free(d);
++    }
++    fuse_reply_err(req, error);
+ }
+ 
+ static int is_dot_or_dotdot(const char *name)
+ {
+-	return name[0] == '.' && (name[1] == '\0' ||
+-				  (name[1] == '.' && name[2] == '\0'));
++    return name[0] == '.' &&
++           (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
+ }
+ 
+ static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
+-			  off_t offset, struct fuse_file_info *fi, int plus)
++                          off_t offset, struct fuse_file_info *fi, int plus)
+ {
+-	struct lo_dirp *d = lo_dirp(fi);
+-	char *buf;
+-	char *p;
+-	size_t rem = size;
+-	int err;
+-
+-	(void) ino;
+-
+-	buf = calloc(1, size);
+-	if (!buf) {
+-		err = ENOMEM;
+-		goto error;
+-	}
+-	p = buf;
+-
+-	if (offset != d->offset) {
+-		seekdir(d->dp, offset);
+-		d->entry = NULL;
+-		d->offset = offset;
+-	}
+-	while (1) {
+-		size_t entsize;
+-		off_t nextoff;
+-		const char *name;
+-
+-		if (!d->entry) {
+-			errno = 0;
+-			d->entry = readdir(d->dp);
+-			if (!d->entry) {
+-				if (errno) {  // Error
+-					err = errno;
+-					goto error;
+-				} else {  // End of stream
+-					break; 
+-				}
+-			}
+-		}
+-		nextoff = d->entry->d_off;
+-		name = d->entry->d_name;
+-		fuse_ino_t entry_ino = 0;
+-		if (plus) {
+-			struct fuse_entry_param e;
+-			if (is_dot_or_dotdot(name)) {
+-				e = (struct fuse_entry_param) {
+-					.attr.st_ino = d->entry->d_ino,
+-					.attr.st_mode = d->entry->d_type << 12,
+-				};
+-			} else {
+-				err = lo_do_lookup(req, ino, name, &e);
+-				if (err)
+-					goto error;
+-				entry_ino = e.ino;
+-			}
+-
+-			entsize = fuse_add_direntry_plus(req, p, rem, name,
+-							 &e, nextoff);
+-		} else {
+-			struct stat st = {
+-				.st_ino = d->entry->d_ino,
+-				.st_mode = d->entry->d_type << 12,
+-			};
+-			entsize = fuse_add_direntry(req, p, rem, name,
+-						    &st, nextoff);
+-		}
+-		if (entsize > rem) {
+-			if (entry_ino != 0) 
+-				lo_forget_one(req, entry_ino, 1);
+-			break;
+-		}
+-		
+-		p += entsize;
+-		rem -= entsize;
+-
+-		d->entry = NULL;
+-		d->offset = nextoff;
+-	}
++    struct lo_dirp *d = lo_dirp(fi);
++    char *buf;
++    char *p;
++    size_t rem = size;
++    int err;
++
++    (void)ino;
++
++    buf = calloc(1, size);
++    if (!buf) {
++        err = ENOMEM;
++        goto error;
++    }
++    p = buf;
++
++    if (offset != d->offset) {
++        seekdir(d->dp, offset);
++        d->entry = NULL;
++        d->offset = offset;
++    }
++    while (1) {
++        size_t entsize;
++        off_t nextoff;
++        const char *name;
++
++        if (!d->entry) {
++            errno = 0;
++            d->entry = readdir(d->dp);
++            if (!d->entry) {
++                if (errno) { /* Error */
++                    err = errno;
++                    goto error;
++                } else { /* End of stream */
++                    break;
++                }
++            }
++        }
++        nextoff = d->entry->d_off;
++        name = d->entry->d_name;
++        fuse_ino_t entry_ino = 0;
++        if (plus) {
++            struct fuse_entry_param e;
++            if (is_dot_or_dotdot(name)) {
++                e = (struct fuse_entry_param){
++                    .attr.st_ino = d->entry->d_ino,
++                    .attr.st_mode = d->entry->d_type << 12,
++                };
++            } else {
++                err = lo_do_lookup(req, ino, name, &e);
++                if (err) {
++                    goto error;
++                }
++                entry_ino = e.ino;
++            }
++
++            entsize = fuse_add_direntry_plus(req, p, rem, name, &e, nextoff);
++        } else {
++            struct stat st = {
++                .st_ino = d->entry->d_ino,
++                .st_mode = d->entry->d_type << 12,
++            };
++            entsize = fuse_add_direntry(req, p, rem, name, &st, nextoff);
++        }
++        if (entsize > rem) {
++            if (entry_ino != 0) {
++                lo_forget_one(req, entry_ino, 1);
++            }
++            break;
++        }
++
++        p += entsize;
++        rem -= entsize;
++
++        d->entry = NULL;
++        d->offset = nextoff;
++    }
+ 
+     err = 0;
+ error:
+-    // If there's an error, we can only signal it if we haven't stored
+-    // any entries yet - otherwise we'd end up with wrong lookup
+-    // counts for the entries that are already in the buffer. So we
+-    // return what we've collected until that point.
+-    if (err && rem == size)
+-	    fuse_reply_err(req, err);
+-    else
+-	    fuse_reply_buf(req, buf, size - rem);
++    /*
++     * If there's an error, we can only signal it if we haven't stored
++     * any entries yet - otherwise we'd end up with wrong lookup
++     * counts for the entries that are already in the buffer. So we
++     * return what we've collected until that point.
++     */
++    if (err && rem == size) {
++        fuse_reply_err(req, err);
++    } else {
++        fuse_reply_buf(req, buf, size - rem);
++    }
+     free(buf);
+ }
+ 
+ static void lo_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
+-		       off_t offset, struct fuse_file_info *fi)
++                       off_t offset, struct fuse_file_info *fi)
+ {
+-	lo_do_readdir(req, ino, size, offset, fi, 0);
++    lo_do_readdir(req, ino, size, offset, fi, 0);
+ }
+ 
+ static void lo_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size,
+-			   off_t offset, struct fuse_file_info *fi)
++                           off_t offset, struct fuse_file_info *fi)
+ {
+-	lo_do_readdir(req, ino, size, offset, fi, 1);
++    lo_do_readdir(req, ino, size, offset, fi, 1);
+ }
+ 
+-static void lo_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
++static void lo_releasedir(fuse_req_t req, fuse_ino_t ino,
++                          struct fuse_file_info *fi)
+ {
+-	struct lo_dirp *d = lo_dirp(fi);
+-	(void) ino;
+-	closedir(d->dp);
+-	free(d);
+-	fuse_reply_err(req, 0);
++    struct lo_dirp *d = lo_dirp(fi);
++    (void)ino;
++    closedir(d->dp);
++    free(d);
++    fuse_reply_err(req, 0);
+ }
+ 
+ static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
+-		      mode_t mode, struct fuse_file_info *fi)
++                      mode_t mode, struct fuse_file_info *fi)
+ {
+-	int fd;
+-	struct lo_data *lo = lo_data(req);
+-	struct fuse_entry_param e;
+-	int err;
+-
+-	if (lo_debug(req))
+-		fuse_log(FUSE_LOG_DEBUG, "lo_create(parent=%" PRIu64 ", name=%s)\n",
+-			parent, name);
+-
+-	fd = openat(lo_fd(req, parent), name,
+-		    (fi->flags | O_CREAT) & ~O_NOFOLLOW, mode);
+-	if (fd == -1)
+-		return (void) fuse_reply_err(req, errno);
+-
+-	fi->fh = fd;
+-	if (lo->cache == CACHE_NEVER)
+-		fi->direct_io = 1;
+-	else if (lo->cache == CACHE_ALWAYS)
+-		fi->keep_cache = 1;
+-
+-	err = lo_do_lookup(req, parent, name, &e);
+-	if (err)
+-		fuse_reply_err(req, err);
+-	else
+-		fuse_reply_create(req, &e, fi);
++    int fd;
++    struct lo_data *lo = lo_data(req);
++    struct fuse_entry_param e;
++    int err;
++
++    if (lo_debug(req)) {
++        fuse_log(FUSE_LOG_DEBUG, "lo_create(parent=%" PRIu64 ", name=%s)\n",
++                 parent, name);
++    }
++
++    fd = openat(lo_fd(req, parent), name, (fi->flags | O_CREAT) & ~O_NOFOLLOW,
++                mode);
++    if (fd == -1) {
++        return (void)fuse_reply_err(req, errno);
++    }
++
++    fi->fh = fd;
++    if (lo->cache == CACHE_NEVER) {
++        fi->direct_io = 1;
++    } else if (lo->cache == CACHE_ALWAYS) {
++        fi->keep_cache = 1;
++    }
++
++    err = lo_do_lookup(req, parent, name, &e);
++    if (err) {
++        fuse_reply_err(req, err);
++    } else {
++        fuse_reply_create(req, &e, fi);
++    }
+ }
+ 
+ static void lo_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
+-			struct fuse_file_info *fi)
++                        struct fuse_file_info *fi)
+ {
+-	int res;
+-	int fd = dirfd(lo_dirp(fi)->dp);
+-	(void) ino;
+-	if (datasync)
+-		res = fdatasync(fd);
+-	else
+-		res = fsync(fd);
+-	fuse_reply_err(req, res == -1 ? errno : 0);
++    int res;
++    int fd = dirfd(lo_dirp(fi)->dp);
++    (void)ino;
++    if (datasync) {
++        res = fdatasync(fd);
++    } else {
++        res = fsync(fd);
++    }
++    fuse_reply_err(req, res == -1 ? errno : 0);
+ }
+ 
+ static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+ {
+-	int fd;
+-	char buf[64];
+-	struct lo_data *lo = lo_data(req);
+-
+-	if (lo_debug(req))
+-		fuse_log(FUSE_LOG_DEBUG, "lo_open(ino=%" PRIu64 ", flags=%d)\n",
+-			ino, fi->flags);
+-
+-	/* With writeback cache, kernel may send read requests even
+-	   when userspace opened write-only */
+-	if (lo->writeback && (fi->flags & O_ACCMODE) == O_WRONLY) {
+-		fi->flags &= ~O_ACCMODE;
+-		fi->flags |= O_RDWR;
+-	}
+-
+-	/* With writeback cache, O_APPEND is handled by the kernel.
+-	   This breaks atomicity (since the file may change in the
+-	   underlying filesystem, so that the kernel's idea of the
+-	   end of the file isn't accurate anymore). In this example,
+-	   we just accept that. A more rigorous filesystem may want
+-	   to return an error here */
+-	if (lo->writeback && (fi->flags & O_APPEND))
+-		fi->flags &= ~O_APPEND;
+-
+-	sprintf(buf, "/proc/self/fd/%i", lo_fd(req, ino));
+-	fd = open(buf, fi->flags & ~O_NOFOLLOW);
+-	if (fd == -1)
+-		return (void) fuse_reply_err(req, errno);
+-
+-	fi->fh = fd;
+-	if (lo->cache == CACHE_NEVER)
+-		fi->direct_io = 1;
+-	else if (lo->cache == CACHE_ALWAYS)
+-		fi->keep_cache = 1;
+-	fuse_reply_open(req, fi);
++    int fd;
++    char buf[64];
++    struct lo_data *lo = lo_data(req);
++
++    if (lo_debug(req)) {
++        fuse_log(FUSE_LOG_DEBUG, "lo_open(ino=%" PRIu64 ", flags=%d)\n", ino,
++                 fi->flags);
++    }
++
++    /*
++     * With writeback cache, kernel may send read requests even
++     * when userspace opened write-only
++     */
++    if (lo->writeback && (fi->flags & O_ACCMODE) == O_WRONLY) {
++        fi->flags &= ~O_ACCMODE;
++        fi->flags |= O_RDWR;
++    }
++
++    /*
++     * With writeback cache, O_APPEND is handled by the kernel.
++     * This breaks atomicity (since the file may change in the
++     * underlying filesystem, so that the kernel's idea of the
++     * end of the file isn't accurate anymore). In this example,
++     * we just accept that. A more rigorous filesystem may want
++     * to return an error here
++     */
++    if (lo->writeback && (fi->flags & O_APPEND)) {
++        fi->flags &= ~O_APPEND;
++    }
++
++    sprintf(buf, "/proc/self/fd/%i", lo_fd(req, ino));
++    fd = open(buf, fi->flags & ~O_NOFOLLOW);
++    if (fd == -1) {
++        return (void)fuse_reply_err(req, errno);
++    }
++
++    fi->fh = fd;
++    if (lo->cache == CACHE_NEVER) {
++        fi->direct_io = 1;
++    } else if (lo->cache == CACHE_ALWAYS) {
++        fi->keep_cache = 1;
++    }
++    fuse_reply_open(req, fi);
+ }
+ 
+-static void lo_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
++static void lo_release(fuse_req_t req, fuse_ino_t ino,
++                       struct fuse_file_info *fi)
+ {
+-	(void) ino;
++    (void)ino;
+ 
+-	close(fi->fh);
+-	fuse_reply_err(req, 0);
++    close(fi->fh);
++    fuse_reply_err(req, 0);
+ }
+ 
+ static void lo_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+ {
+-	int res;
+-	(void) ino;
+-	res = close(dup(fi->fh));
+-	fuse_reply_err(req, res == -1 ? errno : 0);
++    int res;
++    (void)ino;
++    res = close(dup(fi->fh));
++    fuse_reply_err(req, res == -1 ? errno : 0);
+ }
+ 
+ static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
+-		     struct fuse_file_info *fi)
++                     struct fuse_file_info *fi)
+ {
+-	int res;
+-	(void) ino;
+-	if (datasync)
+-		res = fdatasync(fi->fh);
+-	else
+-		res = fsync(fi->fh);
+-	fuse_reply_err(req, res == -1 ? errno : 0);
++    int res;
++    (void)ino;
++    if (datasync) {
++        res = fdatasync(fi->fh);
++    } else {
++        res = fsync(fi->fh);
++    }
++    fuse_reply_err(req, res == -1 ? errno : 0);
+ }
+ 
+-static void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size,
+-		    off_t offset, struct fuse_file_info *fi)
++static void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset,
++                    struct fuse_file_info *fi)
+ {
+-	struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size);
++    struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size);
+ 
+-	if (lo_debug(req))
+-		fuse_log(FUSE_LOG_DEBUG, "lo_read(ino=%" PRIu64 ", size=%zd, "
+-			"off=%lu)\n", ino, size, (unsigned long) offset);
++    if (lo_debug(req)) {
++        fuse_log(FUSE_LOG_DEBUG,
++                 "lo_read(ino=%" PRIu64 ", size=%zd, "
++                 "off=%lu)\n",
++                 ino, size, (unsigned long)offset);
++    }
+ 
+-	buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
+-	buf.buf[0].fd = fi->fh;
+-	buf.buf[0].pos = offset;
++    buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
++    buf.buf[0].fd = fi->fh;
++    buf.buf[0].pos = offset;
+ 
+-	fuse_reply_data(req, &buf, FUSE_BUF_SPLICE_MOVE);
++    fuse_reply_data(req, &buf, FUSE_BUF_SPLICE_MOVE);
+ }
+ 
+ static void lo_write_buf(fuse_req_t req, fuse_ino_t ino,
+-			 struct fuse_bufvec *in_buf, off_t off,
+-			 struct fuse_file_info *fi)
++                         struct fuse_bufvec *in_buf, off_t off,
++                         struct fuse_file_info *fi)
+ {
+-	(void) ino;
+-	ssize_t res;
+-	struct fuse_bufvec out_buf = FUSE_BUFVEC_INIT(fuse_buf_size(in_buf));
+-
+-	out_buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
+-	out_buf.buf[0].fd = fi->fh;
+-	out_buf.buf[0].pos = off;
+-
+-	if (lo_debug(req))
+-		fuse_log(FUSE_LOG_DEBUG, "lo_write(ino=%" PRIu64 ", size=%zd, off=%lu)\n",
+-			ino, out_buf.buf[0].size, (unsigned long) off);
+-
+-	res = fuse_buf_copy(&out_buf, in_buf, 0);
+-	if(res < 0)
+-		fuse_reply_err(req, -res);
+-	else
+-		fuse_reply_write(req, (size_t) res);
++    (void)ino;
++    ssize_t res;
++    struct fuse_bufvec out_buf = FUSE_BUFVEC_INIT(fuse_buf_size(in_buf));
++
++    out_buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
++    out_buf.buf[0].fd = fi->fh;
++    out_buf.buf[0].pos = off;
++
++    if (lo_debug(req)) {
++        fuse_log(FUSE_LOG_DEBUG,
++                 "lo_write(ino=%" PRIu64 ", size=%zd, off=%lu)\n", ino,
++                 out_buf.buf[0].size, (unsigned long)off);
++    }
++
++    res = fuse_buf_copy(&out_buf, in_buf, 0);
++    if (res < 0) {
++        fuse_reply_err(req, -res);
++    } else {
++        fuse_reply_write(req, (size_t)res);
++    }
+ }
+ 
+ static void lo_statfs(fuse_req_t req, fuse_ino_t ino)
+ {
+-	int res;
+-	struct statvfs stbuf;
+-
+-	res = fstatvfs(lo_fd(req, ino), &stbuf);
+-	if (res == -1)
+-		fuse_reply_err(req, errno);
+-	else
+-		fuse_reply_statfs(req, &stbuf);
++    int res;
++    struct statvfs stbuf;
++
++    res = fstatvfs(lo_fd(req, ino), &stbuf);
++    if (res == -1) {
++        fuse_reply_err(req, errno);
++    } else {
++        fuse_reply_statfs(req, &stbuf);
++    }
+ }
+ 
+-static void lo_fallocate(fuse_req_t req, fuse_ino_t ino, int mode,
+-			 off_t offset, off_t length, struct fuse_file_info *fi)
++static void lo_fallocate(fuse_req_t req, fuse_ino_t ino, int mode, off_t offset,
++                         off_t length, struct fuse_file_info *fi)
+ {
+-	int err = EOPNOTSUPP;
+-	(void) ino;
++    int err = EOPNOTSUPP;
++    (void)ino;
+ 
+ #ifdef HAVE_FALLOCATE
+-	err = fallocate(fi->fh, mode, offset, length);
+-	if (err < 0)
+-		err = errno;
++    err = fallocate(fi->fh, mode, offset, length);
++    if (err < 0) {
++        err = errno;
++    }
+ 
+ #elif defined(HAVE_POSIX_FALLOCATE)
+-	if (mode) {
+-		fuse_reply_err(req, EOPNOTSUPP);
+-		return;
+-	}
++    if (mode) {
++        fuse_reply_err(req, EOPNOTSUPP);
++        return;
++    }
+ 
+-	err = posix_fallocate(fi->fh, offset, length);
++    err = posix_fallocate(fi->fh, offset, length);
+ #endif
+ 
+-	fuse_reply_err(req, err);
++    fuse_reply_err(req, err);
+ }
+ 
+ static void lo_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
+-		     int op)
++                     int op)
+ {
+-	int res;
+-	(void) ino;
++    int res;
++    (void)ino;
+ 
+-	res = flock(fi->fh, op);
++    res = flock(fi->fh, op);
+ 
+-	fuse_reply_err(req, res == -1 ? errno : 0);
++    fuse_reply_err(req, res == -1 ? errno : 0);
+ }
+ 
+ static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+-			size_t size)
++                        size_t size)
+ {
+-	char *value = NULL;
+-	char procname[64];
+-	struct lo_inode *inode = lo_inode(req, ino);
+-	ssize_t ret;
+-	int saverr;
+-
+-	saverr = ENOSYS;
+-	if (!lo_data(req)->xattr)
+-		goto out;
+-
+-	if (lo_debug(req)) {
+-		fuse_log(FUSE_LOG_DEBUG, "lo_getxattr(ino=%" PRIu64 ", name=%s size=%zd)\n",
+-			ino, name, size);
+-	}
+-
+-	if (inode->is_symlink) {
+-		/* Sorry, no race free way to getxattr on symlink. */
+-		saverr = EPERM;
+-		goto out;
+-	}
+-
+-	sprintf(procname, "/proc/self/fd/%i", inode->fd);
+-
+-	if (size) {
+-		value = malloc(size);
+-		if (!value)
+-			goto out_err;
+-
+-		ret = getxattr(procname, name, value, size);
+-		if (ret == -1)
+-			goto out_err;
+-		saverr = 0;
+-		if (ret == 0)
+-			goto out;
+-
+-		fuse_reply_buf(req, value, ret);
+-	} else {
+-		ret = getxattr(procname, name, NULL, 0);
+-		if (ret == -1)
+-			goto out_err;
+-
+-		fuse_reply_xattr(req, ret);
+-	}
++    char *value = NULL;
++    char procname[64];
++    struct lo_inode *inode = lo_inode(req, ino);
++    ssize_t ret;
++    int saverr;
++
++    saverr = ENOSYS;
++    if (!lo_data(req)->xattr) {
++        goto out;
++    }
++
++    if (lo_debug(req)) {
++        fuse_log(FUSE_LOG_DEBUG,
++                 "lo_getxattr(ino=%" PRIu64 ", name=%s size=%zd)\n", ino, name,
++                 size);
++    }
++
++    if (inode->is_symlink) {
++        /* Sorry, no race free way to getxattr on symlink. */
++        saverr = EPERM;
++        goto out;
++    }
++
++    sprintf(procname, "/proc/self/fd/%i", inode->fd);
++
++    if (size) {
++        value = malloc(size);
++        if (!value) {
++            goto out_err;
++        }
++
++        ret = getxattr(procname, name, value, size);
++        if (ret == -1) {
++            goto out_err;
++        }
++        saverr = 0;
++        if (ret == 0) {
++            goto out;
++        }
++
++        fuse_reply_buf(req, value, ret);
++    } else {
++        ret = getxattr(procname, name, NULL, 0);
++        if (ret == -1) {
++            goto out_err;
++        }
++
++        fuse_reply_xattr(req, ret);
++    }
+ out_free:
+-	free(value);
+-	return;
++    free(value);
++    return;
+ 
+ out_err:
+-	saverr = errno;
++    saverr = errno;
+ out:
+-	fuse_reply_err(req, saverr);
+-	goto out_free;
++    fuse_reply_err(req, saverr);
++    goto out_free;
+ }
+ 
+ static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
+ {
+-	char *value = NULL;
+-	char procname[64];
+-	struct lo_inode *inode = lo_inode(req, ino);
+-	ssize_t ret;
+-	int saverr;
+-
+-	saverr = ENOSYS;
+-	if (!lo_data(req)->xattr)
+-		goto out;
+-
+-	if (lo_debug(req)) {
+-		fuse_log(FUSE_LOG_DEBUG, "lo_listxattr(ino=%" PRIu64 ", size=%zd)\n",
+-			ino, size);
+-	}
+-
+-	if (inode->is_symlink) {
+-		/* Sorry, no race free way to listxattr on symlink. */
+-		saverr = EPERM;
+-		goto out;
+-	}
+-
+-	sprintf(procname, "/proc/self/fd/%i", inode->fd);
+-
+-	if (size) {
+-		value = malloc(size);
+-		if (!value)
+-			goto out_err;
+-
+-		ret = listxattr(procname, value, size);
+-		if (ret == -1)
+-			goto out_err;
+-		saverr = 0;
+-		if (ret == 0)
+-			goto out;
+-
+-		fuse_reply_buf(req, value, ret);
+-	} else {
+-		ret = listxattr(procname, NULL, 0);
+-		if (ret == -1)
+-			goto out_err;
+-
+-		fuse_reply_xattr(req, ret);
+-	}
++    char *value = NULL;
++    char procname[64];
++    struct lo_inode *inode = lo_inode(req, ino);
++    ssize_t ret;
++    int saverr;
++
++    saverr = ENOSYS;
++    if (!lo_data(req)->xattr) {
++        goto out;
++    }
++
++    if (lo_debug(req)) {
++        fuse_log(FUSE_LOG_DEBUG, "lo_listxattr(ino=%" PRIu64 ", size=%zd)\n",
++                 ino, size);
++    }
++
++    if (inode->is_symlink) {
++        /* Sorry, no race free way to listxattr on symlink. */
++        saverr = EPERM;
++        goto out;
++    }
++
++    sprintf(procname, "/proc/self/fd/%i", inode->fd);
++
++    if (size) {
++        value = malloc(size);
++        if (!value) {
++            goto out_err;
++        }
++
++        ret = listxattr(procname, value, size);
++        if (ret == -1) {
++            goto out_err;
++        }
++        saverr = 0;
++        if (ret == 0) {
++            goto out;
++        }
++
++        fuse_reply_buf(req, value, ret);
++    } else {
++        ret = listxattr(procname, NULL, 0);
++        if (ret == -1) {
++            goto out_err;
++        }
++
++        fuse_reply_xattr(req, ret);
++    }
+ out_free:
+-	free(value);
+-	return;
++    free(value);
++    return;
+ 
+ out_err:
+-	saverr = errno;
++    saverr = errno;
+ out:
+-	fuse_reply_err(req, saverr);
+-	goto out_free;
++    fuse_reply_err(req, saverr);
++    goto out_free;
+ }
+ 
+ static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+-			const char *value, size_t size, int flags)
++                        const char *value, size_t size, int flags)
+ {
+-	char procname[64];
+-	struct lo_inode *inode = lo_inode(req, ino);
+-	ssize_t ret;
+-	int saverr;
++    char procname[64];
++    struct lo_inode *inode = lo_inode(req, ino);
++    ssize_t ret;
++    int saverr;
+ 
+-	saverr = ENOSYS;
+-	if (!lo_data(req)->xattr)
+-		goto out;
++    saverr = ENOSYS;
++    if (!lo_data(req)->xattr) {
++        goto out;
++    }
+ 
+-	if (lo_debug(req)) {
+-		fuse_log(FUSE_LOG_DEBUG, "lo_setxattr(ino=%" PRIu64 ", name=%s value=%s size=%zd)\n",
+-			ino, name, value, size);
+-	}
++    if (lo_debug(req)) {
++        fuse_log(FUSE_LOG_DEBUG,
++                 "lo_setxattr(ino=%" PRIu64 ", name=%s value=%s size=%zd)\n",
++                 ino, name, value, size);
++    }
+ 
+-	if (inode->is_symlink) {
+-		/* Sorry, no race free way to setxattr on symlink. */
+-		saverr = EPERM;
+-		goto out;
+-	}
++    if (inode->is_symlink) {
++        /* Sorry, no race free way to setxattr on symlink. */
++        saverr = EPERM;
++        goto out;
++    }
+ 
+-	sprintf(procname, "/proc/self/fd/%i", inode->fd);
++    sprintf(procname, "/proc/self/fd/%i", inode->fd);
+ 
+-	ret = setxattr(procname, name, value, size, flags);
+-	saverr = ret == -1 ? errno : 0;
++    ret = setxattr(procname, name, value, size, flags);
++    saverr = ret == -1 ? errno : 0;
+ 
+ out:
+-	fuse_reply_err(req, saverr);
++    fuse_reply_err(req, saverr);
+ }
+ 
+ static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
+ {
+-	char procname[64];
+-	struct lo_inode *inode = lo_inode(req, ino);
+-	ssize_t ret;
+-	int saverr;
++    char procname[64];
++    struct lo_inode *inode = lo_inode(req, ino);
++    ssize_t ret;
++    int saverr;
+ 
+-	saverr = ENOSYS;
+-	if (!lo_data(req)->xattr)
+-		goto out;
++    saverr = ENOSYS;
++    if (!lo_data(req)->xattr) {
++        goto out;
++    }
+ 
+-	if (lo_debug(req)) {
+-		fuse_log(FUSE_LOG_DEBUG, "lo_removexattr(ino=%" PRIu64 ", name=%s)\n",
+-			ino, name);
+-	}
++    if (lo_debug(req)) {
++        fuse_log(FUSE_LOG_DEBUG, "lo_removexattr(ino=%" PRIu64 ", name=%s)\n",
++                 ino, name);
++    }
+ 
+-	if (inode->is_symlink) {
+-		/* Sorry, no race free way to setxattr on symlink. */
+-		saverr = EPERM;
+-		goto out;
+-	}
++    if (inode->is_symlink) {
++        /* Sorry, no race free way to setxattr on symlink. */
++        saverr = EPERM;
++        goto out;
++    }
+ 
+-	sprintf(procname, "/proc/self/fd/%i", inode->fd);
++    sprintf(procname, "/proc/self/fd/%i", inode->fd);
+ 
+-	ret = removexattr(procname, name);
+-	saverr = ret == -1 ? errno : 0;
++    ret = removexattr(procname, name);
++    saverr = ret == -1 ? errno : 0;
+ 
+ out:
+-	fuse_reply_err(req, saverr);
++    fuse_reply_err(req, saverr);
+ }
+ 
+ #ifdef HAVE_COPY_FILE_RANGE
+ static void lo_copy_file_range(fuse_req_t req, fuse_ino_t ino_in, off_t off_in,
+-			       struct fuse_file_info *fi_in,
+-			       fuse_ino_t ino_out, off_t off_out,
+-			       struct fuse_file_info *fi_out, size_t len,
+-			       int flags)
++                               struct fuse_file_info *fi_in, fuse_ino_t ino_out,
++                               off_t off_out, struct fuse_file_info *fi_out,
++                               size_t len, int flags)
+ {
+-	ssize_t res;
+-
+-	if (lo_debug(req))
+-		fuse_log(FUSE_LOG_DEBUG, "lo_copy_file_range(ino=%" PRIu64 "/fd=%lu, "
+-				"off=%lu, ino=%" PRIu64 "/fd=%lu, "
+-				"off=%lu, size=%zd, flags=0x%x)\n",
+-			ino_in, fi_in->fh, off_in, ino_out, fi_out->fh, off_out,
+-			len, flags);
+-
+-	res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len,
+-			      flags);
+-	if (res < 0)
+-		fuse_reply_err(req, -errno);
+-	else
+-		fuse_reply_write(req, res);
++    ssize_t res;
++
++    if (lo_debug(req))
++        fuse_log(FUSE_LOG_DEBUG,
++                 "lo_copy_file_range(ino=%" PRIu64 "/fd=%lu, "
++                 "off=%lu, ino=%" PRIu64 "/fd=%lu, "
++                 "off=%lu, size=%zd, flags=0x%x)\n",
++                 ino_in, fi_in->fh, off_in, ino_out, fi_out->fh, off_out, len,
++                 flags);
++
++    res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len, flags);
++    if (res < 0) {
++        fuse_reply_err(req, -errno);
++    } else {
++        fuse_reply_write(req, res);
++    }
+ }
+ #endif
+ 
+ static void lo_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
+-		     struct fuse_file_info *fi)
++                     struct fuse_file_info *fi)
+ {
+-	off_t res;
+-
+-	(void)ino;
+-	res = lseek(fi->fh, off, whence);
+-	if (res != -1)
+-		fuse_reply_lseek(req, res);
+-	else
+-		fuse_reply_err(req, errno);
++    off_t res;
++
++    (void)ino;
++    res = lseek(fi->fh, off, whence);
++    if (res != -1) {
++        fuse_reply_lseek(req, res);
++    } else {
++        fuse_reply_err(req, errno);
++    }
+ }
+ 
+ static struct fuse_lowlevel_ops lo_oper = {
+-	.init		= lo_init,
+-	.lookup		= lo_lookup,
+-	.mkdir		= lo_mkdir,
+-	.mknod		= lo_mknod,
+-	.symlink	= lo_symlink,
+-	.link		= lo_link,
+-	.unlink		= lo_unlink,
+-	.rmdir		= lo_rmdir,
+-	.rename		= lo_rename,
+-	.forget		= lo_forget,
+-	.forget_multi	= lo_forget_multi,
+-	.getattr	= lo_getattr,
+-	.setattr	= lo_setattr,
+-	.readlink	= lo_readlink,
+-	.opendir	= lo_opendir,
+-	.readdir	= lo_readdir,
+-	.readdirplus	= lo_readdirplus,
+-	.releasedir	= lo_releasedir,
+-	.fsyncdir	= lo_fsyncdir,
+-	.create		= lo_create,
+-	.open		= lo_open,
+-	.release	= lo_release,
+-	.flush		= lo_flush,
+-	.fsync		= lo_fsync,
+-	.read		= lo_read,
+-	.write_buf      = lo_write_buf,
+-	.statfs		= lo_statfs,
+-	.fallocate	= lo_fallocate,
+-	.flock		= lo_flock,
+-	.getxattr	= lo_getxattr,
+-	.listxattr	= lo_listxattr,
+-	.setxattr	= lo_setxattr,
+-	.removexattr	= lo_removexattr,
++    .init = lo_init,
++    .lookup = lo_lookup,
++    .mkdir = lo_mkdir,
++    .mknod = lo_mknod,
++    .symlink = lo_symlink,
++    .link = lo_link,
++    .unlink = lo_unlink,
++    .rmdir = lo_rmdir,
++    .rename = lo_rename,
++    .forget = lo_forget,
++    .forget_multi = lo_forget_multi,
++    .getattr = lo_getattr,
++    .setattr = lo_setattr,
++    .readlink = lo_readlink,
++    .opendir = lo_opendir,
++    .readdir = lo_readdir,
++    .readdirplus = lo_readdirplus,
++    .releasedir = lo_releasedir,
++    .fsyncdir = lo_fsyncdir,
++    .create = lo_create,
++    .open = lo_open,
++    .release = lo_release,
++    .flush = lo_flush,
++    .fsync = lo_fsync,
++    .read = lo_read,
++    .write_buf = lo_write_buf,
++    .statfs = lo_statfs,
++    .fallocate = lo_fallocate,
++    .flock = lo_flock,
++    .getxattr = lo_getxattr,
++    .listxattr = lo_listxattr,
++    .setxattr = lo_setxattr,
++    .removexattr = lo_removexattr,
+ #ifdef HAVE_COPY_FILE_RANGE
+-	.copy_file_range = lo_copy_file_range,
++    .copy_file_range = lo_copy_file_range,
+ #endif
+-	.lseek		= lo_lseek,
++    .lseek = lo_lseek,
+ };
+ 
+ int main(int argc, char *argv[])
+ {
+-	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+-	struct fuse_session *se;
+-	struct fuse_cmdline_opts opts;
+-	struct lo_data lo = { .debug = 0,
+-	                      .writeback = 0 };
+-	int ret = -1;
+-
+-	/* Don't mask creation mode, kernel already did that */
+-	umask(0);
+-
+-	pthread_mutex_init(&lo.mutex, NULL);
+-	lo.root.next = lo.root.prev = &lo.root;
+-	lo.root.fd = -1;
+-	lo.cache = CACHE_NORMAL;
+-
+-	if (fuse_parse_cmdline(&args, &opts) != 0)
+-		return 1;
+-	if (opts.show_help) {
+-		printf("usage: %s [options] <mountpoint>\n\n", argv[0]);
+-		fuse_cmdline_help();
+-		fuse_lowlevel_help();
+-		ret = 0;
+-		goto err_out1;
+-	} else if (opts.show_version) {
+-		fuse_lowlevel_version();
+-		ret = 0;
+-		goto err_out1;
+-	}
+-
+-	if(opts.mountpoint == NULL) {
+-		printf("usage: %s [options] <mountpoint>\n", argv[0]);
+-		printf("       %s --help\n", argv[0]);
+-		ret = 1;
+-		goto err_out1;
+-	}
+-
+-	if (fuse_opt_parse(&args, &lo, lo_opts, NULL)== -1)
+-		return 1;
+-
+-	lo.debug = opts.debug;
+-	lo.root.refcount = 2;
+-	if (lo.source) {
+-		struct stat stat;
+-		int res;
+-
+-		res = lstat(lo.source, &stat);
+-		if (res == -1) {
+-			fuse_log(FUSE_LOG_ERR, "failed to stat source (\"%s\"): %m\n",
+-				 lo.source);
+-			exit(1);
+-		}
+-		if (!S_ISDIR(stat.st_mode)) {
+-			fuse_log(FUSE_LOG_ERR, "source is not a directory\n");
+-			exit(1);
+-		}
+-
+-	} else {
+-		lo.source = "/";
+-	}
+-	lo.root.is_symlink = false;
+-	if (!lo.timeout_set) {
+-		switch (lo.cache) {
+-		case CACHE_NEVER:
+-			lo.timeout = 0.0;
+-			break;
+-
+-		case CACHE_NORMAL:
+-			lo.timeout = 1.0;
+-			break;
+-
+-		case CACHE_ALWAYS:
+-			lo.timeout = 86400.0;
+-			break;
+-		}
+-	} else if (lo.timeout < 0) {
+-		fuse_log(FUSE_LOG_ERR, "timeout is negative (%lf)\n",
+-			 lo.timeout);
+-		exit(1);
+-	}
+-
+-	lo.root.fd = open(lo.source, O_PATH);
+-	if (lo.root.fd == -1) {
+-		fuse_log(FUSE_LOG_ERR, "open(\"%s\", O_PATH): %m\n",
+-			 lo.source);
+-		exit(1);
+-	}
+-
+-	se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo);
+-	if (se == NULL)
+-	    goto err_out1;
+-
+-	if (fuse_set_signal_handlers(se) != 0)
+-	    goto err_out2;
+-
+-	if (fuse_session_mount(se, opts.mountpoint) != 0)
+-	    goto err_out3;
+-
+-	fuse_daemonize(opts.foreground);
+-
+-	/* Block until ctrl+c or fusermount -u */
+-	if (opts.singlethread)
+-		ret = fuse_session_loop(se);
+-	else
+-		ret = fuse_session_loop_mt(se, opts.clone_fd);
+-
+-	fuse_session_unmount(se);
++    struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
++    struct fuse_session *se;
++    struct fuse_cmdline_opts opts;
++    struct lo_data lo = { .debug = 0, .writeback = 0 };
++    int ret = -1;
++
++    /* Don't mask creation mode, kernel already did that */
++    umask(0);
++
++    pthread_mutex_init(&lo.mutex, NULL);
++    lo.root.next = lo.root.prev = &lo.root;
++    lo.root.fd = -1;
++    lo.cache = CACHE_NORMAL;
++
++    if (fuse_parse_cmdline(&args, &opts) != 0) {
++        return 1;
++    }
++    if (opts.show_help) {
++        printf("usage: %s [options] <mountpoint>\n\n", argv[0]);
++        fuse_cmdline_help();
++        fuse_lowlevel_help();
++        ret = 0;
++        goto err_out1;
++    } else if (opts.show_version) {
++        fuse_lowlevel_version();
++        ret = 0;
++        goto err_out1;
++    }
++
++    if (opts.mountpoint == NULL) {
++        printf("usage: %s [options] <mountpoint>\n", argv[0]);
++        printf("       %s --help\n", argv[0]);
++        ret = 1;
++        goto err_out1;
++    }
++
++    if (fuse_opt_parse(&args, &lo, lo_opts, NULL) == -1) {
++        return 1;
++    }
++
++    lo.debug = opts.debug;
++    lo.root.refcount = 2;
++    if (lo.source) {
++        struct stat stat;
++        int res;
++
++        res = lstat(lo.source, &stat);
++        if (res == -1) {
++            fuse_log(FUSE_LOG_ERR, "failed to stat source (\"%s\"): %m\n",
++                     lo.source);
++            exit(1);
++        }
++        if (!S_ISDIR(stat.st_mode)) {
++            fuse_log(FUSE_LOG_ERR, "source is not a directory\n");
++            exit(1);
++        }
++
++    } else {
++        lo.source = "/";
++    }
++    lo.root.is_symlink = false;
++    if (!lo.timeout_set) {
++        switch (lo.cache) {
++        case CACHE_NEVER:
++            lo.timeout = 0.0;
++            break;
++
++        case CACHE_NORMAL:
++            lo.timeout = 1.0;
++            break;
++
++        case CACHE_ALWAYS:
++            lo.timeout = 86400.0;
++            break;
++        }
++    } else if (lo.timeout < 0) {
++        fuse_log(FUSE_LOG_ERR, "timeout is negative (%lf)\n", lo.timeout);
++        exit(1);
++    }
++
++    lo.root.fd = open(lo.source, O_PATH);
++    if (lo.root.fd == -1) {
++        fuse_log(FUSE_LOG_ERR, "open(\"%s\", O_PATH): %m\n", lo.source);
++        exit(1);
++    }
++
++    se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo);
++    if (se == NULL) {
++        goto err_out1;
++    }
++
++    if (fuse_set_signal_handlers(se) != 0) {
++        goto err_out2;
++    }
++
++    if (fuse_session_mount(se, opts.mountpoint) != 0) {
++        goto err_out3;
++    }
++
++    fuse_daemonize(opts.foreground);
++
++    /* Block until ctrl+c or fusermount -u */
++    if (opts.singlethread) {
++        ret = fuse_session_loop(se);
++    } else {
++        ret = fuse_session_loop_mt(se, opts.clone_fd);
++    }
++
++    fuse_session_unmount(se);
+ err_out3:
+-	fuse_remove_signal_handlers(se);
++    fuse_remove_signal_handlers(se);
+ err_out2:
+-	fuse_session_destroy(se);
++    fuse_session_destroy(se);
+ err_out1:
+-	free(opts.mountpoint);
+-	fuse_opt_free_args(&args);
++    free(opts.mountpoint);
++    fuse_opt_free_args(&args);
+ 
+-	if (lo.root.fd >= 0)
+-		close(lo.root.fd);
++    if (lo.root.fd >= 0) {
++        close(lo.root.fd);
++    }
+ 
+-	return ret ? 1 : 0;
++    return ret ? 1 : 0;
+ }
diff --git a/0017-virtiofsd-remove-mountpoint-dummy-argument.patch b/0017-virtiofsd-remove-mountpoint-dummy-argument.patch
new file mode 100644
index 0000000..5b73fa9
--- /dev/null
+++ b/0017-virtiofsd-remove-mountpoint-dummy-argument.patch
@@ -0,0 +1,143 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:46 +0000
+Subject: [PATCH] virtiofsd: remove mountpoint dummy argument
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Classic FUSE file system daemons take a mountpoint argument but
+virtiofsd exposes a vhost-user UNIX domain socket instead.  The
+mountpoint argument is not used by virtiofsd but the user is still
+required to pass a dummy argument on the command-line.
+
+Remove the mountpoint argument to clean up the command-line.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 67aab02272f6cb47c56420f60b370c184961b5ca)
+---
+ tools/virtiofsd/fuse_lowlevel.c  |  2 +-
+ tools/virtiofsd/fuse_lowlevel.h  |  4 +---
+ tools/virtiofsd/helper.c         | 20 +++-----------------
+ tools/virtiofsd/passthrough_ll.c | 12 ++----------
+ 4 files changed, 7 insertions(+), 31 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 5c9cb52f2a..2f32c68161 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -2455,7 +2455,7 @@ out1:
+     return NULL;
+ }
+ 
+-int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
++int fuse_session_mount(struct fuse_session *se)
+ {
+     int fd;
+ 
+diff --git a/tools/virtiofsd/fuse_lowlevel.h b/tools/virtiofsd/fuse_lowlevel.h
+index adb9054bb1..8d8909b35d 100644
+--- a/tools/virtiofsd/fuse_lowlevel.h
++++ b/tools/virtiofsd/fuse_lowlevel.h
+@@ -1863,7 +1863,6 @@ struct fuse_cmdline_opts {
+     int foreground;
+     int debug;
+     int nodefault_subtype;
+-    char *mountpoint;
+     int show_version;
+     int show_help;
+     unsigned int max_idle_threads;
+@@ -1924,12 +1923,11 @@ struct fuse_session *fuse_session_new(struct fuse_args *args,
+ /**
+  * Mount a FUSE file system.
+  *
+- * @param mountpoint the mount point path
+  * @param se session object
+  *
+  * @return 0 on success, -1 on failure.
+  **/
+-int fuse_session_mount(struct fuse_session *se, const char *mountpoint);
++int fuse_session_mount(struct fuse_session *se);
+ 
+ /**
+  * Enter a single threaded, blocking event loop.
+diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
+index 5711dd2660..5e6f2051a7 100644
+--- a/tools/virtiofsd/helper.c
++++ b/tools/virtiofsd/helper.c
+@@ -140,27 +140,13 @@ void fuse_cmdline_help(void)
+ static int fuse_helper_opt_proc(void *data, const char *arg, int key,
+                                 struct fuse_args *outargs)
+ {
++    (void)data;
+     (void)outargs;
+-    struct fuse_cmdline_opts *opts = data;
+ 
+     switch (key) {
+     case FUSE_OPT_KEY_NONOPT:
+-        if (!opts->mountpoint) {
+-            if (fuse_mnt_parse_fuse_fd(arg) != -1) {
+-                return fuse_opt_add_opt(&opts->mountpoint, arg);
+-            }
+-
+-            char mountpoint[PATH_MAX] = "";
+-            if (realpath(arg, mountpoint) == NULL) {
+-                fuse_log(FUSE_LOG_ERR, "fuse: bad mount point `%s': %s\n", arg,
+-                         strerror(errno));
+-                return -1;
+-            }
+-            return fuse_opt_add_opt(&opts->mountpoint, mountpoint);
+-        } else {
+-            fuse_log(FUSE_LOG_ERR, "fuse: invalid argument `%s'\n", arg);
+-            return -1;
+-        }
++        fuse_log(FUSE_LOG_ERR, "fuse: invalid argument `%s'\n", arg);
++        return -1;
+ 
+     default:
+         /* Pass through unknown options */
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index c5850ef803..9377718d9d 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -1297,7 +1297,7 @@ int main(int argc, char *argv[])
+         return 1;
+     }
+     if (opts.show_help) {
+-        printf("usage: %s [options] <mountpoint>\n\n", argv[0]);
++        printf("usage: %s [options]\n\n", argv[0]);
+         fuse_cmdline_help();
+         fuse_lowlevel_help();
+         ret = 0;
+@@ -1308,13 +1308,6 @@ int main(int argc, char *argv[])
+         goto err_out1;
+     }
+ 
+-    if (opts.mountpoint == NULL) {
+-        printf("usage: %s [options] <mountpoint>\n", argv[0]);
+-        printf("       %s --help\n", argv[0]);
+-        ret = 1;
+-        goto err_out1;
+-    }
+-
+     if (fuse_opt_parse(&args, &lo, lo_opts, NULL) == -1) {
+         return 1;
+     }
+@@ -1374,7 +1367,7 @@ int main(int argc, char *argv[])
+         goto err_out2;
+     }
+ 
+-    if (fuse_session_mount(se, opts.mountpoint) != 0) {
++    if (fuse_session_mount(se) != 0) {
+         goto err_out3;
+     }
+ 
+@@ -1393,7 +1386,6 @@ err_out3:
+ err_out2:
+     fuse_session_destroy(se);
+ err_out1:
+-    free(opts.mountpoint);
+     fuse_opt_free_args(&args);
+ 
+     if (lo.root.fd >= 0) {
diff --git a/0018-virtiofsd-remove-unused-notify-reply-support.patch b/0018-virtiofsd-remove-unused-notify-reply-support.patch
new file mode 100644
index 0000000..da2fc17
--- /dev/null
+++ b/0018-virtiofsd-remove-unused-notify-reply-support.patch
@@ -0,0 +1,278 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:47 +0000
+Subject: [PATCH] virtiofsd: remove unused notify reply support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Notify reply support is unused by virtiofsd.  The code would need to be
+updated to validate input buffer sizes.  Remove this unused code since
+changes to it are untestable.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 64c6f408a29ef03e9b8da9f5a5d8fd511b0d801e)
+---
+ tools/virtiofsd/fuse_lowlevel.c | 147 +-------------------------------
+ tools/virtiofsd/fuse_lowlevel.h |  47 ----------
+ 2 files changed, 1 insertion(+), 193 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 2f32c68161..eb0ec49d38 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -31,12 +31,6 @@
+ #define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
+ #define OFFSET_MAX 0x7fffffffffffffffLL
+ 
+-#define container_of(ptr, type, member)                    \
+-    ({                                                     \
+-        const typeof(((type *)0)->member) *__mptr = (ptr); \
+-        (type *)((char *)__mptr - offsetof(type, member)); \
+-    })
+-
+ struct fuse_pollhandle {
+     uint64_t kh;
+     struct fuse_session *se;
+@@ -1862,52 +1856,6 @@ static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     send_reply_ok(req, NULL, 0);
+ }
+ 
+-static void list_del_nreq(struct fuse_notify_req *nreq)
+-{
+-    struct fuse_notify_req *prev = nreq->prev;
+-    struct fuse_notify_req *next = nreq->next;
+-    prev->next = next;
+-    next->prev = prev;
+-}
+-
+-static void list_add_nreq(struct fuse_notify_req *nreq,
+-                          struct fuse_notify_req *next)
+-{
+-    struct fuse_notify_req *prev = next->prev;
+-    nreq->next = next;
+-    nreq->prev = prev;
+-    prev->next = nreq;
+-    next->prev = nreq;
+-}
+-
+-static void list_init_nreq(struct fuse_notify_req *nreq)
+-{
+-    nreq->next = nreq;
+-    nreq->prev = nreq;
+-}
+-
+-static void do_notify_reply(fuse_req_t req, fuse_ino_t nodeid,
+-                            const void *inarg, const struct fuse_buf *buf)
+-{
+-    struct fuse_session *se = req->se;
+-    struct fuse_notify_req *nreq;
+-    struct fuse_notify_req *head;
+-
+-    pthread_mutex_lock(&se->lock);
+-    head = &se->notify_list;
+-    for (nreq = head->next; nreq != head; nreq = nreq->next) {
+-        if (nreq->unique == req->unique) {
+-            list_del_nreq(nreq);
+-            break;
+-        }
+-    }
+-    pthread_mutex_unlock(&se->lock);
+-
+-    if (nreq != head) {
+-        nreq->reply(nreq, req, nodeid, inarg, buf);
+-    }
+-}
+-
+ static int send_notify_iov(struct fuse_session *se, int notify_code,
+                            struct iovec *iov, int count)
+ {
+@@ -2059,95 +2007,6 @@ int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
+     return res;
+ }
+ 
+-struct fuse_retrieve_req {
+-    struct fuse_notify_req nreq;
+-    void *cookie;
+-};
+-
+-static void fuse_ll_retrieve_reply(struct fuse_notify_req *nreq, fuse_req_t req,
+-                                   fuse_ino_t ino, const void *inarg,
+-                                   const struct fuse_buf *ibuf)
+-{
+-    struct fuse_session *se = req->se;
+-    struct fuse_retrieve_req *rreq =
+-        container_of(nreq, struct fuse_retrieve_req, nreq);
+-    const struct fuse_notify_retrieve_in *arg = inarg;
+-    struct fuse_bufvec bufv = {
+-        .buf[0] = *ibuf,
+-        .count = 1,
+-    };
+-
+-    if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD)) {
+-        bufv.buf[0].mem = PARAM(arg);
+-    }
+-
+-    bufv.buf[0].size -=
+-        sizeof(struct fuse_in_header) + sizeof(struct fuse_notify_retrieve_in);
+-
+-    if (bufv.buf[0].size < arg->size) {
+-        fuse_log(FUSE_LOG_ERR, "fuse: retrieve reply: buffer size too small\n");
+-        fuse_reply_none(req);
+-        goto out;
+-    }
+-    bufv.buf[0].size = arg->size;
+-
+-    if (se->op.retrieve_reply) {
+-        se->op.retrieve_reply(req, rreq->cookie, ino, arg->offset, &bufv);
+-    } else {
+-        fuse_reply_none(req);
+-    }
+-out:
+-    free(rreq);
+-}
+-
+-int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino,
+-                                  size_t size, off_t offset, void *cookie)
+-{
+-    struct fuse_notify_retrieve_out outarg;
+-    struct iovec iov[2];
+-    struct fuse_retrieve_req *rreq;
+-    int err;
+-
+-    if (!se) {
+-        return -EINVAL;
+-    }
+-
+-    if (se->conn.proto_major < 6 || se->conn.proto_minor < 15) {
+-        return -ENOSYS;
+-    }
+-
+-    rreq = malloc(sizeof(*rreq));
+-    if (rreq == NULL) {
+-        return -ENOMEM;
+-    }
+-
+-    pthread_mutex_lock(&se->lock);
+-    rreq->cookie = cookie;
+-    rreq->nreq.unique = se->notify_ctr++;
+-    rreq->nreq.reply = fuse_ll_retrieve_reply;
+-    list_add_nreq(&rreq->nreq, &se->notify_list);
+-    pthread_mutex_unlock(&se->lock);
+-
+-    outarg.notify_unique = rreq->nreq.unique;
+-    outarg.nodeid = ino;
+-    outarg.offset = offset;
+-    outarg.size = size;
+-    outarg.padding = 0;
+-
+-    iov[1].iov_base = &outarg;
+-    iov[1].iov_len = sizeof(outarg);
+-
+-    err = send_notify_iov(se, FUSE_NOTIFY_RETRIEVE, iov, 2);
+-    if (err) {
+-        pthread_mutex_lock(&se->lock);
+-        list_del_nreq(&rreq->nreq);
+-        pthread_mutex_unlock(&se->lock);
+-        free(rreq);
+-    }
+-
+-    return err;
+-}
+-
+ void *fuse_req_userdata(fuse_req_t req)
+ {
+     return req->se->userdata;
+@@ -2226,7 +2085,7 @@ static struct {
+     [FUSE_POLL] = { do_poll, "POLL" },
+     [FUSE_FALLOCATE] = { do_fallocate, "FALLOCATE" },
+     [FUSE_DESTROY] = { do_destroy, "DESTROY" },
+-    [FUSE_NOTIFY_REPLY] = { (void *)1, "NOTIFY_REPLY" },
++    [FUSE_NOTIFY_REPLY] = { NULL, "NOTIFY_REPLY" },
+     [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" },
+     [FUSE_READDIRPLUS] = { do_readdirplus, "READDIRPLUS" },
+     [FUSE_RENAME2] = { do_rename2, "RENAME2" },
+@@ -2333,8 +2192,6 @@ void fuse_session_process_buf_int(struct fuse_session *se,
+     inarg = (void *)&in[1];
+     if (in->opcode == FUSE_WRITE && se->op.write_buf) {
+         do_write_buf(req, in->nodeid, inarg, buf);
+-    } else if (in->opcode == FUSE_NOTIFY_REPLY) {
+-        do_notify_reply(req, in->nodeid, inarg, buf);
+     } else {
+         fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
+     }
+@@ -2437,8 +2294,6 @@ struct fuse_session *fuse_session_new(struct fuse_args *args,
+ 
+     list_init_req(&se->list);
+     list_init_req(&se->interrupts);
+-    list_init_nreq(&se->notify_list);
+-    se->notify_ctr = 1;
+     fuse_mutex_init(&se->lock);
+ 
+     memcpy(&se->op, op, op_size);
+diff --git a/tools/virtiofsd/fuse_lowlevel.h b/tools/virtiofsd/fuse_lowlevel.h
+index 8d8909b35d..12a84b460f 100644
+--- a/tools/virtiofsd/fuse_lowlevel.h
++++ b/tools/virtiofsd/fuse_lowlevel.h
+@@ -1084,21 +1084,6 @@ struct fuse_lowlevel_ops {
+     void (*write_buf)(fuse_req_t req, fuse_ino_t ino, struct fuse_bufvec *bufv,
+                       off_t off, struct fuse_file_info *fi);
+ 
+-    /**
+-     * Callback function for the retrieve request
+-     *
+-     * Valid replies:
+-     *  fuse_reply_none
+-     *
+-     * @param req request handle
+-     * @param cookie user data supplied to fuse_lowlevel_notify_retrieve()
+-     * @param ino the inode number supplied to fuse_lowlevel_notify_retrieve()
+-     * @param offset the offset supplied to fuse_lowlevel_notify_retrieve()
+-     * @param bufv the buffer containing the returned data
+-     */
+-    void (*retrieve_reply)(fuse_req_t req, void *cookie, fuse_ino_t ino,
+-                           off_t offset, struct fuse_bufvec *bufv);
+-
+     /**
+      * Forget about multiple inodes
+      *
+@@ -1726,38 +1711,6 @@ int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent,
+ int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
+                                off_t offset, struct fuse_bufvec *bufv,
+                                enum fuse_buf_copy_flags flags);
+-/**
+- * Retrieve data from the kernel buffers
+- *
+- * Retrieve data in the kernel buffers belonging to the given inode.
+- * If successful then the retrieve_reply() method will be called with
+- * the returned data.
+- *
+- * Only present pages are returned in the retrieve reply.  Retrieving
+- * stops when it finds a non-present page and only data prior to that
+- * is returned.
+- *
+- * If this function returns an error, then the retrieve will not be
+- * completed and no reply will be sent.
+- *
+- * This function doesn't change the dirty state of pages in the kernel
+- * buffer.  For dirty pages the write() method will be called
+- * regardless of having been retrieved previously.
+- *
+- * Added in FUSE protocol version 7.15. If the kernel does not support
+- * this (or a newer) version, the function will return -ENOSYS and do
+- * nothing.
+- *
+- * @param se the session object
+- * @param ino the inode number
+- * @param size the number of bytes to retrieve
+- * @param offset the starting offset into the file to retrieve from
+- * @param cookie user data to supply to the reply callback
+- * @return zero for success, -errno for failure
+- */
+-int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino,
+-                                  size_t size, off_t offset, void *cookie);
+-
+ 
+ /*
+  * Utility functions
diff --git a/0019-virtiofsd-Remove-unused-enum-fuse_buf_copy_flags.patch b/0019-virtiofsd-Remove-unused-enum-fuse_buf_copy_flags.patch
new file mode 100644
index 0000000..f60bab0
--- /dev/null
+++ b/0019-virtiofsd-Remove-unused-enum-fuse_buf_copy_flags.patch
@@ -0,0 +1,252 @@
+From: Xiao Yang <yangx.jy@cn.fujitsu.com>
+Date: Mon, 27 Jan 2020 19:00:48 +0000
+Subject: [PATCH] virtiofsd: Remove unused enum fuse_buf_copy_flags
+
+Signed-off-by: Xiao Yang <yangx.jy@cn.fujitsu.com>
+Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 8c3fe75e0308ba2f01d160ace534b7e386cea808)
+---
+ tools/virtiofsd/buffer.c         |  7 +++--
+ tools/virtiofsd/fuse_common.h    | 46 +-------------------------------
+ tools/virtiofsd/fuse_lowlevel.c  | 13 ++++-----
+ tools/virtiofsd/fuse_lowlevel.h  | 35 ++----------------------
+ tools/virtiofsd/passthrough_ll.c |  4 +--
+ 5 files changed, 13 insertions(+), 92 deletions(-)
+
+diff --git a/tools/virtiofsd/buffer.c b/tools/virtiofsd/buffer.c
+index 5df946c82c..4d507f3302 100644
+--- a/tools/virtiofsd/buffer.c
++++ b/tools/virtiofsd/buffer.c
+@@ -171,7 +171,7 @@ static ssize_t fuse_buf_fd_to_fd(const struct fuse_buf *dst, size_t dst_off,
+ 
+ static ssize_t fuse_buf_copy_one(const struct fuse_buf *dst, size_t dst_off,
+                                  const struct fuse_buf *src, size_t src_off,
+-                                 size_t len, enum fuse_buf_copy_flags flags)
++                                 size_t len)
+ {
+     int src_is_fd = src->flags & FUSE_BUF_IS_FD;
+     int dst_is_fd = dst->flags & FUSE_BUF_IS_FD;
+@@ -224,8 +224,7 @@ static int fuse_bufvec_advance(struct fuse_bufvec *bufv, size_t len)
+     return 1;
+ }
+ 
+-ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv,
+-                      enum fuse_buf_copy_flags flags)
++ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv)
+ {
+     size_t copied = 0;
+ 
+@@ -249,7 +248,7 @@ ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv,
+         dst_len = dst->size - dstv->off;
+         len = min_size(src_len, dst_len);
+ 
+-        res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len, flags);
++        res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len);
+         if (res < 0) {
+             if (!copied) {
+                 return res;
+diff --git a/tools/virtiofsd/fuse_common.h b/tools/virtiofsd/fuse_common.h
+index bd9bf861f0..0cb33acc2f 100644
+--- a/tools/virtiofsd/fuse_common.h
++++ b/tools/virtiofsd/fuse_common.h
+@@ -604,48 +604,6 @@ enum fuse_buf_flags {
+     FUSE_BUF_FD_RETRY = (1 << 3),
+ };
+ 
+-/**
+- * Buffer copy flags
+- */
+-enum fuse_buf_copy_flags {
+-    /**
+-     * Don't use splice(2)
+-     *
+-     * Always fall back to using read and write instead of
+-     * splice(2) to copy data from one file descriptor to another.
+-     *
+-     * If this flag is not set, then only fall back if splice is
+-     * unavailable.
+-     */
+-    FUSE_BUF_NO_SPLICE = (1 << 1),
+-
+-    /**
+-     * Force splice
+-     *
+-     * Always use splice(2) to copy data from one file descriptor
+-     * to another.  If splice is not available, return -EINVAL.
+-     */
+-    FUSE_BUF_FORCE_SPLICE = (1 << 2),
+-
+-    /**
+-     * Try to move data with splice.
+-     *
+-     * If splice is used, try to move pages from the source to the
+-     * destination instead of copying.  See documentation of
+-     * SPLICE_F_MOVE in splice(2) man page.
+-     */
+-    FUSE_BUF_SPLICE_MOVE = (1 << 3),
+-
+-    /**
+-     * Don't block on the pipe when copying data with splice
+-     *
+-     * Makes the operations on the pipe non-blocking (if the pipe
+-     * is full or empty).  See SPLICE_F_NONBLOCK in the splice(2)
+-     * man page.
+-     */
+-    FUSE_BUF_SPLICE_NONBLOCK = (1 << 4),
+-};
+-
+ /**
+  * Single data buffer
+  *
+@@ -741,11 +699,9 @@ size_t fuse_buf_size(const struct fuse_bufvec *bufv);
+  *
+  * @param dst destination buffer vector
+  * @param src source buffer vector
+- * @param flags flags controlling the copy
+  * @return actual number of bytes copied or -errno on error
+  */
+-ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src,
+-                      enum fuse_buf_copy_flags flags);
++ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src);
+ 
+ /*
+  * Signal handling
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index eb0ec49d38..3da80de233 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -490,16 +490,14 @@ static int fuse_send_data_iov_fallback(struct fuse_session *se,
+ 
+ static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
+                               struct iovec *iov, int iov_count,
+-                              struct fuse_bufvec *buf, unsigned int flags)
++                              struct fuse_bufvec *buf)
+ {
+     size_t len = fuse_buf_size(buf);
+-    (void)flags;
+ 
+     return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
+ }
+ 
+-int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
+-                    enum fuse_buf_copy_flags flags)
++int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv)
+ {
+     struct iovec iov[2];
+     struct fuse_out_header out;
+@@ -511,7 +509,7 @@ int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
+     out.unique = req->unique;
+     out.error = 0;
+ 
+-    res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags);
++    res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv);
+     if (res <= 0) {
+         fuse_free_req(req);
+         return res;
+@@ -1969,8 +1967,7 @@ int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent,
+ }
+ 
+ int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
+-                               off_t offset, struct fuse_bufvec *bufv,
+-                               enum fuse_buf_copy_flags flags)
++                               off_t offset, struct fuse_bufvec *bufv)
+ {
+     struct fuse_out_header out;
+     struct fuse_notify_store_out outarg;
+@@ -1999,7 +1996,7 @@ int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
+     iov[1].iov_base = &outarg;
+     iov[1].iov_len = sizeof(outarg);
+ 
+-    res = fuse_send_data_iov(se, NULL, iov, 2, bufv, flags);
++    res = fuse_send_data_iov(se, NULL, iov, 2, bufv);
+     if (res > 0) {
+         res = -res;
+     }
+diff --git a/tools/virtiofsd/fuse_lowlevel.h b/tools/virtiofsd/fuse_lowlevel.h
+index 12a84b460f..2fa225d40b 100644
+--- a/tools/virtiofsd/fuse_lowlevel.h
++++ b/tools/virtiofsd/fuse_lowlevel.h
+@@ -1363,33 +1363,6 @@ int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size);
+ /**
+  * Reply with data copied/moved from buffer(s)
+  *
+- * Zero copy data transfer ("splicing") will be used under
+- * the following circumstances:
+- *
+- * 1. FUSE_CAP_SPLICE_WRITE is set in fuse_conn_info.want, and
+- * 2. the kernel supports splicing from the fuse device
+- *    (FUSE_CAP_SPLICE_WRITE is set in fuse_conn_info.capable), and
+- * 3. *flags* does not contain FUSE_BUF_NO_SPLICE
+- * 4. The amount of data that is provided in file-descriptor backed
+- *    buffers (i.e., buffers for which bufv[n].flags == FUSE_BUF_FD)
+- *    is at least twice the page size.
+- *
+- * In order for SPLICE_F_MOVE to be used, the following additional
+- * conditions have to be fulfilled:
+- *
+- * 1. FUSE_CAP_SPLICE_MOVE is set in fuse_conn_info.want, and
+- * 2. the kernel supports it (i.e, FUSE_CAP_SPLICE_MOVE is set in
+-      fuse_conn_info.capable), and
+- * 3. *flags* contains FUSE_BUF_SPLICE_MOVE
+- *
+- * Note that, if splice is used, the data is actually spliced twice:
+- * once into a temporary pipe (to prepend header data), and then again
+- * into the kernel. If some of the provided buffers are memory-backed,
+- * the data in them is copied in step one and spliced in step two.
+- *
+- * The FUSE_BUF_SPLICE_FORCE_SPLICE and FUSE_BUF_SPLICE_NONBLOCK flags
+- * are silently ignored.
+- *
+  * Possible requests:
+  *   read, readdir, getxattr, listxattr
+  *
+@@ -1400,11 +1373,9 @@ int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size);
+  *
+  * @param req request handle
+  * @param bufv buffer vector
+- * @param flags flags controlling the copy
+  * @return zero for success, -errno for failure to send reply
+  */
+-int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
+-                    enum fuse_buf_copy_flags flags);
++int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv);
+ 
+ /**
+  * Reply with data vector
+@@ -1705,12 +1676,10 @@ int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent,
+  * @param ino the inode number
+  * @param offset the starting offset into the file to store to
+  * @param bufv buffer vector
+- * @param flags flags controlling the copy
+  * @return zero for success, -errno for failure
+  */
+ int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
+-                               off_t offset, struct fuse_bufvec *bufv,
+-                               enum fuse_buf_copy_flags flags);
++                               off_t offset, struct fuse_bufvec *bufv);
+ 
+ /*
+  * Utility functions
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 9377718d9d..126a56ccbd 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -931,7 +931,7 @@ static void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset,
+     buf.buf[0].fd = fi->fh;
+     buf.buf[0].pos = offset;
+ 
+-    fuse_reply_data(req, &buf, FUSE_BUF_SPLICE_MOVE);
++    fuse_reply_data(req, &buf);
+ }
+ 
+ static void lo_write_buf(fuse_req_t req, fuse_ino_t ino,
+@@ -952,7 +952,7 @@ static void lo_write_buf(fuse_req_t req, fuse_ino_t ino,
+                  out_buf.buf[0].size, (unsigned long)off);
+     }
+ 
+-    res = fuse_buf_copy(&out_buf, in_buf, 0);
++    res = fuse_buf_copy(&out_buf, in_buf);
+     if (res < 0) {
+         fuse_reply_err(req, -res);
+     } else {
diff --git a/0020-virtiofsd-Fix-fuse_daemonize-ignored-return-values.patch b/0020-virtiofsd-Fix-fuse_daemonize-ignored-return-values.patch
new file mode 100644
index 0000000..086f244
--- /dev/null
+++ b/0020-virtiofsd-Fix-fuse_daemonize-ignored-return-values.patch
@@ -0,0 +1,104 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:49 +0000
+Subject: [PATCH] virtiofsd: Fix fuse_daemonize ignored return values
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+QEMU's compiler enables warnings/errors for ignored values
+and the (void) trick used in the fuse code isn't enough.
+Turn all the return values into a return value on the function.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 30d8e49760712d65697ea517c53671bd1d214fc7)
+---
+ tools/virtiofsd/helper.c | 33 ++++++++++++++++++++++-----------
+ 1 file changed, 22 insertions(+), 11 deletions(-)
+
+diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
+index 5e6f2051a7..d9227d7367 100644
+--- a/tools/virtiofsd/helper.c
++++ b/tools/virtiofsd/helper.c
+@@ -10,12 +10,10 @@
+  * See the file COPYING.LIB.
+  */
+ 
+-#include "config.h"
+ #include "fuse_i.h"
+ #include "fuse_lowlevel.h"
+ #include "fuse_misc.h"
+ #include "fuse_opt.h"
+-#include "mount_util.h"
+ 
+ #include <errno.h>
+ #include <limits.h>
+@@ -171,6 +169,7 @@ int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts)
+ 
+ int fuse_daemonize(int foreground)
+ {
++    int ret = 0, rett;
+     if (!foreground) {
+         int nullfd;
+         int waiter[2];
+@@ -192,8 +191,8 @@ int fuse_daemonize(int foreground)
+         case 0:
+             break;
+         default:
+-            (void)read(waiter[0], &completed, sizeof(completed));
+-            _exit(0);
++            _exit(read(waiter[0], &completed,
++                       sizeof(completed) != sizeof(completed)));
+         }
+ 
+         if (setsid() == -1) {
+@@ -201,13 +200,22 @@ int fuse_daemonize(int foreground)
+             return -1;
+         }
+ 
+-        (void)chdir("/");
++        ret = chdir("/");
+ 
+         nullfd = open("/dev/null", O_RDWR, 0);
+         if (nullfd != -1) {
+-            (void)dup2(nullfd, 0);
+-            (void)dup2(nullfd, 1);
+-            (void)dup2(nullfd, 2);
++            rett = dup2(nullfd, 0);
++            if (!ret) {
++                ret = rett;
++            }
++            rett = dup2(nullfd, 1);
++            if (!ret) {
++                ret = rett;
++            }
++            rett = dup2(nullfd, 2);
++            if (!ret) {
++                ret = rett;
++            }
+             if (nullfd > 2) {
+                 close(nullfd);
+             }
+@@ -215,13 +223,16 @@ int fuse_daemonize(int foreground)
+ 
+         /* Propagate completion of daemon initialization */
+         completed = 1;
+-        (void)write(waiter[1], &completed, sizeof(completed));
++        rett = write(waiter[1], &completed, sizeof(completed));
++        if (!ret) {
++            ret = rett;
++        }
+         close(waiter[0]);
+         close(waiter[1]);
+     } else {
+-        (void)chdir("/");
++        ret = chdir("/");
+     }
+-    return 0;
++    return ret;
+ }
+ 
+ void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts,
diff --git a/0021-virtiofsd-Fix-common-header-and-define-for-QEMU-buil.patch b/0021-virtiofsd-Fix-common-header-and-define-for-QEMU-buil.patch
new file mode 100644
index 0000000..942c006
--- /dev/null
+++ b/0021-virtiofsd-Fix-common-header-and-define-for-QEMU-buil.patch
@@ -0,0 +1,147 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:50 +0000
+Subject: [PATCH] virtiofsd: Fix common header and define for QEMU builds
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+All of the fuse files include config.h and define GNU_SOURCE
+where we don't have either under our build - remove them.
+Fixup path to the kernel's fuse.h in the QEMUs world.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 09863ebc7e32a107235b3c815ad54d26cc64f07a)
+---
+ tools/virtiofsd/buffer.c         | 4 +---
+ tools/virtiofsd/fuse_i.h         | 3 +++
+ tools/virtiofsd/fuse_log.c       | 1 +
+ tools/virtiofsd/fuse_lowlevel.c  | 6 ++----
+ tools/virtiofsd/fuse_opt.c       | 2 +-
+ tools/virtiofsd/fuse_signals.c   | 2 +-
+ tools/virtiofsd/helper.c         | 1 +
+ tools/virtiofsd/passthrough_ll.c | 8 ++------
+ 8 files changed, 12 insertions(+), 15 deletions(-)
+
+diff --git a/tools/virtiofsd/buffer.c b/tools/virtiofsd/buffer.c
+index 4d507f3302..772efa922d 100644
+--- a/tools/virtiofsd/buffer.c
++++ b/tools/virtiofsd/buffer.c
+@@ -9,9 +9,7 @@
+  * See the file COPYING.LIB
+  */
+ 
+-#define _GNU_SOURCE
+-
+-#include "config.h"
++#include "qemu/osdep.h"
+ #include "fuse_i.h"
+ #include "fuse_lowlevel.h"
+ #include <assert.h>
+diff --git a/tools/virtiofsd/fuse_i.h b/tools/virtiofsd/fuse_i.h
+index e63cb58388..bae06992e0 100644
+--- a/tools/virtiofsd/fuse_i.h
++++ b/tools/virtiofsd/fuse_i.h
+@@ -6,6 +6,9 @@
+  * See the file COPYING.LIB
+  */
+ 
++#define FUSE_USE_VERSION 31
++
++
+ #include "fuse.h"
+ #include "fuse_lowlevel.h"
+ 
+diff --git a/tools/virtiofsd/fuse_log.c b/tools/virtiofsd/fuse_log.c
+index 11345f9ec8..c301ff6da1 100644
+--- a/tools/virtiofsd/fuse_log.c
++++ b/tools/virtiofsd/fuse_log.c
+@@ -8,6 +8,7 @@
+  * See the file COPYING.LIB
+  */
+ 
++#include "qemu/osdep.h"
+ #include "fuse_log.h"
+ 
+ #include <stdarg.h>
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 3da80de233..07fb8a6095 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -9,11 +9,9 @@
+  * See the file COPYING.LIB
+  */
+ 
+-#define _GNU_SOURCE
+-
+-#include "config.h"
++#include "qemu/osdep.h"
+ #include "fuse_i.h"
+-#include "fuse_kernel.h"
++#include "standard-headers/linux/fuse.h"
+ #include "fuse_misc.h"
+ #include "fuse_opt.h"
+ 
+diff --git a/tools/virtiofsd/fuse_opt.c b/tools/virtiofsd/fuse_opt.c
+index edd36f4a3b..28922361a2 100644
+--- a/tools/virtiofsd/fuse_opt.c
++++ b/tools/virtiofsd/fuse_opt.c
+@@ -9,8 +9,8 @@
+  * See the file COPYING.LIB
+  */
+ 
++#include "qemu/osdep.h"
+ #include "fuse_opt.h"
+-#include "config.h"
+ #include "fuse_i.h"
+ #include "fuse_misc.h"
+ 
+diff --git a/tools/virtiofsd/fuse_signals.c b/tools/virtiofsd/fuse_signals.c
+index 19d6791cb9..dc7c8ac025 100644
+--- a/tools/virtiofsd/fuse_signals.c
++++ b/tools/virtiofsd/fuse_signals.c
+@@ -8,7 +8,7 @@
+  * See the file COPYING.LIB
+  */
+ 
+-#include "config.h"
++#include "qemu/osdep.h"
+ #include "fuse_i.h"
+ #include "fuse_lowlevel.h"
+ 
+diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
+index d9227d7367..9333691525 100644
+--- a/tools/virtiofsd/helper.c
++++ b/tools/virtiofsd/helper.c
+@@ -10,6 +10,7 @@
+  * See the file COPYING.LIB.
+  */
+ 
++#include "qemu/osdep.h"
+ #include "fuse_i.h"
+ #include "fuse_lowlevel.h"
+ #include "fuse_misc.h"
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 126a56ccbd..322a889cdf 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -35,15 +35,11 @@
+  * \include passthrough_ll.c
+  */
+ 
+-#define _GNU_SOURCE
+-#define FUSE_USE_VERSION 31
+-
+-#include "config.h"
+-
++#include "qemu/osdep.h"
++#include "fuse_lowlevel.h"
+ #include <assert.h>
+ #include <dirent.h>
+ #include <errno.h>
+-#include <fuse_lowlevel.h>
+ #include <inttypes.h>
+ #include <limits.h>
+ #include <pthread.h>
diff --git a/0022-virtiofsd-Trim-out-compatibility-code.patch b/0022-virtiofsd-Trim-out-compatibility-code.patch
new file mode 100644
index 0000000..5da556a
--- /dev/null
+++ b/0022-virtiofsd-Trim-out-compatibility-code.patch
@@ -0,0 +1,529 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:51 +0000
+Subject: [PATCH] virtiofsd: Trim out compatibility code
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+virtiofsd only supports major=7, minor>=31; trim out a lot of
+old compatibility code.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 72c42e2d65510e073cf78fdc924d121c77fa0080)
+---
+ tools/virtiofsd/fuse_lowlevel.c | 330 ++++++++++++--------------------
+ 1 file changed, 119 insertions(+), 211 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 07fb8a6095..514d79cb24 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -387,16 +387,7 @@ static void fill_open(struct fuse_open_out *arg, const struct fuse_file_info *f)
+ int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
+ {
+     struct fuse_entry_out arg;
+-    size_t size = req->se->conn.proto_minor < 9 ? FUSE_COMPAT_ENTRY_OUT_SIZE :
+-                                                  sizeof(arg);
+-
+-    /*
+-     * before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
+-     * negative entry
+-     */
+-    if (!e->ino && req->se->conn.proto_minor < 4) {
+-        return fuse_reply_err(req, ENOENT);
+-    }
++    size_t size = sizeof(arg);
+ 
+     memset(&arg, 0, sizeof(arg));
+     fill_entry(&arg, e);
+@@ -407,9 +398,7 @@ int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
+                       const struct fuse_file_info *f)
+ {
+     char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)];
+-    size_t entrysize = req->se->conn.proto_minor < 9 ?
+-                           FUSE_COMPAT_ENTRY_OUT_SIZE :
+-                           sizeof(struct fuse_entry_out);
++    size_t entrysize = sizeof(struct fuse_entry_out);
+     struct fuse_entry_out *earg = (struct fuse_entry_out *)buf;
+     struct fuse_open_out *oarg = (struct fuse_open_out *)(buf + entrysize);
+ 
+@@ -423,8 +412,7 @@ int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
+                     double attr_timeout)
+ {
+     struct fuse_attr_out arg;
+-    size_t size =
+-        req->se->conn.proto_minor < 9 ? FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg);
++    size_t size = sizeof(arg);
+ 
+     memset(&arg, 0, sizeof(arg));
+     arg.attr_valid = calc_timeout_sec(attr_timeout);
+@@ -519,8 +507,7 @@ int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv)
+ int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
+ {
+     struct fuse_statfs_out arg;
+-    size_t size =
+-        req->se->conn.proto_minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
++    size_t size = sizeof(arg);
+ 
+     memset(&arg, 0, sizeof(arg));
+     convert_statfs(stbuf, &arg.st);
+@@ -604,45 +591,31 @@ int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov,
+     iov[count].iov_len = sizeof(arg);
+     count++;
+ 
+-    if (req->se->conn.proto_minor < 16) {
+-        if (in_count) {
+-            iov[count].iov_base = (void *)in_iov;
+-            iov[count].iov_len = sizeof(in_iov[0]) * in_count;
+-            count++;
+-        }
++    /* Can't handle non-compat 64bit ioctls on 32bit */
++    if (sizeof(void *) == 4 && req->ioctl_64bit) {
++        res = fuse_reply_err(req, EINVAL);
++        goto out;
++    }
+ 
+-        if (out_count) {
+-            iov[count].iov_base = (void *)out_iov;
+-            iov[count].iov_len = sizeof(out_iov[0]) * out_count;
+-            count++;
++    if (in_count) {
++        in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count);
++        if (!in_fiov) {
++            goto enomem;
+         }
+-    } else {
+-        /* Can't handle non-compat 64bit ioctls on 32bit */
+-        if (sizeof(void *) == 4 && req->ioctl_64bit) {
+-            res = fuse_reply_err(req, EINVAL);
+-            goto out;
+-        }
+-
+-        if (in_count) {
+-            in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count);
+-            if (!in_fiov) {
+-                goto enomem;
+-            }
+ 
+-            iov[count].iov_base = (void *)in_fiov;
+-            iov[count].iov_len = sizeof(in_fiov[0]) * in_count;
+-            count++;
++        iov[count].iov_base = (void *)in_fiov;
++        iov[count].iov_len = sizeof(in_fiov[0]) * in_count;
++        count++;
++    }
++    if (out_count) {
++        out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count);
++        if (!out_fiov) {
++            goto enomem;
+         }
+-        if (out_count) {
+-            out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count);
+-            if (!out_fiov) {
+-                goto enomem;
+-            }
+ 
+-            iov[count].iov_base = (void *)out_fiov;
+-            iov[count].iov_len = sizeof(out_fiov[0]) * out_count;
+-            count++;
+-        }
++        iov[count].iov_base = (void *)out_fiov;
++        iov[count].iov_len = sizeof(out_fiov[0]) * out_count;
++        count++;
+     }
+ 
+     res = send_reply_iov(req, 0, iov, count);
+@@ -784,14 +757,12 @@ static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     struct fuse_file_info *fip = NULL;
+     struct fuse_file_info fi;
+ 
+-    if (req->se->conn.proto_minor >= 9) {
+-        struct fuse_getattr_in *arg = (struct fuse_getattr_in *)inarg;
++    struct fuse_getattr_in *arg = (struct fuse_getattr_in *)inarg;
+ 
+-        if (arg->getattr_flags & FUSE_GETATTR_FH) {
+-            memset(&fi, 0, sizeof(fi));
+-            fi.fh = arg->fh;
+-            fip = &fi;
+-        }
++    if (arg->getattr_flags & FUSE_GETATTR_FH) {
++        memset(&fi, 0, sizeof(fi));
++        fi.fh = arg->fh;
++        fip = &fi;
+     }
+ 
+     if (req->se->op.getattr) {
+@@ -856,11 +827,7 @@ static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     struct fuse_mknod_in *arg = (struct fuse_mknod_in *)inarg;
+     char *name = PARAM(arg);
+ 
+-    if (req->se->conn.proto_minor >= 12) {
+-        req->ctx.umask = arg->umask;
+-    } else {
+-        name = (char *)inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
+-    }
++    req->ctx.umask = arg->umask;
+ 
+     if (req->se->op.mknod) {
+         req->se->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
+@@ -873,9 +840,7 @@ static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+     struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *)inarg;
+ 
+-    if (req->se->conn.proto_minor >= 12) {
+-        req->ctx.umask = arg->umask;
+-    }
++    req->ctx.umask = arg->umask;
+ 
+     if (req->se->op.mkdir) {
+         req->se->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
+@@ -967,11 +932,7 @@ static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+         memset(&fi, 0, sizeof(fi));
+         fi.flags = arg->flags;
+ 
+-        if (req->se->conn.proto_minor >= 12) {
+-            req->ctx.umask = arg->umask;
+-        } else {
+-            name = (char *)inarg + sizeof(struct fuse_open_in);
+-        }
++        req->ctx.umask = arg->umask;
+ 
+         req->se->op.create(req, nodeid, name, arg->mode, &fi);
+     } else {
+@@ -1003,10 +964,8 @@ static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ 
+         memset(&fi, 0, sizeof(fi));
+         fi.fh = arg->fh;
+-        if (req->se->conn.proto_minor >= 9) {
+-            fi.lock_owner = arg->lock_owner;
+-            fi.flags = arg->flags;
+-        }
++        fi.lock_owner = arg->lock_owner;
++        fi.flags = arg->flags;
+         req->se->op.read(req, nodeid, arg->size, arg->offset, &fi);
+     } else {
+         fuse_reply_err(req, ENOSYS);
+@@ -1023,13 +982,9 @@ static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     fi.fh = arg->fh;
+     fi.writepage = (arg->write_flags & FUSE_WRITE_CACHE) != 0;
+ 
+-    if (req->se->conn.proto_minor < 9) {
+-        param = ((char *)arg) + FUSE_COMPAT_WRITE_IN_SIZE;
+-    } else {
+-        fi.lock_owner = arg->lock_owner;
+-        fi.flags = arg->flags;
+-        param = PARAM(arg);
+-    }
++    fi.lock_owner = arg->lock_owner;
++    fi.flags = arg->flags;
++    param = PARAM(arg);
+ 
+     if (req->se->op.write) {
+         req->se->op.write(req, nodeid, param, arg->size, arg->offset, &fi);
+@@ -1053,21 +1008,14 @@ static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid, const void *inarg,
+     fi.fh = arg->fh;
+     fi.writepage = arg->write_flags & FUSE_WRITE_CACHE;
+ 
+-    if (se->conn.proto_minor < 9) {
+-        bufv.buf[0].mem = ((char *)arg) + FUSE_COMPAT_WRITE_IN_SIZE;
+-        bufv.buf[0].size -=
+-            sizeof(struct fuse_in_header) + FUSE_COMPAT_WRITE_IN_SIZE;
+-        assert(!(bufv.buf[0].flags & FUSE_BUF_IS_FD));
+-    } else {
+-        fi.lock_owner = arg->lock_owner;
+-        fi.flags = arg->flags;
+-        if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD)) {
+-            bufv.buf[0].mem = PARAM(arg);
+-        }
+-
+-        bufv.buf[0].size -=
+-            sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in);
++    fi.lock_owner = arg->lock_owner;
++    fi.flags = arg->flags;
++    if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD)) {
++        bufv.buf[0].mem = PARAM(arg);
+     }
++
++    bufv.buf[0].size -=
++        sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in);
+     if (bufv.buf[0].size < arg->size) {
+         fuse_log(FUSE_LOG_ERR, "fuse: do_write_buf: buffer size too small\n");
+         fuse_reply_err(req, EIO);
+@@ -1086,9 +1034,7 @@ static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     memset(&fi, 0, sizeof(fi));
+     fi.fh = arg->fh;
+     fi.flush = 1;
+-    if (req->se->conn.proto_minor >= 7) {
+-        fi.lock_owner = arg->lock_owner;
+-    }
++    fi.lock_owner = arg->lock_owner;
+ 
+     if (req->se->op.flush) {
+         req->se->op.flush(req, nodeid, &fi);
+@@ -1105,10 +1051,8 @@ static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     memset(&fi, 0, sizeof(fi));
+     fi.flags = arg->flags;
+     fi.fh = arg->fh;
+-    if (req->se->conn.proto_minor >= 8) {
+-        fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
+-        fi.lock_owner = arg->lock_owner;
+-    }
++    fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
++    fi.lock_owner = arg->lock_owner;
+     if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) {
+         fi.flock_release = 1;
+         fi.lock_owner = arg->lock_owner;
+@@ -1477,8 +1421,7 @@ static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     memset(&fi, 0, sizeof(fi));
+     fi.fh = arg->fh;
+ 
+-    if (sizeof(void *) == 4 && req->se->conn.proto_minor >= 16 &&
+-        !(flags & FUSE_IOCTL_32BIT)) {
++    if (sizeof(void *) == 4 && !(flags & FUSE_IOCTL_32BIT)) {
+         req->ioctl_64bit = 1;
+     }
+ 
+@@ -1603,7 +1546,7 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     outarg.major = FUSE_KERNEL_VERSION;
+     outarg.minor = FUSE_KERNEL_MINOR_VERSION;
+ 
+-    if (arg->major < 7) {
++    if (arg->major < 7 || (arg->major == 7 && arg->minor < 31)) {
+         fuse_log(FUSE_LOG_ERR, "fuse: unsupported protocol version: %u.%u\n",
+                  arg->major, arg->minor);
+         fuse_reply_err(req, EPROTO);
+@@ -1616,81 +1559,71 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+         return;
+     }
+ 
+-    if (arg->minor >= 6) {
+-        if (arg->max_readahead < se->conn.max_readahead) {
+-            se->conn.max_readahead = arg->max_readahead;
+-        }
+-        if (arg->flags & FUSE_ASYNC_READ) {
+-            se->conn.capable |= FUSE_CAP_ASYNC_READ;
+-        }
+-        if (arg->flags & FUSE_POSIX_LOCKS) {
+-            se->conn.capable |= FUSE_CAP_POSIX_LOCKS;
+-        }
+-        if (arg->flags & FUSE_ATOMIC_O_TRUNC) {
+-            se->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC;
+-        }
+-        if (arg->flags & FUSE_EXPORT_SUPPORT) {
+-            se->conn.capable |= FUSE_CAP_EXPORT_SUPPORT;
+-        }
+-        if (arg->flags & FUSE_DONT_MASK) {
+-            se->conn.capable |= FUSE_CAP_DONT_MASK;
+-        }
+-        if (arg->flags & FUSE_FLOCK_LOCKS) {
+-            se->conn.capable |= FUSE_CAP_FLOCK_LOCKS;
+-        }
+-        if (arg->flags & FUSE_AUTO_INVAL_DATA) {
+-            se->conn.capable |= FUSE_CAP_AUTO_INVAL_DATA;
+-        }
+-        if (arg->flags & FUSE_DO_READDIRPLUS) {
+-            se->conn.capable |= FUSE_CAP_READDIRPLUS;
+-        }
+-        if (arg->flags & FUSE_READDIRPLUS_AUTO) {
+-            se->conn.capable |= FUSE_CAP_READDIRPLUS_AUTO;
+-        }
+-        if (arg->flags & FUSE_ASYNC_DIO) {
+-            se->conn.capable |= FUSE_CAP_ASYNC_DIO;
+-        }
+-        if (arg->flags & FUSE_WRITEBACK_CACHE) {
+-            se->conn.capable |= FUSE_CAP_WRITEBACK_CACHE;
+-        }
+-        if (arg->flags & FUSE_NO_OPEN_SUPPORT) {
+-            se->conn.capable |= FUSE_CAP_NO_OPEN_SUPPORT;
+-        }
+-        if (arg->flags & FUSE_PARALLEL_DIROPS) {
+-            se->conn.capable |= FUSE_CAP_PARALLEL_DIROPS;
+-        }
+-        if (arg->flags & FUSE_POSIX_ACL) {
+-            se->conn.capable |= FUSE_CAP_POSIX_ACL;
+-        }
+-        if (arg->flags & FUSE_HANDLE_KILLPRIV) {
+-            se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV;
+-        }
+-        if (arg->flags & FUSE_NO_OPENDIR_SUPPORT) {
+-            se->conn.capable |= FUSE_CAP_NO_OPENDIR_SUPPORT;
+-        }
+-        if (!(arg->flags & FUSE_MAX_PAGES)) {
+-            size_t max_bufsize =
+-                FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize() +
+-                FUSE_BUFFER_HEADER_SIZE;
+-            if (bufsize > max_bufsize) {
+-                bufsize = max_bufsize;
+-            }
++    if (arg->max_readahead < se->conn.max_readahead) {
++        se->conn.max_readahead = arg->max_readahead;
++    }
++    if (arg->flags & FUSE_ASYNC_READ) {
++        se->conn.capable |= FUSE_CAP_ASYNC_READ;
++    }
++    if (arg->flags & FUSE_POSIX_LOCKS) {
++        se->conn.capable |= FUSE_CAP_POSIX_LOCKS;
++    }
++    if (arg->flags & FUSE_ATOMIC_O_TRUNC) {
++        se->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC;
++    }
++    if (arg->flags & FUSE_EXPORT_SUPPORT) {
++        se->conn.capable |= FUSE_CAP_EXPORT_SUPPORT;
++    }
++    if (arg->flags & FUSE_DONT_MASK) {
++        se->conn.capable |= FUSE_CAP_DONT_MASK;
++    }
++    if (arg->flags & FUSE_FLOCK_LOCKS) {
++        se->conn.capable |= FUSE_CAP_FLOCK_LOCKS;
++    }
++    if (arg->flags & FUSE_AUTO_INVAL_DATA) {
++        se->conn.capable |= FUSE_CAP_AUTO_INVAL_DATA;
++    }
++    if (arg->flags & FUSE_DO_READDIRPLUS) {
++        se->conn.capable |= FUSE_CAP_READDIRPLUS;
++    }
++    if (arg->flags & FUSE_READDIRPLUS_AUTO) {
++        se->conn.capable |= FUSE_CAP_READDIRPLUS_AUTO;
++    }
++    if (arg->flags & FUSE_ASYNC_DIO) {
++        se->conn.capable |= FUSE_CAP_ASYNC_DIO;
++    }
++    if (arg->flags & FUSE_WRITEBACK_CACHE) {
++        se->conn.capable |= FUSE_CAP_WRITEBACK_CACHE;
++    }
++    if (arg->flags & FUSE_NO_OPEN_SUPPORT) {
++        se->conn.capable |= FUSE_CAP_NO_OPEN_SUPPORT;
++    }
++    if (arg->flags & FUSE_PARALLEL_DIROPS) {
++        se->conn.capable |= FUSE_CAP_PARALLEL_DIROPS;
++    }
++    if (arg->flags & FUSE_POSIX_ACL) {
++        se->conn.capable |= FUSE_CAP_POSIX_ACL;
++    }
++    if (arg->flags & FUSE_HANDLE_KILLPRIV) {
++        se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV;
++    }
++    if (arg->flags & FUSE_NO_OPENDIR_SUPPORT) {
++        se->conn.capable |= FUSE_CAP_NO_OPENDIR_SUPPORT;
++    }
++    if (!(arg->flags & FUSE_MAX_PAGES)) {
++        size_t max_bufsize = FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize() +
++                             FUSE_BUFFER_HEADER_SIZE;
++        if (bufsize > max_bufsize) {
++            bufsize = max_bufsize;
+         }
+-    } else {
+-        se->conn.max_readahead = 0;
+     }
+-
+-    if (se->conn.proto_minor >= 14) {
+ #ifdef HAVE_SPLICE
+ #ifdef HAVE_VMSPLICE
+-        se->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE;
++    se->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE;
+ #endif
+-        se->conn.capable |= FUSE_CAP_SPLICE_READ;
++    se->conn.capable |= FUSE_CAP_SPLICE_READ;
+ #endif
+-    }
+-    if (se->conn.proto_minor >= 18) {
+-        se->conn.capable |= FUSE_CAP_IOCTL_DIR;
+-    }
++    se->conn.capable |= FUSE_CAP_IOCTL_DIR;
+ 
+     /*
+      * Default settings for modern filesystems.
+@@ -1797,24 +1730,20 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+     outarg.max_readahead = se->conn.max_readahead;
+     outarg.max_write = se->conn.max_write;
+-    if (se->conn.proto_minor >= 13) {
+-        if (se->conn.max_background >= (1 << 16)) {
+-            se->conn.max_background = (1 << 16) - 1;
+-        }
+-        if (se->conn.congestion_threshold > se->conn.max_background) {
+-            se->conn.congestion_threshold = se->conn.max_background;
+-        }
+-        if (!se->conn.congestion_threshold) {
+-            se->conn.congestion_threshold = se->conn.max_background * 3 / 4;
+-        }
+-
+-        outarg.max_background = se->conn.max_background;
+-        outarg.congestion_threshold = se->conn.congestion_threshold;
++    if (se->conn.max_background >= (1 << 16)) {
++        se->conn.max_background = (1 << 16) - 1;
++    }
++    if (se->conn.congestion_threshold > se->conn.max_background) {
++        se->conn.congestion_threshold = se->conn.max_background;
+     }
+-    if (se->conn.proto_minor >= 23) {
+-        outarg.time_gran = se->conn.time_gran;
++    if (!se->conn.congestion_threshold) {
++        se->conn.congestion_threshold = se->conn.max_background * 3 / 4;
+     }
+ 
++    outarg.max_background = se->conn.max_background;
++    outarg.congestion_threshold = se->conn.congestion_threshold;
++    outarg.time_gran = se->conn.time_gran;
++
+     if (se->debug) {
+         fuse_log(FUSE_LOG_DEBUG, "   INIT: %u.%u\n", outarg.major,
+                  outarg.minor);
+@@ -1828,11 +1757,6 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+                  outarg.congestion_threshold);
+         fuse_log(FUSE_LOG_DEBUG, "   time_gran=%u\n", outarg.time_gran);
+     }
+-    if (arg->minor < 5) {
+-        outargsize = FUSE_COMPAT_INIT_OUT_SIZE;
+-    } else if (arg->minor < 23) {
+-        outargsize = FUSE_COMPAT_22_INIT_OUT_SIZE;
+-    }
+ 
+     send_reply_ok(req, &outarg, outargsize);
+ }
+@@ -1896,10 +1820,6 @@ int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
+         return -EINVAL;
+     }
+ 
+-    if (se->conn.proto_major < 6 || se->conn.proto_minor < 12) {
+-        return -ENOSYS;
+-    }
+-
+     outarg.ino = ino;
+     outarg.off = off;
+     outarg.len = len;
+@@ -1920,10 +1840,6 @@ int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
+         return -EINVAL;
+     }
+ 
+-    if (se->conn.proto_major < 6 || se->conn.proto_minor < 12) {
+-        return -ENOSYS;
+-    }
+-
+     outarg.parent = parent;
+     outarg.namelen = namelen;
+     outarg.padding = 0;
+@@ -1947,10 +1863,6 @@ int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent,
+         return -EINVAL;
+     }
+ 
+-    if (se->conn.proto_major < 6 || se->conn.proto_minor < 18) {
+-        return -ENOSYS;
+-    }
+-
+     outarg.parent = parent;
+     outarg.child = child;
+     outarg.namelen = namelen;
+@@ -1977,10 +1889,6 @@ int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
+         return -EINVAL;
+     }
+ 
+-    if (se->conn.proto_major < 6 || se->conn.proto_minor < 15) {
+-        return -ENOSYS;
+-    }
+-
+     out.unique = 0;
+     out.error = FUSE_NOTIFY_STORE;
+ 
diff --git a/0023-vitriofsd-passthrough_ll-fix-fallocate-ifdefs.patch b/0023-vitriofsd-passthrough_ll-fix-fallocate-ifdefs.patch
new file mode 100644
index 0000000..529af3b
--- /dev/null
+++ b/0023-vitriofsd-passthrough_ll-fix-fallocate-ifdefs.patch
@@ -0,0 +1,36 @@
+From: Xiao Yang <yangx.jy@cn.fujitsu.com>
+Date: Mon, 27 Jan 2020 19:00:52 +0000
+Subject: [PATCH] vitriofsd/passthrough_ll: fix fallocate() ifdefs
+
+1) Use correct CONFIG_FALLOCATE macro to check if fallocate() is supported.(i.e configure
+   script sets CONFIG_FALLOCATE intead of HAVE_FALLOCATE if fallocate() is supported)
+2) Replace HAVE_POSIX_FALLOCATE with CONFIG_POSIX_FALLOCATE.
+
+Signed-off-by: Xiao Yang <yangx.jy@cn.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+  Merged from two of Xiao Yang's patches
+(cherry picked from commit 9776457ca6f05d5900e27decb1dba2ffddf95a22)
+---
+ tools/virtiofsd/passthrough_ll.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 322a889cdf..6c4da18075 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -975,13 +975,13 @@ static void lo_fallocate(fuse_req_t req, fuse_ino_t ino, int mode, off_t offset,
+     int err = EOPNOTSUPP;
+     (void)ino;
+ 
+-#ifdef HAVE_FALLOCATE
++#ifdef CONFIG_FALLOCATE
+     err = fallocate(fi->fh, mode, offset, length);
+     if (err < 0) {
+         err = errno;
+     }
+ 
+-#elif defined(HAVE_POSIX_FALLOCATE)
++#elif defined(CONFIG_POSIX_FALLOCATE)
+     if (mode) {
+         fuse_reply_err(req, EOPNOTSUPP);
+         return;
diff --git a/0024-virtiofsd-Make-fsync-work-even-if-only-inode-is-pass.patch b/0024-virtiofsd-Make-fsync-work-even-if-only-inode-is-pass.patch
new file mode 100644
index 0000000..119bcdb
--- /dev/null
+++ b/0024-virtiofsd-Make-fsync-work-even-if-only-inode-is-pass.patch
@@ -0,0 +1,79 @@
+From: Vivek Goyal <vgoyal@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:53 +0000
+Subject: [PATCH] virtiofsd: Make fsync work even if only inode is passed in
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+If caller has not sent file handle in request, then using inode, retrieve
+the fd opened using O_PATH and use that to open file again and issue
+fsync. This will be needed when dax_flush() calls fsync. At that time
+we only have inode information (and not file).
+
+Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 1b209805f8159c3f4d89ddb9390a5f64887cebff)
+---
+ tools/virtiofsd/fuse_lowlevel.c  |  6 +++++-
+ tools/virtiofsd/passthrough_ll.c | 28 ++++++++++++++++++++++++++--
+ 2 files changed, 31 insertions(+), 3 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 514d79cb24..8552cfb8af 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -1075,7 +1075,11 @@ static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     fi.fh = arg->fh;
+ 
+     if (req->se->op.fsync) {
+-        req->se->op.fsync(req, nodeid, datasync, &fi);
++        if (fi.fh == (uint64_t)-1) {
++            req->se->op.fsync(req, nodeid, datasync, NULL);
++        } else {
++            req->se->op.fsync(req, nodeid, datasync, &fi);
++        }
+     } else {
+         fuse_reply_err(req, ENOSYS);
+     }
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 6c4da18075..26ac87013b 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -903,10 +903,34 @@ static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
+ {
+     int res;
+     (void)ino;
++    int fd;
++    char *buf;
++
++    fuse_log(FUSE_LOG_DEBUG, "lo_fsync(ino=%" PRIu64 ", fi=0x%p)\n", ino,
++             (void *)fi);
++
++    if (!fi) {
++        res = asprintf(&buf, "/proc/self/fd/%i", lo_fd(req, ino));
++        if (res == -1) {
++            return (void)fuse_reply_err(req, errno);
++        }
++
++        fd = open(buf, O_RDWR);
++        free(buf);
++        if (fd == -1) {
++            return (void)fuse_reply_err(req, errno);
++        }
++    } else {
++        fd = fi->fh;
++    }
++
+     if (datasync) {
+-        res = fdatasync(fi->fh);
++        res = fdatasync(fd);
+     } else {
+-        res = fsync(fi->fh);
++        res = fsync(fd);
++    }
++    if (!fi) {
++        close(fd);
+     }
+     fuse_reply_err(req, res == -1 ? errno : 0);
+ }
diff --git a/0025-virtiofsd-Add-options-for-virtio.patch b/0025-virtiofsd-Add-options-for-virtio.patch
new file mode 100644
index 0000000..f0193f8
--- /dev/null
+++ b/0025-virtiofsd-Add-options-for-virtio.patch
@@ -0,0 +1,84 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:54 +0000
+Subject: [PATCH] virtiofsd: Add options for virtio
+
+Add options to specify parameters for virtio-fs paths, i.e.
+
+   ./virtiofsd -o vhost_user_socket=/tmp/vhostqemu
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 205de006aab8dcbe546a7e3a51d295c2d05e654b)
+---
+ tools/virtiofsd/fuse_i.h        |  1 +
+ tools/virtiofsd/fuse_lowlevel.c | 11 ++++++++---
+ tools/virtiofsd/helper.c        | 14 +++++++-------
+ 3 files changed, 16 insertions(+), 10 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_i.h b/tools/virtiofsd/fuse_i.h
+index bae06992e0..26b1a7da88 100644
+--- a/tools/virtiofsd/fuse_i.h
++++ b/tools/virtiofsd/fuse_i.h
+@@ -63,6 +63,7 @@ struct fuse_session {
+     struct fuse_notify_req notify_list;
+     size_t bufsize;
+     int error;
++    char *vu_socket_path;
+ };
+ 
+ struct fuse_chan {
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 8552cfb8af..17e8718283 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -2115,8 +2115,11 @@ reply_err:
+     }
+ 
+ static const struct fuse_opt fuse_ll_opts[] = {
+-    LL_OPTION("debug", debug, 1), LL_OPTION("-d", debug, 1),
+-    LL_OPTION("--debug", debug, 1), LL_OPTION("allow_root", deny_others, 1),
++    LL_OPTION("debug", debug, 1),
++    LL_OPTION("-d", debug, 1),
++    LL_OPTION("--debug", debug, 1),
++    LL_OPTION("allow_root", deny_others, 1),
++    LL_OPTION("--socket-path=%s", vu_socket_path, 0),
+     FUSE_OPT_END
+ };
+ 
+@@ -2132,7 +2135,9 @@ void fuse_lowlevel_help(void)
+      * These are not all options, but the ones that are
+      * potentially of interest to an end-user
+      */
+-    printf("    -o allow_root          allow access by root\n");
++    printf(
++        "    -o allow_root              allow access by root\n"
++        "    --socket-path=PATH         path for the vhost-user socket\n");
+ }
+ 
+ void fuse_session_destroy(struct fuse_session *se)
+diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
+index 9333691525..676032e71f 100644
+--- a/tools/virtiofsd/helper.c
++++ b/tools/virtiofsd/helper.c
+@@ -127,13 +127,13 @@ static const struct fuse_opt conn_info_opt_spec[] = {
+ 
+ void fuse_cmdline_help(void)
+ {
+-    printf(
+-        "    -h   --help            print help\n"
+-        "    -V   --version         print version\n"
+-        "    -d   -o debug          enable debug output (implies -f)\n"
+-        "    -f                     foreground operation\n"
+-        "    -o max_idle_threads    the maximum number of idle worker threads\n"
+-        "                           allowed (default: 10)\n");
++    printf("    -h   --help                print help\n"
++           "    -V   --version             print version\n"
++           "    -d   -o debug              enable debug output (implies -f)\n"
++           "    -f                         foreground operation\n"
++           "    -o max_idle_threads        the maximum number of idle worker "
++           "threads\n"
++           "                               allowed (default: 10)\n");
+ }
+ 
+ static int fuse_helper_opt_proc(void *data, const char *arg, int key,
diff --git a/0026-virtiofsd-add-o-source-PATH-to-help-output.patch b/0026-virtiofsd-add-o-source-PATH-to-help-output.patch
new file mode 100644
index 0000000..43f1c59
--- /dev/null
+++ b/0026-virtiofsd-add-o-source-PATH-to-help-output.patch
@@ -0,0 +1,30 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:55 +0000
+Subject: [PATCH] virtiofsd: add -o source=PATH to help output
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The -o source=PATH option will be used by most command-line invocations.
+Let's document it!
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 4ff075f72be2f489c8998ae492ec5cdbbbd73e07)
+---
+ tools/virtiofsd/passthrough_ll.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 26ac87013b..fc9b264d56 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -1319,6 +1319,7 @@ int main(int argc, char *argv[])
+     if (opts.show_help) {
+         printf("usage: %s [options]\n\n", argv[0]);
+         fuse_cmdline_help();
++        printf("    -o source=PATH             shared directory tree\n");
+         fuse_lowlevel_help();
+         ret = 0;
+         goto err_out1;
diff --git a/0027-virtiofsd-Open-vhost-connection-instead-of-mounting.patch b/0027-virtiofsd-Open-vhost-connection-instead-of-mounting.patch
new file mode 100644
index 0000000..01e1514
--- /dev/null
+++ b/0027-virtiofsd-Open-vhost-connection-instead-of-mounting.patch
@@ -0,0 +1,241 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:56 +0000
+Subject: [PATCH] virtiofsd: Open vhost connection instead of mounting
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When run with vhost-user options we conect to the QEMU instead
+via a socket.  Start this off by creating the socket.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Reviewed-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit d14bf584dd965821e80d14c16d9292a464b1ab85)
+---
+ tools/virtiofsd/fuse_i.h        |  7 ++-
+ tools/virtiofsd/fuse_lowlevel.c | 55 +++--------------------
+ tools/virtiofsd/fuse_virtio.c   | 79 +++++++++++++++++++++++++++++++++
+ tools/virtiofsd/fuse_virtio.h   | 23 ++++++++++
+ 4 files changed, 114 insertions(+), 50 deletions(-)
+ create mode 100644 tools/virtiofsd/fuse_virtio.c
+ create mode 100644 tools/virtiofsd/fuse_virtio.h
+
+diff --git a/tools/virtiofsd/fuse_i.h b/tools/virtiofsd/fuse_i.h
+index 26b1a7da88..82d6ac7115 100644
+--- a/tools/virtiofsd/fuse_i.h
++++ b/tools/virtiofsd/fuse_i.h
+@@ -6,9 +6,10 @@
+  * See the file COPYING.LIB
+  */
+ 
+-#define FUSE_USE_VERSION 31
+-
++#ifndef FUSE_I_H
++#define FUSE_I_H
+ 
++#define FUSE_USE_VERSION 31
+ #include "fuse.h"
+ #include "fuse_lowlevel.h"
+ 
+@@ -101,3 +102,5 @@ void fuse_session_process_buf_int(struct fuse_session *se,
+ 
+ /* room needed in buffer to accommodate header */
+ #define FUSE_BUFFER_HEADER_SIZE 0x1000
++
++#endif
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 17e8718283..5df124e64b 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -14,6 +14,7 @@
+ #include "standard-headers/linux/fuse.h"
+ #include "fuse_misc.h"
+ #include "fuse_opt.h"
++#include "fuse_virtio.h"
+ 
+ #include <assert.h>
+ #include <errno.h>
+@@ -2202,6 +2203,11 @@ struct fuse_session *fuse_session_new(struct fuse_args *args,
+         goto out4;
+     }
+ 
++    if (!se->vu_socket_path) {
++        fprintf(stderr, "fuse: missing -o vhost_user_socket option\n");
++        goto out4;
++    }
++
+     se->bufsize = FUSE_MAX_MAX_PAGES * getpagesize() + FUSE_BUFFER_HEADER_SIZE;
+ 
+     list_init_req(&se->list);
+@@ -2224,54 +2230,7 @@ out1:
+ 
+ int fuse_session_mount(struct fuse_session *se)
+ {
+-    int fd;
+-
+-    /*
+-     * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
+-     * would ensue.
+-     */
+-    do {
+-        fd = open("/dev/null", O_RDWR);
+-        if (fd > 2) {
+-            close(fd);
+-        }
+-    } while (fd >= 0 && fd <= 2);
+-
+-    /*
+-     * To allow FUSE daemons to run without privileges, the caller may open
+-     * /dev/fuse before launching the file system and pass on the file
+-     * descriptor by specifying /dev/fd/N as the mount point. Note that the
+-     * parent process takes care of performing the mount in this case.
+-     */
+-    fd = fuse_mnt_parse_fuse_fd(mountpoint);
+-    if (fd != -1) {
+-        if (fcntl(fd, F_GETFD) == -1) {
+-            fuse_log(FUSE_LOG_ERR, "fuse: Invalid file descriptor /dev/fd/%u\n",
+-                     fd);
+-            return -1;
+-        }
+-        se->fd = fd;
+-        return 0;
+-    }
+-
+-    /* Open channel */
+-    fd = fuse_kern_mount(mountpoint, se->mo);
+-    if (fd == -1) {
+-        return -1;
+-    }
+-    se->fd = fd;
+-
+-    /* Save mountpoint */
+-    se->mountpoint = strdup(mountpoint);
+-    if (se->mountpoint == NULL) {
+-        goto error_out;
+-    }
+-
+-    return 0;
+-
+-error_out:
+-    fuse_kern_unmount(mountpoint, fd);
+-    return -1;
++    return virtio_session_mount(se);
+ }
+ 
+ int fuse_session_fd(struct fuse_session *se)
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+new file mode 100644
+index 0000000000..cbef6ffdda
+--- /dev/null
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -0,0 +1,79 @@
++/*
++ * virtio-fs glue for FUSE
++ * Copyright (C) 2018 Red Hat, Inc. and/or its affiliates
++ *
++ * Authors:
++ *   Dave Gilbert  <dgilbert@redhat.com>
++ *
++ * Implements the glue between libfuse and libvhost-user
++ *
++ * This program can be distributed under the terms of the GNU LGPLv2.
++ * See the file COPYING.LIB
++ */
++
++#include "fuse_i.h"
++#include "standard-headers/linux/fuse.h"
++#include "fuse_misc.h"
++#include "fuse_opt.h"
++#include "fuse_virtio.h"
++
++#include <stdint.h>
++#include <stdio.h>
++#include <string.h>
++#include <sys/socket.h>
++#include <sys/types.h>
++#include <sys/un.h>
++#include <unistd.h>
++
++/* From spec */
++struct virtio_fs_config {
++    char tag[36];
++    uint32_t num_queues;
++};
++
++int virtio_session_mount(struct fuse_session *se)
++{
++    struct sockaddr_un un;
++    mode_t old_umask;
++
++    if (strlen(se->vu_socket_path) >= sizeof(un.sun_path)) {
++        fuse_log(FUSE_LOG_ERR, "Socket path too long\n");
++        return -1;
++    }
++
++    se->fd = -1;
++
++    /*
++     * Create the Unix socket to communicate with qemu
++     * based on QEMU's vhost-user-bridge
++     */
++    unlink(se->vu_socket_path);
++    strcpy(un.sun_path, se->vu_socket_path);
++    size_t addr_len = sizeof(un);
++
++    int listen_sock = socket(AF_UNIX, SOCK_STREAM, 0);
++    if (listen_sock == -1) {
++        fuse_log(FUSE_LOG_ERR, "vhost socket creation: %m\n");
++        return -1;
++    }
++    un.sun_family = AF_UNIX;
++
++    /*
++     * Unfortunately bind doesn't let you set the mask on the socket,
++     * so set umask to 077 and restore it later.
++     */
++    old_umask = umask(0077);
++    if (bind(listen_sock, (struct sockaddr *)&un, addr_len) == -1) {
++        fuse_log(FUSE_LOG_ERR, "vhost socket bind: %m\n");
++        umask(old_umask);
++        return -1;
++    }
++    umask(old_umask);
++
++    if (listen(listen_sock, 1) == -1) {
++        fuse_log(FUSE_LOG_ERR, "vhost socket listen: %m\n");
++        return -1;
++    }
++
++    return -1;
++}
+diff --git a/tools/virtiofsd/fuse_virtio.h b/tools/virtiofsd/fuse_virtio.h
+new file mode 100644
+index 0000000000..8f2edb69ca
+--- /dev/null
++++ b/tools/virtiofsd/fuse_virtio.h
+@@ -0,0 +1,23 @@
++/*
++ * virtio-fs glue for FUSE
++ * Copyright (C) 2018 Red Hat, Inc. and/or its affiliates
++ *
++ * Authors:
++ *   Dave Gilbert  <dgilbert@redhat.com>
++ *
++ * Implements the glue between libfuse and libvhost-user
++ *
++ * This program can be distributed under the terms of the GNU LGPLv2.
++ *  See the file COPYING.LIB
++ */
++
++#ifndef FUSE_VIRTIO_H
++#define FUSE_VIRTIO_H
++
++#include "fuse_i.h"
++
++struct fuse_session;
++
++int virtio_session_mount(struct fuse_session *se);
++
++#endif
diff --git a/0028-virtiofsd-Start-wiring-up-vhost-user.patch b/0028-virtiofsd-Start-wiring-up-vhost-user.patch
new file mode 100644
index 0000000..1fdd8a4
--- /dev/null
+++ b/0028-virtiofsd-Start-wiring-up-vhost-user.patch
@@ -0,0 +1,231 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:57 +0000
+Subject: [PATCH] virtiofsd: Start wiring up vhost-user
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Listen on our unix socket for the connection from QEMU, when we get it
+initialise vhost-user and dive into our own loop variant (currently
+dummy).
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit f6f3573c6f271af5ded63ce28589a113f7205c72)
+---
+ tools/virtiofsd/fuse_i.h         |  4 ++
+ tools/virtiofsd/fuse_lowlevel.c  |  5 ++
+ tools/virtiofsd/fuse_lowlevel.h  |  7 +++
+ tools/virtiofsd/fuse_virtio.c    | 87 +++++++++++++++++++++++++++++++-
+ tools/virtiofsd/fuse_virtio.h    |  2 +
+ tools/virtiofsd/passthrough_ll.c |  7 +--
+ 6 files changed, 106 insertions(+), 6 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_i.h b/tools/virtiofsd/fuse_i.h
+index 82d6ac7115..ec04449069 100644
+--- a/tools/virtiofsd/fuse_i.h
++++ b/tools/virtiofsd/fuse_i.h
+@@ -13,6 +13,8 @@
+ #include "fuse.h"
+ #include "fuse_lowlevel.h"
+ 
++struct fv_VuDev;
++
+ struct fuse_req {
+     struct fuse_session *se;
+     uint64_t unique;
+@@ -65,6 +67,8 @@ struct fuse_session {
+     size_t bufsize;
+     int error;
+     char *vu_socket_path;
++    int   vu_socketfd;
++    struct fv_VuDev *virtio_dev;
+ };
+ 
+ struct fuse_chan {
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 5df124e64b..af09fa2b94 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -2242,6 +2242,11 @@ void fuse_session_unmount(struct fuse_session *se)
+ {
+ }
+ 
++int fuse_lowlevel_is_virtio(struct fuse_session *se)
++{
++    return se->vu_socket_path != NULL;
++}
++
+ #ifdef linux
+ int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
+ {
+diff --git a/tools/virtiofsd/fuse_lowlevel.h b/tools/virtiofsd/fuse_lowlevel.h
+index 2fa225d40b..f6b34700af 100644
+--- a/tools/virtiofsd/fuse_lowlevel.h
++++ b/tools/virtiofsd/fuse_lowlevel.h
+@@ -1755,6 +1755,13 @@ void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
+  */
+ int fuse_req_interrupted(fuse_req_t req);
+ 
++/**
++ * Check if the session is connected via virtio
++ *
++ * @param se session object
++ * @return 1 if the session is a virtio session
++ */
++int fuse_lowlevel_is_virtio(struct fuse_session *se);
+ 
+ /*
+  * Inquiry functions
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+index cbef6ffdda..2ae3c764dd 100644
+--- a/tools/virtiofsd/fuse_virtio.c
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -19,18 +19,78 @@
+ 
+ #include <stdint.h>
+ #include <stdio.h>
++#include <stdlib.h>
+ #include <string.h>
+ #include <sys/socket.h>
+ #include <sys/types.h>
+ #include <sys/un.h>
+ #include <unistd.h>
+ 
++#include "contrib/libvhost-user/libvhost-user.h"
++
++/*
++ * We pass the dev element into libvhost-user
++ * and then use it to get back to the outer
++ * container for other data.
++ */
++struct fv_VuDev {
++    VuDev dev;
++    struct fuse_session *se;
++};
++
+ /* From spec */
+ struct virtio_fs_config {
+     char tag[36];
+     uint32_t num_queues;
+ };
+ 
++/*
++ * Callback from libvhost-user if there's a new fd we're supposed to listen
++ * to, typically a queue kick?
++ */
++static void fv_set_watch(VuDev *dev, int fd, int condition, vu_watch_cb cb,
++                         void *data)
++{
++    fuse_log(FUSE_LOG_WARNING, "%s: TODO! fd=%d\n", __func__, fd);
++}
++
++/*
++ * Callback from libvhost-user if we're no longer supposed to listen on an fd
++ */
++static void fv_remove_watch(VuDev *dev, int fd)
++{
++    fuse_log(FUSE_LOG_WARNING, "%s: TODO! fd=%d\n", __func__, fd);
++}
++
++/* Callback from libvhost-user to panic */
++static void fv_panic(VuDev *dev, const char *err)
++{
++    fuse_log(FUSE_LOG_ERR, "%s: libvhost-user: %s\n", __func__, err);
++    /* TODO: Allow reconnects?? */
++    exit(EXIT_FAILURE);
++}
++
++static bool fv_queue_order(VuDev *dev, int qidx)
++{
++    return false;
++}
++
++static const VuDevIface fv_iface = {
++    /* TODO: Add other callbacks */
++    .queue_is_processed_in_order = fv_queue_order,
++};
++
++int virtio_loop(struct fuse_session *se)
++{
++    fuse_log(FUSE_LOG_INFO, "%s: Entry\n", __func__);
++
++    while (1) {
++        /* TODO: Add stuffing */
++    }
++
++    fuse_log(FUSE_LOG_INFO, "%s: Exit\n", __func__);
++}
++
+ int virtio_session_mount(struct fuse_session *se)
+ {
+     struct sockaddr_un un;
+@@ -75,5 +135,30 @@ int virtio_session_mount(struct fuse_session *se)
+         return -1;
+     }
+ 
+-    return -1;
++    fuse_log(FUSE_LOG_INFO, "%s: Waiting for vhost-user socket connection...\n",
++             __func__);
++    int data_sock = accept(listen_sock, NULL, NULL);
++    if (data_sock == -1) {
++        fuse_log(FUSE_LOG_ERR, "vhost socket accept: %m\n");
++        close(listen_sock);
++        return -1;
++    }
++    close(listen_sock);
++    fuse_log(FUSE_LOG_INFO, "%s: Received vhost-user socket connection\n",
++             __func__);
++
++    /* TODO: Some cleanup/deallocation! */
++    se->virtio_dev = calloc(sizeof(struct fv_VuDev), 1);
++    if (!se->virtio_dev) {
++        fuse_log(FUSE_LOG_ERR, "%s: virtio_dev calloc failed\n", __func__);
++        close(data_sock);
++        return -1;
++    }
++
++    se->vu_socketfd = data_sock;
++    se->virtio_dev->se = se;
++    vu_init(&se->virtio_dev->dev, 2, se->vu_socketfd, fv_panic, fv_set_watch,
++            fv_remove_watch, &fv_iface);
++
++    return 0;
+ }
+diff --git a/tools/virtiofsd/fuse_virtio.h b/tools/virtiofsd/fuse_virtio.h
+index 8f2edb69ca..23026d6e4c 100644
+--- a/tools/virtiofsd/fuse_virtio.h
++++ b/tools/virtiofsd/fuse_virtio.h
+@@ -20,4 +20,6 @@ struct fuse_session;
+ 
+ int virtio_session_mount(struct fuse_session *se);
+ 
++int virtio_loop(struct fuse_session *se);
++
+ #endif
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index fc9b264d56..037c5d7b26 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -36,6 +36,7 @@
+  */
+ 
+ #include "qemu/osdep.h"
++#include "fuse_virtio.h"
+ #include "fuse_lowlevel.h"
+ #include <assert.h>
+ #include <dirent.h>
+@@ -1395,11 +1396,7 @@ int main(int argc, char *argv[])
+     fuse_daemonize(opts.foreground);
+ 
+     /* Block until ctrl+c or fusermount -u */
+-    if (opts.singlethread) {
+-        ret = fuse_session_loop(se);
+-    } else {
+-        ret = fuse_session_loop_mt(se, opts.clone_fd);
+-    }
++    ret = virtio_loop(se);
+ 
+     fuse_session_unmount(se);
+ err_out3:
diff --git a/0029-virtiofsd-Add-main-virtio-loop.patch b/0029-virtiofsd-Add-main-virtio-loop.patch
new file mode 100644
index 0000000..d8217c4
--- /dev/null
+++ b/0029-virtiofsd-Add-main-virtio-loop.patch
@@ -0,0 +1,89 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:58 +0000
+Subject: [PATCH] virtiofsd: Add main virtio loop
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Processes incoming requests on the vhost-user fd.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 204d8ae57b3c57098642c79b3c03d42495149c09)
+---
+ tools/virtiofsd/fuse_virtio.c | 42 ++++++++++++++++++++++++++++++++---
+ 1 file changed, 39 insertions(+), 3 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+index 2ae3c764dd..1928a2025c 100644
+--- a/tools/virtiofsd/fuse_virtio.c
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -11,12 +11,14 @@
+  * See the file COPYING.LIB
+  */
+ 
++#include "fuse_virtio.h"
+ #include "fuse_i.h"
+ #include "standard-headers/linux/fuse.h"
+ #include "fuse_misc.h"
+ #include "fuse_opt.h"
+-#include "fuse_virtio.h"
+ 
++#include <assert.h>
++#include <errno.h>
+ #include <stdint.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+@@ -80,15 +82,49 @@ static const VuDevIface fv_iface = {
+     .queue_is_processed_in_order = fv_queue_order,
+ };
+ 
++/*
++ * Main loop; this mostly deals with events on the vhost-user
++ * socket itself, and not actual fuse data.
++ */
+ int virtio_loop(struct fuse_session *se)
+ {
+     fuse_log(FUSE_LOG_INFO, "%s: Entry\n", __func__);
+ 
+-    while (1) {
+-        /* TODO: Add stuffing */
++    while (!fuse_session_exited(se)) {
++        struct pollfd pf[1];
++        pf[0].fd = se->vu_socketfd;
++        pf[0].events = POLLIN;
++        pf[0].revents = 0;
++
++        fuse_log(FUSE_LOG_DEBUG, "%s: Waiting for VU event\n", __func__);
++        int poll_res = ppoll(pf, 1, NULL, NULL);
++
++        if (poll_res == -1) {
++            if (errno == EINTR) {
++                fuse_log(FUSE_LOG_INFO, "%s: ppoll interrupted, going around\n",
++                         __func__);
++                continue;
++            }
++            fuse_log(FUSE_LOG_ERR, "virtio_loop ppoll: %m\n");
++            break;
++        }
++        assert(poll_res == 1);
++        if (pf[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
++            fuse_log(FUSE_LOG_ERR, "%s: Unexpected poll revents %x\n", __func__,
++                     pf[0].revents);
++            break;
++        }
++        assert(pf[0].revents & POLLIN);
++        fuse_log(FUSE_LOG_DEBUG, "%s: Got VU event\n", __func__);
++        if (!vu_dispatch(&se->virtio_dev->dev)) {
++            fuse_log(FUSE_LOG_ERR, "%s: vu_dispatch failed\n", __func__);
++            break;
++        }
+     }
+ 
+     fuse_log(FUSE_LOG_INFO, "%s: Exit\n", __func__);
++
++    return 0;
+ }
+ 
+ int virtio_session_mount(struct fuse_session *se)
diff --git a/0030-virtiofsd-get-set-features-callbacks.patch b/0030-virtiofsd-get-set-features-callbacks.patch
new file mode 100644
index 0000000..cd07092
--- /dev/null
+++ b/0030-virtiofsd-get-set-features-callbacks.patch
@@ -0,0 +1,50 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:00:59 +0000
+Subject: [PATCH] virtiofsd: get/set features callbacks
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add the get/set features callbacks.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit f2cef5fb9ae20136ca18d16328787b69b3abfa18)
+---
+ tools/virtiofsd/fuse_virtio.c | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+index 1928a2025c..4819e56568 100644
+--- a/tools/virtiofsd/fuse_virtio.c
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -46,6 +46,17 @@ struct virtio_fs_config {
+     uint32_t num_queues;
+ };
+ 
++/* Callback from libvhost-user */
++static uint64_t fv_get_features(VuDev *dev)
++{
++    return 1ULL << VIRTIO_F_VERSION_1;
++}
++
++/* Callback from libvhost-user */
++static void fv_set_features(VuDev *dev, uint64_t features)
++{
++}
++
+ /*
+  * Callback from libvhost-user if there's a new fd we're supposed to listen
+  * to, typically a queue kick?
+@@ -78,7 +89,9 @@ static bool fv_queue_order(VuDev *dev, int qidx)
+ }
+ 
+ static const VuDevIface fv_iface = {
+-    /* TODO: Add other callbacks */
++    .get_features = fv_get_features,
++    .set_features = fv_set_features,
++
+     .queue_is_processed_in_order = fv_queue_order,
+ };
+ 
diff --git a/0031-virtiofsd-Start-queue-threads.patch b/0031-virtiofsd-Start-queue-threads.patch
new file mode 100644
index 0000000..f463a47
--- /dev/null
+++ b/0031-virtiofsd-Start-queue-threads.patch
@@ -0,0 +1,148 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:00 +0000
+Subject: [PATCH] virtiofsd: Start queue threads
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Start a thread for each queue when we get notified it's been started.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+fix by:
+Signed-off-by: Jun Piao <piaojun@huawei.com>
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit e4c55a3c144493b436e40031e2eed61a84eca47b)
+---
+ tools/virtiofsd/fuse_virtio.c | 89 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 89 insertions(+)
+
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+index 4819e56568..2a94bb3cca 100644
+--- a/tools/virtiofsd/fuse_virtio.c
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -11,6 +11,7 @@
+  * See the file COPYING.LIB
+  */
+ 
++#include "qemu/osdep.h"
+ #include "fuse_virtio.h"
+ #include "fuse_i.h"
+ #include "standard-headers/linux/fuse.h"
+@@ -30,6 +31,15 @@
+ 
+ #include "contrib/libvhost-user/libvhost-user.h"
+ 
++struct fv_QueueInfo {
++    pthread_t thread;
++    struct fv_VuDev *virtio_dev;
++
++    /* Our queue index, corresponds to array position */
++    int qidx;
++    int kick_fd;
++};
++
+ /*
+  * We pass the dev element into libvhost-user
+  * and then use it to get back to the outer
+@@ -38,6 +48,13 @@
+ struct fv_VuDev {
+     VuDev dev;
+     struct fuse_session *se;
++
++    /*
++     * The following pair of fields are only accessed in the main
++     * virtio_loop
++     */
++    size_t nqueues;
++    struct fv_QueueInfo **qi;
+ };
+ 
+ /* From spec */
+@@ -83,6 +100,75 @@ static void fv_panic(VuDev *dev, const char *err)
+     exit(EXIT_FAILURE);
+ }
+ 
++static void *fv_queue_thread(void *opaque)
++{
++    struct fv_QueueInfo *qi = opaque;
++    fuse_log(FUSE_LOG_INFO, "%s: Start for queue %d kick_fd %d\n", __func__,
++             qi->qidx, qi->kick_fd);
++    while (1) {
++        /* TODO */
++    }
++
++    return NULL;
++}
++
++/* Callback from libvhost-user on start or stop of a queue */
++static void fv_queue_set_started(VuDev *dev, int qidx, bool started)
++{
++    struct fv_VuDev *vud = container_of(dev, struct fv_VuDev, dev);
++    struct fv_QueueInfo *ourqi;
++
++    fuse_log(FUSE_LOG_INFO, "%s: qidx=%d started=%d\n", __func__, qidx,
++             started);
++    assert(qidx >= 0);
++
++    /*
++     * Ignore additional request queues for now.  passthrough_ll.c must be
++     * audited for thread-safety issues first.  It was written with a
++     * well-behaved client in mind and may not protect against all types of
++     * races yet.
++     */
++    if (qidx > 1) {
++        fuse_log(FUSE_LOG_ERR,
++                 "%s: multiple request queues not yet implemented, please only "
++                 "configure 1 request queue\n",
++                 __func__);
++        exit(EXIT_FAILURE);
++    }
++
++    if (started) {
++        /* Fire up a thread to watch this queue */
++        if (qidx >= vud->nqueues) {
++            vud->qi = realloc(vud->qi, (qidx + 1) * sizeof(vud->qi[0]));
++            assert(vud->qi);
++            memset(vud->qi + vud->nqueues, 0,
++                   sizeof(vud->qi[0]) * (1 + (qidx - vud->nqueues)));
++            vud->nqueues = qidx + 1;
++        }
++        if (!vud->qi[qidx]) {
++            vud->qi[qidx] = calloc(sizeof(struct fv_QueueInfo), 1);
++            assert(vud->qi[qidx]);
++            vud->qi[qidx]->virtio_dev = vud;
++            vud->qi[qidx]->qidx = qidx;
++        } else {
++            /* Shouldn't have been started */
++            assert(vud->qi[qidx]->kick_fd == -1);
++        }
++        ourqi = vud->qi[qidx];
++        ourqi->kick_fd = dev->vq[qidx].kick_fd;
++        if (pthread_create(&ourqi->thread, NULL, fv_queue_thread, ourqi)) {
++            fuse_log(FUSE_LOG_ERR, "%s: Failed to create thread for queue %d\n",
++                     __func__, qidx);
++            assert(0);
++        }
++    } else {
++        /* TODO: Kill the thread */
++        assert(qidx < vud->nqueues);
++        ourqi = vud->qi[qidx];
++        ourqi->kick_fd = -1;
++    }
++}
++
+ static bool fv_queue_order(VuDev *dev, int qidx)
+ {
+     return false;
+@@ -92,6 +178,9 @@ static const VuDevIface fv_iface = {
+     .get_features = fv_get_features,
+     .set_features = fv_set_features,
+ 
++    /* Don't need process message, we've not got any at vhost-user level */
++    .queue_set_started = fv_queue_set_started,
++
+     .queue_is_processed_in_order = fv_queue_order,
+ };
+ 
diff --git a/0032-virtiofsd-Poll-kick_fd-for-queue.patch b/0032-virtiofsd-Poll-kick_fd-for-queue.patch
new file mode 100644
index 0000000..085ca83
--- /dev/null
+++ b/0032-virtiofsd-Poll-kick_fd-for-queue.patch
@@ -0,0 +1,81 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:01 +0000
+Subject: [PATCH] virtiofsd: Poll kick_fd for queue
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+In the queue thread poll the kick_fd we're passed.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 5dcd1f56141378226d33dc3df68ec57913e0aa04)
+---
+ tools/virtiofsd/fuse_virtio.c | 40 ++++++++++++++++++++++++++++++++++-
+ 1 file changed, 39 insertions(+), 1 deletion(-)
+
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+index 2a94bb3cca..05e7258712 100644
+--- a/tools/virtiofsd/fuse_virtio.c
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -24,6 +24,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <sys/eventfd.h>
+ #include <sys/socket.h>
+ #include <sys/types.h>
+ #include <sys/un.h>
+@@ -100,13 +101,50 @@ static void fv_panic(VuDev *dev, const char *err)
+     exit(EXIT_FAILURE);
+ }
+ 
++/* Thread function for individual queues, created when a queue is 'started' */
+ static void *fv_queue_thread(void *opaque)
+ {
+     struct fv_QueueInfo *qi = opaque;
+     fuse_log(FUSE_LOG_INFO, "%s: Start for queue %d kick_fd %d\n", __func__,
+              qi->qidx, qi->kick_fd);
+     while (1) {
+-        /* TODO */
++        struct pollfd pf[1];
++        pf[0].fd = qi->kick_fd;
++        pf[0].events = POLLIN;
++        pf[0].revents = 0;
++
++        fuse_log(FUSE_LOG_DEBUG, "%s: Waiting for Queue %d event\n", __func__,
++                 qi->qidx);
++        int poll_res = ppoll(pf, 1, NULL, NULL);
++
++        if (poll_res == -1) {
++            if (errno == EINTR) {
++                fuse_log(FUSE_LOG_INFO, "%s: ppoll interrupted, going around\n",
++                         __func__);
++                continue;
++            }
++            fuse_log(FUSE_LOG_ERR, "fv_queue_thread ppoll: %m\n");
++            break;
++        }
++        assert(poll_res == 1);
++        if (pf[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
++            fuse_log(FUSE_LOG_ERR, "%s: Unexpected poll revents %x Queue %d\n",
++                     __func__, pf[0].revents, qi->qidx);
++            break;
++        }
++        assert(pf[0].revents & POLLIN);
++        fuse_log(FUSE_LOG_DEBUG, "%s: Got queue event on Queue %d\n", __func__,
++                 qi->qidx);
++
++        eventfd_t evalue;
++        if (eventfd_read(qi->kick_fd, &evalue)) {
++            fuse_log(FUSE_LOG_ERR, "Eventfd_read for queue: %m\n");
++            break;
++        }
++        if (qi->virtio_dev->se->debug) {
++            fprintf(stderr, "%s: Queue %d gave evalue: %zx\n", __func__,
++                    qi->qidx, (size_t)evalue);
++        }
+     }
+ 
+     return NULL;
diff --git a/0033-virtiofsd-Start-reading-commands-from-queue.patch b/0033-virtiofsd-Start-reading-commands-from-queue.patch
new file mode 100644
index 0000000..8b652e5
--- /dev/null
+++ b/0033-virtiofsd-Start-reading-commands-from-queue.patch
@@ -0,0 +1,184 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:02 +0000
+Subject: [PATCH] virtiofsd: Start reading commands from queue
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Pop queue elements off queues, copy the data from them and
+pass that to fuse.
+
+  Note: 'out' in a VuVirtqElement is from QEMU
+        'in' in libfuse is into the daemon
+
+  So we read from the out iov's to get a fuse_in_header
+
+When we get a kick we've got to read all the elements until the queue
+is empty.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit b509e1228b3e5eb83c14819045988999fc2dbd1b)
+---
+ tools/virtiofsd/fuse_i.h      |  2 +
+ tools/virtiofsd/fuse_virtio.c | 99 +++++++++++++++++++++++++++++++++--
+ 2 files changed, 98 insertions(+), 3 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_i.h b/tools/virtiofsd/fuse_i.h
+index ec04449069..1126723d18 100644
+--- a/tools/virtiofsd/fuse_i.h
++++ b/tools/virtiofsd/fuse_i.h
+@@ -14,6 +14,7 @@
+ #include "fuse_lowlevel.h"
+ 
+ struct fv_VuDev;
++struct fv_QueueInfo;
+ 
+ struct fuse_req {
+     struct fuse_session *se;
+@@ -75,6 +76,7 @@ struct fuse_chan {
+     pthread_mutex_t lock;
+     int ctr;
+     int fd;
++    struct fv_QueueInfo *qi;
+ };
+ 
+ /**
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+index 05e7258712..3841b20129 100644
+--- a/tools/virtiofsd/fuse_virtio.c
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -12,6 +12,7 @@
+  */
+ 
+ #include "qemu/osdep.h"
++#include "qemu/iov.h"
+ #include "fuse_virtio.h"
+ #include "fuse_i.h"
+ #include "standard-headers/linux/fuse.h"
+@@ -32,6 +33,7 @@
+ 
+ #include "contrib/libvhost-user/libvhost-user.h"
+ 
++struct fv_VuDev;
+ struct fv_QueueInfo {
+     pthread_t thread;
+     struct fv_VuDev *virtio_dev;
+@@ -101,10 +103,41 @@ static void fv_panic(VuDev *dev, const char *err)
+     exit(EXIT_FAILURE);
+ }
+ 
++/*
++ * Copy from an iovec into a fuse_buf (memory only)
++ * Caller must ensure there is space
++ */
++static void copy_from_iov(struct fuse_buf *buf, size_t out_num,
++                          const struct iovec *out_sg)
++{
++    void *dest = buf->mem;
++
++    while (out_num) {
++        size_t onelen = out_sg->iov_len;
++        memcpy(dest, out_sg->iov_base, onelen);
++        dest += onelen;
++        out_sg++;
++        out_num--;
++    }
++}
++
+ /* Thread function for individual queues, created when a queue is 'started' */
+ static void *fv_queue_thread(void *opaque)
+ {
+     struct fv_QueueInfo *qi = opaque;
++    struct VuDev *dev = &qi->virtio_dev->dev;
++    struct VuVirtq *q = vu_get_queue(dev, qi->qidx);
++    struct fuse_session *se = qi->virtio_dev->se;
++    struct fuse_chan ch;
++    struct fuse_buf fbuf;
++
++    fbuf.mem = NULL;
++    fbuf.flags = 0;
++
++    fuse_mutex_init(&ch.lock);
++    ch.fd = (int)0xdaff0d111;
++    ch.qi = qi;
++
+     fuse_log(FUSE_LOG_INFO, "%s: Start for queue %d kick_fd %d\n", __func__,
+              qi->qidx, qi->kick_fd);
+     while (1) {
+@@ -141,11 +174,71 @@ static void *fv_queue_thread(void *opaque)
+             fuse_log(FUSE_LOG_ERR, "Eventfd_read for queue: %m\n");
+             break;
+         }
+-        if (qi->virtio_dev->se->debug) {
+-            fprintf(stderr, "%s: Queue %d gave evalue: %zx\n", __func__,
+-                    qi->qidx, (size_t)evalue);
++        /* out is from guest, in is too guest */
++        unsigned int in_bytes, out_bytes;
++        vu_queue_get_avail_bytes(dev, q, &in_bytes, &out_bytes, ~0, ~0);
++
++        fuse_log(FUSE_LOG_DEBUG,
++                 "%s: Queue %d gave evalue: %zx available: in: %u out: %u\n",
++                 __func__, qi->qidx, (size_t)evalue, in_bytes, out_bytes);
++
++        while (1) {
++            /*
++             * An element contains one request and the space to send our
++             * response They're spread over multiple descriptors in a
++             * scatter/gather set and we can't trust the guest to keep them
++             * still; so copy in/out.
++             */
++            VuVirtqElement *elem = vu_queue_pop(dev, q, sizeof(VuVirtqElement));
++            if (!elem) {
++                break;
++            }
++
++            if (!fbuf.mem) {
++                fbuf.mem = malloc(se->bufsize);
++                assert(fbuf.mem);
++                assert(se->bufsize > sizeof(struct fuse_in_header));
++            }
++            /* The 'out' part of the elem is from qemu */
++            unsigned int out_num = elem->out_num;
++            struct iovec *out_sg = elem->out_sg;
++            size_t out_len = iov_size(out_sg, out_num);
++            fuse_log(FUSE_LOG_DEBUG,
++                     "%s: elem %d: with %d out desc of length %zd\n", __func__,
++                     elem->index, out_num, out_len);
++
++            /*
++             * The elem should contain a 'fuse_in_header' (in to fuse)
++             * plus the data based on the len in the header.
++             */
++            if (out_len < sizeof(struct fuse_in_header)) {
++                fuse_log(FUSE_LOG_ERR, "%s: elem %d too short for in_header\n",
++                         __func__, elem->index);
++                assert(0); /* TODO */
++            }
++            if (out_len > se->bufsize) {
++                fuse_log(FUSE_LOG_ERR, "%s: elem %d too large for buffer\n",
++                         __func__, elem->index);
++                assert(0); /* TODO */
++            }
++            copy_from_iov(&fbuf, out_num, out_sg);
++            fbuf.size = out_len;
++
++            /* TODO! Endianness of header */
++
++            /* TODO: Fixup fuse_send_msg */
++            /* TODO: Add checks for fuse_session_exited */
++            fuse_session_process_buf_int(se, &fbuf, &ch);
++
++            /* TODO: vu_queue_push(dev, q, elem, qi->write_count); */
++            vu_queue_notify(dev, q);
++
++            free(elem);
++            elem = NULL;
+         }
+     }
++    pthread_mutex_destroy(&ch.lock);
++    free(fbuf.mem);
+ 
+     return NULL;
+ }
diff --git a/0034-virtiofsd-Send-replies-to-messages.patch b/0034-virtiofsd-Send-replies-to-messages.patch
new file mode 100644
index 0000000..66b9376
--- /dev/null
+++ b/0034-virtiofsd-Send-replies-to-messages.patch
@@ -0,0 +1,183 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:03 +0000
+Subject: [PATCH] virtiofsd: Send replies to messages
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Route fuse out messages back through the same queue elements
+that had the command that triggered the request.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit df57ba919ec3edef9cc208d35685095e6e92713e)
+---
+ tools/virtiofsd/fuse_lowlevel.c |   4 ++
+ tools/virtiofsd/fuse_virtio.c   | 107 ++++++++++++++++++++++++++++++--
+ tools/virtiofsd/fuse_virtio.h   |   4 ++
+ 3 files changed, 111 insertions(+), 4 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index af09fa2b94..380d93bd01 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -171,6 +171,10 @@ static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
+         }
+     }
+ 
++    if (fuse_lowlevel_is_virtio(se)) {
++        return virtio_send_msg(se, ch, iov, count);
++    }
++
+     abort(); /* virtio should have taken it before here */
+     return 0;
+ }
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+index 3841b20129..05d0e29f12 100644
+--- a/tools/virtiofsd/fuse_virtio.c
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -41,6 +41,9 @@ struct fv_QueueInfo {
+     /* Our queue index, corresponds to array position */
+     int qidx;
+     int kick_fd;
++
++    /* The element for the command currently being processed */
++    VuVirtqElement *qe;
+ };
+ 
+ /*
+@@ -121,6 +124,105 @@ static void copy_from_iov(struct fuse_buf *buf, size_t out_num,
+     }
+ }
+ 
++/*
++ * Copy from one iov to another, the given number of bytes
++ * The caller must have checked sizes.
++ */
++static void copy_iov(struct iovec *src_iov, int src_count,
++                     struct iovec *dst_iov, int dst_count, size_t to_copy)
++{
++    size_t dst_offset = 0;
++    /* Outer loop copies 'src' elements */
++    while (to_copy) {
++        assert(src_count);
++        size_t src_len = src_iov[0].iov_len;
++        size_t src_offset = 0;
++
++        if (src_len > to_copy) {
++            src_len = to_copy;
++        }
++        /* Inner loop copies contents of one 'src' to maybe multiple dst. */
++        while (src_len) {
++            assert(dst_count);
++            size_t dst_len = dst_iov[0].iov_len - dst_offset;
++            if (dst_len > src_len) {
++                dst_len = src_len;
++            }
++
++            memcpy(dst_iov[0].iov_base + dst_offset,
++                   src_iov[0].iov_base + src_offset, dst_len);
++            src_len -= dst_len;
++            to_copy -= dst_len;
++            src_offset += dst_len;
++            dst_offset += dst_len;
++
++            assert(dst_offset <= dst_iov[0].iov_len);
++            if (dst_offset == dst_iov[0].iov_len) {
++                dst_offset = 0;
++                dst_iov++;
++                dst_count--;
++            }
++        }
++        src_iov++;
++        src_count--;
++    }
++}
++
++/*
++ * Called back by ll whenever it wants to send a reply/message back
++ * The 1st element of the iov starts with the fuse_out_header
++ * 'unique'==0 means it's a notify message.
++ */
++int virtio_send_msg(struct fuse_session *se, struct fuse_chan *ch,
++                    struct iovec *iov, int count)
++{
++    VuVirtqElement *elem;
++    VuVirtq *q;
++
++    assert(count >= 1);
++    assert(iov[0].iov_len >= sizeof(struct fuse_out_header));
++
++    struct fuse_out_header *out = iov[0].iov_base;
++    /* TODO: Endianness! */
++
++    size_t tosend_len = iov_size(iov, count);
++
++    /* unique == 0 is notification, which we don't support */
++    assert(out->unique);
++    /* For virtio we always have ch */
++    assert(ch);
++    elem = ch->qi->qe;
++    q = &ch->qi->virtio_dev->dev.vq[ch->qi->qidx];
++
++    /* The 'in' part of the elem is to qemu */
++    unsigned int in_num = elem->in_num;
++    struct iovec *in_sg = elem->in_sg;
++    size_t in_len = iov_size(in_sg, in_num);
++    fuse_log(FUSE_LOG_DEBUG, "%s: elem %d: with %d in desc of length %zd\n",
++             __func__, elem->index, in_num, in_len);
++
++    /*
++     * The elem should have room for a 'fuse_out_header' (out from fuse)
++     * plus the data based on the len in the header.
++     */
++    if (in_len < sizeof(struct fuse_out_header)) {
++        fuse_log(FUSE_LOG_ERR, "%s: elem %d too short for out_header\n",
++                 __func__, elem->index);
++        return -E2BIG;
++    }
++    if (in_len < tosend_len) {
++        fuse_log(FUSE_LOG_ERR, "%s: elem %d too small for data len %zd\n",
++                 __func__, elem->index, tosend_len);
++        return -E2BIG;
++    }
++
++    copy_iov(iov, count, in_sg, in_num, tosend_len);
++    vu_queue_push(&se->virtio_dev->dev, q, elem, tosend_len);
++    vu_queue_notify(&se->virtio_dev->dev, q);
++
++    return 0;
++}
++
+ /* Thread function for individual queues, created when a queue is 'started' */
+ static void *fv_queue_thread(void *opaque)
+ {
+@@ -226,13 +328,10 @@ static void *fv_queue_thread(void *opaque)
+ 
+             /* TODO! Endianness of header */
+ 
+-            /* TODO: Fixup fuse_send_msg */
+             /* TODO: Add checks for fuse_session_exited */
+             fuse_session_process_buf_int(se, &fbuf, &ch);
+ 
+-            /* TODO: vu_queue_push(dev, q, elem, qi->write_count); */
+-            vu_queue_notify(dev, q);
+-
++            qi->qe = NULL;
+             free(elem);
+             elem = NULL;
+         }
+diff --git a/tools/virtiofsd/fuse_virtio.h b/tools/virtiofsd/fuse_virtio.h
+index 23026d6e4c..135a14875a 100644
+--- a/tools/virtiofsd/fuse_virtio.h
++++ b/tools/virtiofsd/fuse_virtio.h
+@@ -22,4 +22,8 @@ int virtio_session_mount(struct fuse_session *se);
+ 
+ int virtio_loop(struct fuse_session *se);
+ 
++
++int virtio_send_msg(struct fuse_session *se, struct fuse_chan *ch,
++                    struct iovec *iov, int count);
++
+ #endif
diff --git a/0035-virtiofsd-Keep-track-of-replies.patch b/0035-virtiofsd-Keep-track-of-replies.patch
new file mode 100644
index 0000000..874a16d
--- /dev/null
+++ b/0035-virtiofsd-Keep-track-of-replies.patch
@@ -0,0 +1,100 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:04 +0000
+Subject: [PATCH] virtiofsd: Keep track of replies
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Keep track of whether we sent a reply to a request; this is a bit
+paranoid but it means:
+  a) We should always recycle an element even if there was an error
+     in the request
+  b) Never try and send two replies on one queue element
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 2f65e69a7f22da8d20c747f34f339ebb40a0634f)
+---
+ tools/virtiofsd/fuse_virtio.c | 23 ++++++++++++++++++++---
+ 1 file changed, 20 insertions(+), 3 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+index 05d0e29f12..f1adeb6345 100644
+--- a/tools/virtiofsd/fuse_virtio.c
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -44,6 +44,7 @@ struct fv_QueueInfo {
+ 
+     /* The element for the command currently being processed */
+     VuVirtqElement *qe;
++    bool reply_sent;
+ };
+ 
+ /*
+@@ -178,6 +179,7 @@ int virtio_send_msg(struct fuse_session *se, struct fuse_chan *ch,
+ {
+     VuVirtqElement *elem;
+     VuVirtq *q;
++    int ret = 0;
+ 
+     assert(count >= 1);
+     assert(iov[0].iov_len >= sizeof(struct fuse_out_header));
+@@ -191,6 +193,7 @@ int virtio_send_msg(struct fuse_session *se, struct fuse_chan *ch,
+     assert(out->unique);
+     /* For virtio we always have ch */
+     assert(ch);
++    assert(!ch->qi->reply_sent);
+     elem = ch->qi->qe;
+     q = &ch->qi->virtio_dev->dev.vq[ch->qi->qidx];
+ 
+@@ -208,19 +211,23 @@ int virtio_send_msg(struct fuse_session *se, struct fuse_chan *ch,
+     if (in_len < sizeof(struct fuse_out_header)) {
+         fuse_log(FUSE_LOG_ERR, "%s: elem %d too short for out_header\n",
+                  __func__, elem->index);
+-        return -E2BIG;
++        ret = -E2BIG;
++        goto err;
+     }
+     if (in_len < tosend_len) {
+         fuse_log(FUSE_LOG_ERR, "%s: elem %d too small for data len %zd\n",
+                  __func__, elem->index, tosend_len);
+-        return -E2BIG;
++        ret = -E2BIG;
++        goto err;
+     }
+ 
+     copy_iov(iov, count, in_sg, in_num, tosend_len);
+     vu_queue_push(&se->virtio_dev->dev, q, elem, tosend_len);
+     vu_queue_notify(&se->virtio_dev->dev, q);
++    ch->qi->reply_sent = true;
+ 
+-    return 0;
++err:
++    return ret;
+ }
+ 
+ /* Thread function for individual queues, created when a queue is 'started' */
+@@ -296,6 +303,9 @@ static void *fv_queue_thread(void *opaque)
+                 break;
+             }
+ 
++            qi->qe = elem;
++            qi->reply_sent = false;
++
+             if (!fbuf.mem) {
+                 fbuf.mem = malloc(se->bufsize);
+                 assert(fbuf.mem);
+@@ -331,6 +341,13 @@ static void *fv_queue_thread(void *opaque)
+             /* TODO: Add checks for fuse_session_exited */
+             fuse_session_process_buf_int(se, &fbuf, &ch);
+ 
++            if (!qi->reply_sent) {
++                fuse_log(FUSE_LOG_DEBUG, "%s: elem %d no reply sent\n",
++                         __func__, elem->index);
++                /* I think we've still got to recycle the element */
++                vu_queue_push(dev, q, elem, 0);
++                vu_queue_notify(dev, q);
++            }
+             qi->qe = NULL;
+             free(elem);
+             elem = NULL;
diff --git a/0036-virtiofsd-Add-Makefile-wiring-for-virtiofsd-contrib.patch b/0036-virtiofsd-Add-Makefile-wiring-for-virtiofsd-contrib.patch
new file mode 100644
index 0000000..a52d5dd
--- /dev/null
+++ b/0036-virtiofsd-Add-Makefile-wiring-for-virtiofsd-contrib.patch
@@ -0,0 +1,90 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:05 +0000
+Subject: [PATCH] virtiofsd: Add Makefile wiring for virtiofsd contrib
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Wire up the building of the virtiofsd in tools.
+
+virtiofsd relies on Linux-specific system calls and seccomp.  Anyone
+wishing to port it to other host operating systems should do so
+carefully and without reducing security.
+
+Only allow building on Linux hosts.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Liam Merwick <liam.merwick@oracle.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 81bfc42dcf473bc8d3790622633410da72d8e622)
+---
+ Makefile                      | 10 ++++++++++
+ Makefile.objs                 |  1 +
+ tools/virtiofsd/Makefile.objs |  9 +++++++++
+ 3 files changed, 20 insertions(+)
+ create mode 100644 tools/virtiofsd/Makefile.objs
+
+diff --git a/Makefile b/Makefile
+index b437a346d7..10fd31e705 100644
+--- a/Makefile
++++ b/Makefile
+@@ -330,6 +330,10 @@ endif
+ endif
+ endif
+ 
++ifdef CONFIG_LINUX
++HELPERS-y += virtiofsd$(EXESUF)
++endif
++
+ # Sphinx does not allow building manuals into the same directory as
+ # the source files, so if we're doing an in-tree QEMU build we must
+ # build the manuals into a subdirectory (and then install them from
+@@ -430,6 +434,7 @@ dummy := $(call unnest-vars,, \
+                 elf2dmp-obj-y \
+                 ivshmem-client-obj-y \
+                 ivshmem-server-obj-y \
++                virtiofsd-obj-y \
+                 rdmacm-mux-obj-y \
+                 libvhost-user-obj-y \
+                 vhost-user-scsi-obj-y \
+@@ -674,6 +679,11 @@ rdmacm-mux$(EXESUF): LIBS += "-libumad"
+ rdmacm-mux$(EXESUF): $(rdmacm-mux-obj-y) $(COMMON_LDADDS)
+ 	$(call LINK, $^)
+ 
++ifdef CONFIG_LINUX # relies on Linux-specific syscalls
++virtiofsd$(EXESUF): $(virtiofsd-obj-y) libvhost-user.a $(COMMON_LDADDS)
++	$(call LINK, $^)
++endif
++
+ vhost-user-gpu$(EXESUF): $(vhost-user-gpu-obj-y) $(libvhost-user-obj-y) libqemuutil.a libqemustub.a
+ 	$(call LINK, $^)
+ 
+diff --git a/Makefile.objs b/Makefile.objs
+index 11ba1a36bd..b5f667a4ba 100644
+--- a/Makefile.objs
++++ b/Makefile.objs
+@@ -125,6 +125,7 @@ vhost-user-blk-obj-y = contrib/vhost-user-blk/
+ rdmacm-mux-obj-y = contrib/rdmacm-mux/
+ vhost-user-input-obj-y = contrib/vhost-user-input/
+ vhost-user-gpu-obj-y = contrib/vhost-user-gpu/
++virtiofsd-obj-y = tools/virtiofsd/
+ 
+ ######################################################################
+ trace-events-subdirs =
+diff --git a/tools/virtiofsd/Makefile.objs b/tools/virtiofsd/Makefile.objs
+new file mode 100644
+index 0000000000..45a807500d
+--- /dev/null
++++ b/tools/virtiofsd/Makefile.objs
+@@ -0,0 +1,9 @@
++virtiofsd-obj-y = buffer.o \
++                  fuse_opt.o \
++                  fuse_log.o \
++                  fuse_lowlevel.o \
++                  fuse_signals.o \
++                  fuse_virtio.o \
++                  helper.o \
++                  passthrough_ll.o
++
diff --git a/0037-virtiofsd-Fast-path-for-virtio-read.patch b/0037-virtiofsd-Fast-path-for-virtio-read.patch
new file mode 100644
index 0000000..200f1da
--- /dev/null
+++ b/0037-virtiofsd-Fast-path-for-virtio-read.patch
@@ -0,0 +1,220 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:06 +0000
+Subject: [PATCH] virtiofsd: Fast path for virtio read
+
+Readv the data straight into the guests buffer.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+With fix by:
+Signed-off-by: Eryu Guan <eguan@linux.alibaba.com>
+Reviewed-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit eb49d187ef5134483a34c970bbfece28aaa686a7)
+---
+ tools/virtiofsd/fuse_lowlevel.c |   5 +
+ tools/virtiofsd/fuse_virtio.c   | 162 ++++++++++++++++++++++++++++++++
+ tools/virtiofsd/fuse_virtio.h   |   4 +
+ 3 files changed, 171 insertions(+)
+
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 380d93bd01..4f4684d942 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -475,6 +475,11 @@ static int fuse_send_data_iov_fallback(struct fuse_session *se,
+         return fuse_send_msg(se, ch, iov, iov_count);
+     }
+ 
++    if (fuse_lowlevel_is_virtio(se) && buf->count == 1 &&
++        buf->buf[0].flags == (FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK)) {
++        return virtio_send_data_iov(se, ch, iov, iov_count, buf, len);
++    }
++
+     abort(); /* Will have taken vhost path */
+     return 0;
+ }
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+index f1adeb6345..7e2711b504 100644
+--- a/tools/virtiofsd/fuse_virtio.c
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -230,6 +230,168 @@ err:
+     return ret;
+ }
+ 
++/*
++ * Callback from fuse_send_data_iov_* when it's virtio and the buffer
++ * is a single FD with FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK
++ * We need send the iov and then the buffer.
++ * Return 0 on success
++ */
++int virtio_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
++                         struct iovec *iov, int count, struct fuse_bufvec *buf,
++                         size_t len)
++{
++    int ret = 0;
++    VuVirtqElement *elem;
++    VuVirtq *q;
++
++    assert(count >= 1);
++    assert(iov[0].iov_len >= sizeof(struct fuse_out_header));
++
++    struct fuse_out_header *out = iov[0].iov_base;
++    /* TODO: Endianness! */
++
++    size_t iov_len = iov_size(iov, count);
++    size_t tosend_len = iov_len + len;
++
++    out->len = tosend_len;
++
++    fuse_log(FUSE_LOG_DEBUG, "%s: count=%d len=%zd iov_len=%zd\n", __func__,
++             count, len, iov_len);
++
++    /* unique == 0 is notification which we don't support */
++    assert(out->unique);
++
++    /* For virtio we always have ch */
++    assert(ch);
++    assert(!ch->qi->reply_sent);
++    elem = ch->qi->qe;
++    q = &ch->qi->virtio_dev->dev.vq[ch->qi->qidx];
++
++    /* The 'in' part of the elem is to qemu */
++    unsigned int in_num = elem->in_num;
++    struct iovec *in_sg = elem->in_sg;
++    size_t in_len = iov_size(in_sg, in_num);
++    fuse_log(FUSE_LOG_DEBUG, "%s: elem %d: with %d in desc of length %zd\n",
++             __func__, elem->index, in_num, in_len);
++
++    /*
++     * The elem should have room for a 'fuse_out_header' (out from fuse)
++     * plus the data based on the len in the header.
++     */
++    if (in_len < sizeof(struct fuse_out_header)) {
++        fuse_log(FUSE_LOG_ERR, "%s: elem %d too short for out_header\n",
++                 __func__, elem->index);
++        ret = E2BIG;
++        goto err;
++    }
++    if (in_len < tosend_len) {
++        fuse_log(FUSE_LOG_ERR, "%s: elem %d too small for data len %zd\n",
++                 __func__, elem->index, tosend_len);
++        ret = E2BIG;
++        goto err;
++    }
++
++    /* TODO: Limit to 'len' */
++
++    /* First copy the header data from iov->in_sg */
++    copy_iov(iov, count, in_sg, in_num, iov_len);
++
++    /*
++     * Build a copy of the the in_sg iov so we can skip bits in it,
++     * including changing the offsets
++     */
++    struct iovec *in_sg_cpy = calloc(sizeof(struct iovec), in_num);
++    assert(in_sg_cpy);
++    memcpy(in_sg_cpy, in_sg, sizeof(struct iovec) * in_num);
++    /* These get updated as we skip */
++    struct iovec *in_sg_ptr = in_sg_cpy;
++    int in_sg_cpy_count = in_num;
++
++    /* skip over parts of in_sg that contained the header iov */
++    size_t skip_size = iov_len;
++
++    size_t in_sg_left = 0;
++    do {
++        while (skip_size != 0 && in_sg_cpy_count) {
++            if (skip_size >= in_sg_ptr[0].iov_len) {
++                skip_size -= in_sg_ptr[0].iov_len;
++                in_sg_ptr++;
++                in_sg_cpy_count--;
++            } else {
++                in_sg_ptr[0].iov_len -= skip_size;
++                in_sg_ptr[0].iov_base += skip_size;
++                break;
++            }
++        }
++
++        int i;
++        for (i = 0, in_sg_left = 0; i < in_sg_cpy_count; i++) {
++            in_sg_left += in_sg_ptr[i].iov_len;
++        }
++        fuse_log(FUSE_LOG_DEBUG,
++                 "%s: after skip skip_size=%zd in_sg_cpy_count=%d "
++                 "in_sg_left=%zd\n",
++                 __func__, skip_size, in_sg_cpy_count, in_sg_left);
++        ret = preadv(buf->buf[0].fd, in_sg_ptr, in_sg_cpy_count,
++                     buf->buf[0].pos);
++
++        if (ret == -1) {
++            ret = errno;
++            fuse_log(FUSE_LOG_DEBUG, "%s: preadv failed (%m) len=%zd\n",
++                     __func__, len);
++            free(in_sg_cpy);
++            goto err;
++        }
++        fuse_log(FUSE_LOG_DEBUG, "%s: preadv ret=%d len=%zd\n", __func__,
++                 ret, len);
++        if (ret < len && ret) {
++            fuse_log(FUSE_LOG_DEBUG, "%s: ret < len\n", __func__);
++            /* Skip over this much next time around */
++            skip_size = ret;
++            buf->buf[0].pos += ret;
++            len -= ret;
++
++            /* Lets do another read */
++            continue;
++        }
++        if (!ret) {
++            /* EOF case? */
++            fuse_log(FUSE_LOG_DEBUG, "%s: !ret in_sg_left=%zd\n", __func__,
++                     in_sg_left);
++            break;
++        }
++        if (ret != len) {
++            fuse_log(FUSE_LOG_DEBUG, "%s: ret!=len\n", __func__);
++            ret = EIO;
++            free(in_sg_cpy);
++            goto err;
++        }
++        in_sg_left -= ret;
++        len -= ret;
++    } while (in_sg_left);
++    free(in_sg_cpy);
++
++    /* Need to fix out->len on EOF */
++    if (len) {
++        struct fuse_out_header *out_sg = in_sg[0].iov_base;
++
++        tosend_len -= len;
++        out_sg->len = tosend_len;
++    }
++
++    ret = 0;
++
++    vu_queue_push(&se->virtio_dev->dev, q, elem, tosend_len);
++    vu_queue_notify(&se->virtio_dev->dev, q);
++
++err:
++    if (ret == 0) {
++        ch->qi->reply_sent = true;
++    }
++
++    return ret;
++}
++
+ /* Thread function for individual queues, created when a queue is 'started' */
+ static void *fv_queue_thread(void *opaque)
+ {
+diff --git a/tools/virtiofsd/fuse_virtio.h b/tools/virtiofsd/fuse_virtio.h
+index 135a14875a..cc676b9193 100644
+--- a/tools/virtiofsd/fuse_virtio.h
++++ b/tools/virtiofsd/fuse_virtio.h
+@@ -26,4 +26,8 @@ int virtio_loop(struct fuse_session *se);
+ int virtio_send_msg(struct fuse_session *se, struct fuse_chan *ch,
+                     struct iovec *iov, int count);
+ 
++int virtio_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
++                         struct iovec *iov, int count,
++                         struct fuse_bufvec *buf, size_t len);
++
+ #endif
diff --git a/0038-virtiofsd-add-fd-FDNUM-fd-passing-option.patch b/0038-virtiofsd-add-fd-FDNUM-fd-passing-option.patch
new file mode 100644
index 0000000..2947b73
--- /dev/null
+++ b/0038-virtiofsd-add-fd-FDNUM-fd-passing-option.patch
@@ -0,0 +1,154 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:07 +0000
+Subject: [PATCH] virtiofsd: add --fd=FDNUM fd passing option
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Although --socket-path=PATH is useful for manual invocations, management
+tools typically create the UNIX domain socket themselves and pass it to
+the vhost-user device backend.  This way QEMU can be launched
+immediately with a valid socket.  No waiting for the vhost-user device
+backend is required when fd passing is used.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit cee8e35d4386e34bf79c3ca2aab7f7b1bb48cf8d)
+---
+ tools/virtiofsd/fuse_i.h        |  1 +
+ tools/virtiofsd/fuse_lowlevel.c | 16 ++++++++++++----
+ tools/virtiofsd/fuse_virtio.c   | 31 +++++++++++++++++++++++++------
+ 3 files changed, 38 insertions(+), 10 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_i.h b/tools/virtiofsd/fuse_i.h
+index 1126723d18..45995f3246 100644
+--- a/tools/virtiofsd/fuse_i.h
++++ b/tools/virtiofsd/fuse_i.h
+@@ -68,6 +68,7 @@ struct fuse_session {
+     size_t bufsize;
+     int error;
+     char *vu_socket_path;
++    int   vu_listen_fd;
+     int   vu_socketfd;
+     struct fv_VuDev *virtio_dev;
+ };
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 4f4684d942..95f4db8fcf 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -2130,6 +2130,7 @@ static const struct fuse_opt fuse_ll_opts[] = {
+     LL_OPTION("--debug", debug, 1),
+     LL_OPTION("allow_root", deny_others, 1),
+     LL_OPTION("--socket-path=%s", vu_socket_path, 0),
++    LL_OPTION("--fd=%d", vu_listen_fd, 0),
+     FUSE_OPT_END
+ };
+ 
+@@ -2147,7 +2148,8 @@ void fuse_lowlevel_help(void)
+      */
+     printf(
+         "    -o allow_root              allow access by root\n"
+-        "    --socket-path=PATH         path for the vhost-user socket\n");
++        "    --socket-path=PATH         path for the vhost-user socket\n"
++        "    --fd=FDNUM                 fd number of vhost-user socket\n");
+ }
+ 
+ void fuse_session_destroy(struct fuse_session *se)
+@@ -2191,6 +2193,7 @@ struct fuse_session *fuse_session_new(struct fuse_args *args,
+         goto out1;
+     }
+     se->fd = -1;
++    se->vu_listen_fd = -1;
+     se->conn.max_write = UINT_MAX;
+     se->conn.max_readahead = UINT_MAX;
+ 
+@@ -2212,8 +2215,13 @@ struct fuse_session *fuse_session_new(struct fuse_args *args,
+         goto out4;
+     }
+ 
+-    if (!se->vu_socket_path) {
+-        fprintf(stderr, "fuse: missing -o vhost_user_socket option\n");
++    if (!se->vu_socket_path && se->vu_listen_fd < 0) {
++        fuse_log(FUSE_LOG_ERR, "fuse: missing --socket-path or --fd option\n");
++        goto out4;
++    }
++    if (se->vu_socket_path && se->vu_listen_fd >= 0) {
++        fuse_log(FUSE_LOG_ERR,
++                 "fuse: --socket-path and --fd cannot be given together\n");
+         goto out4;
+     }
+ 
+@@ -2253,7 +2261,7 @@ void fuse_session_unmount(struct fuse_session *se)
+ 
+ int fuse_lowlevel_is_virtio(struct fuse_session *se)
+ {
+-    return se->vu_socket_path != NULL;
++    return !!se->virtio_dev;
+ }
+ 
+ #ifdef linux
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+index 7e2711b504..635f87756a 100644
+--- a/tools/virtiofsd/fuse_virtio.c
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -638,18 +638,21 @@ int virtio_loop(struct fuse_session *se)
+     return 0;
+ }
+ 
+-int virtio_session_mount(struct fuse_session *se)
++static int fv_create_listen_socket(struct fuse_session *se)
+ {
+     struct sockaddr_un un;
+     mode_t old_umask;
+ 
++    /* Nothing to do if fd is already initialized */
++    if (se->vu_listen_fd >= 0) {
++        return 0;
++    }
++
+     if (strlen(se->vu_socket_path) >= sizeof(un.sun_path)) {
+         fuse_log(FUSE_LOG_ERR, "Socket path too long\n");
+         return -1;
+     }
+ 
+-    se->fd = -1;
+-
+     /*
+      * Create the Unix socket to communicate with qemu
+      * based on QEMU's vhost-user-bridge
+@@ -682,15 +685,31 @@ int virtio_session_mount(struct fuse_session *se)
+         return -1;
+     }
+ 
++    se->vu_listen_fd = listen_sock;
++    return 0;
++}
++
++int virtio_session_mount(struct fuse_session *se)
++{
++    int ret;
++
++    ret = fv_create_listen_socket(se);
++    if (ret < 0) {
++        return ret;
++    }
++
++    se->fd = -1;
++
+     fuse_log(FUSE_LOG_INFO, "%s: Waiting for vhost-user socket connection...\n",
+              __func__);
+-    int data_sock = accept(listen_sock, NULL, NULL);
++    int data_sock = accept(se->vu_listen_fd, NULL, NULL);
+     if (data_sock == -1) {
+         fuse_log(FUSE_LOG_ERR, "vhost socket accept: %m\n");
+-        close(listen_sock);
++        close(se->vu_listen_fd);
+         return -1;
+     }
+-    close(listen_sock);
++    close(se->vu_listen_fd);
++    se->vu_listen_fd = -1;
+     fuse_log(FUSE_LOG_INFO, "%s: Received vhost-user socket connection\n",
+              __func__);
+ 
diff --git a/0039-virtiofsd-make-f-foreground-the-default.patch b/0039-virtiofsd-make-f-foreground-the-default.patch
new file mode 100644
index 0000000..2712afc
--- /dev/null
+++ b/0039-virtiofsd-make-f-foreground-the-default.patch
@@ -0,0 +1,60 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:08 +0000
+Subject: [PATCH] virtiofsd: make -f (foreground) the default
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+According to vhost-user.rst "Backend program conventions", backend
+programs should run in the foregound by default.  Follow the
+conventions so libvirt and other management tools can control virtiofsd
+in a standard way.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 0bbd31753714ac2899efda0f0de31e353e965789)
+---
+ tools/virtiofsd/helper.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
+index 676032e71f..a3645fc807 100644
+--- a/tools/virtiofsd/helper.c
++++ b/tools/virtiofsd/helper.c
+@@ -29,6 +29,11 @@
+     {                                               \
+         t, offsetof(struct fuse_cmdline_opts, p), 1 \
+     }
++#define FUSE_HELPER_OPT_VALUE(t, p, v)              \
++    {                                               \
++        t, offsetof(struct fuse_cmdline_opts, p), v \
++    }
++
+ 
+ static const struct fuse_opt fuse_helper_opts[] = {
+     FUSE_HELPER_OPT("-h", show_help),
+@@ -42,6 +47,7 @@ static const struct fuse_opt fuse_helper_opts[] = {
+     FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
+     FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
+     FUSE_HELPER_OPT("-f", foreground),
++    FUSE_HELPER_OPT_VALUE("--daemonize", foreground, 0),
+     FUSE_HELPER_OPT("fsname=", nodefault_subtype),
+     FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP),
+     FUSE_HELPER_OPT("subtype=", nodefault_subtype),
+@@ -131,6 +137,7 @@ void fuse_cmdline_help(void)
+            "    -V   --version             print version\n"
+            "    -d   -o debug              enable debug output (implies -f)\n"
+            "    -f                         foreground operation\n"
++           "    --daemonize                run in background\n"
+            "    -o max_idle_threads        the maximum number of idle worker "
+            "threads\n"
+            "                               allowed (default: 10)\n");
+@@ -158,6 +165,7 @@ int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts)
+     memset(opts, 0, sizeof(struct fuse_cmdline_opts));
+ 
+     opts->max_idle_threads = 10;
++    opts->foreground = 1;
+ 
+     if (fuse_opt_parse(args, opts, fuse_helper_opts, fuse_helper_opt_proc) ==
+         -1) {
diff --git a/0040-virtiofsd-add-vhost-user.json-file.patch b/0040-virtiofsd-add-vhost-user.json-file.patch
new file mode 100644
index 0000000..0af1555
--- /dev/null
+++ b/0040-virtiofsd-add-vhost-user.json-file.patch
@@ -0,0 +1,57 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:09 +0000
+Subject: [PATCH] virtiofsd: add vhost-user.json file
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Install a vhost-user.json file describing virtiofsd.  This allows
+libvirt and other management tools to enumerate vhost-user backend
+programs.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 315616ed50ba15a5d7236ade8a402a93898202de)
+---
+ .gitignore                                | 1 +
+ Makefile                                  | 1 +
+ tools/virtiofsd/50-qemu-virtiofsd.json.in | 5 +++++
+ 3 files changed, 7 insertions(+)
+ create mode 100644 tools/virtiofsd/50-qemu-virtiofsd.json.in
+
+diff --git a/.gitignore b/.gitignore
+index 7de868d1ea..c56ec1d122 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -6,6 +6,7 @@
+ /config-target.*
+ /config.status
+ /config-temp
++/tools/virtiofsd/50-qemu-virtiofsd.json
+ /elf2dmp
+ /trace-events-all
+ /trace/generated-events.h
+diff --git a/Makefile b/Makefile
+index 10fd31e705..aebb57aed8 100644
+--- a/Makefile
++++ b/Makefile
+@@ -332,6 +332,7 @@ endif
+ 
+ ifdef CONFIG_LINUX
+ HELPERS-y += virtiofsd$(EXESUF)
++vhost-user-json-y += tools/virtiofsd/50-qemu-virtiofsd.json
+ endif
+ 
+ # Sphinx does not allow building manuals into the same directory as
+diff --git a/tools/virtiofsd/50-qemu-virtiofsd.json.in b/tools/virtiofsd/50-qemu-virtiofsd.json.in
+new file mode 100644
+index 0000000000..9bcd86f8dc
+--- /dev/null
++++ b/tools/virtiofsd/50-qemu-virtiofsd.json.in
+@@ -0,0 +1,5 @@
++{
++  "description": "QEMU virtiofsd vhost-user-fs",
++  "type": "fs",
++  "binary": "@libexecdir@/virtiofsd"
++}
diff --git a/0041-virtiofsd-add-print-capabilities-option.patch b/0041-virtiofsd-add-print-capabilities-option.patch
new file mode 100644
index 0000000..f7bd267
--- /dev/null
+++ b/0041-virtiofsd-add-print-capabilities-option.patch
@@ -0,0 +1,105 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:10 +0000
+Subject: [PATCH] virtiofsd: add --print-capabilities option
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add the --print-capabilities option as per vhost-user.rst "Backend
+programs conventions".  Currently there are no advertised features.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 45018fbb0a73ce66fd3dd87ecd2872b45658add4)
+---
+ docs/interop/vhost-user.json     |  4 +++-
+ tools/virtiofsd/fuse_lowlevel.h  |  1 +
+ tools/virtiofsd/helper.c         |  2 ++
+ tools/virtiofsd/passthrough_ll.c | 12 ++++++++++++
+ 4 files changed, 18 insertions(+), 1 deletion(-)
+
+diff --git a/docs/interop/vhost-user.json b/docs/interop/vhost-user.json
+index da6aaf51c8..d4ea1f7ac5 100644
+--- a/docs/interop/vhost-user.json
++++ b/docs/interop/vhost-user.json
+@@ -31,6 +31,7 @@
+ # @rproc-serial: virtio remoteproc serial link
+ # @scsi: virtio scsi
+ # @vsock: virtio vsock transport
++# @fs: virtio fs (since 4.2)
+ #
+ # Since: 4.0
+ ##
+@@ -50,7 +51,8 @@
+       'rpmsg',
+       'rproc-serial',
+       'scsi',
+-      'vsock'
++      'vsock',
++      'fs'
+   ]
+ }
+ 
+diff --git a/tools/virtiofsd/fuse_lowlevel.h b/tools/virtiofsd/fuse_lowlevel.h
+index f6b34700af..0d61df8110 100644
+--- a/tools/virtiofsd/fuse_lowlevel.h
++++ b/tools/virtiofsd/fuse_lowlevel.h
+@@ -1794,6 +1794,7 @@ struct fuse_cmdline_opts {
+     int nodefault_subtype;
+     int show_version;
+     int show_help;
++    int print_capabilities;
+     unsigned int max_idle_threads;
+ };
+ 
+diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
+index a3645fc807..b8ec5ac8dc 100644
+--- a/tools/virtiofsd/helper.c
++++ b/tools/virtiofsd/helper.c
+@@ -40,6 +40,7 @@ static const struct fuse_opt fuse_helper_opts[] = {
+     FUSE_HELPER_OPT("--help", show_help),
+     FUSE_HELPER_OPT("-V", show_version),
+     FUSE_HELPER_OPT("--version", show_version),
++    FUSE_HELPER_OPT("--print-capabilities", print_capabilities),
+     FUSE_HELPER_OPT("-d", debug),
+     FUSE_HELPER_OPT("debug", debug),
+     FUSE_HELPER_OPT("-d", foreground),
+@@ -135,6 +136,7 @@ void fuse_cmdline_help(void)
+ {
+     printf("    -h   --help                print help\n"
+            "    -V   --version             print version\n"
++           "    --print-capabilities       print vhost-user.json\n"
+            "    -d   -o debug              enable debug output (implies -f)\n"
+            "    -f                         foreground operation\n"
+            "    --daemonize                run in background\n"
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 037c5d7b26..cd27c09f59 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -1298,6 +1298,14 @@ static struct fuse_lowlevel_ops lo_oper = {
+     .lseek = lo_lseek,
+ };
+ 
++/* Print vhost-user.json backend program capabilities */
++static void print_capabilities(void)
++{
++    printf("{\n");
++    printf("  \"type\": \"fs\"\n");
++    printf("}\n");
++}
++
+ int main(int argc, char *argv[])
+ {
+     struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+@@ -1328,6 +1336,10 @@ int main(int argc, char *argv[])
+         fuse_lowlevel_version();
+         ret = 0;
+         goto err_out1;
++    } else if (opts.print_capabilities) {
++        print_capabilities();
++        ret = 0;
++        goto err_out1;
+     }
+ 
+     if (fuse_opt_parse(&args, &lo, lo_opts, NULL) == -1) {
diff --git a/0042-virtiofs-Add-maintainers-entry.patch b/0042-virtiofs-Add-maintainers-entry.patch
new file mode 100644
index 0000000..224e64b
--- /dev/null
+++ b/0042-virtiofs-Add-maintainers-entry.patch
@@ -0,0 +1,36 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:11 +0000
+Subject: [PATCH] virtiofs: Add maintainers entry
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit bad7d2c3ad1af9344df035aedaf8e0967a543070)
+---
+ MAINTAINERS | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 5e5e3e52d6..d1b3e262d2 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -1575,6 +1575,14 @@ T: git https://github.com/cohuck/qemu.git s390-next
+ T: git https://github.com/borntraeger/qemu.git s390-next
+ L: qemu-s390x@nongnu.org
+ 
++virtiofs
++M: Dr. David Alan Gilbert <dgilbert@redhat.com>
++M: Stefan Hajnoczi <stefanha@redhat.com>
++S: Supported
++F: tools/virtiofsd/*
++F: hw/virtio/vhost-user-fs*
++F: include/hw/virtio/vhost-user-fs.h
++
+ virtio-input
+ M: Gerd Hoffmann <kraxel@redhat.com>
+ S: Maintained
diff --git a/0043-virtiofsd-passthrough_ll-create-new-files-in-caller-.patch b/0043-virtiofsd-passthrough_ll-create-new-files-in-caller-.patch
new file mode 100644
index 0000000..9412335
--- /dev/null
+++ b/0043-virtiofsd-passthrough_ll-create-new-files-in-caller-.patch
@@ -0,0 +1,179 @@
+From: Vivek Goyal <vgoyal@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:12 +0000
+Subject: [PATCH] virtiofsd: passthrough_ll: create new files in caller's
+ context
+
+We need to create files in the caller's context. Otherwise after
+creating a file, the caller might not be able to do file operations on
+that file.
+
+Changed effective uid/gid to caller's uid/gid, create file and then
+switch back to uid/gid 0.
+
+Use syscall(setresuid, ...) otherwise glibc does some magic to change EUID
+in all threads, which is not what we want.
+
+Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 929cfb7a9a1b101cdfc9ac19807ecab4c81a13e4)
+---
+ tools/virtiofsd/passthrough_ll.c | 96 ++++++++++++++++++++++++++++++--
+ 1 file changed, 91 insertions(+), 5 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index cd27c09f59..5e061797d4 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -50,6 +50,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <sys/file.h>
++#include <sys/syscall.h>
+ #include <sys/xattr.h>
+ #include <unistd.h>
+ 
+@@ -83,6 +84,11 @@ struct lo_inode {
+     uint64_t refcount; /* protected by lo->mutex */
+ };
+ 
++struct lo_cred {
++    uid_t euid;
++    gid_t egid;
++};
++
+ enum {
+     CACHE_NEVER,
+     CACHE_NORMAL,
+@@ -383,6 +389,69 @@ static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
+     }
+ }
+ 
++/*
++ * On some archs, setres*id is limited to 2^16 but they
++ * provide setres*id32 variants that allow 2^32.
++ * Others just let setres*id do 2^32 anyway.
++ */
++#ifdef SYS_setresgid32
++#define OURSYS_setresgid SYS_setresgid32
++#else
++#define OURSYS_setresgid SYS_setresgid
++#endif
++
++#ifdef SYS_setresuid32
++#define OURSYS_setresuid SYS_setresuid32
++#else
++#define OURSYS_setresuid SYS_setresuid
++#endif
++
++/*
++ * Change to uid/gid of caller so that file is created with
++ * ownership of caller.
++ * TODO: What about selinux context?
++ */
++static int lo_change_cred(fuse_req_t req, struct lo_cred *old)
++{
++    int res;
++
++    old->euid = geteuid();
++    old->egid = getegid();
++
++    res = syscall(OURSYS_setresgid, -1, fuse_req_ctx(req)->gid, -1);
++    if (res == -1) {
++        return errno;
++    }
++
++    res = syscall(OURSYS_setresuid, -1, fuse_req_ctx(req)->uid, -1);
++    if (res == -1) {
++        int errno_save = errno;
++
++        syscall(OURSYS_setresgid, -1, old->egid, -1);
++        return errno_save;
++    }
++
++    return 0;
++}
++
++/* Regain Privileges */
++static void lo_restore_cred(struct lo_cred *old)
++{
++    int res;
++
++    res = syscall(OURSYS_setresuid, -1, old->euid, -1);
++    if (res == -1) {
++        fuse_log(FUSE_LOG_ERR, "seteuid(%u): %m\n", old->euid);
++        exit(1);
++    }
++
++    res = syscall(OURSYS_setresgid, -1, old->egid, -1);
++    if (res == -1) {
++        fuse_log(FUSE_LOG_ERR, "setegid(%u): %m\n", old->egid);
++        exit(1);
++    }
++}
++
+ static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent,
+                              const char *name, mode_t mode, dev_t rdev,
+                              const char *link)
+@@ -391,12 +460,21 @@ static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent,
+     int saverr;
+     struct lo_inode *dir = lo_inode(req, parent);
+     struct fuse_entry_param e;
++    struct lo_cred old = {};
+ 
+     saverr = ENOMEM;
+ 
++    saverr = lo_change_cred(req, &old);
++    if (saverr) {
++        goto out;
++    }
++
+     res = mknod_wrapper(dir->fd, name, link, mode, rdev);
+ 
+     saverr = errno;
++
++    lo_restore_cred(&old);
++
+     if (res == -1) {
+         goto out;
+     }
+@@ -794,26 +872,34 @@ static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
+     struct lo_data *lo = lo_data(req);
+     struct fuse_entry_param e;
+     int err;
++    struct lo_cred old = {};
+ 
+     if (lo_debug(req)) {
+         fuse_log(FUSE_LOG_DEBUG, "lo_create(parent=%" PRIu64 ", name=%s)\n",
+                  parent, name);
+     }
+ 
++    err = lo_change_cred(req, &old);
++    if (err) {
++        goto out;
++    }
++
+     fd = openat(lo_fd(req, parent), name, (fi->flags | O_CREAT) & ~O_NOFOLLOW,
+                 mode);
+-    if (fd == -1) {
+-        return (void)fuse_reply_err(req, errno);
+-    }
++    err = fd == -1 ? errno : 0;
++    lo_restore_cred(&old);
+ 
+-    fi->fh = fd;
++    if (!err) {
++        fi->fh = fd;
++        err = lo_do_lookup(req, parent, name, &e);
++    }
+     if (lo->cache == CACHE_NEVER) {
+         fi->direct_io = 1;
+     } else if (lo->cache == CACHE_ALWAYS) {
+         fi->keep_cache = 1;
+     }
+ 
+-    err = lo_do_lookup(req, parent, name, &e);
++out:
+     if (err) {
+         fuse_reply_err(req, err);
+     } else {
diff --git a/0044-virtiofsd-passthrough_ll-add-lo_map-for-ino-fh-indir.patch b/0044-virtiofsd-passthrough_ll-add-lo_map-for-ino-fh-indir.patch
new file mode 100644
index 0000000..43ee290
--- /dev/null
+++ b/0044-virtiofsd-passthrough_ll-add-lo_map-for-ino-fh-indir.patch
@@ -0,0 +1,162 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:13 +0000
+Subject: [PATCH] virtiofsd: passthrough_ll: add lo_map for ino/fh indirection
+
+A layer of indirection is needed because passthrough_ll cannot expose
+pointers or file descriptor numbers to untrusted clients.  Malicious
+clients could send invalid pointers or file descriptors in order to
+crash or exploit the file system daemon.
+
+lo_map provides an integer key->value mapping.  This will be used for
+ino and fh fields in the patches that follow.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 25c135727b08dca90f00094e522a69170b13dfac)
+---
+ tools/virtiofsd/passthrough_ll.c | 124 +++++++++++++++++++++++++++++++
+ 1 file changed, 124 insertions(+)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 5e061797d4..e83a976587 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -74,6 +74,21 @@ struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct {
+ };
+ #endif
+ 
++struct lo_map_elem {
++    union {
++        /* Element values will go here... */
++        ssize_t freelist;
++    };
++    bool in_use;
++};
++
++/* Maps FUSE fh or ino values to internal objects */
++struct lo_map {
++    struct lo_map_elem *elems;
++    size_t nelems;
++    ssize_t freelist;
++};
++
+ struct lo_inode {
+     struct lo_inode *next; /* protected by lo->mutex */
+     struct lo_inode *prev; /* protected by lo->mutex */
+@@ -130,6 +145,115 @@ static struct lo_data *lo_data(fuse_req_t req)
+     return (struct lo_data *)fuse_req_userdata(req);
+ }
+ 
++__attribute__((unused)) static void lo_map_init(struct lo_map *map)
++{
++    map->elems = NULL;
++    map->nelems = 0;
++    map->freelist = -1;
++}
++
++__attribute__((unused)) static void lo_map_destroy(struct lo_map *map)
++{
++    free(map->elems);
++}
++
++static int lo_map_grow(struct lo_map *map, size_t new_nelems)
++{
++    struct lo_map_elem *new_elems;
++    size_t i;
++
++    if (new_nelems <= map->nelems) {
++        return 1;
++    }
++
++    new_elems = realloc(map->elems, sizeof(map->elems[0]) * new_nelems);
++    if (!new_elems) {
++        return 0;
++    }
++
++    for (i = map->nelems; i < new_nelems; i++) {
++        new_elems[i].freelist = i + 1;
++        new_elems[i].in_use = false;
++    }
++    new_elems[new_nelems - 1].freelist = -1;
++
++    map->elems = new_elems;
++    map->freelist = map->nelems;
++    map->nelems = new_nelems;
++    return 1;
++}
++
++__attribute__((unused)) static struct lo_map_elem *
++lo_map_alloc_elem(struct lo_map *map)
++{
++    struct lo_map_elem *elem;
++
++    if (map->freelist == -1 && !lo_map_grow(map, map->nelems + 256)) {
++        return NULL;
++    }
++
++    elem = &map->elems[map->freelist];
++    map->freelist = elem->freelist;
++
++    elem->in_use = true;
++
++    return elem;
++}
++
++__attribute__((unused)) static struct lo_map_elem *
++lo_map_reserve(struct lo_map *map, size_t key)
++{
++    ssize_t *prev;
++
++    if (!lo_map_grow(map, key + 1)) {
++        return NULL;
++    }
++
++    for (prev = &map->freelist; *prev != -1;
++         prev = &map->elems[*prev].freelist) {
++        if (*prev == key) {
++            struct lo_map_elem *elem = &map->elems[key];
++
++            *prev = elem->freelist;
++            elem->in_use = true;
++            return elem;
++        }
++    }
++    return NULL;
++}
++
++__attribute__((unused)) static struct lo_map_elem *
++lo_map_get(struct lo_map *map, size_t key)
++{
++    if (key >= map->nelems) {
++        return NULL;
++    }
++    if (!map->elems[key].in_use) {
++        return NULL;
++    }
++    return &map->elems[key];
++}
++
++__attribute__((unused)) static void lo_map_remove(struct lo_map *map,
++                                                  size_t key)
++{
++    struct lo_map_elem *elem;
++
++    if (key >= map->nelems) {
++        return;
++    }
++
++    elem = &map->elems[key];
++    if (!elem->in_use) {
++        return;
++    }
++
++    elem->in_use = false;
++
++    elem->freelist = map->freelist;
++    map->freelist = key;
++}
++
+ static struct lo_inode *lo_inode(fuse_req_t req, fuse_ino_t ino)
+ {
+     if (ino == FUSE_ROOT_ID) {
diff --git a/0045-virtiofsd-passthrough_ll-add-ino_map-to-hide-lo_inod.patch b/0045-virtiofsd-passthrough_ll-add-ino_map-to-hide-lo_inod.patch
new file mode 100644
index 0000000..9fb606a
--- /dev/null
+++ b/0045-virtiofsd-passthrough_ll-add-ino_map-to-hide-lo_inod.patch
@@ -0,0 +1,376 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:14 +0000
+Subject: [PATCH] virtiofsd: passthrough_ll: add ino_map to hide lo_inode
+ pointers
+
+Do not expose lo_inode pointers to clients.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 92fb57b83cdbfc4bf53c0c46a3d0bcbc36e64126)
+---
+ tools/virtiofsd/passthrough_ll.c | 144 ++++++++++++++++++++++++-------
+ 1 file changed, 114 insertions(+), 30 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index e83a976587..a3ebf74eab 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -57,8 +57,8 @@
+ #include "passthrough_helpers.h"
+ 
+ /*
+- * We are re-using pointers to our `struct lo_inode` and `struct
+- * lo_dirp` elements as inodes. This means that we must be able to
++ * We are re-using pointers to our `struct lo_inode`
++ * elements as inodes. This means that we must be able to
+  * store uintptr_t values in a fuse_ino_t variable. The following
+  * incantation checks this condition at compile time.
+  */
+@@ -76,7 +76,7 @@ struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct {
+ 
+ struct lo_map_elem {
+     union {
+-        /* Element values will go here... */
++        struct lo_inode *inode;
+         ssize_t freelist;
+     };
+     bool in_use;
+@@ -97,6 +97,7 @@ struct lo_inode {
+     ino_t ino;
+     dev_t dev;
+     uint64_t refcount; /* protected by lo->mutex */
++    fuse_ino_t fuse_ino;
+ };
+ 
+ struct lo_cred {
+@@ -121,6 +122,7 @@ struct lo_data {
+     int cache;
+     int timeout_set;
+     struct lo_inode root; /* protected by lo->mutex */
++    struct lo_map ino_map; /* protected by lo->mutex */
+ };
+ 
+ static const struct fuse_opt lo_opts[] = {
+@@ -145,14 +147,14 @@ static struct lo_data *lo_data(fuse_req_t req)
+     return (struct lo_data *)fuse_req_userdata(req);
+ }
+ 
+-__attribute__((unused)) static void lo_map_init(struct lo_map *map)
++static void lo_map_init(struct lo_map *map)
+ {
+     map->elems = NULL;
+     map->nelems = 0;
+     map->freelist = -1;
+ }
+ 
+-__attribute__((unused)) static void lo_map_destroy(struct lo_map *map)
++static void lo_map_destroy(struct lo_map *map)
+ {
+     free(map->elems);
+ }
+@@ -183,8 +185,7 @@ static int lo_map_grow(struct lo_map *map, size_t new_nelems)
+     return 1;
+ }
+ 
+-__attribute__((unused)) static struct lo_map_elem *
+-lo_map_alloc_elem(struct lo_map *map)
++static struct lo_map_elem *lo_map_alloc_elem(struct lo_map *map)
+ {
+     struct lo_map_elem *elem;
+ 
+@@ -200,8 +201,7 @@ lo_map_alloc_elem(struct lo_map *map)
+     return elem;
+ }
+ 
+-__attribute__((unused)) static struct lo_map_elem *
+-lo_map_reserve(struct lo_map *map, size_t key)
++static struct lo_map_elem *lo_map_reserve(struct lo_map *map, size_t key)
+ {
+     ssize_t *prev;
+ 
+@@ -222,8 +222,7 @@ lo_map_reserve(struct lo_map *map, size_t key)
+     return NULL;
+ }
+ 
+-__attribute__((unused)) static struct lo_map_elem *
+-lo_map_get(struct lo_map *map, size_t key)
++static struct lo_map_elem *lo_map_get(struct lo_map *map, size_t key)
+ {
+     if (key >= map->nelems) {
+         return NULL;
+@@ -234,8 +233,7 @@ lo_map_get(struct lo_map *map, size_t key)
+     return &map->elems[key];
+ }
+ 
+-__attribute__((unused)) static void lo_map_remove(struct lo_map *map,
+-                                                  size_t key)
++static void lo_map_remove(struct lo_map *map, size_t key)
+ {
+     struct lo_map_elem *elem;
+ 
+@@ -254,18 +252,40 @@ __attribute__((unused)) static void lo_map_remove(struct lo_map *map,
+     map->freelist = key;
+ }
+ 
++/* Assumes lo->mutex is held */
++static ssize_t lo_add_inode_mapping(fuse_req_t req, struct lo_inode *inode)
++{
++    struct lo_map_elem *elem;
++
++    elem = lo_map_alloc_elem(&lo_data(req)->ino_map);
++    if (!elem) {
++        return -1;
++    }
++
++    elem->inode = inode;
++    return elem - lo_data(req)->ino_map.elems;
++}
++
+ static struct lo_inode *lo_inode(fuse_req_t req, fuse_ino_t ino)
+ {
+-    if (ino == FUSE_ROOT_ID) {
+-        return &lo_data(req)->root;
+-    } else {
+-        return (struct lo_inode *)(uintptr_t)ino;
++    struct lo_data *lo = lo_data(req);
++    struct lo_map_elem *elem;
++
++    pthread_mutex_lock(&lo->mutex);
++    elem = lo_map_get(&lo->ino_map, ino);
++    pthread_mutex_unlock(&lo->mutex);
++
++    if (!elem) {
++        return NULL;
+     }
++
++    return elem->inode;
+ }
+ 
+ static int lo_fd(fuse_req_t req, fuse_ino_t ino)
+ {
+-    return lo_inode(req, ino)->fd;
++    struct lo_inode *inode = lo_inode(req, ino);
++    return inode ? inode->fd : -1;
+ }
+ 
+ static bool lo_debug(fuse_req_t req)
+@@ -337,10 +357,18 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+ {
+     int saverr;
+     char procname[64];
+-    struct lo_inode *inode = lo_inode(req, ino);
+-    int ifd = inode->fd;
++    struct lo_inode *inode;
++    int ifd;
+     int res;
+ 
++    inode = lo_inode(req, ino);
++    if (!inode) {
++        fuse_reply_err(req, EBADF);
++        return;
++    }
++
++    ifd = inode->fd;
++
+     if (valid & FUSE_SET_ATTR_MODE) {
+         if (fi) {
+             res = fchmod(fi->fh, attr->st_mode);
+@@ -470,6 +498,7 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+         inode->dev = e->attr.st_dev;
+ 
+         pthread_mutex_lock(&lo->mutex);
++        inode->fuse_ino = lo_add_inode_mapping(req, inode);
+         prev = &lo->root;
+         next = prev->next;
+         next->prev = inode;
+@@ -478,7 +507,7 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+         prev->next = inode;
+         pthread_mutex_unlock(&lo->mutex);
+     }
+-    e->ino = (uintptr_t)inode;
++    e->ino = inode->fuse_ino;
+ 
+     if (lo_debug(req)) {
+         fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
+@@ -582,10 +611,16 @@ static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent,
+ {
+     int res;
+     int saverr;
+-    struct lo_inode *dir = lo_inode(req, parent);
++    struct lo_inode *dir;
+     struct fuse_entry_param e;
+     struct lo_cred old = {};
+ 
++    dir = lo_inode(req, parent);
++    if (!dir) {
++        fuse_reply_err(req, EBADF);
++        return;
++    }
++
+     saverr = ENOMEM;
+ 
+     saverr = lo_change_cred(req, &old);
+@@ -663,10 +698,16 @@ static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
+ {
+     int res;
+     struct lo_data *lo = lo_data(req);
+-    struct lo_inode *inode = lo_inode(req, ino);
++    struct lo_inode *inode;
+     struct fuse_entry_param e;
+     int saverr;
+ 
++    inode = lo_inode(req, ino);
++    if (!inode) {
++        fuse_reply_err(req, EBADF);
++        return;
++    }
++
+     memset(&e, 0, sizeof(struct fuse_entry_param));
+     e.attr_timeout = lo->timeout;
+     e.entry_timeout = lo->timeout;
+@@ -684,7 +725,7 @@ static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
+     pthread_mutex_lock(&lo->mutex);
+     inode->refcount++;
+     pthread_mutex_unlock(&lo->mutex);
+-    e.ino = (uintptr_t)inode;
++    e.ino = inode->fuse_ino;
+ 
+     if (lo_debug(req)) {
+         fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
+@@ -750,10 +791,10 @@ static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n)
+         next->prev = prev;
+         prev->next = next;
+ 
++        lo_map_remove(&lo->ino_map, inode->fuse_ino);
+         pthread_mutex_unlock(&lo->mutex);
+         close(inode->fd);
+         free(inode);
+-
+     } else {
+         pthread_mutex_unlock(&lo->mutex);
+     }
+@@ -762,7 +803,12 @@ static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n)
+ static void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
+ {
+     struct lo_data *lo = lo_data(req);
+-    struct lo_inode *inode = lo_inode(req, ino);
++    struct lo_inode *inode;
++
++    inode = lo_inode(req, ino);
++    if (!inode) {
++        return;
++    }
+ 
+     if (lo_debug(req)) {
+         fuse_log(FUSE_LOG_DEBUG, "  forget %lli %lli -%lli\n",
+@@ -1244,10 +1290,16 @@ static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+ {
+     char *value = NULL;
+     char procname[64];
+-    struct lo_inode *inode = lo_inode(req, ino);
++    struct lo_inode *inode;
+     ssize_t ret;
+     int saverr;
+ 
++    inode = lo_inode(req, ino);
++    if (!inode) {
++        fuse_reply_err(req, EBADF);
++        return;
++    }
++
+     saverr = ENOSYS;
+     if (!lo_data(req)->xattr) {
+         goto out;
+@@ -1306,10 +1358,16 @@ static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
+ {
+     char *value = NULL;
+     char procname[64];
+-    struct lo_inode *inode = lo_inode(req, ino);
++    struct lo_inode *inode;
+     ssize_t ret;
+     int saverr;
+ 
++    inode = lo_inode(req, ino);
++    if (!inode) {
++        fuse_reply_err(req, EBADF);
++        return;
++    }
++
+     saverr = ENOSYS;
+     if (!lo_data(req)->xattr) {
+         goto out;
+@@ -1367,10 +1425,16 @@ static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+                         const char *value, size_t size, int flags)
+ {
+     char procname[64];
+-    struct lo_inode *inode = lo_inode(req, ino);
++    struct lo_inode *inode;
+     ssize_t ret;
+     int saverr;
+ 
++    inode = lo_inode(req, ino);
++    if (!inode) {
++        fuse_reply_err(req, EBADF);
++        return;
++    }
++
+     saverr = ENOSYS;
+     if (!lo_data(req)->xattr) {
+         goto out;
+@@ -1400,10 +1464,16 @@ out:
+ static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
+ {
+     char procname[64];
+-    struct lo_inode *inode = lo_inode(req, ino);
++    struct lo_inode *inode;
+     ssize_t ret;
+     int saverr;
+ 
++    inode = lo_inode(req, ino);
++    if (!inode) {
++        fuse_reply_err(req, EBADF);
++        return;
++    }
++
+     saverr = ENOSYS;
+     if (!lo_data(req)->xattr) {
+         goto out;
+@@ -1522,6 +1592,7 @@ int main(int argc, char *argv[])
+     struct fuse_session *se;
+     struct fuse_cmdline_opts opts;
+     struct lo_data lo = { .debug = 0, .writeback = 0 };
++    struct lo_map_elem *root_elem;
+     int ret = -1;
+ 
+     /* Don't mask creation mode, kernel already did that */
+@@ -1530,8 +1601,19 @@ int main(int argc, char *argv[])
+     pthread_mutex_init(&lo.mutex, NULL);
+     lo.root.next = lo.root.prev = &lo.root;
+     lo.root.fd = -1;
++    lo.root.fuse_ino = FUSE_ROOT_ID;
+     lo.cache = CACHE_NORMAL;
+ 
++    /*
++     * Set up the ino map like this:
++     * [0] Reserved (will not be used)
++     * [1] Root inode
++     */
++    lo_map_init(&lo.ino_map);
++    lo_map_reserve(&lo.ino_map, 0)->in_use = false;
++    root_elem = lo_map_reserve(&lo.ino_map, lo.root.fuse_ino);
++    root_elem->inode = &lo.root;
++
+     if (fuse_parse_cmdline(&args, &opts) != 0) {
+         return 1;
+     }
+@@ -1628,6 +1710,8 @@ err_out2:
+ err_out1:
+     fuse_opt_free_args(&args);
+ 
++    lo_map_destroy(&lo.ino_map);
++
+     if (lo.root.fd >= 0) {
+         close(lo.root.fd);
+     }
diff --git a/0046-virtiofsd-passthrough_ll-add-dirp_map-to-hide-lo_dir.patch b/0046-virtiofsd-passthrough_ll-add-dirp_map-to-hide-lo_dir.patch
new file mode 100644
index 0000000..1e4ed85
--- /dev/null
+++ b/0046-virtiofsd-passthrough_ll-add-dirp_map-to-hide-lo_dir.patch
@@ -0,0 +1,222 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:15 +0000
+Subject: [PATCH] virtiofsd: passthrough_ll: add dirp_map to hide lo_dirp
+ pointers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Do not expose lo_dirp pointers to clients.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit b39bce121bfad8757eec0ee41f14607b883935d3)
+---
+ tools/virtiofsd/passthrough_ll.c | 103 +++++++++++++++++++++++--------
+ 1 file changed, 76 insertions(+), 27 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index a3ebf74eab..5f5a72fdbb 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -56,27 +56,10 @@
+ 
+ #include "passthrough_helpers.h"
+ 
+-/*
+- * We are re-using pointers to our `struct lo_inode`
+- * elements as inodes. This means that we must be able to
+- * store uintptr_t values in a fuse_ino_t variable. The following
+- * incantation checks this condition at compile time.
+- */
+-#if defined(__GNUC__) &&                                      \
+-    (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && \
+-    !defined __cplusplus
+-_Static_assert(sizeof(fuse_ino_t) >= sizeof(uintptr_t),
+-               "fuse_ino_t too small to hold uintptr_t values!");
+-#else
+-struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct {
+-    unsigned _uintptr_to_must_hold_fuse_ino_t
+-        : ((sizeof(fuse_ino_t) >= sizeof(uintptr_t)) ? 1 : -1);
+-};
+-#endif
+-
+ struct lo_map_elem {
+     union {
+         struct lo_inode *inode;
++        struct lo_dirp *dirp;
+         ssize_t freelist;
+     };
+     bool in_use;
+@@ -123,6 +106,7 @@ struct lo_data {
+     int timeout_set;
+     struct lo_inode root; /* protected by lo->mutex */
+     struct lo_map ino_map; /* protected by lo->mutex */
++    struct lo_map dirp_map; /* protected by lo->mutex */
+ };
+ 
+ static const struct fuse_opt lo_opts[] = {
+@@ -252,6 +236,20 @@ static void lo_map_remove(struct lo_map *map, size_t key)
+     map->freelist = key;
+ }
+ 
++/* Assumes lo->mutex is held */
++static ssize_t lo_add_dirp_mapping(fuse_req_t req, struct lo_dirp *dirp)
++{
++    struct lo_map_elem *elem;
++
++    elem = lo_map_alloc_elem(&lo_data(req)->dirp_map);
++    if (!elem) {
++        return -1;
++    }
++
++    elem->dirp = dirp;
++    return elem - lo_data(req)->dirp_map.elems;
++}
++
+ /* Assumes lo->mutex is held */
+ static ssize_t lo_add_inode_mapping(fuse_req_t req, struct lo_inode *inode)
+ {
+@@ -861,9 +859,19 @@ struct lo_dirp {
+     off_t offset;
+ };
+ 
+-static struct lo_dirp *lo_dirp(struct fuse_file_info *fi)
++static struct lo_dirp *lo_dirp(fuse_req_t req, struct fuse_file_info *fi)
+ {
+-    return (struct lo_dirp *)(uintptr_t)fi->fh;
++    struct lo_data *lo = lo_data(req);
++    struct lo_map_elem *elem;
++
++    pthread_mutex_lock(&lo->mutex);
++    elem = lo_map_get(&lo->dirp_map, fi->fh);
++    pthread_mutex_unlock(&lo->mutex);
++    if (!elem) {
++        return NULL;
++    }
++
++    return elem->dirp;
+ }
+ 
+ static void lo_opendir(fuse_req_t req, fuse_ino_t ino,
+@@ -873,6 +881,7 @@ static void lo_opendir(fuse_req_t req, fuse_ino_t ino,
+     struct lo_data *lo = lo_data(req);
+     struct lo_dirp *d;
+     int fd;
++    ssize_t fh;
+ 
+     d = calloc(1, sizeof(struct lo_dirp));
+     if (d == NULL) {
+@@ -892,7 +901,14 @@ static void lo_opendir(fuse_req_t req, fuse_ino_t ino,
+     d->offset = 0;
+     d->entry = NULL;
+ 
+-    fi->fh = (uintptr_t)d;
++    pthread_mutex_lock(&lo->mutex);
++    fh = lo_add_dirp_mapping(req, d);
++    pthread_mutex_unlock(&lo->mutex);
++    if (fh == -1) {
++        goto out_err;
++    }
++
++    fi->fh = fh;
+     if (lo->cache == CACHE_ALWAYS) {
+         fi->keep_cache = 1;
+     }
+@@ -903,6 +919,9 @@ out_errno:
+     error = errno;
+ out_err:
+     if (d) {
++        if (d->dp) {
++            closedir(d->dp);
++        }
+         if (fd != -1) {
+             close(fd);
+         }
+@@ -920,17 +939,21 @@ static int is_dot_or_dotdot(const char *name)
+ static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
+                           off_t offset, struct fuse_file_info *fi, int plus)
+ {
+-    struct lo_dirp *d = lo_dirp(fi);
+-    char *buf;
++    struct lo_dirp *d;
++    char *buf = NULL;
+     char *p;
+     size_t rem = size;
+-    int err;
++    int err = ENOMEM;
+ 
+     (void)ino;
+ 
++    d = lo_dirp(req, fi);
++    if (!d) {
++        goto error;
++    }
++
+     buf = calloc(1, size);
+     if (!buf) {
+-        err = ENOMEM;
+         goto error;
+     }
+     p = buf;
+@@ -1028,8 +1051,21 @@ static void lo_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size,
+ static void lo_releasedir(fuse_req_t req, fuse_ino_t ino,
+                           struct fuse_file_info *fi)
+ {
+-    struct lo_dirp *d = lo_dirp(fi);
++    struct lo_data *lo = lo_data(req);
++    struct lo_dirp *d;
++
+     (void)ino;
++
++    d = lo_dirp(req, fi);
++    if (!d) {
++        fuse_reply_err(req, EBADF);
++        return;
++    }
++
++    pthread_mutex_lock(&lo->mutex);
++    lo_map_remove(&lo->dirp_map, fi->fh);
++    pthread_mutex_unlock(&lo->mutex);
++
+     closedir(d->dp);
+     free(d);
+     fuse_reply_err(req, 0);
+@@ -1081,8 +1117,18 @@ static void lo_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
+                         struct fuse_file_info *fi)
+ {
+     int res;
+-    int fd = dirfd(lo_dirp(fi)->dp);
++    struct lo_dirp *d;
++    int fd;
++
+     (void)ino;
++
++    d = lo_dirp(req, fi);
++    if (!d) {
++        fuse_reply_err(req, EBADF);
++        return;
++    }
++
++    fd = dirfd(d->dp);
+     if (datasync) {
+         res = fdatasync(fd);
+     } else {
+@@ -1614,6 +1660,8 @@ int main(int argc, char *argv[])
+     root_elem = lo_map_reserve(&lo.ino_map, lo.root.fuse_ino);
+     root_elem->inode = &lo.root;
+ 
++    lo_map_init(&lo.dirp_map);
++
+     if (fuse_parse_cmdline(&args, &opts) != 0) {
+         return 1;
+     }
+@@ -1710,6 +1758,7 @@ err_out2:
+ err_out1:
+     fuse_opt_free_args(&args);
+ 
++    lo_map_destroy(&lo.dirp_map);
+     lo_map_destroy(&lo.ino_map);
+ 
+     if (lo.root.fd >= 0) {
diff --git a/0047-virtiofsd-passthrough_ll-add-fd_map-to-hide-file-des.patch b/0047-virtiofsd-passthrough_ll-add-fd_map-to-hide-file-des.patch
new file mode 100644
index 0000000..485a73b
--- /dev/null
+++ b/0047-virtiofsd-passthrough_ll-add-fd_map-to-hide-file-des.patch
@@ -0,0 +1,308 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:16 +0000
+Subject: [PATCH] virtiofsd: passthrough_ll: add fd_map to hide file
+ descriptors
+
+Do not expose file descriptor numbers to clients.  This prevents the
+abuse of internal file descriptors (like stdin/stdout).
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Fix from:
+Signed-off-by: Xiao Yang <yangx.jy@cn.fujitsu.com>
+dgilbert:
+  Added lseek
+Reviewed-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 73b4d19dfc4248a74c1f3e511cfa934681d9c602)
+---
+ tools/virtiofsd/passthrough_ll.c | 116 +++++++++++++++++++++++++------
+ 1 file changed, 94 insertions(+), 22 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 5f5a72fdbb..9815bfa5c5 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -60,6 +60,7 @@ struct lo_map_elem {
+     union {
+         struct lo_inode *inode;
+         struct lo_dirp *dirp;
++        int fd;
+         ssize_t freelist;
+     };
+     bool in_use;
+@@ -107,6 +108,7 @@ struct lo_data {
+     struct lo_inode root; /* protected by lo->mutex */
+     struct lo_map ino_map; /* protected by lo->mutex */
+     struct lo_map dirp_map; /* protected by lo->mutex */
++    struct lo_map fd_map; /* protected by lo->mutex */
+ };
+ 
+ static const struct fuse_opt lo_opts[] = {
+@@ -236,6 +238,20 @@ static void lo_map_remove(struct lo_map *map, size_t key)
+     map->freelist = key;
+ }
+ 
++/* Assumes lo->mutex is held */
++static ssize_t lo_add_fd_mapping(fuse_req_t req, int fd)
++{
++    struct lo_map_elem *elem;
++
++    elem = lo_map_alloc_elem(&lo_data(req)->fd_map);
++    if (!elem) {
++        return -1;
++    }
++
++    elem->fd = fd;
++    return elem - lo_data(req)->fd_map.elems;
++}
++
+ /* Assumes lo->mutex is held */
+ static ssize_t lo_add_dirp_mapping(fuse_req_t req, struct lo_dirp *dirp)
+ {
+@@ -350,6 +366,22 @@ static int utimensat_empty_nofollow(struct lo_inode *inode,
+     return utimensat(AT_FDCWD, procname, tv, 0);
+ }
+ 
++static int lo_fi_fd(fuse_req_t req, struct fuse_file_info *fi)
++{
++    struct lo_data *lo = lo_data(req);
++    struct lo_map_elem *elem;
++
++    pthread_mutex_lock(&lo->mutex);
++    elem = lo_map_get(&lo->fd_map, fi->fh);
++    pthread_mutex_unlock(&lo->mutex);
++
++    if (!elem) {
++        return -1;
++    }
++
++    return elem->fd;
++}
++
+ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+                        int valid, struct fuse_file_info *fi)
+ {
+@@ -358,6 +390,7 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+     struct lo_inode *inode;
+     int ifd;
+     int res;
++    int fd;
+ 
+     inode = lo_inode(req, ino);
+     if (!inode) {
+@@ -367,9 +400,14 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+ 
+     ifd = inode->fd;
+ 
++    /* If fi->fh is invalid we'll report EBADF later */
++    if (fi) {
++        fd = lo_fi_fd(req, fi);
++    }
++
+     if (valid & FUSE_SET_ATTR_MODE) {
+         if (fi) {
+-            res = fchmod(fi->fh, attr->st_mode);
++            res = fchmod(fd, attr->st_mode);
+         } else {
+             sprintf(procname, "/proc/self/fd/%i", ifd);
+             res = chmod(procname, attr->st_mode);
+@@ -389,7 +427,7 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+     }
+     if (valid & FUSE_SET_ATTR_SIZE) {
+         if (fi) {
+-            res = ftruncate(fi->fh, attr->st_size);
++            res = ftruncate(fd, attr->st_size);
+         } else {
+             sprintf(procname, "/proc/self/fd/%i", ifd);
+             res = truncate(procname, attr->st_size);
+@@ -419,7 +457,7 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+         }
+ 
+         if (fi) {
+-            res = futimens(fi->fh, tv);
++            res = futimens(fd, tv);
+         } else {
+             res = utimensat_empty_nofollow(inode, tv);
+         }
+@@ -1096,7 +1134,18 @@ static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
+     lo_restore_cred(&old);
+ 
+     if (!err) {
+-        fi->fh = fd;
++        ssize_t fh;
++
++        pthread_mutex_lock(&lo->mutex);
++        fh = lo_add_fd_mapping(req, fd);
++        pthread_mutex_unlock(&lo->mutex);
++        if (fh == -1) {
++            close(fd);
++            fuse_reply_err(req, ENOMEM);
++            return;
++        }
++
++        fi->fh = fh;
+         err = lo_do_lookup(req, parent, name, &e);
+     }
+     if (lo->cache == CACHE_NEVER) {
+@@ -1140,6 +1189,7 @@ static void lo_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
+ static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+ {
+     int fd;
++    ssize_t fh;
+     char buf[64];
+     struct lo_data *lo = lo_data(req);
+ 
+@@ -1175,7 +1225,16 @@ static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+         return (void)fuse_reply_err(req, errno);
+     }
+ 
+-    fi->fh = fd;
++    pthread_mutex_lock(&lo->mutex);
++    fh = lo_add_fd_mapping(req, fd);
++    pthread_mutex_unlock(&lo->mutex);
++    if (fh == -1) {
++        close(fd);
++        fuse_reply_err(req, ENOMEM);
++        return;
++    }
++
++    fi->fh = fh;
+     if (lo->cache == CACHE_NEVER) {
+         fi->direct_io = 1;
+     } else if (lo->cache == CACHE_ALWAYS) {
+@@ -1187,9 +1246,18 @@ static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+ static void lo_release(fuse_req_t req, fuse_ino_t ino,
+                        struct fuse_file_info *fi)
+ {
++    struct lo_data *lo = lo_data(req);
++    int fd;
++
+     (void)ino;
+ 
+-    close(fi->fh);
++    fd = lo_fi_fd(req, fi);
++
++    pthread_mutex_lock(&lo->mutex);
++    lo_map_remove(&lo->fd_map, fi->fh);
++    pthread_mutex_unlock(&lo->mutex);
++
++    close(fd);
+     fuse_reply_err(req, 0);
+ }
+ 
+@@ -1197,7 +1265,7 @@ static void lo_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+ {
+     int res;
+     (void)ino;
+-    res = close(dup(fi->fh));
++    res = close(dup(lo_fi_fd(req, fi)));
+     fuse_reply_err(req, res == -1 ? errno : 0);
+ }
+ 
+@@ -1224,7 +1292,7 @@ static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
+             return (void)fuse_reply_err(req, errno);
+         }
+     } else {
+-        fd = fi->fh;
++        fd = lo_fi_fd(req, fi);
+     }
+ 
+     if (datasync) {
+@@ -1251,7 +1319,7 @@ static void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset,
+     }
+ 
+     buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
+-    buf.buf[0].fd = fi->fh;
++    buf.buf[0].fd = lo_fi_fd(req, fi);
+     buf.buf[0].pos = offset;
+ 
+     fuse_reply_data(req, &buf);
+@@ -1266,7 +1334,7 @@ static void lo_write_buf(fuse_req_t req, fuse_ino_t ino,
+     struct fuse_bufvec out_buf = FUSE_BUFVEC_INIT(fuse_buf_size(in_buf));
+ 
+     out_buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
+-    out_buf.buf[0].fd = fi->fh;
++    out_buf.buf[0].fd = lo_fi_fd(req, fi);
+     out_buf.buf[0].pos = off;
+ 
+     if (lo_debug(req)) {
+@@ -1303,7 +1371,7 @@ static void lo_fallocate(fuse_req_t req, fuse_ino_t ino, int mode, off_t offset,
+     (void)ino;
+ 
+ #ifdef CONFIG_FALLOCATE
+-    err = fallocate(fi->fh, mode, offset, length);
++    err = fallocate(lo_fi_fd(req, fi), mode, offset, length);
+     if (err < 0) {
+         err = errno;
+     }
+@@ -1314,7 +1382,7 @@ static void lo_fallocate(fuse_req_t req, fuse_ino_t ino, int mode, off_t offset,
+         return;
+     }
+ 
+-    err = posix_fallocate(fi->fh, offset, length);
++    err = posix_fallocate(lo_fi_fd(req, fi), offset, length);
+ #endif
+ 
+     fuse_reply_err(req, err);
+@@ -1326,7 +1394,7 @@ static void lo_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
+     int res;
+     (void)ino;
+ 
+-    res = flock(fi->fh, op);
++    res = flock(lo_fi_fd(req, fi), op);
+ 
+     fuse_reply_err(req, res == -1 ? errno : 0);
+ }
+@@ -1551,17 +1619,19 @@ static void lo_copy_file_range(fuse_req_t req, fuse_ino_t ino_in, off_t off_in,
+                                off_t off_out, struct fuse_file_info *fi_out,
+                                size_t len, int flags)
+ {
++    int in_fd, out_fd;
+     ssize_t res;
+ 
+-    if (lo_debug(req))
+-        fuse_log(FUSE_LOG_DEBUG,
+-                 "lo_copy_file_range(ino=%" PRIu64 "/fd=%lu, "
+-                 "off=%lu, ino=%" PRIu64 "/fd=%lu, "
+-                 "off=%lu, size=%zd, flags=0x%x)\n",
+-                 ino_in, fi_in->fh, off_in, ino_out, fi_out->fh, off_out, len,
+-                 flags);
++    in_fd = lo_fi_fd(req, fi_in);
++    out_fd = lo_fi_fd(req, fi_out);
++
++    fuse_log(FUSE_LOG_DEBUG,
++             "lo_copy_file_range(ino=%" PRIu64 "/fd=%d, "
++             "off=%lu, ino=%" PRIu64 "/fd=%d, "
++             "off=%lu, size=%zd, flags=0x%x)\n",
++             ino_in, in_fd, off_in, ino_out, out_fd, off_out, len, flags);
+ 
+-    res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len, flags);
++    res = copy_file_range(in_fd, &off_in, out_fd, &off_out, len, flags);
+     if (res < 0) {
+         fuse_reply_err(req, -errno);
+     } else {
+@@ -1576,7 +1646,7 @@ static void lo_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
+     off_t res;
+ 
+     (void)ino;
+-    res = lseek(fi->fh, off, whence);
++    res = lseek(lo_fi_fd(req, fi), off, whence);
+     if (res != -1) {
+         fuse_reply_lseek(req, res);
+     } else {
+@@ -1661,6 +1731,7 @@ int main(int argc, char *argv[])
+     root_elem->inode = &lo.root;
+ 
+     lo_map_init(&lo.dirp_map);
++    lo_map_init(&lo.fd_map);
+ 
+     if (fuse_parse_cmdline(&args, &opts) != 0) {
+         return 1;
+@@ -1758,6 +1829,7 @@ err_out2:
+ err_out1:
+     fuse_opt_free_args(&args);
+ 
++    lo_map_destroy(&lo.fd_map);
+     lo_map_destroy(&lo.dirp_map);
+     lo_map_destroy(&lo.ino_map);
+ 
diff --git a/0048-virtiofsd-passthrough_ll-add-fallback-for-racy-ops.patch b/0048-virtiofsd-passthrough_ll-add-fallback-for-racy-ops.patch
new file mode 100644
index 0000000..f843056
--- /dev/null
+++ b/0048-virtiofsd-passthrough_ll-add-fallback-for-racy-ops.patch
@@ -0,0 +1,284 @@
+From: Miklos Szeredi <mszeredi@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:17 +0000
+Subject: [PATCH] virtiofsd: passthrough_ll: add fallback for racy ops
+
+We have two operations that cannot be done race-free on a symlink in
+certain cases: utimes and link.
+
+Add racy fallback for these if the race-free method doesn't work.  We do
+our best to avoid races even in this case:
+
+  - get absolute path by reading /proc/self/fd/NN symlink
+
+  - lookup parent directory: after this we are safe against renames in
+    ancestors
+
+  - lookup name in parent directory, and verify that we got to the original
+    inode,  if not retry the whole thing
+
+Both utimes(2) and link(2) hold i_lock on the inode across the operation,
+so a racing rename/delete by this fuse instance is not possible, only from
+other entities changing the filesystem.
+
+If the "norace" option is given, then disable the racy fallbacks.
+
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Reviewed-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 5fe319a7b19c9c328e6e061bffcf1ff6cc8b89ce)
+---
+ tools/virtiofsd/helper.c         |   5 +-
+ tools/virtiofsd/passthrough_ll.c | 157 +++++++++++++++++++++++++++----
+ 2 files changed, 145 insertions(+), 17 deletions(-)
+
+diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
+index b8ec5ac8dc..5531425223 100644
+--- a/tools/virtiofsd/helper.c
++++ b/tools/virtiofsd/helper.c
+@@ -142,7 +142,10 @@ void fuse_cmdline_help(void)
+            "    --daemonize                run in background\n"
+            "    -o max_idle_threads        the maximum number of idle worker "
+            "threads\n"
+-           "                               allowed (default: 10)\n");
++           "                               allowed (default: 10)\n"
++           "    -o norace                  disable racy fallback\n"
++           "                               default: false\n"
++          );
+ }
+ 
+ static int fuse_helper_opt_proc(void *data, const char *arg, int key,
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 9815bfa5c5..ac380efcb1 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -98,6 +98,7 @@ enum {
+ struct lo_data {
+     pthread_mutex_t mutex;
+     int debug;
++    int norace;
+     int writeback;
+     int flock;
+     int xattr;
+@@ -124,10 +125,15 @@ static const struct fuse_opt lo_opts[] = {
+     { "cache=never", offsetof(struct lo_data, cache), CACHE_NEVER },
+     { "cache=auto", offsetof(struct lo_data, cache), CACHE_NORMAL },
+     { "cache=always", offsetof(struct lo_data, cache), CACHE_ALWAYS },
+-
++    { "norace", offsetof(struct lo_data, norace), 1 },
+     FUSE_OPT_END
+ };
+ 
++static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n);
++
++static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st);
++
++
+ static struct lo_data *lo_data(fuse_req_t req)
+ {
+     return (struct lo_data *)fuse_req_userdata(req);
+@@ -347,23 +353,127 @@ static void lo_getattr(fuse_req_t req, fuse_ino_t ino,
+     fuse_reply_attr(req, &buf, lo->timeout);
+ }
+ 
+-static int utimensat_empty_nofollow(struct lo_inode *inode,
+-                                    const struct timespec *tv)
++static int lo_parent_and_name(struct lo_data *lo, struct lo_inode *inode,
++                              char path[PATH_MAX], struct lo_inode **parent)
+ {
+-    int res;
+     char procname[64];
++    char *last;
++    struct stat stat;
++    struct lo_inode *p;
++    int retries = 2;
++    int res;
++
++retry:
++    sprintf(procname, "/proc/self/fd/%i", inode->fd);
++
++    res = readlink(procname, path, PATH_MAX);
++    if (res < 0) {
++        fuse_log(FUSE_LOG_WARNING, "%s: readlink failed: %m\n", __func__);
++        goto fail_noretry;
++    }
++
++    if (res >= PATH_MAX) {
++        fuse_log(FUSE_LOG_WARNING, "%s: readlink overflowed\n", __func__);
++        goto fail_noretry;
++    }
++    path[res] = '\0';
++
++    last = strrchr(path, '/');
++    if (last == NULL) {
++        /* Shouldn't happen */
++        fuse_log(
++            FUSE_LOG_WARNING,
++            "%s: INTERNAL ERROR: bad path read from proc\n", __func__);
++        goto fail_noretry;
++    }
++    if (last == path) {
++        p = &lo->root;
++        pthread_mutex_lock(&lo->mutex);
++        p->refcount++;
++        pthread_mutex_unlock(&lo->mutex);
++    } else {
++        *last = '\0';
++        res = fstatat(AT_FDCWD, last == path ? "/" : path, &stat, 0);
++        if (res == -1) {
++            if (!retries) {
++                fuse_log(FUSE_LOG_WARNING,
++                         "%s: failed to stat parent: %m\n", __func__);
++            }
++            goto fail;
++        }
++        p = lo_find(lo, &stat);
++        if (p == NULL) {
++            if (!retries) {
++                fuse_log(FUSE_LOG_WARNING,
++                         "%s: failed to find parent\n", __func__);
++            }
++            goto fail;
++        }
++    }
++    last++;
++    res = fstatat(p->fd, last, &stat, AT_SYMLINK_NOFOLLOW);
++    if (res == -1) {
++        if (!retries) {
++            fuse_log(FUSE_LOG_WARNING,
++                     "%s: failed to stat last\n", __func__);
++        }
++        goto fail_unref;
++    }
++    if (stat.st_dev != inode->dev || stat.st_ino != inode->ino) {
++        if (!retries) {
++            fuse_log(FUSE_LOG_WARNING,
++                     "%s: failed to match last\n", __func__);
++        }
++        goto fail_unref;
++    }
++    *parent = p;
++    memmove(path, last, strlen(last) + 1);
++
++    return 0;
++
++fail_unref:
++    unref_inode(lo, p, 1);
++fail:
++    if (retries) {
++        retries--;
++        goto retry;
++    }
++fail_noretry:
++    errno = EIO;
++    return -1;
++}
++
++static int utimensat_empty(struct lo_data *lo, struct lo_inode *inode,
++                           const struct timespec *tv)
++{
++    int res;
++    struct lo_inode *parent;
++    char path[PATH_MAX];
+ 
+     if (inode->is_symlink) {
+-        res = utimensat(inode->fd, "", tv, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
++        res = utimensat(inode->fd, "", tv, AT_EMPTY_PATH);
+         if (res == -1 && errno == EINVAL) {
+             /* Sorry, no race free way to set times on symlink. */
+-            errno = EPERM;
++            if (lo->norace) {
++                errno = EPERM;
++            } else {
++                goto fallback;
++            }
+         }
+         return res;
+     }
+-    sprintf(procname, "/proc/self/fd/%i", inode->fd);
++    sprintf(path, "/proc/self/fd/%i", inode->fd);
+ 
+-    return utimensat(AT_FDCWD, procname, tv, 0);
++    return utimensat(AT_FDCWD, path, tv, 0);
++
++fallback:
++    res = lo_parent_and_name(lo, inode, path, &parent);
++    if (res != -1) {
++        res = utimensat(parent->fd, path, tv, AT_SYMLINK_NOFOLLOW);
++        unref_inode(lo, parent, 1);
++    }
++
++    return res;
+ }
+ 
+ static int lo_fi_fd(fuse_req_t req, struct fuse_file_info *fi)
+@@ -387,6 +497,7 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+ {
+     int saverr;
+     char procname[64];
++    struct lo_data *lo = lo_data(req);
+     struct lo_inode *inode;
+     int ifd;
+     int res;
+@@ -459,7 +570,7 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+         if (fi) {
+             res = futimens(fd, tv);
+         } else {
+-            res = utimensat_empty_nofollow(inode, tv);
++            res = utimensat_empty(lo, inode, tv);
+         }
+         if (res == -1) {
+             goto out_err;
+@@ -709,24 +820,38 @@ static void lo_symlink(fuse_req_t req, const char *link, fuse_ino_t parent,
+     lo_mknod_symlink(req, parent, name, S_IFLNK, 0, link);
+ }
+ 
+-static int linkat_empty_nofollow(struct lo_inode *inode, int dfd,
+-                                 const char *name)
++static int linkat_empty_nofollow(struct lo_data *lo, struct lo_inode *inode,
++                                 int dfd, const char *name)
+ {
+     int res;
+-    char procname[64];
++    struct lo_inode *parent;
++    char path[PATH_MAX];
+ 
+     if (inode->is_symlink) {
+         res = linkat(inode->fd, "", dfd, name, AT_EMPTY_PATH);
+         if (res == -1 && (errno == ENOENT || errno == EINVAL)) {
+             /* Sorry, no race free way to hard-link a symlink. */
+-            errno = EPERM;
++            if (lo->norace) {
++                errno = EPERM;
++            } else {
++                goto fallback;
++            }
+         }
+         return res;
+     }
+ 
+-    sprintf(procname, "/proc/self/fd/%i", inode->fd);
++    sprintf(path, "/proc/self/fd/%i", inode->fd);
++
++    return linkat(AT_FDCWD, path, dfd, name, AT_SYMLINK_FOLLOW);
++
++fallback:
++    res = lo_parent_and_name(lo, inode, path, &parent);
++    if (res != -1) {
++        res = linkat(parent->fd, path, dfd, name, 0);
++        unref_inode(lo, parent, 1);
++    }
+ 
+-    return linkat(AT_FDCWD, procname, dfd, name, AT_SYMLINK_FOLLOW);
++    return res;
+ }
+ 
+ static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
+@@ -748,7 +873,7 @@ static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
+     e.attr_timeout = lo->timeout;
+     e.entry_timeout = lo->timeout;
+ 
+-    res = linkat_empty_nofollow(inode, lo_fd(req, parent), name);
++    res = linkat_empty_nofollow(lo, inode, lo_fd(req, parent), name);
+     if (res == -1) {
+         goto out_err;
+     }
diff --git a/0049-virtiofsd-validate-path-components.patch b/0049-virtiofsd-validate-path-components.patch
new file mode 100644
index 0000000..1e5bd2b
--- /dev/null
+++ b/0049-virtiofsd-validate-path-components.patch
@@ -0,0 +1,148 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:18 +0000
+Subject: [PATCH] virtiofsd: validate path components
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Several FUSE requests contain single path components.  A correct FUSE
+client sends well-formed path components but there is currently no input
+validation in case something went wrong or the client is malicious.
+
+Refuse ".", "..", and paths containing '/' when we expect a path
+component.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 25dae28c58d7e706b5d5db99042c9db3cef2e657)
+---
+ tools/virtiofsd/passthrough_ll.c | 59 ++++++++++++++++++++++++++++----
+ 1 file changed, 53 insertions(+), 6 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index ac380efcb1..e375406160 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -133,6 +133,21 @@ static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n);
+ 
+ static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st);
+ 
++static int is_dot_or_dotdot(const char *name)
++{
++    return name[0] == '.' &&
++           (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
++}
++
++/* Is `path` a single path component that is not "." or ".."? */
++static int is_safe_path_component(const char *path)
++{
++    if (strchr(path, '/')) {
++        return 0;
++    }
++
++    return !is_dot_or_dotdot(path);
++}
+ 
+ static struct lo_data *lo_data(fuse_req_t req)
+ {
+@@ -681,6 +696,15 @@ static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
+                  parent, name);
+     }
+ 
++    /*
++     * Don't use is_safe_path_component(), allow "." and ".." for NFS export
++     * support.
++     */
++    if (strchr(name, '/')) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
+     err = lo_do_lookup(req, parent, name, &e);
+     if (err) {
+         fuse_reply_err(req, err);
+@@ -762,6 +786,11 @@ static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent,
+     struct fuse_entry_param e;
+     struct lo_cred old = {};
+ 
++    if (!is_safe_path_component(name)) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
+     dir = lo_inode(req, parent);
+     if (!dir) {
+         fuse_reply_err(req, EBADF);
+@@ -863,6 +892,11 @@ static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
+     struct fuse_entry_param e;
+     int saverr;
+ 
++    if (!is_safe_path_component(name)) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
+     inode = lo_inode(req, ino);
+     if (!inode) {
+         fuse_reply_err(req, EBADF);
+@@ -904,6 +938,10 @@ out_err:
+ static void lo_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
+ {
+     int res;
++    if (!is_safe_path_component(name)) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+ 
+     res = unlinkat(lo_fd(req, parent), name, AT_REMOVEDIR);
+ 
+@@ -916,6 +954,11 @@ static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
+ {
+     int res;
+ 
++    if (!is_safe_path_component(name) || !is_safe_path_component(newname)) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
+     if (flags) {
+         fuse_reply_err(req, EINVAL);
+         return;
+@@ -930,6 +973,11 @@ static void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
+ {
+     int res;
+ 
++    if (!is_safe_path_component(name)) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
+     res = unlinkat(lo_fd(req, parent), name, 0);
+ 
+     fuse_reply_err(req, res == -1 ? errno : 0);
+@@ -1093,12 +1141,6 @@ out_err:
+     fuse_reply_err(req, error);
+ }
+ 
+-static int is_dot_or_dotdot(const char *name)
+-{
+-    return name[0] == '.' &&
+-           (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
+-}
+-
+ static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
+                           off_t offset, struct fuse_file_info *fi, int plus)
+ {
+@@ -1248,6 +1290,11 @@ static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
+                  parent, name);
+     }
+ 
++    if (!is_safe_path_component(name)) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
+     err = lo_change_cred(req, &old);
+     if (err) {
+         goto out;
diff --git a/0050-virtiofsd-Plumb-fuse_bufvec-through-to-do_write_buf.patch b/0050-virtiofsd-Plumb-fuse_bufvec-through-to-do_write_buf.patch
new file mode 100644
index 0000000..451e3b9
--- /dev/null
+++ b/0050-virtiofsd-Plumb-fuse_bufvec-through-to-do_write_buf.patch
@@ -0,0 +1,149 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:19 +0000
+Subject: [PATCH] virtiofsd: Plumb fuse_bufvec through to do_write_buf
+
+Let fuse_session_process_buf_int take a fuse_bufvec * instead of a
+fuse_buf;  and then through to do_write_buf - where in the best
+case it can pass that straight through to op.write_buf without copying
+(other than skipping a header).
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 469f9d2fc405b0508e6cf1b4b5bbcadfc82064e5)
+---
+ tools/virtiofsd/fuse_i.h        |  2 +-
+ tools/virtiofsd/fuse_lowlevel.c | 61 ++++++++++++++++++++++-----------
+ tools/virtiofsd/fuse_virtio.c   |  3 +-
+ 3 files changed, 44 insertions(+), 22 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_i.h b/tools/virtiofsd/fuse_i.h
+index 45995f3246..a20854f1c4 100644
+--- a/tools/virtiofsd/fuse_i.h
++++ b/tools/virtiofsd/fuse_i.h
+@@ -100,7 +100,7 @@ int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
+ void fuse_free_req(fuse_req_t req);
+ 
+ void fuse_session_process_buf_int(struct fuse_session *se,
+-                                  const struct fuse_buf *buf,
++                                  struct fuse_bufvec *bufv,
+                                   struct fuse_chan *ch);
+ 
+ 
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 95f4db8fcf..7e10995adc 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -1004,11 +1004,12 @@ static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ }
+ 
+ static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid, const void *inarg,
+-                         const struct fuse_buf *ibuf)
++                         struct fuse_bufvec *ibufv)
+ {
+     struct fuse_session *se = req->se;
+-    struct fuse_bufvec bufv = {
+-        .buf[0] = *ibuf,
++    struct fuse_bufvec *pbufv = ibufv;
++    struct fuse_bufvec tmpbufv = {
++        .buf[0] = ibufv->buf[0],
+         .count = 1,
+     };
+     struct fuse_write_in *arg = (struct fuse_write_in *)inarg;
+@@ -1018,22 +1019,31 @@ static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid, const void *inarg,
+     fi.fh = arg->fh;
+     fi.writepage = arg->write_flags & FUSE_WRITE_CACHE;
+ 
+-    fi.lock_owner = arg->lock_owner;
+-    fi.flags = arg->flags;
+-    if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD)) {
+-        bufv.buf[0].mem = PARAM(arg);
+-    }
+-
+-    bufv.buf[0].size -=
+-        sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in);
+-    if (bufv.buf[0].size < arg->size) {
+-        fuse_log(FUSE_LOG_ERR, "fuse: do_write_buf: buffer size too small\n");
+-        fuse_reply_err(req, EIO);
+-        return;
++    if (ibufv->count == 1) {
++        fi.lock_owner = arg->lock_owner;
++        fi.flags = arg->flags;
++        if (!(tmpbufv.buf[0].flags & FUSE_BUF_IS_FD)) {
++            tmpbufv.buf[0].mem = PARAM(arg);
++        }
++        tmpbufv.buf[0].size -=
++            sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in);
++        if (tmpbufv.buf[0].size < arg->size) {
++            fuse_log(FUSE_LOG_ERR,
++                     "fuse: do_write_buf: buffer size too small\n");
++            fuse_reply_err(req, EIO);
++            return;
++        }
++        tmpbufv.buf[0].size = arg->size;
++        pbufv = &tmpbufv;
++    } else {
++        /*
++         *  Input bufv contains the headers in the first element
++         * and the data in the rest, we need to skip that first element
++         */
++        ibufv->buf[0].size = 0;
+     }
+-    bufv.buf[0].size = arg->size;
+ 
+-    se->op.write_buf(req, nodeid, &bufv, arg->offset, &fi);
++    se->op.write_buf(req, nodeid, pbufv, arg->offset, &fi);
+ }
+ 
+ static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+@@ -2024,13 +2034,24 @@ static const char *opname(enum fuse_opcode opcode)
+ void fuse_session_process_buf(struct fuse_session *se,
+                               const struct fuse_buf *buf)
+ {
+-    fuse_session_process_buf_int(se, buf, NULL);
++    struct fuse_bufvec bufv = { .buf[0] = *buf, .count = 1 };
++    fuse_session_process_buf_int(se, &bufv, NULL);
+ }
+ 
++/*
++ * Restriction:
++ *   bufv is normally a single entry buffer, except for a write
++ *   where (if it's in memory) then the bufv may be multiple entries,
++ *   where the first entry contains all headers and subsequent entries
++ *   contain data
++ *   bufv shall not use any offsets etc to make the data anything
++ *   other than contiguous starting from 0.
++ */
+ void fuse_session_process_buf_int(struct fuse_session *se,
+-                                  const struct fuse_buf *buf,
++                                  struct fuse_bufvec *bufv,
+                                   struct fuse_chan *ch)
+ {
++    const struct fuse_buf *buf = bufv->buf;
+     struct fuse_in_header *in;
+     const void *inarg;
+     struct fuse_req *req;
+@@ -2108,7 +2129,7 @@ void fuse_session_process_buf_int(struct fuse_session *se,
+ 
+     inarg = (void *)&in[1];
+     if (in->opcode == FUSE_WRITE && se->op.write_buf) {
+-        do_write_buf(req, in->nodeid, inarg, buf);
++        do_write_buf(req, in->nodeid, inarg, bufv);
+     } else {
+         fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
+     }
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+index 635f87756a..fd588a4829 100644
+--- a/tools/virtiofsd/fuse_virtio.c
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -501,7 +501,8 @@ static void *fv_queue_thread(void *opaque)
+             /* TODO! Endianness of header */
+ 
+             /* TODO: Add checks for fuse_session_exited */
+-            fuse_session_process_buf_int(se, &fbuf, &ch);
++            struct fuse_bufvec bufv = { .buf[0] = fbuf, .count = 1 };
++            fuse_session_process_buf_int(se, &bufv, &ch);
+ 
+             if (!qi->reply_sent) {
+                 fuse_log(FUSE_LOG_DEBUG, "%s: elem %d no reply sent\n",
diff --git a/0051-virtiofsd-Pass-write-iov-s-all-the-way-through.patch b/0051-virtiofsd-Pass-write-iov-s-all-the-way-through.patch
new file mode 100644
index 0000000..d32681d
--- /dev/null
+++ b/0051-virtiofsd-Pass-write-iov-s-all-the-way-through.patch
@@ -0,0 +1,121 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:20 +0000
+Subject: [PATCH] virtiofsd: Pass write iov's all the way through
+
+Pass the write iov pointing to guest RAM all the way through rather
+than copying the data.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Xiao Yang <yangx.jy@cn.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit e17f7a580e2c599330ad3a6946be615ca2fe97d9)
+---
+ tools/virtiofsd/fuse_virtio.c | 79 ++++++++++++++++++++++++++++++++---
+ 1 file changed, 73 insertions(+), 6 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+index fd588a4829..872968f2c8 100644
+--- a/tools/virtiofsd/fuse_virtio.c
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -454,6 +454,10 @@ static void *fv_queue_thread(void *opaque)
+                  __func__, qi->qidx, (size_t)evalue, in_bytes, out_bytes);
+ 
+         while (1) {
++            bool allocated_bufv = false;
++            struct fuse_bufvec bufv;
++            struct fuse_bufvec *pbufv;
++
+             /*
+              * An element contains one request and the space to send our
+              * response They're spread over multiple descriptors in a
+@@ -495,14 +499,76 @@ static void *fv_queue_thread(void *opaque)
+                          __func__, elem->index);
+                 assert(0); /* TODO */
+             }
+-            copy_from_iov(&fbuf, out_num, out_sg);
+-            fbuf.size = out_len;
++            /* Copy just the first element and look at it */
++            copy_from_iov(&fbuf, 1, out_sg);
++
++            if (out_num > 2 &&
++                out_sg[0].iov_len == sizeof(struct fuse_in_header) &&
++                ((struct fuse_in_header *)fbuf.mem)->opcode == FUSE_WRITE &&
++                out_sg[1].iov_len == sizeof(struct fuse_write_in)) {
++                /*
++                 * For a write we don't actually need to copy the
++                 * data, we can just do it straight out of guest memory
++                 * but we must still copy the headers in case the guest
++                 * was nasty and changed them while we were using them.
++                 */
++                fuse_log(FUSE_LOG_DEBUG, "%s: Write special case\n", __func__);
++
++                /* copy the fuse_write_in header after the fuse_in_header */
++                fbuf.mem += out_sg->iov_len;
++                copy_from_iov(&fbuf, 1, out_sg + 1);
++                fbuf.mem -= out_sg->iov_len;
++                fbuf.size = out_sg[0].iov_len + out_sg[1].iov_len;
++
++                /* Allocate the bufv, with space for the rest of the iov */
++                allocated_bufv = true;
++                pbufv = malloc(sizeof(struct fuse_bufvec) +
++                               sizeof(struct fuse_buf) * (out_num - 2));
++                if (!pbufv) {
++                    vu_queue_unpop(dev, q, elem, 0);
++                    free(elem);
++                    fuse_log(FUSE_LOG_ERR, "%s: pbufv malloc failed\n",
++                             __func__);
++                    goto out;
++                }
++
++                pbufv->count = 1;
++                pbufv->buf[0] = fbuf;
++
++                size_t iovindex, pbufvindex;
++                iovindex = 2; /* 2 headers, separate iovs */
++                pbufvindex = 1; /* 2 headers, 1 fusebuf */
++
++                for (; iovindex < out_num; iovindex++, pbufvindex++) {
++                    pbufv->count++;
++                    pbufv->buf[pbufvindex].pos = ~0; /* Dummy */
++                    pbufv->buf[pbufvindex].flags = 0;
++                    pbufv->buf[pbufvindex].mem = out_sg[iovindex].iov_base;
++                    pbufv->buf[pbufvindex].size = out_sg[iovindex].iov_len;
++                }
++            } else {
++                /* Normal (non fast write) path */
++
++                /* Copy the rest of the buffer */
++                fbuf.mem += out_sg->iov_len;
++                copy_from_iov(&fbuf, out_num - 1, out_sg + 1);
++                fbuf.mem -= out_sg->iov_len;
++                fbuf.size = out_len;
+ 
+-            /* TODO! Endianness of header */
++                /* TODO! Endianness of header */
+ 
+-            /* TODO: Add checks for fuse_session_exited */
+-            struct fuse_bufvec bufv = { .buf[0] = fbuf, .count = 1 };
+-            fuse_session_process_buf_int(se, &bufv, &ch);
++                /* TODO: Add checks for fuse_session_exited */
++                bufv.buf[0] = fbuf;
++                bufv.count = 1;
++                pbufv = &bufv;
++            }
++            pbufv->idx = 0;
++            pbufv->off = 0;
++            fuse_session_process_buf_int(se, pbufv, &ch);
++
++            if (allocated_bufv) {
++                free(pbufv);
++            }
+ 
+             if (!qi->reply_sent) {
+                 fuse_log(FUSE_LOG_DEBUG, "%s: elem %d no reply sent\n",
+@@ -516,6 +582,7 @@ static void *fv_queue_thread(void *opaque)
+             elem = NULL;
+         }
+     }
++out:
+     pthread_mutex_destroy(&ch.lock);
+     free(fbuf.mem);
+ 
diff --git a/0052-virtiofsd-add-fuse_mbuf_iter-API.patch b/0052-virtiofsd-add-fuse_mbuf_iter-API.patch
new file mode 100644
index 0000000..1358aa8
--- /dev/null
+++ b/0052-virtiofsd-add-fuse_mbuf_iter-API.patch
@@ -0,0 +1,115 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:21 +0000
+Subject: [PATCH] virtiofsd: add fuse_mbuf_iter API
+
+Introduce an API for consuming bytes from a buffer with size checks.
+All FUSE operations will be converted to use this safe API instead of
+void *inarg.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit dad157e880416ab3a0e45beaa0e81977516568bc)
+---
+ tools/virtiofsd/buffer.c      | 28 ++++++++++++++++++++
+ tools/virtiofsd/fuse_common.h | 49 ++++++++++++++++++++++++++++++++++-
+ 2 files changed, 76 insertions(+), 1 deletion(-)
+
+diff --git a/tools/virtiofsd/buffer.c b/tools/virtiofsd/buffer.c
+index 772efa922d..42a608f6bd 100644
+--- a/tools/virtiofsd/buffer.c
++++ b/tools/virtiofsd/buffer.c
+@@ -267,3 +267,31 @@ ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv)
+ 
+     return copied;
+ }
++
++void *fuse_mbuf_iter_advance(struct fuse_mbuf_iter *iter, size_t len)
++{
++    void *ptr;
++
++    if (len > iter->size - iter->pos) {
++        return NULL;
++    }
++
++    ptr = iter->mem + iter->pos;
++    iter->pos += len;
++    return ptr;
++}
++
++const char *fuse_mbuf_iter_advance_str(struct fuse_mbuf_iter *iter)
++{
++    const char *str = iter->mem + iter->pos;
++    size_t remaining = iter->size - iter->pos;
++    size_t i;
++
++    for (i = 0; i < remaining; i++) {
++        if (str[i] == '\0') {
++            iter->pos += i + 1;
++            return str;
++        }
++    }
++    return NULL;
++}
+diff --git a/tools/virtiofsd/fuse_common.h b/tools/virtiofsd/fuse_common.h
+index 0cb33acc2f..f8f6433743 100644
+--- a/tools/virtiofsd/fuse_common.h
++++ b/tools/virtiofsd/fuse_common.h
+@@ -703,10 +703,57 @@ size_t fuse_buf_size(const struct fuse_bufvec *bufv);
+  */
+ ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src);
+ 
++/**
++ * Memory buffer iterator
++ *
++ */
++struct fuse_mbuf_iter {
++    /**
++     * Data pointer
++     */
++    void *mem;
++
++    /**
++     * Total length, in bytes
++     */
++    size_t size;
++
++    /**
++     * Offset from start of buffer
++     */
++    size_t pos;
++};
++
++/* Initialize memory buffer iterator from a fuse_buf */
++#define FUSE_MBUF_ITER_INIT(fbuf) \
++    ((struct fuse_mbuf_iter){     \
++        .mem = fbuf->mem,         \
++        .size = fbuf->size,       \
++        .pos = 0,                 \
++    })
++
++/**
++ * Consume bytes from a memory buffer iterator
++ *
++ * @param iter memory buffer iterator
++ * @param len number of bytes to consume
++ * @return pointer to start of consumed bytes or
++ *         NULL if advancing beyond end of buffer
++ */
++void *fuse_mbuf_iter_advance(struct fuse_mbuf_iter *iter, size_t len);
++
++/**
++ * Consume a NUL-terminated string from a memory buffer iterator
++ *
++ * @param iter memory buffer iterator
++ * @return pointer to the string or
++ *         NULL if advancing beyond end of buffer or there is no NUL-terminator
++ */
++const char *fuse_mbuf_iter_advance_str(struct fuse_mbuf_iter *iter);
++
+ /*
+  * Signal handling
+  */
+-
+ /**
+  * Exit session on HUP, TERM and INT signals and ignore PIPE signal
+  *
diff --git a/0053-virtiofsd-validate-input-buffer-sizes-in-do_write_bu.patch b/0053-virtiofsd-validate-input-buffer-sizes-in-do_write_bu.patch
new file mode 100644
index 0000000..d5ad1dd
--- /dev/null
+++ b/0053-virtiofsd-validate-input-buffer-sizes-in-do_write_bu.patch
@@ -0,0 +1,117 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:22 +0000
+Subject: [PATCH] virtiofsd: validate input buffer sizes in do_write_buf()
+
+There is a small change in behavior: if fuse_write_in->size doesn't
+match the input buffer size then the request is failed.  Previously
+write requests with 1 fuse_buf element would truncate to
+fuse_write_in->size.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Sergio Lopez <slp@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 0ba8c3c6fce8fe949d59c1fd84d98d220ef9e759)
+---
+ tools/virtiofsd/fuse_lowlevel.c | 49 ++++++++++++++++++++-------------
+ 1 file changed, 30 insertions(+), 19 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 7e10995adc..611e8b0354 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -1003,8 +1003,8 @@ static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid, const void *inarg,
+-                         struct fuse_bufvec *ibufv)
++static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid,
++                         struct fuse_mbuf_iter *iter, struct fuse_bufvec *ibufv)
+ {
+     struct fuse_session *se = req->se;
+     struct fuse_bufvec *pbufv = ibufv;
+@@ -1012,28 +1012,27 @@ static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid, const void *inarg,
+         .buf[0] = ibufv->buf[0],
+         .count = 1,
+     };
+-    struct fuse_write_in *arg = (struct fuse_write_in *)inarg;
++    struct fuse_write_in *arg;
++    size_t arg_size = sizeof(*arg);
+     struct fuse_file_info fi;
+ 
+     memset(&fi, 0, sizeof(fi));
++
++    arg = fuse_mbuf_iter_advance(iter, arg_size);
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
++    fi.lock_owner = arg->lock_owner;
++    fi.flags = arg->flags;
+     fi.fh = arg->fh;
+     fi.writepage = arg->write_flags & FUSE_WRITE_CACHE;
+ 
+     if (ibufv->count == 1) {
+-        fi.lock_owner = arg->lock_owner;
+-        fi.flags = arg->flags;
+-        if (!(tmpbufv.buf[0].flags & FUSE_BUF_IS_FD)) {
+-            tmpbufv.buf[0].mem = PARAM(arg);
+-        }
+-        tmpbufv.buf[0].size -=
+-            sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in);
+-        if (tmpbufv.buf[0].size < arg->size) {
+-            fuse_log(FUSE_LOG_ERR,
+-                     "fuse: do_write_buf: buffer size too small\n");
+-            fuse_reply_err(req, EIO);
+-            return;
+-        }
+-        tmpbufv.buf[0].size = arg->size;
++        assert(!(tmpbufv.buf[0].flags & FUSE_BUF_IS_FD));
++        tmpbufv.buf[0].mem = ((char *)arg) + arg_size;
++        tmpbufv.buf[0].size -= sizeof(struct fuse_in_header) + arg_size;
+         pbufv = &tmpbufv;
+     } else {
+         /*
+@@ -1043,6 +1042,13 @@ static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid, const void *inarg,
+         ibufv->buf[0].size = 0;
+     }
+ 
++    if (fuse_buf_size(pbufv) != arg->size) {
++        fuse_log(FUSE_LOG_ERR,
++                 "fuse: do_write_buf: buffer size doesn't match arg->size\n");
++        fuse_reply_err(req, EIO);
++        return;
++    }
++
+     se->op.write_buf(req, nodeid, pbufv, arg->offset, &fi);
+ }
+ 
+@@ -2052,12 +2058,17 @@ void fuse_session_process_buf_int(struct fuse_session *se,
+                                   struct fuse_chan *ch)
+ {
+     const struct fuse_buf *buf = bufv->buf;
++    struct fuse_mbuf_iter iter = FUSE_MBUF_ITER_INIT(buf);
+     struct fuse_in_header *in;
+     const void *inarg;
+     struct fuse_req *req;
+     int err;
+ 
+-    in = buf->mem;
++    /* The first buffer must be a memory buffer */
++    assert(!(buf->flags & FUSE_BUF_IS_FD));
++
++    in = fuse_mbuf_iter_advance(&iter, sizeof(*in));
++    assert(in); /* caller guarantees the input buffer is large enough */
+ 
+     if (se->debug) {
+         fuse_log(FUSE_LOG_DEBUG,
+@@ -2129,7 +2140,7 @@ void fuse_session_process_buf_int(struct fuse_session *se,
+ 
+     inarg = (void *)&in[1];
+     if (in->opcode == FUSE_WRITE && se->op.write_buf) {
+-        do_write_buf(req, in->nodeid, inarg, bufv);
++        do_write_buf(req, in->nodeid, &iter, bufv);
+     } else {
+         fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
+     }
diff --git a/0054-virtiofsd-check-input-buffer-size-in-fuse_lowlevel.c.patch b/0054-virtiofsd-check-input-buffer-size-in-fuse_lowlevel.c.patch
new file mode 100644
index 0000000..6746752
--- /dev/null
+++ b/0054-virtiofsd-check-input-buffer-size-in-fuse_lowlevel.c.patch
@@ -0,0 +1,1091 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:23 +0000
+Subject: [PATCH] virtiofsd: check input buffer size in fuse_lowlevel.c ops
+
+Each FUSE operation involves parsing the input buffer.  Currently the
+code assumes the input buffer is large enough for the expected
+arguments.  This patch uses fuse_mbuf_iter to check the size.
+
+Most operations are simple to convert.  Some are more complicated due to
+variable-length inputs or different sizes depending on the protocol
+version.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Sergio Lopez <slp@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 70995754416eb4491c31607fe380a83cfd25a087)
+---
+ tools/virtiofsd/fuse_lowlevel.c | 581 +++++++++++++++++++++++++-------
+ 1 file changed, 456 insertions(+), 125 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 611e8b0354..02e1d83038 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -19,6 +19,7 @@
+ #include <assert.h>
+ #include <errno.h>
+ #include <limits.h>
++#include <stdbool.h>
+ #include <stddef.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+@@ -27,7 +28,6 @@
+ #include <unistd.h>
+ 
+ 
+-#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
+ #define OFFSET_MAX 0x7fffffffffffffffLL
+ 
+ struct fuse_pollhandle {
+@@ -706,9 +706,14 @@ int fuse_reply_lseek(fuse_req_t req, off_t off)
+     return send_reply_ok(req, &arg, sizeof(arg));
+ }
+ 
+-static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_lookup(fuse_req_t req, fuse_ino_t nodeid,
++                      struct fuse_mbuf_iter *iter)
+ {
+-    char *name = (char *)inarg;
++    const char *name = fuse_mbuf_iter_advance_str(iter);
++    if (!name) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+ 
+     if (req->se->op.lookup) {
+         req->se->op.lookup(req, nodeid, name);
+@@ -717,9 +722,16 @@ static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_forget(fuse_req_t req, fuse_ino_t nodeid,
++                      struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_forget_in *arg = (struct fuse_forget_in *)inarg;
++    struct fuse_forget_in *arg;
++
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+ 
+     if (req->se->op.forget) {
+         req->se->op.forget(req, nodeid, arg->nlookup);
+@@ -729,20 +741,48 @@ static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ }
+ 
+ static void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid,
+-                            const void *inarg)
++                            struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_batch_forget_in *arg = (void *)inarg;
+-    struct fuse_forget_one *param = (void *)PARAM(arg);
+-    unsigned int i;
++    struct fuse_batch_forget_in *arg;
++    struct fuse_forget_data *forgets;
++    size_t scount;
+ 
+     (void)nodeid;
+ 
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_none(req);
++        return;
++    }
++
++    /*
++     * Prevent integer overflow.  The compiler emits the following warning
++     * unless we use the scount local variable:
++     *
++     * error: comparison is always false due to limited range of data type
++     * [-Werror=type-limits]
++     *
++     * This may be true on 64-bit hosts but we need this check for 32-bit
++     * hosts.
++     */
++    scount = arg->count;
++    if (scount > SIZE_MAX / sizeof(forgets[0])) {
++        fuse_reply_none(req);
++        return;
++    }
++
++    forgets = fuse_mbuf_iter_advance(iter, arg->count * sizeof(forgets[0]));
++    if (!forgets) {
++        fuse_reply_none(req);
++        return;
++    }
++
+     if (req->se->op.forget_multi) {
+-        req->se->op.forget_multi(req, arg->count,
+-                                 (struct fuse_forget_data *)param);
++        req->se->op.forget_multi(req, arg->count, forgets);
+     } else if (req->se->op.forget) {
++        unsigned int i;
++
+         for (i = 0; i < arg->count; i++) {
+-            struct fuse_forget_one *forget = &param[i];
+             struct fuse_req *dummy_req;
+ 
+             dummy_req = fuse_ll_alloc_req(req->se);
+@@ -754,7 +794,7 @@ static void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid,
+             dummy_req->ctx = req->ctx;
+             dummy_req->ch = NULL;
+ 
+-            req->se->op.forget(dummy_req, forget->nodeid, forget->nlookup);
++            req->se->op.forget(dummy_req, forgets[i].ino, forgets[i].nlookup);
+         }
+         fuse_reply_none(req);
+     } else {
+@@ -762,12 +802,19 @@ static void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid,
+     }
+ }
+ 
+-static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_getattr(fuse_req_t req, fuse_ino_t nodeid,
++                       struct fuse_mbuf_iter *iter)
+ {
+     struct fuse_file_info *fip = NULL;
+     struct fuse_file_info fi;
+ 
+-    struct fuse_getattr_in *arg = (struct fuse_getattr_in *)inarg;
++    struct fuse_getattr_in *arg;
++
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+ 
+     if (arg->getattr_flags & FUSE_GETATTR_FH) {
+         memset(&fi, 0, sizeof(fi));
+@@ -782,14 +829,21 @@ static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_setattr(fuse_req_t req, fuse_ino_t nodeid,
++                       struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_setattr_in *arg = (struct fuse_setattr_in *)inarg;
+-
+     if (req->se->op.setattr) {
++        struct fuse_setattr_in *arg;
+         struct fuse_file_info *fi = NULL;
+         struct fuse_file_info fi_store;
+         struct stat stbuf;
++
++        arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++        if (!arg) {
++            fuse_reply_err(req, EINVAL);
++            return;
++        }
++
+         memset(&stbuf, 0, sizeof(stbuf));
+         convert_attr(arg, &stbuf);
+         if (arg->valid & FATTR_FH) {
+@@ -810,9 +864,16 @@ static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_access(fuse_req_t req, fuse_ino_t nodeid,
++                      struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_access_in *arg = (struct fuse_access_in *)inarg;
++    struct fuse_access_in *arg;
++
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+ 
+     if (req->se->op.access) {
+         req->se->op.access(req, nodeid, arg->mask);
+@@ -821,9 +882,10 @@ static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_readlink(fuse_req_t req, fuse_ino_t nodeid,
++                        struct fuse_mbuf_iter *iter)
+ {
+-    (void)inarg;
++    (void)iter;
+ 
+     if (req->se->op.readlink) {
+         req->se->op.readlink(req, nodeid);
+@@ -832,10 +894,18 @@ static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_mknod(fuse_req_t req, fuse_ino_t nodeid,
++                     struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_mknod_in *arg = (struct fuse_mknod_in *)inarg;
+-    char *name = PARAM(arg);
++    struct fuse_mknod_in *arg;
++    const char *name;
++
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    name = fuse_mbuf_iter_advance_str(iter);
++    if (!arg || !name) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+ 
+     req->ctx.umask = arg->umask;
+ 
+@@ -846,22 +916,37 @@ static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid,
++                     struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *)inarg;
++    struct fuse_mkdir_in *arg;
++    const char *name;
++
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    name = fuse_mbuf_iter_advance_str(iter);
++    if (!arg || !name) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+ 
+     req->ctx.umask = arg->umask;
+ 
+     if (req->se->op.mkdir) {
+-        req->se->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
++        req->se->op.mkdir(req, nodeid, name, arg->mode);
+     } else {
+         fuse_reply_err(req, ENOSYS);
+     }
+ }
+ 
+-static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_unlink(fuse_req_t req, fuse_ino_t nodeid,
++                      struct fuse_mbuf_iter *iter)
+ {
+-    char *name = (char *)inarg;
++    const char *name = fuse_mbuf_iter_advance_str(iter);
++
++    if (!name) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+ 
+     if (req->se->op.unlink) {
+         req->se->op.unlink(req, nodeid, name);
+@@ -870,9 +955,15 @@ static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid,
++                     struct fuse_mbuf_iter *iter)
+ {
+-    char *name = (char *)inarg;
++    const char *name = fuse_mbuf_iter_advance_str(iter);
++
++    if (!name) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+ 
+     if (req->se->op.rmdir) {
+         req->se->op.rmdir(req, nodeid, name);
+@@ -881,10 +972,16 @@ static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_symlink(fuse_req_t req, fuse_ino_t nodeid,
++                       struct fuse_mbuf_iter *iter)
+ {
+-    char *name = (char *)inarg;
+-    char *linkname = ((char *)inarg) + strlen((char *)inarg) + 1;
++    const char *name = fuse_mbuf_iter_advance_str(iter);
++    const char *linkname = fuse_mbuf_iter_advance_str(iter);
++
++    if (!name || !linkname) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+ 
+     if (req->se->op.symlink) {
+         req->se->op.symlink(req, linkname, nodeid, name);
+@@ -893,11 +990,20 @@ static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_rename(fuse_req_t req, fuse_ino_t nodeid,
++                      struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_rename_in *arg = (struct fuse_rename_in *)inarg;
+-    char *oldname = PARAM(arg);
+-    char *newname = oldname + strlen(oldname) + 1;
++    struct fuse_rename_in *arg;
++    const char *oldname;
++    const char *newname;
++
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    oldname = fuse_mbuf_iter_advance_str(iter);
++    newname = fuse_mbuf_iter_advance_str(iter);
++    if (!arg || !oldname || !newname) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+ 
+     if (req->se->op.rename) {
+         req->se->op.rename(req, nodeid, oldname, arg->newdir, newname, 0);
+@@ -906,11 +1012,20 @@ static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_rename2(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_rename2(fuse_req_t req, fuse_ino_t nodeid,
++                       struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_rename2_in *arg = (struct fuse_rename2_in *)inarg;
+-    char *oldname = PARAM(arg);
+-    char *newname = oldname + strlen(oldname) + 1;
++    struct fuse_rename2_in *arg;
++    const char *oldname;
++    const char *newname;
++
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    oldname = fuse_mbuf_iter_advance_str(iter);
++    newname = fuse_mbuf_iter_advance_str(iter);
++    if (!arg || !oldname || !newname) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+ 
+     if (req->se->op.rename) {
+         req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
+@@ -920,24 +1035,38 @@ static void do_rename2(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_link(fuse_req_t req, fuse_ino_t nodeid,
++                    struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_link_in *arg = (struct fuse_link_in *)inarg;
++    struct fuse_link_in *arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    const char *name = fuse_mbuf_iter_advance_str(iter);
++
++    if (!arg || !name) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+ 
+     if (req->se->op.link) {
+-        req->se->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
++        req->se->op.link(req, arg->oldnodeid, nodeid, name);
+     } else {
+         fuse_reply_err(req, ENOSYS);
+     }
+ }
+ 
+-static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_create(fuse_req_t req, fuse_ino_t nodeid,
++                      struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_create_in *arg = (struct fuse_create_in *)inarg;
+-
+     if (req->se->op.create) {
++        struct fuse_create_in *arg;
+         struct fuse_file_info fi;
+-        char *name = PARAM(arg);
++        const char *name;
++
++        arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++        name = fuse_mbuf_iter_advance_str(iter);
++        if (!arg || !name) {
++            fuse_reply_err(req, EINVAL);
++            return;
++        }
+ 
+         memset(&fi, 0, sizeof(fi));
+         fi.flags = arg->flags;
+@@ -950,11 +1079,18 @@ static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_open(fuse_req_t req, fuse_ino_t nodeid,
++                    struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_open_in *arg = (struct fuse_open_in *)inarg;
++    struct fuse_open_in *arg;
+     struct fuse_file_info fi;
+ 
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
+     memset(&fi, 0, sizeof(fi));
+     fi.flags = arg->flags;
+ 
+@@ -965,13 +1101,15 @@ static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_read(fuse_req_t req, fuse_ino_t nodeid,
++                    struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_read_in *arg = (struct fuse_read_in *)inarg;
+-
+     if (req->se->op.read) {
++        struct fuse_read_in *arg;
+         struct fuse_file_info fi;
+ 
++        arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++
+         memset(&fi, 0, sizeof(fi));
+         fi.fh = arg->fh;
+         fi.lock_owner = arg->lock_owner;
+@@ -982,11 +1120,24 @@ static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_write(fuse_req_t req, fuse_ino_t nodeid,
++                     struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_write_in *arg = (struct fuse_write_in *)inarg;
++    struct fuse_write_in *arg;
+     struct fuse_file_info fi;
+-    char *param;
++    const char *param;
++
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
++    param = fuse_mbuf_iter_advance(iter, arg->size);
++    if (!param) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+ 
+     memset(&fi, 0, sizeof(fi));
+     fi.fh = arg->fh;
+@@ -994,7 +1145,6 @@ static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ 
+     fi.lock_owner = arg->lock_owner;
+     fi.flags = arg->flags;
+-    param = PARAM(arg);
+ 
+     if (req->se->op.write) {
+         req->se->op.write(req, nodeid, param, arg->size, arg->offset, &fi);
+@@ -1052,11 +1202,18 @@ static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid,
+     se->op.write_buf(req, nodeid, pbufv, arg->offset, &fi);
+ }
+ 
+-static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_flush(fuse_req_t req, fuse_ino_t nodeid,
++                     struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_flush_in *arg = (struct fuse_flush_in *)inarg;
++    struct fuse_flush_in *arg;
+     struct fuse_file_info fi;
+ 
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
+     memset(&fi, 0, sizeof(fi));
+     fi.fh = arg->fh;
+     fi.flush = 1;
+@@ -1069,19 +1226,26 @@ static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_release(fuse_req_t req, fuse_ino_t nodeid,
++                       struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_release_in *arg = (struct fuse_release_in *)inarg;
++    struct fuse_release_in *arg;
+     struct fuse_file_info fi;
+ 
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
+     memset(&fi, 0, sizeof(fi));
+     fi.flags = arg->flags;
+     fi.fh = arg->fh;
+     fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
+     fi.lock_owner = arg->lock_owner;
++
+     if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) {
+         fi.flock_release = 1;
+-        fi.lock_owner = arg->lock_owner;
+     }
+ 
+     if (req->se->op.release) {
+@@ -1091,11 +1255,19 @@ static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_fsync(fuse_req_t req, fuse_ino_t nodeid,
++                     struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_fsync_in *arg = (struct fuse_fsync_in *)inarg;
++    struct fuse_fsync_in *arg;
+     struct fuse_file_info fi;
+-    int datasync = arg->fsync_flags & 1;
++    int datasync;
++
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++    datasync = arg->fsync_flags & 1;
+ 
+     memset(&fi, 0, sizeof(fi));
+     fi.fh = arg->fh;
+@@ -1111,11 +1283,18 @@ static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_opendir(fuse_req_t req, fuse_ino_t nodeid,
++                       struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_open_in *arg = (struct fuse_open_in *)inarg;
++    struct fuse_open_in *arg;
+     struct fuse_file_info fi;
+ 
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
+     memset(&fi, 0, sizeof(fi));
+     fi.flags = arg->flags;
+ 
+@@ -1126,11 +1305,18 @@ static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_readdir(fuse_req_t req, fuse_ino_t nodeid,
++                       struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_read_in *arg = (struct fuse_read_in *)inarg;
++    struct fuse_read_in *arg;
+     struct fuse_file_info fi;
+ 
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
+     memset(&fi, 0, sizeof(fi));
+     fi.fh = arg->fh;
+ 
+@@ -1141,11 +1327,18 @@ static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_readdirplus(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_readdirplus(fuse_req_t req, fuse_ino_t nodeid,
++                           struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_read_in *arg = (struct fuse_read_in *)inarg;
++    struct fuse_read_in *arg;
+     struct fuse_file_info fi;
+ 
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
+     memset(&fi, 0, sizeof(fi));
+     fi.fh = arg->fh;
+ 
+@@ -1156,11 +1349,18 @@ static void do_readdirplus(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid,
++                          struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_release_in *arg = (struct fuse_release_in *)inarg;
++    struct fuse_release_in *arg;
+     struct fuse_file_info fi;
+ 
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
+     memset(&fi, 0, sizeof(fi));
+     fi.flags = arg->flags;
+     fi.fh = arg->fh;
+@@ -1172,11 +1372,19 @@ static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid,
++                        struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_fsync_in *arg = (struct fuse_fsync_in *)inarg;
++    struct fuse_fsync_in *arg;
+     struct fuse_file_info fi;
+-    int datasync = arg->fsync_flags & 1;
++    int datasync;
++
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++    datasync = arg->fsync_flags & 1;
+ 
+     memset(&fi, 0, sizeof(fi));
+     fi.fh = arg->fh;
+@@ -1188,10 +1396,11 @@ static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_statfs(fuse_req_t req, fuse_ino_t nodeid,
++                      struct fuse_mbuf_iter *iter)
+ {
+     (void)nodeid;
+-    (void)inarg;
++    (void)iter;
+ 
+     if (req->se->op.statfs) {
+         req->se->op.statfs(req, nodeid);
+@@ -1204,11 +1413,25 @@ static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid,
++                        struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *)inarg;
+-    char *name = PARAM(arg);
+-    char *value = name + strlen(name) + 1;
++    struct fuse_setxattr_in *arg;
++    const char *name;
++    const char *value;
++
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    name = fuse_mbuf_iter_advance_str(iter);
++    if (!arg || !name) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
++    value = fuse_mbuf_iter_advance(iter, arg->size);
++    if (!value) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+ 
+     if (req->se->op.setxattr) {
+         req->se->op.setxattr(req, nodeid, name, value, arg->size, arg->flags);
+@@ -1217,20 +1440,36 @@ static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid,
++                        struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *)inarg;
++    struct fuse_getxattr_in *arg;
++    const char *name;
++
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    name = fuse_mbuf_iter_advance_str(iter);
++    if (!arg || !name) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+ 
+     if (req->se->op.getxattr) {
+-        req->se->op.getxattr(req, nodeid, PARAM(arg), arg->size);
++        req->se->op.getxattr(req, nodeid, name, arg->size);
+     } else {
+         fuse_reply_err(req, ENOSYS);
+     }
+ }
+ 
+-static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid,
++                         struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *)inarg;
++    struct fuse_getxattr_in *arg;
++
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+ 
+     if (req->se->op.listxattr) {
+         req->se->op.listxattr(req, nodeid, arg->size);
+@@ -1239,9 +1478,15 @@ static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid,
++                           struct fuse_mbuf_iter *iter)
+ {
+-    char *name = (char *)inarg;
++    const char *name = fuse_mbuf_iter_advance_str(iter);
++
++    if (!name) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+ 
+     if (req->se->op.removexattr) {
+         req->se->op.removexattr(req, nodeid, name);
+@@ -1265,12 +1510,19 @@ static void convert_fuse_file_lock(struct fuse_file_lock *fl,
+     flock->l_pid = fl->pid;
+ }
+ 
+-static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_getlk(fuse_req_t req, fuse_ino_t nodeid,
++                     struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_lk_in *arg = (struct fuse_lk_in *)inarg;
++    struct fuse_lk_in *arg;
+     struct fuse_file_info fi;
+     struct flock flock;
+ 
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
+     memset(&fi, 0, sizeof(fi));
+     fi.fh = arg->fh;
+     fi.lock_owner = arg->owner;
+@@ -1284,12 +1536,18 @@ static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ }
+ 
+ static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid,
+-                            const void *inarg, int sleep)
++                            struct fuse_mbuf_iter *iter, int sleep)
+ {
+-    struct fuse_lk_in *arg = (struct fuse_lk_in *)inarg;
++    struct fuse_lk_in *arg;
+     struct fuse_file_info fi;
+     struct flock flock;
+ 
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
+     memset(&fi, 0, sizeof(fi));
+     fi.fh = arg->fh;
+     fi.lock_owner = arg->owner;
+@@ -1327,14 +1585,16 @@ static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid,
+     }
+ }
+ 
+-static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_setlk(fuse_req_t req, fuse_ino_t nodeid,
++                     struct fuse_mbuf_iter *iter)
+ {
+-    do_setlk_common(req, nodeid, inarg, 0);
++    do_setlk_common(req, nodeid, iter, 0);
+ }
+ 
+-static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid,
++                      struct fuse_mbuf_iter *iter)
+ {
+-    do_setlk_common(req, nodeid, inarg, 1);
++    do_setlk_common(req, nodeid, iter, 1);
+ }
+ 
+ static int find_interrupted(struct fuse_session *se, struct fuse_req *req)
+@@ -1379,12 +1639,20 @@ static int find_interrupted(struct fuse_session *se, struct fuse_req *req)
+     return 0;
+ }
+ 
+-static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid,
++                         struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *)inarg;
++    struct fuse_interrupt_in *arg;
+     struct fuse_session *se = req->se;
+ 
+     (void)nodeid;
++
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
+     if (se->debug) {
+         fuse_log(FUSE_LOG_DEBUG, "INTERRUPT: %llu\n",
+                  (unsigned long long)arg->unique);
+@@ -1425,9 +1693,15 @@ static struct fuse_req *check_interrupt(struct fuse_session *se,
+     }
+ }
+ 
+-static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_bmap(fuse_req_t req, fuse_ino_t nodeid,
++                    struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_bmap_in *arg = (struct fuse_bmap_in *)inarg;
++    struct fuse_bmap_in *arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+ 
+     if (req->se->op.bmap) {
+         req->se->op.bmap(req, nodeid, arg->blocksize, arg->block);
+@@ -1436,18 +1710,34 @@ static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid,
++                     struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_ioctl_in *arg = (struct fuse_ioctl_in *)inarg;
+-    unsigned int flags = arg->flags;
+-    void *in_buf = arg->in_size ? PARAM(arg) : NULL;
++    struct fuse_ioctl_in *arg;
++    unsigned int flags;
++    void *in_buf = NULL;
+     struct fuse_file_info fi;
+ 
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
++    flags = arg->flags;
+     if (flags & FUSE_IOCTL_DIR && !(req->se->conn.want & FUSE_CAP_IOCTL_DIR)) {
+         fuse_reply_err(req, ENOTTY);
+         return;
+     }
+ 
++    if (arg->in_size) {
++        in_buf = fuse_mbuf_iter_advance(iter, arg->in_size);
++        if (!in_buf) {
++            fuse_reply_err(req, EINVAL);
++            return;
++        }
++    }
++
+     memset(&fi, 0, sizeof(fi));
+     fi.fh = arg->fh;
+ 
+@@ -1468,11 +1758,18 @@ void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
+     free(ph);
+ }
+ 
+-static void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_poll(fuse_req_t req, fuse_ino_t nodeid,
++                    struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_poll_in *arg = (struct fuse_poll_in *)inarg;
++    struct fuse_poll_in *arg;
+     struct fuse_file_info fi;
+ 
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
+     memset(&fi, 0, sizeof(fi));
+     fi.fh = arg->fh;
+     fi.poll_events = arg->events;
+@@ -1496,11 +1793,18 @@ static void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_fallocate(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_fallocate(fuse_req_t req, fuse_ino_t nodeid,
++                         struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_fallocate_in *arg = (struct fuse_fallocate_in *)inarg;
++    struct fuse_fallocate_in *arg;
+     struct fuse_file_info fi;
+ 
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
+     memset(&fi, 0, sizeof(fi));
+     fi.fh = arg->fh;
+ 
+@@ -1513,12 +1817,17 @@ static void do_fallocate(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ }
+ 
+ static void do_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in,
+-                               const void *inarg)
++                               struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_copy_file_range_in *arg =
+-        (struct fuse_copy_file_range_in *)inarg;
++    struct fuse_copy_file_range_in *arg;
+     struct fuse_file_info fi_in, fi_out;
+ 
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
+     memset(&fi_in, 0, sizeof(fi_in));
+     fi_in.fh = arg->fh_in;
+ 
+@@ -1535,11 +1844,17 @@ static void do_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in,
+     }
+ }
+ 
+-static void do_lseek(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_lseek(fuse_req_t req, fuse_ino_t nodeid,
++                     struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_lseek_in *arg = (struct fuse_lseek_in *)inarg;
++    struct fuse_lseek_in *arg;
+     struct fuse_file_info fi;
+ 
++    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
+     memset(&fi, 0, sizeof(fi));
+     fi.fh = arg->fh;
+ 
+@@ -1550,15 +1865,33 @@ static void do_lseek(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     }
+ }
+ 
+-static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_init(fuse_req_t req, fuse_ino_t nodeid,
++                    struct fuse_mbuf_iter *iter)
+ {
+-    struct fuse_init_in *arg = (struct fuse_init_in *)inarg;
++    size_t compat_size = offsetof(struct fuse_init_in, max_readahead);
++    struct fuse_init_in *arg;
+     struct fuse_init_out outarg;
+     struct fuse_session *se = req->se;
+     size_t bufsize = se->bufsize;
+     size_t outargsize = sizeof(outarg);
+ 
+     (void)nodeid;
++
++    /* First consume the old fields... */
++    arg = fuse_mbuf_iter_advance(iter, compat_size);
++    if (!arg) {
++        fuse_reply_err(req, EINVAL);
++        return;
++    }
++
++    /* ...and now consume the new fields. */
++    if (arg->major == 7 && arg->minor >= 6) {
++        if (!fuse_mbuf_iter_advance(iter, sizeof(*arg) - compat_size)) {
++            fuse_reply_err(req, EINVAL);
++            return;
++        }
++    }
++
+     if (se->debug) {
+         fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor);
+         if (arg->major == 7 && arg->minor >= 6) {
+@@ -1791,12 +2124,13 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+     send_reply_ok(req, &outarg, outargsize);
+ }
+ 
+-static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++static void do_destroy(fuse_req_t req, fuse_ino_t nodeid,
++                       struct fuse_mbuf_iter *iter)
+ {
+     struct fuse_session *se = req->se;
+ 
+     (void)nodeid;
+-    (void)inarg;
++    (void)iter;
+ 
+     se->got_destroy = 1;
+     if (se->op.destroy) {
+@@ -1976,7 +2310,7 @@ int fuse_req_interrupted(fuse_req_t req)
+ }
+ 
+ static struct {
+-    void (*func)(fuse_req_t, fuse_ino_t, const void *);
++    void (*func)(fuse_req_t, fuse_ino_t, struct fuse_mbuf_iter *);
+     const char *name;
+ } fuse_ll_ops[] = {
+     [FUSE_LOOKUP] = { do_lookup, "LOOKUP" },
+@@ -2060,7 +2394,6 @@ void fuse_session_process_buf_int(struct fuse_session *se,
+     const struct fuse_buf *buf = bufv->buf;
+     struct fuse_mbuf_iter iter = FUSE_MBUF_ITER_INIT(buf);
+     struct fuse_in_header *in;
+-    const void *inarg;
+     struct fuse_req *req;
+     int err;
+ 
+@@ -2138,13 +2471,11 @@ void fuse_session_process_buf_int(struct fuse_session *se,
+         }
+     }
+ 
+-    inarg = (void *)&in[1];
+     if (in->opcode == FUSE_WRITE && se->op.write_buf) {
+         do_write_buf(req, in->nodeid, &iter, bufv);
+     } else {
+-        fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
++        fuse_ll_ops[in->opcode].func(req, in->nodeid, &iter);
+     }
+-
+     return;
+ 
+ reply_err:
diff --git a/0055-virtiofsd-prevent-.-escape-in-lo_do_lookup.patch b/0055-virtiofsd-prevent-.-escape-in-lo_do_lookup.patch
new file mode 100644
index 0000000..00894ad
--- /dev/null
+++ b/0055-virtiofsd-prevent-.-escape-in-lo_do_lookup.patch
@@ -0,0 +1,35 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:24 +0000
+Subject: [PATCH] virtiofsd: prevent ".." escape in lo_do_lookup()
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Sergio Lopez <slp@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 854684bc0b3d63eb90b3abdfe471c2e4271ef176)
+---
+ tools/virtiofsd/passthrough_ll.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index e375406160..79d5966eea 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -624,12 +624,17 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+     int res;
+     int saverr;
+     struct lo_data *lo = lo_data(req);
+-    struct lo_inode *inode;
++    struct lo_inode *inode, *dir = lo_inode(req, parent);
+ 
+     memset(e, 0, sizeof(*e));
+     e->attr_timeout = lo->timeout;
+     e->entry_timeout = lo->timeout;
+ 
++    /* Do not allow escaping root directory */
++    if (dir == &lo->root && strcmp(name, "..") == 0) {
++        name = ".";
++    }
++
+     newfd = openat(lo_fd(req, parent), name, O_PATH | O_NOFOLLOW);
+     if (newfd == -1) {
+         goto out_err;
diff --git a/0056-virtiofsd-prevent-.-escape-in-lo_do_readdir.patch b/0056-virtiofsd-prevent-.-escape-in-lo_do_readdir.patch
new file mode 100644
index 0000000..47845ba
--- /dev/null
+++ b/0056-virtiofsd-prevent-.-escape-in-lo_do_readdir.patch
@@ -0,0 +1,89 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:25 +0000
+Subject: [PATCH] virtiofsd: prevent ".." escape in lo_do_readdir()
+
+Construct a fake dirent for the root directory's ".." entry.  This hides
+the parent directory from the FUSE client.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Sergio Lopez <slp@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 752272da2b68a2312f0e11fc5303015a6c3ee1ac)
+---
+ tools/virtiofsd/passthrough_ll.c | 36 +++++++++++++++++++-------------
+ 1 file changed, 22 insertions(+), 14 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 79d5966eea..e3d65c3676 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -1149,19 +1149,25 @@ out_err:
+ static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
+                           off_t offset, struct fuse_file_info *fi, int plus)
+ {
++    struct lo_data *lo = lo_data(req);
+     struct lo_dirp *d;
++    struct lo_inode *dinode;
+     char *buf = NULL;
+     char *p;
+     size_t rem = size;
+-    int err = ENOMEM;
++    int err = EBADF;
+ 
+-    (void)ino;
++    dinode = lo_inode(req, ino);
++    if (!dinode) {
++        goto error;
++    }
+ 
+     d = lo_dirp(req, fi);
+     if (!d) {
+         goto error;
+     }
+ 
++    err = ENOMEM;
+     buf = calloc(1, size);
+     if (!buf) {
+         goto error;
+@@ -1192,15 +1198,21 @@ static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
+         }
+         nextoff = d->entry->d_off;
+         name = d->entry->d_name;
++
+         fuse_ino_t entry_ino = 0;
++        struct fuse_entry_param e = (struct fuse_entry_param){
++            .attr.st_ino = d->entry->d_ino,
++            .attr.st_mode = d->entry->d_type << 12,
++        };
++
++        /* Hide root's parent directory */
++        if (dinode == &lo->root && strcmp(name, "..") == 0) {
++            e.attr.st_ino = lo->root.ino;
++            e.attr.st_mode = DT_DIR << 12;
++        }
++
+         if (plus) {
+-            struct fuse_entry_param e;
+-            if (is_dot_or_dotdot(name)) {
+-                e = (struct fuse_entry_param){
+-                    .attr.st_ino = d->entry->d_ino,
+-                    .attr.st_mode = d->entry->d_type << 12,
+-                };
+-            } else {
++            if (!is_dot_or_dotdot(name)) {
+                 err = lo_do_lookup(req, ino, name, &e);
+                 if (err) {
+                     goto error;
+@@ -1210,11 +1222,7 @@ static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
+ 
+             entsize = fuse_add_direntry_plus(req, p, rem, name, &e, nextoff);
+         } else {
+-            struct stat st = {
+-                .st_ino = d->entry->d_ino,
+-                .st_mode = d->entry->d_type << 12,
+-            };
+-            entsize = fuse_add_direntry(req, p, rem, name, &st, nextoff);
++            entsize = fuse_add_direntry(req, p, rem, name, &e.attr, nextoff);
+         }
+         if (entsize > rem) {
+             if (entry_ino != 0) {
diff --git a/0057-virtiofsd-use-proc-self-fd-O_PATH-file-descriptor.patch b/0057-virtiofsd-use-proc-self-fd-O_PATH-file-descriptor.patch
new file mode 100644
index 0000000..d3473e0
--- /dev/null
+++ b/0057-virtiofsd-use-proc-self-fd-O_PATH-file-descriptor.patch
@@ -0,0 +1,374 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:26 +0000
+Subject: [PATCH] virtiofsd: use /proc/self/fd/ O_PATH file descriptor
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Sandboxing will remove /proc from the mount namespace so we can no
+longer build string paths into "/proc/self/fd/...".
+
+Keep an O_PATH file descriptor so we can still re-open fds via
+/proc/self/fd.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 9f59d175e2ca96f0b87f534dba69ea547dd35945)
+---
+ tools/virtiofsd/passthrough_ll.c | 130 ++++++++++++++++++++++++-------
+ 1 file changed, 103 insertions(+), 27 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index e3d65c3676..e2e2211ea1 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -110,6 +110,9 @@ struct lo_data {
+     struct lo_map ino_map; /* protected by lo->mutex */
+     struct lo_map dirp_map; /* protected by lo->mutex */
+     struct lo_map fd_map; /* protected by lo->mutex */
++
++    /* An O_PATH file descriptor to /proc/self/fd/ */
++    int proc_self_fd;
+ };
+ 
+ static const struct fuse_opt lo_opts[] = {
+@@ -379,9 +382,9 @@ static int lo_parent_and_name(struct lo_data *lo, struct lo_inode *inode,
+     int res;
+ 
+ retry:
+-    sprintf(procname, "/proc/self/fd/%i", inode->fd);
++    sprintf(procname, "%i", inode->fd);
+ 
+-    res = readlink(procname, path, PATH_MAX);
++    res = readlinkat(lo->proc_self_fd, procname, path, PATH_MAX);
+     if (res < 0) {
+         fuse_log(FUSE_LOG_WARNING, "%s: readlink failed: %m\n", __func__);
+         goto fail_noretry;
+@@ -477,9 +480,9 @@ static int utimensat_empty(struct lo_data *lo, struct lo_inode *inode,
+         }
+         return res;
+     }
+-    sprintf(path, "/proc/self/fd/%i", inode->fd);
++    sprintf(path, "%i", inode->fd);
+ 
+-    return utimensat(AT_FDCWD, path, tv, 0);
++    return utimensat(lo->proc_self_fd, path, tv, 0);
+ 
+ fallback:
+     res = lo_parent_and_name(lo, inode, path, &parent);
+@@ -535,8 +538,8 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+         if (fi) {
+             res = fchmod(fd, attr->st_mode);
+         } else {
+-            sprintf(procname, "/proc/self/fd/%i", ifd);
+-            res = chmod(procname, attr->st_mode);
++            sprintf(procname, "%i", ifd);
++            res = fchmodat(lo->proc_self_fd, procname, attr->st_mode, 0);
+         }
+         if (res == -1) {
+             goto out_err;
+@@ -552,11 +555,23 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+         }
+     }
+     if (valid & FUSE_SET_ATTR_SIZE) {
++        int truncfd;
++
+         if (fi) {
+-            res = ftruncate(fd, attr->st_size);
++            truncfd = fd;
+         } else {
+-            sprintf(procname, "/proc/self/fd/%i", ifd);
+-            res = truncate(procname, attr->st_size);
++            sprintf(procname, "%i", ifd);
++            truncfd = openat(lo->proc_self_fd, procname, O_RDWR);
++            if (truncfd < 0) {
++                goto out_err;
++            }
++        }
++
++        res = ftruncate(truncfd, attr->st_size);
++        if (!fi) {
++            saverr = errno;
++            close(truncfd);
++            errno = saverr;
+         }
+         if (res == -1) {
+             goto out_err;
+@@ -874,9 +889,9 @@ static int linkat_empty_nofollow(struct lo_data *lo, struct lo_inode *inode,
+         return res;
+     }
+ 
+-    sprintf(path, "/proc/self/fd/%i", inode->fd);
++    sprintf(path, "%i", inode->fd);
+ 
+-    return linkat(AT_FDCWD, path, dfd, name, AT_SYMLINK_FOLLOW);
++    return linkat(lo->proc_self_fd, path, dfd, name, AT_SYMLINK_FOLLOW);
+ 
+ fallback:
+     res = lo_parent_and_name(lo, inode, path, &parent);
+@@ -1404,8 +1419,8 @@ static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+         fi->flags &= ~O_APPEND;
+     }
+ 
+-    sprintf(buf, "/proc/self/fd/%i", lo_fd(req, ino));
+-    fd = open(buf, fi->flags & ~O_NOFOLLOW);
++    sprintf(buf, "%i", lo_fd(req, ino));
++    fd = openat(lo->proc_self_fd, buf, fi->flags & ~O_NOFOLLOW);
+     if (fd == -1) {
+         return (void)fuse_reply_err(req, errno);
+     }
+@@ -1458,7 +1473,6 @@ static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
+                      struct fuse_file_info *fi)
+ {
+     int res;
+-    (void)ino;
+     int fd;
+     char *buf;
+ 
+@@ -1466,12 +1480,14 @@ static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
+              (void *)fi);
+ 
+     if (!fi) {
+-        res = asprintf(&buf, "/proc/self/fd/%i", lo_fd(req, ino));
++        struct lo_data *lo = lo_data(req);
++
++        res = asprintf(&buf, "%i", lo_fd(req, ino));
+         if (res == -1) {
+             return (void)fuse_reply_err(req, errno);
+         }
+ 
+-        fd = open(buf, O_RDWR);
++        fd = openat(lo->proc_self_fd, buf, O_RDWR);
+         free(buf);
+         if (fd == -1) {
+             return (void)fuse_reply_err(req, errno);
+@@ -1587,11 +1603,13 @@ static void lo_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
+ static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+                         size_t size)
+ {
++    struct lo_data *lo = lo_data(req);
+     char *value = NULL;
+     char procname[64];
+     struct lo_inode *inode;
+     ssize_t ret;
+     int saverr;
++    int fd = -1;
+ 
+     inode = lo_inode(req, ino);
+     if (!inode) {
+@@ -1616,7 +1634,11 @@ static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+         goto out;
+     }
+ 
+-    sprintf(procname, "/proc/self/fd/%i", inode->fd);
++    sprintf(procname, "%i", inode->fd);
++    fd = openat(lo->proc_self_fd, procname, O_RDONLY);
++    if (fd < 0) {
++        goto out_err;
++    }
+ 
+     if (size) {
+         value = malloc(size);
+@@ -1624,7 +1646,7 @@ static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+             goto out_err;
+         }
+ 
+-        ret = getxattr(procname, name, value, size);
++        ret = fgetxattr(fd, name, value, size);
+         if (ret == -1) {
+             goto out_err;
+         }
+@@ -1635,7 +1657,7 @@ static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+ 
+         fuse_reply_buf(req, value, ret);
+     } else {
+-        ret = getxattr(procname, name, NULL, 0);
++        ret = fgetxattr(fd, name, NULL, 0);
+         if (ret == -1) {
+             goto out_err;
+         }
+@@ -1644,6 +1666,10 @@ static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+     }
+ out_free:
+     free(value);
++
++    if (fd >= 0) {
++        close(fd);
++    }
+     return;
+ 
+ out_err:
+@@ -1655,11 +1681,13 @@ out:
+ 
+ static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
+ {
++    struct lo_data *lo = lo_data(req);
+     char *value = NULL;
+     char procname[64];
+     struct lo_inode *inode;
+     ssize_t ret;
+     int saverr;
++    int fd = -1;
+ 
+     inode = lo_inode(req, ino);
+     if (!inode) {
+@@ -1683,7 +1711,11 @@ static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
+         goto out;
+     }
+ 
+-    sprintf(procname, "/proc/self/fd/%i", inode->fd);
++    sprintf(procname, "%i", inode->fd);
++    fd = openat(lo->proc_self_fd, procname, O_RDONLY);
++    if (fd < 0) {
++        goto out_err;
++    }
+ 
+     if (size) {
+         value = malloc(size);
+@@ -1691,7 +1723,7 @@ static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
+             goto out_err;
+         }
+ 
+-        ret = listxattr(procname, value, size);
++        ret = flistxattr(fd, value, size);
+         if (ret == -1) {
+             goto out_err;
+         }
+@@ -1702,7 +1734,7 @@ static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
+ 
+         fuse_reply_buf(req, value, ret);
+     } else {
+-        ret = listxattr(procname, NULL, 0);
++        ret = flistxattr(fd, NULL, 0);
+         if (ret == -1) {
+             goto out_err;
+         }
+@@ -1711,6 +1743,10 @@ static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
+     }
+ out_free:
+     free(value);
++
++    if (fd >= 0) {
++        close(fd);
++    }
+     return;
+ 
+ out_err:
+@@ -1724,9 +1760,11 @@ static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+                         const char *value, size_t size, int flags)
+ {
+     char procname[64];
++    struct lo_data *lo = lo_data(req);
+     struct lo_inode *inode;
+     ssize_t ret;
+     int saverr;
++    int fd = -1;
+ 
+     inode = lo_inode(req, ino);
+     if (!inode) {
+@@ -1751,21 +1789,31 @@ static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+         goto out;
+     }
+ 
+-    sprintf(procname, "/proc/self/fd/%i", inode->fd);
++    sprintf(procname, "%i", inode->fd);
++    fd = openat(lo->proc_self_fd, procname, O_RDWR);
++    if (fd < 0) {
++        saverr = errno;
++        goto out;
++    }
+ 
+-    ret = setxattr(procname, name, value, size, flags);
++    ret = fsetxattr(fd, name, value, size, flags);
+     saverr = ret == -1 ? errno : 0;
+ 
+ out:
++    if (fd >= 0) {
++        close(fd);
++    }
+     fuse_reply_err(req, saverr);
+ }
+ 
+ static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
+ {
+     char procname[64];
++    struct lo_data *lo = lo_data(req);
+     struct lo_inode *inode;
+     ssize_t ret;
+     int saverr;
++    int fd = -1;
+ 
+     inode = lo_inode(req, ino);
+     if (!inode) {
+@@ -1789,12 +1837,20 @@ static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
+         goto out;
+     }
+ 
+-    sprintf(procname, "/proc/self/fd/%i", inode->fd);
++    sprintf(procname, "%i", inode->fd);
++    fd = openat(lo->proc_self_fd, procname, O_RDWR);
++    if (fd < 0) {
++        saverr = errno;
++        goto out;
++    }
+ 
+-    ret = removexattr(procname, name);
++    ret = fremovexattr(fd, name);
+     saverr = ret == -1 ? errno : 0;
+ 
+ out:
++    if (fd >= 0) {
++        close(fd);
++    }
+     fuse_reply_err(req, saverr);
+ }
+ 
+@@ -1887,12 +1943,25 @@ static void print_capabilities(void)
+     printf("}\n");
+ }
+ 
++static void setup_proc_self_fd(struct lo_data *lo)
++{
++    lo->proc_self_fd = open("/proc/self/fd", O_PATH);
++    if (lo->proc_self_fd == -1) {
++        fuse_log(FUSE_LOG_ERR, "open(/proc/self/fd, O_PATH): %m\n");
++        exit(1);
++    }
++}
++
+ int main(int argc, char *argv[])
+ {
+     struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+     struct fuse_session *se;
+     struct fuse_cmdline_opts opts;
+-    struct lo_data lo = { .debug = 0, .writeback = 0 };
++    struct lo_data lo = {
++        .debug = 0,
++        .writeback = 0,
++        .proc_self_fd = -1,
++    };
+     struct lo_map_elem *root_elem;
+     int ret = -1;
+ 
+@@ -2003,6 +2072,9 @@ int main(int argc, char *argv[])
+ 
+     fuse_daemonize(opts.foreground);
+ 
++    /* Must be after daemonize to get the right /proc/self/fd */
++    setup_proc_self_fd(&lo);
++
+     /* Block until ctrl+c or fusermount -u */
+     ret = virtio_loop(se);
+ 
+@@ -2018,6 +2090,10 @@ err_out1:
+     lo_map_destroy(&lo.dirp_map);
+     lo_map_destroy(&lo.ino_map);
+ 
++    if (lo.proc_self_fd >= 0) {
++        close(lo.proc_self_fd);
++    }
++
+     if (lo.root.fd >= 0) {
+         close(lo.root.fd);
+     }
diff --git a/0058-virtiofsd-sandbox-mount-namespace.patch b/0058-virtiofsd-sandbox-mount-namespace.patch
new file mode 100644
index 0000000..76fb892
--- /dev/null
+++ b/0058-virtiofsd-sandbox-mount-namespace.patch
@@ -0,0 +1,150 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:27 +0000
+Subject: [PATCH] virtiofsd: sandbox mount namespace
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Use a mount namespace with the shared directory tree mounted at "/" and
+no other mounts.
+
+This prevents symlink escape attacks because symlink targets are
+resolved only against the shared directory and cannot go outside it.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Signed-off-by: Peng Tao <tao.peng@linux.alibaba.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 5baa3b8e95064c2434bd9e2f312edd5e9ae275dc)
+---
+ tools/virtiofsd/passthrough_ll.c | 89 ++++++++++++++++++++++++++++++++
+ 1 file changed, 89 insertions(+)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index e2e2211ea1..0570453eef 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -50,6 +50,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <sys/file.h>
++#include <sys/mount.h>
+ #include <sys/syscall.h>
+ #include <sys/xattr.h>
+ #include <unistd.h>
+@@ -1943,6 +1944,58 @@ static void print_capabilities(void)
+     printf("}\n");
+ }
+ 
++/* This magic is based on lxc's lxc_pivot_root() */
++static void setup_pivot_root(const char *source)
++{
++    int oldroot;
++    int newroot;
++
++    oldroot = open("/", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
++    if (oldroot < 0) {
++        fuse_log(FUSE_LOG_ERR, "open(/): %m\n");
++        exit(1);
++    }
++
++    newroot = open(source, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
++    if (newroot < 0) {
++        fuse_log(FUSE_LOG_ERR, "open(%s): %m\n", source);
++        exit(1);
++    }
++
++    if (fchdir(newroot) < 0) {
++        fuse_log(FUSE_LOG_ERR, "fchdir(newroot): %m\n");
++        exit(1);
++    }
++
++    if (syscall(__NR_pivot_root, ".", ".") < 0) {
++        fuse_log(FUSE_LOG_ERR, "pivot_root(., .): %m\n");
++        exit(1);
++    }
++
++    if (fchdir(oldroot) < 0) {
++        fuse_log(FUSE_LOG_ERR, "fchdir(oldroot): %m\n");
++        exit(1);
++    }
++
++    if (mount("", ".", "", MS_SLAVE | MS_REC, NULL) < 0) {
++        fuse_log(FUSE_LOG_ERR, "mount(., MS_SLAVE | MS_REC): %m\n");
++        exit(1);
++    }
++
++    if (umount2(".", MNT_DETACH) < 0) {
++        fuse_log(FUSE_LOG_ERR, "umount2(., MNT_DETACH): %m\n");
++        exit(1);
++    }
++
++    if (fchdir(newroot) < 0) {
++        fuse_log(FUSE_LOG_ERR, "fchdir(newroot): %m\n");
++        exit(1);
++    }
++
++    close(newroot);
++    close(oldroot);
++}
++
+ static void setup_proc_self_fd(struct lo_data *lo)
+ {
+     lo->proc_self_fd = open("/proc/self/fd", O_PATH);
+@@ -1952,6 +2005,39 @@ static void setup_proc_self_fd(struct lo_data *lo)
+     }
+ }
+ 
++/*
++ * Make the source directory our root so symlinks cannot escape and no other
++ * files are accessible.
++ */
++static void setup_mount_namespace(const char *source)
++{
++    if (unshare(CLONE_NEWNS) != 0) {
++        fuse_log(FUSE_LOG_ERR, "unshare(CLONE_NEWNS): %m\n");
++        exit(1);
++    }
++
++    if (mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL) < 0) {
++        fuse_log(FUSE_LOG_ERR, "mount(/, MS_REC|MS_PRIVATE): %m\n");
++        exit(1);
++    }
++
++    if (mount(source, source, NULL, MS_BIND, NULL) < 0) {
++        fuse_log(FUSE_LOG_ERR, "mount(%s, %s, MS_BIND): %m\n", source, source);
++        exit(1);
++    }
++
++    setup_pivot_root(source);
++}
++
++/*
++ * Lock down this process to prevent access to other processes or files outside
++ * source directory.  This reduces the impact of arbitrary code execution bugs.
++ */
++static void setup_sandbox(struct lo_data *lo)
++{
++    setup_mount_namespace(lo->source);
++}
++
+ int main(int argc, char *argv[])
+ {
+     struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+@@ -2052,6 +2138,7 @@ int main(int argc, char *argv[])
+     }
+ 
+     lo.root.fd = open(lo.source, O_PATH);
++
+     if (lo.root.fd == -1) {
+         fuse_log(FUSE_LOG_ERR, "open(\"%s\", O_PATH): %m\n", lo.source);
+         exit(1);
+@@ -2075,6 +2162,8 @@ int main(int argc, char *argv[])
+     /* Must be after daemonize to get the right /proc/self/fd */
+     setup_proc_self_fd(&lo);
+ 
++    setup_sandbox(&lo);
++
+     /* Block until ctrl+c or fusermount -u */
+     ret = virtio_loop(se);
+ 
diff --git a/0059-virtiofsd-move-to-an-empty-network-namespace.patch b/0059-virtiofsd-move-to-an-empty-network-namespace.patch
new file mode 100644
index 0000000..043aa5f
--- /dev/null
+++ b/0059-virtiofsd-move-to-an-empty-network-namespace.patch
@@ -0,0 +1,50 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:28 +0000
+Subject: [PATCH] virtiofsd: move to an empty network namespace
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+If the process is compromised there should be no network access.  Use an
+empty network namespace to sandbox networking.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit d74830d12ae233186ff74ddf64c552d26bb39e50)
+---
+ tools/virtiofsd/passthrough_ll.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 0570453eef..27ab328722 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -1944,6 +1944,19 @@ static void print_capabilities(void)
+     printf("}\n");
+ }
+ 
++/*
++ * Called after our UNIX domain sockets have been created, now we can move to
++ * an empty network namespace to prevent TCP/IP and other network activity in
++ * case this process is compromised.
++ */
++static void setup_net_namespace(void)
++{
++    if (unshare(CLONE_NEWNET) != 0) {
++        fuse_log(FUSE_LOG_ERR, "unshare(CLONE_NEWNET): %m\n");
++        exit(1);
++    }
++}
++
+ /* This magic is based on lxc's lxc_pivot_root() */
+ static void setup_pivot_root(const char *source)
+ {
+@@ -2035,6 +2048,7 @@ static void setup_mount_namespace(const char *source)
+  */
+ static void setup_sandbox(struct lo_data *lo)
+ {
++    setup_net_namespace();
+     setup_mount_namespace(lo->source);
+ }
+ 
diff --git a/0060-virtiofsd-move-to-a-new-pid-namespace.patch b/0060-virtiofsd-move-to-a-new-pid-namespace.patch
new file mode 100644
index 0000000..043f962
--- /dev/null
+++ b/0060-virtiofsd-move-to-a-new-pid-namespace.patch
@@ -0,0 +1,207 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:29 +0000
+Subject: [PATCH] virtiofsd: move to a new pid namespace
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+virtiofsd needs access to /proc/self/fd.  Let's move to a new pid
+namespace so that a compromised process cannot see another other
+processes running on the system.
+
+One wrinkle in this approach: unshare(CLONE_NEWPID) affects *child*
+processes and not the current process.  Therefore we need to fork the
+pid 1 process that will actually run virtiofsd and leave a parent in
+waitpid(2).  This is not the same thing as daemonization and parent
+processes should not notice a difference.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 8e1d4ef231d8327be219f7aea7aa15d181375bbc)
+---
+ tools/virtiofsd/passthrough_ll.c | 134 ++++++++++++++++++++-----------
+ 1 file changed, 86 insertions(+), 48 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 27ab328722..0947d14e5b 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -51,7 +51,10 @@
+ #include <string.h>
+ #include <sys/file.h>
+ #include <sys/mount.h>
++#include <sys/prctl.h>
+ #include <sys/syscall.h>
++#include <sys/types.h>
++#include <sys/wait.h>
+ #include <sys/xattr.h>
+ #include <unistd.h>
+ 
+@@ -1945,24 +1948,95 @@ static void print_capabilities(void)
+ }
+ 
+ /*
+- * Called after our UNIX domain sockets have been created, now we can move to
+- * an empty network namespace to prevent TCP/IP and other network activity in
+- * case this process is compromised.
++ * Move to a new mount, net, and pid namespaces to isolate this process.
+  */
+-static void setup_net_namespace(void)
++static void setup_namespaces(struct lo_data *lo, struct fuse_session *se)
+ {
+-    if (unshare(CLONE_NEWNET) != 0) {
+-        fuse_log(FUSE_LOG_ERR, "unshare(CLONE_NEWNET): %m\n");
++    pid_t child;
++
++    /*
++     * Create a new pid namespace for *child* processes.  We'll have to
++     * fork in order to enter the new pid namespace.  A new mount namespace
++     * is also needed so that we can remount /proc for the new pid
++     * namespace.
++     *
++     * Our UNIX domain sockets have been created.  Now we can move to
++     * an empty network namespace to prevent TCP/IP and other network
++     * activity in case this process is compromised.
++     */
++    if (unshare(CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWNET) != 0) {
++        fuse_log(FUSE_LOG_ERR, "unshare(CLONE_NEWPID | CLONE_NEWNS): %m\n");
++        exit(1);
++    }
++
++    child = fork();
++    if (child < 0) {
++        fuse_log(FUSE_LOG_ERR, "fork() failed: %m\n");
++        exit(1);
++    }
++    if (child > 0) {
++        pid_t waited;
++        int wstatus;
++
++        /* The parent waits for the child */
++        do {
++            waited = waitpid(child, &wstatus, 0);
++        } while (waited < 0 && errno == EINTR && !se->exited);
++
++        /* We were terminated by a signal, see fuse_signals.c */
++        if (se->exited) {
++            exit(0);
++        }
++
++        if (WIFEXITED(wstatus)) {
++            exit(WEXITSTATUS(wstatus));
++        }
++
++        exit(1);
++    }
++
++    /* Send us SIGTERM when the parent thread terminates, see prctl(2) */
++    prctl(PR_SET_PDEATHSIG, SIGTERM);
++
++    /*
++     * If the mounts have shared propagation then we want to opt out so our
++     * mount changes don't affect the parent mount namespace.
++     */
++    if (mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL) < 0) {
++        fuse_log(FUSE_LOG_ERR, "mount(/, MS_REC|MS_SLAVE): %m\n");
++        exit(1);
++    }
++
++    /* The child must remount /proc to use the new pid namespace */
++    if (mount("proc", "/proc", "proc",
++              MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_RELATIME, NULL) < 0) {
++        fuse_log(FUSE_LOG_ERR, "mount(/proc): %m\n");
++        exit(1);
++    }
++
++    /* Now we can get our /proc/self/fd directory file descriptor */
++    lo->proc_self_fd = open("/proc/self/fd", O_PATH);
++    if (lo->proc_self_fd == -1) {
++        fuse_log(FUSE_LOG_ERR, "open(/proc/self/fd, O_PATH): %m\n");
+         exit(1);
+     }
+ }
+ 
+-/* This magic is based on lxc's lxc_pivot_root() */
+-static void setup_pivot_root(const char *source)
++/*
++ * Make the source directory our root so symlinks cannot escape and no other
++ * files are accessible.  Assumes unshare(CLONE_NEWNS) was already called.
++ */
++static void setup_mounts(const char *source)
+ {
+     int oldroot;
+     int newroot;
+ 
++    if (mount(source, source, NULL, MS_BIND, NULL) < 0) {
++        fuse_log(FUSE_LOG_ERR, "mount(%s, %s, MS_BIND): %m\n", source, source);
++        exit(1);
++    }
++
++    /* This magic is based on lxc's lxc_pivot_root() */
+     oldroot = open("/", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
+     if (oldroot < 0) {
+         fuse_log(FUSE_LOG_ERR, "open(/): %m\n");
+@@ -2009,47 +2083,14 @@ static void setup_pivot_root(const char *source)
+     close(oldroot);
+ }
+ 
+-static void setup_proc_self_fd(struct lo_data *lo)
+-{
+-    lo->proc_self_fd = open("/proc/self/fd", O_PATH);
+-    if (lo->proc_self_fd == -1) {
+-        fuse_log(FUSE_LOG_ERR, "open(/proc/self/fd, O_PATH): %m\n");
+-        exit(1);
+-    }
+-}
+-
+-/*
+- * Make the source directory our root so symlinks cannot escape and no other
+- * files are accessible.
+- */
+-static void setup_mount_namespace(const char *source)
+-{
+-    if (unshare(CLONE_NEWNS) != 0) {
+-        fuse_log(FUSE_LOG_ERR, "unshare(CLONE_NEWNS): %m\n");
+-        exit(1);
+-    }
+-
+-    if (mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL) < 0) {
+-        fuse_log(FUSE_LOG_ERR, "mount(/, MS_REC|MS_PRIVATE): %m\n");
+-        exit(1);
+-    }
+-
+-    if (mount(source, source, NULL, MS_BIND, NULL) < 0) {
+-        fuse_log(FUSE_LOG_ERR, "mount(%s, %s, MS_BIND): %m\n", source, source);
+-        exit(1);
+-    }
+-
+-    setup_pivot_root(source);
+-}
+-
+ /*
+  * Lock down this process to prevent access to other processes or files outside
+  * source directory.  This reduces the impact of arbitrary code execution bugs.
+  */
+-static void setup_sandbox(struct lo_data *lo)
++static void setup_sandbox(struct lo_data *lo, struct fuse_session *se)
+ {
+-    setup_net_namespace();
+-    setup_mount_namespace(lo->source);
++    setup_namespaces(lo, se);
++    setup_mounts(lo->source);
+ }
+ 
+ int main(int argc, char *argv[])
+@@ -2173,10 +2214,7 @@ int main(int argc, char *argv[])
+ 
+     fuse_daemonize(opts.foreground);
+ 
+-    /* Must be after daemonize to get the right /proc/self/fd */
+-    setup_proc_self_fd(&lo);
+-
+-    setup_sandbox(&lo);
++    setup_sandbox(&lo, se);
+ 
+     /* Block until ctrl+c or fusermount -u */
+     ret = virtio_loop(se);
diff --git a/0061-virtiofsd-add-seccomp-whitelist.patch b/0061-virtiofsd-add-seccomp-whitelist.patch
new file mode 100644
index 0000000..124cd4e
--- /dev/null
+++ b/0061-virtiofsd-add-seccomp-whitelist.patch
@@ -0,0 +1,265 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:30 +0000
+Subject: [PATCH] virtiofsd: add seccomp whitelist
+
+Only allow system calls that are needed by virtiofsd.  All other system
+calls cause SIGSYS to be directed at the thread and the process will
+coredump.
+
+Restricting system calls reduces the kernel attack surface and limits
+what the process can do when compromised.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+with additional entries by:
+Signed-off-by: Ganesh Maharaj Mahalingam <ganesh.mahalingam@intel.com>
+Signed-off-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+Signed-off-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Signed-off-by: piaojun <piaojun@huawei.com>
+Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
+Signed-off-by: Eric Ren <renzhen@linux.alibaba.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 4f8bde99c175ffd86b5125098a4707d43f5e80c6)
+---
+ Makefile                         |   5 +-
+ tools/virtiofsd/Makefile.objs    |   5 +-
+ tools/virtiofsd/passthrough_ll.c |   2 +
+ tools/virtiofsd/seccomp.c        | 151 +++++++++++++++++++++++++++++++
+ tools/virtiofsd/seccomp.h        |  14 +++
+ 5 files changed, 174 insertions(+), 3 deletions(-)
+ create mode 100644 tools/virtiofsd/seccomp.c
+ create mode 100644 tools/virtiofsd/seccomp.h
+
+diff --git a/Makefile b/Makefile
+index aebb57aed8..9a17e34603 100644
+--- a/Makefile
++++ b/Makefile
+@@ -330,7 +330,7 @@ endif
+ endif
+ endif
+ 
+-ifdef CONFIG_LINUX
++ifeq ($(CONFIG_LINUX)$(CONFIG_SECCOMP),yy)
+ HELPERS-y += virtiofsd$(EXESUF)
+ vhost-user-json-y += tools/virtiofsd/50-qemu-virtiofsd.json
+ endif
+@@ -680,7 +680,8 @@ rdmacm-mux$(EXESUF): LIBS += "-libumad"
+ rdmacm-mux$(EXESUF): $(rdmacm-mux-obj-y) $(COMMON_LDADDS)
+ 	$(call LINK, $^)
+ 
+-ifdef CONFIG_LINUX # relies on Linux-specific syscalls
++# relies on Linux-specific syscalls
++ifeq ($(CONFIG_LINUX)$(CONFIG_SECCOMP),yy)
+ virtiofsd$(EXESUF): $(virtiofsd-obj-y) libvhost-user.a $(COMMON_LDADDS)
+ 	$(call LINK, $^)
+ endif
+diff --git a/tools/virtiofsd/Makefile.objs b/tools/virtiofsd/Makefile.objs
+index 45a807500d..076f667e46 100644
+--- a/tools/virtiofsd/Makefile.objs
++++ b/tools/virtiofsd/Makefile.objs
+@@ -5,5 +5,8 @@ virtiofsd-obj-y = buffer.o \
+                   fuse_signals.o \
+                   fuse_virtio.o \
+                   helper.o \
+-                  passthrough_ll.o
++                  passthrough_ll.o \
++                  seccomp.o
+ 
++seccomp.o-cflags := $(SECCOMP_CFLAGS)
++seccomp.o-libs := $(SECCOMP_LIBS)
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 0947d14e5b..bd8925bd83 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -59,6 +59,7 @@
+ #include <unistd.h>
+ 
+ #include "passthrough_helpers.h"
++#include "seccomp.h"
+ 
+ struct lo_map_elem {
+     union {
+@@ -2091,6 +2092,7 @@ static void setup_sandbox(struct lo_data *lo, struct fuse_session *se)
+ {
+     setup_namespaces(lo, se);
+     setup_mounts(lo->source);
++    setup_seccomp();
+ }
+ 
+ int main(int argc, char *argv[])
+diff --git a/tools/virtiofsd/seccomp.c b/tools/virtiofsd/seccomp.c
+new file mode 100644
+index 0000000000..691fb63dea
+--- /dev/null
++++ b/tools/virtiofsd/seccomp.c
+@@ -0,0 +1,151 @@
++/*
++ * Seccomp sandboxing for virtiofsd
++ *
++ * Copyright (C) 2019 Red Hat, Inc.
++ *
++ * SPDX-License-Identifier: GPL-2.0-or-later
++ */
++
++#include "qemu/osdep.h"
++#include "seccomp.h"
++#include "fuse_i.h"
++#include "fuse_log.h"
++#include <errno.h>
++#include <glib.h>
++#include <seccomp.h>
++#include <stdlib.h>
++
++/* Bodge for libseccomp 2.4.2 which broke ppoll */
++#if !defined(__SNR_ppoll) && defined(__SNR_brk)
++#ifdef __NR_ppoll
++#define __SNR_ppoll __NR_ppoll
++#else
++#define __SNR_ppoll __PNR_ppoll
++#endif
++#endif
++
++static const int syscall_whitelist[] = {
++    /* TODO ireg sem*() syscalls */
++    SCMP_SYS(brk),
++    SCMP_SYS(capget), /* For CAP_FSETID */
++    SCMP_SYS(capset),
++    SCMP_SYS(clock_gettime),
++    SCMP_SYS(clone),
++#ifdef __NR_clone3
++    SCMP_SYS(clone3),
++#endif
++    SCMP_SYS(close),
++    SCMP_SYS(copy_file_range),
++    SCMP_SYS(dup),
++    SCMP_SYS(eventfd2),
++    SCMP_SYS(exit),
++    SCMP_SYS(exit_group),
++    SCMP_SYS(fallocate),
++    SCMP_SYS(fchmodat),
++    SCMP_SYS(fchownat),
++    SCMP_SYS(fcntl),
++    SCMP_SYS(fdatasync),
++    SCMP_SYS(fgetxattr),
++    SCMP_SYS(flistxattr),
++    SCMP_SYS(flock),
++    SCMP_SYS(fremovexattr),
++    SCMP_SYS(fsetxattr),
++    SCMP_SYS(fstat),
++    SCMP_SYS(fstatfs),
++    SCMP_SYS(fsync),
++    SCMP_SYS(ftruncate),
++    SCMP_SYS(futex),
++    SCMP_SYS(getdents),
++    SCMP_SYS(getdents64),
++    SCMP_SYS(getegid),
++    SCMP_SYS(geteuid),
++    SCMP_SYS(getpid),
++    SCMP_SYS(gettid),
++    SCMP_SYS(gettimeofday),
++    SCMP_SYS(linkat),
++    SCMP_SYS(lseek),
++    SCMP_SYS(madvise),
++    SCMP_SYS(mkdirat),
++    SCMP_SYS(mknodat),
++    SCMP_SYS(mmap),
++    SCMP_SYS(mprotect),
++    SCMP_SYS(mremap),
++    SCMP_SYS(munmap),
++    SCMP_SYS(newfstatat),
++    SCMP_SYS(open),
++    SCMP_SYS(openat),
++    SCMP_SYS(ppoll),
++    SCMP_SYS(prctl), /* TODO restrict to just PR_SET_NAME? */
++    SCMP_SYS(preadv),
++    SCMP_SYS(pread64),
++    SCMP_SYS(pwritev),
++    SCMP_SYS(pwrite64),
++    SCMP_SYS(read),
++    SCMP_SYS(readlinkat),
++    SCMP_SYS(recvmsg),
++    SCMP_SYS(renameat),
++    SCMP_SYS(renameat2),
++    SCMP_SYS(rt_sigaction),
++    SCMP_SYS(rt_sigprocmask),
++    SCMP_SYS(rt_sigreturn),
++    SCMP_SYS(sendmsg),
++    SCMP_SYS(setresgid),
++    SCMP_SYS(setresuid),
++#ifdef __NR_setresgid32
++    SCMP_SYS(setresgid32),
++#endif
++#ifdef __NR_setresuid32
++    SCMP_SYS(setresuid32),
++#endif
++    SCMP_SYS(set_robust_list),
++    SCMP_SYS(symlinkat),
++    SCMP_SYS(time), /* Rarely needed, except on static builds */
++    SCMP_SYS(tgkill),
++    SCMP_SYS(unlinkat),
++    SCMP_SYS(utimensat),
++    SCMP_SYS(write),
++    SCMP_SYS(writev),
++};
++
++void setup_seccomp(void)
++{
++    scmp_filter_ctx ctx;
++    size_t i;
++
++#ifdef SCMP_ACT_KILL_PROCESS
++    ctx = seccomp_init(SCMP_ACT_KILL_PROCESS);
++    /* Handle a newer libseccomp but an older kernel */
++    if (!ctx && errno == EOPNOTSUPP) {
++        ctx = seccomp_init(SCMP_ACT_TRAP);
++    }
++#else
++    ctx = seccomp_init(SCMP_ACT_TRAP);
++#endif
++    if (!ctx) {
++        fuse_log(FUSE_LOG_ERR, "seccomp_init() failed\n");
++        exit(1);
++    }
++
++    for (i = 0; i < G_N_ELEMENTS(syscall_whitelist); i++) {
++        if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW,
++                             syscall_whitelist[i], 0) != 0) {
++            fuse_log(FUSE_LOG_ERR, "seccomp_rule_add syscall %d",
++                     syscall_whitelist[i]);
++            exit(1);
++        }
++    }
++
++    /* libvhost-user calls this for post-copy migration, we don't need it */
++    if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOSYS),
++                         SCMP_SYS(userfaultfd), 0) != 0) {
++        fuse_log(FUSE_LOG_ERR, "seccomp_rule_add userfaultfd failed\n");
++        exit(1);
++    }
++
++    if (seccomp_load(ctx) < 0) {
++        fuse_log(FUSE_LOG_ERR, "seccomp_load() failed\n");
++        exit(1);
++    }
++
++    seccomp_release(ctx);
++}
+diff --git a/tools/virtiofsd/seccomp.h b/tools/virtiofsd/seccomp.h
+new file mode 100644
+index 0000000000..86bce72652
+--- /dev/null
++++ b/tools/virtiofsd/seccomp.h
+@@ -0,0 +1,14 @@
++/*
++ * Seccomp sandboxing for virtiofsd
++ *
++ * Copyright (C) 2019 Red Hat, Inc.
++ *
++ * SPDX-License-Identifier: GPL-2.0-or-later
++ */
++
++#ifndef VIRTIOFSD_SECCOMP_H
++#define VIRTIOFSD_SECCOMP_H
++
++void setup_seccomp(void);
++
++#endif /* VIRTIOFSD_SECCOMP_H */
diff --git a/0062-virtiofsd-Parse-flag-FUSE_WRITE_KILL_PRIV.patch b/0062-virtiofsd-Parse-flag-FUSE_WRITE_KILL_PRIV.patch
new file mode 100644
index 0000000..1670c83
--- /dev/null
+++ b/0062-virtiofsd-Parse-flag-FUSE_WRITE_KILL_PRIV.patch
@@ -0,0 +1,57 @@
+From: Vivek Goyal <vgoyal@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:31 +0000
+Subject: [PATCH] virtiofsd: Parse flag FUSE_WRITE_KILL_PRIV
+
+Caller can set FUSE_WRITE_KILL_PRIV in write_flags. Parse it and pass it
+to the filesystem.
+
+Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
+Reviewed-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Reviewed-by: Sergio Lopez <slp@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit f779bc5265e7e7abb13a03d4bfbc74151afc15c2)
+---
+ tools/virtiofsd/fuse_common.h   | 6 +++++-
+ tools/virtiofsd/fuse_lowlevel.c | 4 +++-
+ 2 files changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_common.h b/tools/virtiofsd/fuse_common.h
+index f8f6433743..686c42c0a5 100644
+--- a/tools/virtiofsd/fuse_common.h
++++ b/tools/virtiofsd/fuse_common.h
+@@ -93,8 +93,12 @@ struct fuse_file_info {
+      */
+     unsigned int cache_readdir:1;
+ 
++    /* Indicates that suid/sgid bits should be removed upon write */
++    unsigned int kill_priv:1;
++
++
+     /** Padding.  Reserved for future use*/
+-    unsigned int padding:25;
++    unsigned int padding:24;
+     unsigned int padding2:32;
+ 
+     /*
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 02e1d83038..2d6dc5a680 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -1142,6 +1142,7 @@ static void do_write(fuse_req_t req, fuse_ino_t nodeid,
+     memset(&fi, 0, sizeof(fi));
+     fi.fh = arg->fh;
+     fi.writepage = (arg->write_flags & FUSE_WRITE_CACHE) != 0;
++    fi.kill_priv = !!(arg->write_flags & FUSE_WRITE_KILL_PRIV);
+ 
+     fi.lock_owner = arg->lock_owner;
+     fi.flags = arg->flags;
+@@ -1177,7 +1178,8 @@ static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid,
+     fi.lock_owner = arg->lock_owner;
+     fi.flags = arg->flags;
+     fi.fh = arg->fh;
+-    fi.writepage = arg->write_flags & FUSE_WRITE_CACHE;
++    fi.writepage = !!(arg->write_flags & FUSE_WRITE_CACHE);
++    fi.kill_priv = !!(arg->write_flags & FUSE_WRITE_KILL_PRIV);
+ 
+     if (ibufv->count == 1) {
+         assert(!(tmpbufv.buf[0].flags & FUSE_BUF_IS_FD));
diff --git a/0063-virtiofsd-cap-ng-helpers.patch b/0063-virtiofsd-cap-ng-helpers.patch
new file mode 100644
index 0000000..7bc8ca9
--- /dev/null
+++ b/0063-virtiofsd-cap-ng-helpers.patch
@@ -0,0 +1,159 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:32 +0000
+Subject: [PATCH] virtiofsd: cap-ng helpers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+libcap-ng reads /proc during capng_get_caps_process, and virtiofsd's
+sandboxing doesn't have /proc mounted; thus we have to do the
+caps read before we sandbox it and save/restore the state.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 2405f3c0d19eb4d516a88aa4e5c54e5f9c6bbea3)
+---
+ Makefile                         |  4 +-
+ tools/virtiofsd/passthrough_ll.c | 72 ++++++++++++++++++++++++++++++++
+ 2 files changed, 74 insertions(+), 2 deletions(-)
+
+diff --git a/Makefile b/Makefile
+index 9a17e34603..14793cad11 100644
+--- a/Makefile
++++ b/Makefile
+@@ -330,7 +330,7 @@ endif
+ endif
+ endif
+ 
+-ifeq ($(CONFIG_LINUX)$(CONFIG_SECCOMP),yy)
++ifeq ($(CONFIG_LINUX)$(CONFIG_SECCOMP)$(CONFIG_LIBCAP_NG),yyy)
+ HELPERS-y += virtiofsd$(EXESUF)
+ vhost-user-json-y += tools/virtiofsd/50-qemu-virtiofsd.json
+ endif
+@@ -681,7 +681,7 @@ rdmacm-mux$(EXESUF): $(rdmacm-mux-obj-y) $(COMMON_LDADDS)
+ 	$(call LINK, $^)
+ 
+ # relies on Linux-specific syscalls
+-ifeq ($(CONFIG_LINUX)$(CONFIG_SECCOMP),yy)
++ifeq ($(CONFIG_LINUX)$(CONFIG_SECCOMP)$(CONFIG_LIBCAP_NG),yyy)
+ virtiofsd$(EXESUF): $(virtiofsd-obj-y) libvhost-user.a $(COMMON_LDADDS)
+ 	$(call LINK, $^)
+ endif
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index bd8925bd83..97e7c75667 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -39,6 +39,7 @@
+ #include "fuse_virtio.h"
+ #include "fuse_lowlevel.h"
+ #include <assert.h>
++#include <cap-ng.h>
+ #include <dirent.h>
+ #include <errno.h>
+ #include <inttypes.h>
+@@ -139,6 +140,13 @@ static const struct fuse_opt lo_opts[] = {
+ 
+ static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n);
+ 
++static struct {
++    pthread_mutex_t mutex;
++    void *saved;
++} cap;
++/* That we loaded cap-ng in the current thread from the saved */
++static __thread bool cap_loaded = 0;
++
+ static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st);
+ 
+ static int is_dot_or_dotdot(const char *name)
+@@ -162,6 +170,37 @@ static struct lo_data *lo_data(fuse_req_t req)
+     return (struct lo_data *)fuse_req_userdata(req);
+ }
+ 
++/*
++ * Load capng's state from our saved state if the current thread
++ * hadn't previously been loaded.
++ * returns 0 on success
++ */
++static int load_capng(void)
++{
++    if (!cap_loaded) {
++        pthread_mutex_lock(&cap.mutex);
++        capng_restore_state(&cap.saved);
++        /*
++         * restore_state free's the saved copy
++         * so make another.
++         */
++        cap.saved = capng_save_state();
++        if (!cap.saved) {
++            fuse_log(FUSE_LOG_ERR, "capng_save_state (thread)\n");
++            return -EINVAL;
++        }
++        pthread_mutex_unlock(&cap.mutex);
++
++        /*
++         * We want to use the loaded state for our pid,
++         * not the original
++         */
++        capng_setpid(syscall(SYS_gettid));
++        cap_loaded = true;
++    }
++    return 0;
++}
++
+ static void lo_map_init(struct lo_map *map)
+ {
+     map->elems = NULL;
+@@ -2023,6 +2062,35 @@ static void setup_namespaces(struct lo_data *lo, struct fuse_session *se)
+     }
+ }
+ 
++/*
++ * Capture the capability state, we'll need to restore this for individual
++ * threads later; see load_capng.
++ */
++static void setup_capng(void)
++{
++    /* Note this accesses /proc so has to happen before the sandbox */
++    if (capng_get_caps_process()) {
++        fuse_log(FUSE_LOG_ERR, "capng_get_caps_process\n");
++        exit(1);
++    }
++    pthread_mutex_init(&cap.mutex, NULL);
++    pthread_mutex_lock(&cap.mutex);
++    cap.saved = capng_save_state();
++    if (!cap.saved) {
++        fuse_log(FUSE_LOG_ERR, "capng_save_state\n");
++        exit(1);
++    }
++    pthread_mutex_unlock(&cap.mutex);
++}
++
++static void cleanup_capng(void)
++{
++    free(cap.saved);
++    cap.saved = NULL;
++    pthread_mutex_destroy(&cap.mutex);
++}
++
++
+ /*
+  * Make the source directory our root so symlinks cannot escape and no other
+  * files are accessible.  Assumes unshare(CLONE_NEWNS) was already called.
+@@ -2216,12 +2284,16 @@ int main(int argc, char *argv[])
+ 
+     fuse_daemonize(opts.foreground);
+ 
++    /* Must be before sandbox since it wants /proc */
++    setup_capng();
++
+     setup_sandbox(&lo, se);
+ 
+     /* Block until ctrl+c or fusermount -u */
+     ret = virtio_loop(se);
+ 
+     fuse_session_unmount(se);
++    cleanup_capng();
+ err_out3:
+     fuse_remove_signal_handlers(se);
+ err_out2:
diff --git a/0064-virtiofsd-Drop-CAP_FSETID-if-client-asked-for-it.patch b/0064-virtiofsd-Drop-CAP_FSETID-if-client-asked-for-it.patch
new file mode 100644
index 0000000..13438cc
--- /dev/null
+++ b/0064-virtiofsd-Drop-CAP_FSETID-if-client-asked-for-it.patch
@@ -0,0 +1,156 @@
+From: Vivek Goyal <vgoyal@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:33 +0000
+Subject: [PATCH] virtiofsd: Drop CAP_FSETID if client asked for it
+
+If client requested killing setuid/setgid bits on file being written, drop
+CAP_FSETID capability so that setuid/setgid bits are cleared upon write
+automatically.
+
+pjdfstest chown/12.t needs this.
+
+Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
+  dgilbert: reworked for libcap-ng
+Reviewed-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Reviewed-by: Sergio Lopez <slp@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit ee88465224b3aed2596049caa28f86cbe0d5a3d0)
+---
+ tools/virtiofsd/passthrough_ll.c | 105 +++++++++++++++++++++++++++++++
+ 1 file changed, 105 insertions(+)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 97e7c75667..d53cb1e005 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -201,6 +201,91 @@ static int load_capng(void)
+     return 0;
+ }
+ 
++/*
++ * Helpers for dropping and regaining effective capabilities. Returns 0
++ * on success, error otherwise
++ */
++static int drop_effective_cap(const char *cap_name, bool *cap_dropped)
++{
++    int cap, ret;
++
++    cap = capng_name_to_capability(cap_name);
++    if (cap < 0) {
++        ret = errno;
++        fuse_log(FUSE_LOG_ERR, "capng_name_to_capability(%s) failed:%s\n",
++                 cap_name, strerror(errno));
++        goto out;
++    }
++
++    if (load_capng()) {
++        ret = errno;
++        fuse_log(FUSE_LOG_ERR, "load_capng() failed\n");
++        goto out;
++    }
++
++    /* We dont have this capability in effective set already. */
++    if (!capng_have_capability(CAPNG_EFFECTIVE, cap)) {
++        ret = 0;
++        goto out;
++    }
++
++    if (capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, cap)) {
++        ret = errno;
++        fuse_log(FUSE_LOG_ERR, "capng_update(DROP,) failed\n");
++        goto out;
++    }
++
++    if (capng_apply(CAPNG_SELECT_CAPS)) {
++        ret = errno;
++        fuse_log(FUSE_LOG_ERR, "drop:capng_apply() failed\n");
++        goto out;
++    }
++
++    ret = 0;
++    if (cap_dropped) {
++        *cap_dropped = true;
++    }
++
++out:
++    return ret;
++}
++
++static int gain_effective_cap(const char *cap_name)
++{
++    int cap;
++    int ret = 0;
++
++    cap = capng_name_to_capability(cap_name);
++    if (cap < 0) {
++        ret = errno;
++        fuse_log(FUSE_LOG_ERR, "capng_name_to_capability(%s) failed:%s\n",
++                 cap_name, strerror(errno));
++        goto out;
++    }
++
++    if (load_capng()) {
++        ret = errno;
++        fuse_log(FUSE_LOG_ERR, "load_capng() failed\n");
++        goto out;
++    }
++
++    if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, cap)) {
++        ret = errno;
++        fuse_log(FUSE_LOG_ERR, "capng_update(ADD,) failed\n");
++        goto out;
++    }
++
++    if (capng_apply(CAPNG_SELECT_CAPS)) {
++        ret = errno;
++        fuse_log(FUSE_LOG_ERR, "gain:capng_apply() failed\n");
++        goto out;
++    }
++    ret = 0;
++
++out:
++    return ret;
++}
++
+ static void lo_map_init(struct lo_map *map)
+ {
+     map->elems = NULL;
+@@ -1577,6 +1662,7 @@ static void lo_write_buf(fuse_req_t req, fuse_ino_t ino,
+     (void)ino;
+     ssize_t res;
+     struct fuse_bufvec out_buf = FUSE_BUFVEC_INIT(fuse_buf_size(in_buf));
++    bool cap_fsetid_dropped = false;
+ 
+     out_buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
+     out_buf.buf[0].fd = lo_fi_fd(req, fi);
+@@ -1588,12 +1674,31 @@ static void lo_write_buf(fuse_req_t req, fuse_ino_t ino,
+                  out_buf.buf[0].size, (unsigned long)off);
+     }
+ 
++    /*
++     * If kill_priv is set, drop CAP_FSETID which should lead to kernel
++     * clearing setuid/setgid on file.
++     */
++    if (fi->kill_priv) {
++        res = drop_effective_cap("FSETID", &cap_fsetid_dropped);
++        if (res != 0) {
++            fuse_reply_err(req, res);
++            return;
++        }
++    }
++
+     res = fuse_buf_copy(&out_buf, in_buf);
+     if (res < 0) {
+         fuse_reply_err(req, -res);
+     } else {
+         fuse_reply_write(req, (size_t)res);
+     }
++
++    if (cap_fsetid_dropped) {
++        res = gain_effective_cap("FSETID");
++        if (res) {
++            fuse_log(FUSE_LOG_ERR, "Failed to gain CAP_FSETID\n");
++        }
++    }
+ }
+ 
+ static void lo_statfs(fuse_req_t req, fuse_ino_t ino)
diff --git a/0065-virtiofsd-set-maximum-RLIMIT_NOFILE-limit.patch b/0065-virtiofsd-set-maximum-RLIMIT_NOFILE-limit.patch
new file mode 100644
index 0000000..9782dc5
--- /dev/null
+++ b/0065-virtiofsd-set-maximum-RLIMIT_NOFILE-limit.patch
@@ -0,0 +1,77 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:34 +0000
+Subject: [PATCH] virtiofsd: set maximum RLIMIT_NOFILE limit
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+virtiofsd can exceed the default open file descriptor limit easily on
+most systems.  Take advantage of the fact that it runs as root to raise
+the limit.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 01a6dc95ec7f71eeff9963fe3cb03d85225fba3e)
+---
+ tools/virtiofsd/passthrough_ll.c | 32 ++++++++++++++++++++++++++++++++
+ 1 file changed, 32 insertions(+)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index d53cb1e005..c281d817af 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -53,6 +53,7 @@
+ #include <sys/file.h>
+ #include <sys/mount.h>
+ #include <sys/prctl.h>
++#include <sys/resource.h>
+ #include <sys/syscall.h>
+ #include <sys/types.h>
+ #include <sys/wait.h>
+@@ -2268,6 +2269,35 @@ static void setup_sandbox(struct lo_data *lo, struct fuse_session *se)
+     setup_seccomp();
+ }
+ 
++/* Raise the maximum number of open file descriptors */
++static void setup_nofile_rlimit(void)
++{
++    const rlim_t max_fds = 1000000;
++    struct rlimit rlim;
++
++    if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
++        fuse_log(FUSE_LOG_ERR, "getrlimit(RLIMIT_NOFILE): %m\n");
++        exit(1);
++    }
++
++    if (rlim.rlim_cur >= max_fds) {
++        return; /* nothing to do */
++    }
++
++    rlim.rlim_cur = max_fds;
++    rlim.rlim_max = max_fds;
++
++    if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
++        /* Ignore SELinux denials */
++        if (errno == EPERM) {
++            return;
++        }
++
++        fuse_log(FUSE_LOG_ERR, "setrlimit(RLIMIT_NOFILE): %m\n");
++        exit(1);
++    }
++}
++
+ int main(int argc, char *argv[])
+ {
+     struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+@@ -2389,6 +2419,8 @@ int main(int argc, char *argv[])
+ 
+     fuse_daemonize(opts.foreground);
+ 
++    setup_nofile_rlimit();
++
+     /* Must be before sandbox since it wants /proc */
+     setup_capng();
+ 
diff --git a/0066-virtiofsd-fix-libfuse-information-leaks.patch b/0066-virtiofsd-fix-libfuse-information-leaks.patch
new file mode 100644
index 0000000..8a5b630
--- /dev/null
+++ b/0066-virtiofsd-fix-libfuse-information-leaks.patch
@@ -0,0 +1,306 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:35 +0000
+Subject: [PATCH] virtiofsd: fix libfuse information leaks
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Some FUSE message replies contain padding fields that are not
+initialized by libfuse.  This is fine in traditional FUSE applications
+because the kernel is trusted.  virtiofsd does not trust the guest and
+must not expose uninitialized memory.
+
+Use C struct initializers to automatically zero out memory.  Not all of
+these code changes are strictly necessary but they will prevent future
+information leaks if the structs are extended.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 3db2876a0153ac7103c077c53090e020faffb3ea)
+---
+ tools/virtiofsd/fuse_lowlevel.c | 150 ++++++++++++++++----------------
+ 1 file changed, 76 insertions(+), 74 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 2d6dc5a680..6ceb33d913 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -44,21 +44,23 @@ static __attribute__((constructor)) void fuse_ll_init_pagesize(void)
+ 
+ static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
+ {
+-    attr->ino = stbuf->st_ino;
+-    attr->mode = stbuf->st_mode;
+-    attr->nlink = stbuf->st_nlink;
+-    attr->uid = stbuf->st_uid;
+-    attr->gid = stbuf->st_gid;
+-    attr->rdev = stbuf->st_rdev;
+-    attr->size = stbuf->st_size;
+-    attr->blksize = stbuf->st_blksize;
+-    attr->blocks = stbuf->st_blocks;
+-    attr->atime = stbuf->st_atime;
+-    attr->mtime = stbuf->st_mtime;
+-    attr->ctime = stbuf->st_ctime;
+-    attr->atimensec = ST_ATIM_NSEC(stbuf);
+-    attr->mtimensec = ST_MTIM_NSEC(stbuf);
+-    attr->ctimensec = ST_CTIM_NSEC(stbuf);
++    *attr = (struct fuse_attr){
++        .ino = stbuf->st_ino,
++        .mode = stbuf->st_mode,
++        .nlink = stbuf->st_nlink,
++        .uid = stbuf->st_uid,
++        .gid = stbuf->st_gid,
++        .rdev = stbuf->st_rdev,
++        .size = stbuf->st_size,
++        .blksize = stbuf->st_blksize,
++        .blocks = stbuf->st_blocks,
++        .atime = stbuf->st_atime,
++        .mtime = stbuf->st_mtime,
++        .ctime = stbuf->st_ctime,
++        .atimensec = ST_ATIM_NSEC(stbuf),
++        .mtimensec = ST_MTIM_NSEC(stbuf),
++        .ctimensec = ST_CTIM_NSEC(stbuf),
++    };
+ }
+ 
+ static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
+@@ -183,16 +185,16 @@ static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
+ int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
+                                int count)
+ {
+-    struct fuse_out_header out;
++    struct fuse_out_header out = {
++        .unique = req->unique,
++        .error = error,
++    };
+ 
+     if (error <= -1000 || error > 0) {
+         fuse_log(FUSE_LOG_ERR, "fuse: bad error value: %i\n", error);
+         error = -ERANGE;
+     }
+ 
+-    out.unique = req->unique;
+-    out.error = error;
+-
+     iov[0].iov_base = &out;
+     iov[0].iov_len = sizeof(struct fuse_out_header);
+ 
+@@ -277,14 +279,16 @@ size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
+ static void convert_statfs(const struct statvfs *stbuf,
+                            struct fuse_kstatfs *kstatfs)
+ {
+-    kstatfs->bsize = stbuf->f_bsize;
+-    kstatfs->frsize = stbuf->f_frsize;
+-    kstatfs->blocks = stbuf->f_blocks;
+-    kstatfs->bfree = stbuf->f_bfree;
+-    kstatfs->bavail = stbuf->f_bavail;
+-    kstatfs->files = stbuf->f_files;
+-    kstatfs->ffree = stbuf->f_ffree;
+-    kstatfs->namelen = stbuf->f_namemax;
++    *kstatfs = (struct fuse_kstatfs){
++        .bsize = stbuf->f_bsize,
++        .frsize = stbuf->f_frsize,
++        .blocks = stbuf->f_blocks,
++        .bfree = stbuf->f_bfree,
++        .bavail = stbuf->f_bavail,
++        .files = stbuf->f_files,
++        .ffree = stbuf->f_ffree,
++        .namelen = stbuf->f_namemax,
++    };
+ }
+ 
+ static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
+@@ -328,12 +332,14 @@ static unsigned int calc_timeout_nsec(double t)
+ static void fill_entry(struct fuse_entry_out *arg,
+                        const struct fuse_entry_param *e)
+ {
+-    arg->nodeid = e->ino;
+-    arg->generation = e->generation;
+-    arg->entry_valid = calc_timeout_sec(e->entry_timeout);
+-    arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
+-    arg->attr_valid = calc_timeout_sec(e->attr_timeout);
+-    arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
++    *arg = (struct fuse_entry_out){
++        .nodeid = e->ino,
++        .generation = e->generation,
++        .entry_valid = calc_timeout_sec(e->entry_timeout),
++        .entry_valid_nsec = calc_timeout_nsec(e->entry_timeout),
++        .attr_valid = calc_timeout_sec(e->attr_timeout),
++        .attr_valid_nsec = calc_timeout_nsec(e->attr_timeout),
++    };
+     convert_stat(&e->attr, &arg->attr);
+ }
+ 
+@@ -362,10 +368,12 @@ size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
+     fill_entry(&dp->entry_out, e);
+ 
+     struct fuse_dirent *dirent = &dp->dirent;
+-    dirent->ino = e->attr.st_ino;
+-    dirent->off = off;
+-    dirent->namelen = namelen;
+-    dirent->type = (e->attr.st_mode & S_IFMT) >> 12;
++    *dirent = (struct fuse_dirent){
++        .ino = e->attr.st_ino,
++        .off = off,
++        .namelen = namelen,
++        .type = (e->attr.st_mode & S_IFMT) >> 12,
++    };
+     memcpy(dirent->name, name, namelen);
+     memset(dirent->name + namelen, 0, entlen_padded - entlen);
+ 
+@@ -496,15 +504,14 @@ static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
+ int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv)
+ {
+     struct iovec iov[2];
+-    struct fuse_out_header out;
++    struct fuse_out_header out = {
++        .unique = req->unique,
++    };
+     int res;
+ 
+     iov[0].iov_base = &out;
+     iov[0].iov_len = sizeof(struct fuse_out_header);
+ 
+-    out.unique = req->unique;
+-    out.error = 0;
+-
+     res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv);
+     if (res <= 0) {
+         fuse_free_req(req);
+@@ -2145,14 +2152,14 @@ static void do_destroy(fuse_req_t req, fuse_ino_t nodeid,
+ static int send_notify_iov(struct fuse_session *se, int notify_code,
+                            struct iovec *iov, int count)
+ {
+-    struct fuse_out_header out;
++    struct fuse_out_header out = {
++        .error = notify_code,
++    };
+ 
+     if (!se->got_init) {
+         return -ENOTCONN;
+     }
+ 
+-    out.unique = 0;
+-    out.error = notify_code;
+     iov[0].iov_base = &out;
+     iov[0].iov_len = sizeof(struct fuse_out_header);
+ 
+@@ -2162,11 +2169,11 @@ static int send_notify_iov(struct fuse_session *se, int notify_code,
+ int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
+ {
+     if (ph != NULL) {
+-        struct fuse_notify_poll_wakeup_out outarg;
++        struct fuse_notify_poll_wakeup_out outarg = {
++            .kh = ph->kh,
++        };
+         struct iovec iov[2];
+ 
+-        outarg.kh = ph->kh;
+-
+         iov[1].iov_base = &outarg;
+         iov[1].iov_len = sizeof(outarg);
+ 
+@@ -2179,17 +2186,17 @@ int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
+ int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
+                                      off_t off, off_t len)
+ {
+-    struct fuse_notify_inval_inode_out outarg;
++    struct fuse_notify_inval_inode_out outarg = {
++        .ino = ino,
++        .off = off,
++        .len = len,
++    };
+     struct iovec iov[2];
+ 
+     if (!se) {
+         return -EINVAL;
+     }
+ 
+-    outarg.ino = ino;
+-    outarg.off = off;
+-    outarg.len = len;
+-
+     iov[1].iov_base = &outarg;
+     iov[1].iov_len = sizeof(outarg);
+ 
+@@ -2199,17 +2206,16 @@ int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
+ int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
+                                      const char *name, size_t namelen)
+ {
+-    struct fuse_notify_inval_entry_out outarg;
++    struct fuse_notify_inval_entry_out outarg = {
++        .parent = parent,
++        .namelen = namelen,
++    };
+     struct iovec iov[3];
+ 
+     if (!se) {
+         return -EINVAL;
+     }
+ 
+-    outarg.parent = parent;
+-    outarg.namelen = namelen;
+-    outarg.padding = 0;
+-
+     iov[1].iov_base = &outarg;
+     iov[1].iov_len = sizeof(outarg);
+     iov[2].iov_base = (void *)name;
+@@ -2222,18 +2228,17 @@ int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent,
+                                 fuse_ino_t child, const char *name,
+                                 size_t namelen)
+ {
+-    struct fuse_notify_delete_out outarg;
++    struct fuse_notify_delete_out outarg = {
++        .parent = parent,
++        .child = child,
++        .namelen = namelen,
++    };
+     struct iovec iov[3];
+ 
+     if (!se) {
+         return -EINVAL;
+     }
+ 
+-    outarg.parent = parent;
+-    outarg.child = child;
+-    outarg.namelen = namelen;
+-    outarg.padding = 0;
+-
+     iov[1].iov_base = &outarg;
+     iov[1].iov_len = sizeof(outarg);
+     iov[2].iov_base = (void *)name;
+@@ -2245,24 +2250,21 @@ int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent,
+ int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
+                                off_t offset, struct fuse_bufvec *bufv)
+ {
+-    struct fuse_out_header out;
+-    struct fuse_notify_store_out outarg;
++    struct fuse_out_header out = {
++        .error = FUSE_NOTIFY_STORE,
++    };
++    struct fuse_notify_store_out outarg = {
++        .nodeid = ino,
++        .offset = offset,
++        .size = fuse_buf_size(bufv),
++    };
+     struct iovec iov[3];
+-    size_t size = fuse_buf_size(bufv);
+     int res;
+ 
+     if (!se) {
+         return -EINVAL;
+     }
+ 
+-    out.unique = 0;
+-    out.error = FUSE_NOTIFY_STORE;
+-
+-    outarg.nodeid = ino;
+-    outarg.offset = offset;
+-    outarg.size = size;
+-    outarg.padding = 0;
+-
+     iov[0].iov_base = &out;
+     iov[0].iov_len = sizeof(out);
+     iov[1].iov_base = &outarg;
diff --git a/0067-virtiofsd-add-syslog-command-line-option.patch b/0067-virtiofsd-add-syslog-command-line-option.patch
new file mode 100644
index 0000000..756de55
--- /dev/null
+++ b/0067-virtiofsd-add-syslog-command-line-option.patch
@@ -0,0 +1,223 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:36 +0000
+Subject: [PATCH] virtiofsd: add --syslog command-line option
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Sometimes collecting output from stderr is inconvenient or does not fit
+within the overall logging architecture.  Add syslog(3) support for
+cases where stderr cannot be used.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+dgilbert: Reworked as a logging function
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit f185621d41f03a23b55795b89e6584253fa23505)
+---
+ tools/virtiofsd/fuse_lowlevel.h  |  1 +
+ tools/virtiofsd/helper.c         |  2 ++
+ tools/virtiofsd/passthrough_ll.c | 50 ++++++++++++++++++++++++++++++--
+ tools/virtiofsd/seccomp.c        | 32 ++++++++++++++------
+ tools/virtiofsd/seccomp.h        |  4 ++-
+ 5 files changed, 76 insertions(+), 13 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_lowlevel.h b/tools/virtiofsd/fuse_lowlevel.h
+index 0d61df8110..f2750bc189 100644
+--- a/tools/virtiofsd/fuse_lowlevel.h
++++ b/tools/virtiofsd/fuse_lowlevel.h
+@@ -1795,6 +1795,7 @@ struct fuse_cmdline_opts {
+     int show_version;
+     int show_help;
+     int print_capabilities;
++    int syslog;
+     unsigned int max_idle_threads;
+ };
+ 
+diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
+index 5531425223..9692ef9f1f 100644
+--- a/tools/virtiofsd/helper.c
++++ b/tools/virtiofsd/helper.c
+@@ -54,6 +54,7 @@ static const struct fuse_opt fuse_helper_opts[] = {
+     FUSE_HELPER_OPT("subtype=", nodefault_subtype),
+     FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP),
+     FUSE_HELPER_OPT("max_idle_threads=%u", max_idle_threads),
++    FUSE_HELPER_OPT("--syslog", syslog),
+     FUSE_OPT_END
+ };
+ 
+@@ -138,6 +139,7 @@ void fuse_cmdline_help(void)
+            "    -V   --version             print version\n"
+            "    --print-capabilities       print vhost-user.json\n"
+            "    -d   -o debug              enable debug output (implies -f)\n"
++           "    --syslog                   log to syslog (default stderr)\n"
+            "    -f                         foreground operation\n"
+            "    --daemonize                run in background\n"
+            "    -o max_idle_threads        the maximum number of idle worker "
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index c281d817af..0372aca143 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -58,6 +58,7 @@
+ #include <sys/types.h>
+ #include <sys/wait.h>
+ #include <sys/xattr.h>
++#include <syslog.h>
+ #include <unistd.h>
+ 
+ #include "passthrough_helpers.h"
+@@ -138,6 +139,7 @@ static const struct fuse_opt lo_opts[] = {
+     { "norace", offsetof(struct lo_data, norace), 1 },
+     FUSE_OPT_END
+ };
++static bool use_syslog = false;
+ 
+ static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n);
+ 
+@@ -2262,11 +2264,12 @@ static void setup_mounts(const char *source)
+  * Lock down this process to prevent access to other processes or files outside
+  * source directory.  This reduces the impact of arbitrary code execution bugs.
+  */
+-static void setup_sandbox(struct lo_data *lo, struct fuse_session *se)
++static void setup_sandbox(struct lo_data *lo, struct fuse_session *se,
++                          bool enable_syslog)
+ {
+     setup_namespaces(lo, se);
+     setup_mounts(lo->source);
+-    setup_seccomp();
++    setup_seccomp(enable_syslog);
+ }
+ 
+ /* Raise the maximum number of open file descriptors */
+@@ -2298,6 +2301,42 @@ static void setup_nofile_rlimit(void)
+     }
+ }
+ 
++static void log_func(enum fuse_log_level level, const char *fmt, va_list ap)
++{
++    if (use_syslog) {
++        int priority = LOG_ERR;
++        switch (level) {
++        case FUSE_LOG_EMERG:
++            priority = LOG_EMERG;
++            break;
++        case FUSE_LOG_ALERT:
++            priority = LOG_ALERT;
++            break;
++        case FUSE_LOG_CRIT:
++            priority = LOG_CRIT;
++            break;
++        case FUSE_LOG_ERR:
++            priority = LOG_ERR;
++            break;
++        case FUSE_LOG_WARNING:
++            priority = LOG_WARNING;
++            break;
++        case FUSE_LOG_NOTICE:
++            priority = LOG_NOTICE;
++            break;
++        case FUSE_LOG_INFO:
++            priority = LOG_INFO;
++            break;
++        case FUSE_LOG_DEBUG:
++            priority = LOG_DEBUG;
++            break;
++        }
++        vsyslog(priority, fmt, ap);
++    } else {
++        vfprintf(stderr, fmt, ap);
++    }
++}
++
+ int main(int argc, char *argv[])
+ {
+     struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+@@ -2336,6 +2375,11 @@ int main(int argc, char *argv[])
+     if (fuse_parse_cmdline(&args, &opts) != 0) {
+         return 1;
+     }
++    fuse_set_log_func(log_func);
++    use_syslog = opts.syslog;
++    if (use_syslog) {
++        openlog("virtiofsd", LOG_PID, LOG_DAEMON);
++    }
+     if (opts.show_help) {
+         printf("usage: %s [options]\n\n", argv[0]);
+         fuse_cmdline_help();
+@@ -2424,7 +2468,7 @@ int main(int argc, char *argv[])
+     /* Must be before sandbox since it wants /proc */
+     setup_capng();
+ 
+-    setup_sandbox(&lo, se);
++    setup_sandbox(&lo, se, opts.syslog);
+ 
+     /* Block until ctrl+c or fusermount -u */
+     ret = virtio_loop(se);
+diff --git a/tools/virtiofsd/seccomp.c b/tools/virtiofsd/seccomp.c
+index 691fb63dea..2d9d4a7ec0 100644
+--- a/tools/virtiofsd/seccomp.c
++++ b/tools/virtiofsd/seccomp.c
+@@ -107,11 +107,28 @@ static const int syscall_whitelist[] = {
+     SCMP_SYS(writev),
+ };
+ 
+-void setup_seccomp(void)
++/* Syscalls used when --syslog is enabled */
++static const int syscall_whitelist_syslog[] = {
++    SCMP_SYS(sendto),
++};
++
++static void add_whitelist(scmp_filter_ctx ctx, const int syscalls[], size_t len)
+ {
+-    scmp_filter_ctx ctx;
+     size_t i;
+ 
++    for (i = 0; i < len; i++) {
++        if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscalls[i], 0) != 0) {
++            fuse_log(FUSE_LOG_ERR, "seccomp_rule_add syscall %d failed\n",
++                     syscalls[i]);
++            exit(1);
++        }
++    }
++}
++
++void setup_seccomp(bool enable_syslog)
++{
++    scmp_filter_ctx ctx;
++
+ #ifdef SCMP_ACT_KILL_PROCESS
+     ctx = seccomp_init(SCMP_ACT_KILL_PROCESS);
+     /* Handle a newer libseccomp but an older kernel */
+@@ -126,13 +143,10 @@ void setup_seccomp(void)
+         exit(1);
+     }
+ 
+-    for (i = 0; i < G_N_ELEMENTS(syscall_whitelist); i++) {
+-        if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW,
+-                             syscall_whitelist[i], 0) != 0) {
+-            fuse_log(FUSE_LOG_ERR, "seccomp_rule_add syscall %d",
+-                     syscall_whitelist[i]);
+-            exit(1);
+-        }
++    add_whitelist(ctx, syscall_whitelist, G_N_ELEMENTS(syscall_whitelist));
++    if (enable_syslog) {
++        add_whitelist(ctx, syscall_whitelist_syslog,
++                      G_N_ELEMENTS(syscall_whitelist_syslog));
+     }
+ 
+     /* libvhost-user calls this for post-copy migration, we don't need it */
+diff --git a/tools/virtiofsd/seccomp.h b/tools/virtiofsd/seccomp.h
+index 86bce72652..d47c8eade6 100644
+--- a/tools/virtiofsd/seccomp.h
++++ b/tools/virtiofsd/seccomp.h
+@@ -9,6 +9,8 @@
+ #ifndef VIRTIOFSD_SECCOMP_H
+ #define VIRTIOFSD_SECCOMP_H
+ 
+-void setup_seccomp(void);
++#include <stdbool.h>
++
++void setup_seccomp(bool enable_syslog);
+ 
+ #endif /* VIRTIOFSD_SECCOMP_H */
diff --git a/0068-virtiofsd-print-log-only-when-priority-is-high-enoug.patch b/0068-virtiofsd-print-log-only-when-priority-is-high-enoug.patch
new file mode 100644
index 0000000..fa679f4
--- /dev/null
+++ b/0068-virtiofsd-print-log-only-when-priority-is-high-enoug.patch
@@ -0,0 +1,451 @@
+From: Eryu Guan <eguan@linux.alibaba.com>
+Date: Mon, 27 Jan 2020 19:01:37 +0000
+Subject: [PATCH] virtiofsd: print log only when priority is high enough
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Introduce "-o log_level=" command line option to specify current log
+level (priority), valid values are "debug info warn err", e.g.
+
+    ./virtiofsd -o log_level=debug ...
+
+So only log priority higher than "debug" will be printed to
+stderr/syslog. And the default level is info.
+
+The "-o debug"/"-d" options are kept, and imply debug log level.
+
+Signed-off-by: Eryu Guan <eguan@linux.alibaba.com>
+dgilbert: Reworked for libfuse's log_func
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+with fix by:
+Signed-off-by: Xiao Yang <yangx.jy@cn.fujitsu.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit d240314a1a18a1d914af1b5763fe8c9a572e6409)
+---
+ tools/virtiofsd/fuse_lowlevel.c  |  75 ++++++++------------
+ tools/virtiofsd/fuse_lowlevel.h  |   1 +
+ tools/virtiofsd/helper.c         |   8 ++-
+ tools/virtiofsd/passthrough_ll.c | 118 +++++++++++++------------------
+ 4 files changed, 87 insertions(+), 115 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 6ceb33d913..a7a19685b5 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -158,19 +158,17 @@ static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
+     struct fuse_out_header *out = iov[0].iov_base;
+ 
+     out->len = iov_length(iov, count);
+-    if (se->debug) {
+-        if (out->unique == 0) {
+-            fuse_log(FUSE_LOG_DEBUG, "NOTIFY: code=%d length=%u\n", out->error,
+-                     out->len);
+-        } else if (out->error) {
+-            fuse_log(FUSE_LOG_DEBUG,
+-                     "   unique: %llu, error: %i (%s), outsize: %i\n",
+-                     (unsigned long long)out->unique, out->error,
+-                     strerror(-out->error), out->len);
+-        } else {
+-            fuse_log(FUSE_LOG_DEBUG, "   unique: %llu, success, outsize: %i\n",
+-                     (unsigned long long)out->unique, out->len);
+-        }
++    if (out->unique == 0) {
++        fuse_log(FUSE_LOG_DEBUG, "NOTIFY: code=%d length=%u\n", out->error,
++                 out->len);
++    } else if (out->error) {
++        fuse_log(FUSE_LOG_DEBUG,
++                 "   unique: %llu, error: %i (%s), outsize: %i\n",
++                 (unsigned long long)out->unique, out->error,
++                 strerror(-out->error), out->len);
++    } else {
++        fuse_log(FUSE_LOG_DEBUG, "   unique: %llu, success, outsize: %i\n",
++                 (unsigned long long)out->unique, out->len);
+     }
+ 
+     if (fuse_lowlevel_is_virtio(se)) {
+@@ -1662,10 +1660,8 @@ static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid,
+         return;
+     }
+ 
+-    if (se->debug) {
+-        fuse_log(FUSE_LOG_DEBUG, "INTERRUPT: %llu\n",
+-                 (unsigned long long)arg->unique);
+-    }
++    fuse_log(FUSE_LOG_DEBUG, "INTERRUPT: %llu\n",
++             (unsigned long long)arg->unique);
+ 
+     req->u.i.unique = arg->unique;
+ 
+@@ -1901,13 +1897,10 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid,
+         }
+     }
+ 
+-    if (se->debug) {
+-        fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor);
+-        if (arg->major == 7 && arg->minor >= 6) {
+-            fuse_log(FUSE_LOG_DEBUG, "flags=0x%08x\n", arg->flags);
+-            fuse_log(FUSE_LOG_DEBUG, "max_readahead=0x%08x\n",
+-                     arg->max_readahead);
+-        }
++    fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor);
++    if (arg->major == 7 && arg->minor >= 6) {
++        fuse_log(FUSE_LOG_DEBUG, "flags=0x%08x\n", arg->flags);
++        fuse_log(FUSE_LOG_DEBUG, "max_readahead=0x%08x\n", arg->max_readahead);
+     }
+     se->conn.proto_major = arg->major;
+     se->conn.proto_minor = arg->minor;
+@@ -2116,19 +2109,14 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid,
+     outarg.congestion_threshold = se->conn.congestion_threshold;
+     outarg.time_gran = se->conn.time_gran;
+ 
+-    if (se->debug) {
+-        fuse_log(FUSE_LOG_DEBUG, "   INIT: %u.%u\n", outarg.major,
+-                 outarg.minor);
+-        fuse_log(FUSE_LOG_DEBUG, "   flags=0x%08x\n", outarg.flags);
+-        fuse_log(FUSE_LOG_DEBUG, "   max_readahead=0x%08x\n",
+-                 outarg.max_readahead);
+-        fuse_log(FUSE_LOG_DEBUG, "   max_write=0x%08x\n", outarg.max_write);
+-        fuse_log(FUSE_LOG_DEBUG, "   max_background=%i\n",
+-                 outarg.max_background);
+-        fuse_log(FUSE_LOG_DEBUG, "   congestion_threshold=%i\n",
+-                 outarg.congestion_threshold);
+-        fuse_log(FUSE_LOG_DEBUG, "   time_gran=%u\n", outarg.time_gran);
+-    }
++    fuse_log(FUSE_LOG_DEBUG, "   INIT: %u.%u\n", outarg.major, outarg.minor);
++    fuse_log(FUSE_LOG_DEBUG, "   flags=0x%08x\n", outarg.flags);
++    fuse_log(FUSE_LOG_DEBUG, "   max_readahead=0x%08x\n", outarg.max_readahead);
++    fuse_log(FUSE_LOG_DEBUG, "   max_write=0x%08x\n", outarg.max_write);
++    fuse_log(FUSE_LOG_DEBUG, "   max_background=%i\n", outarg.max_background);
++    fuse_log(FUSE_LOG_DEBUG, "   congestion_threshold=%i\n",
++             outarg.congestion_threshold);
++    fuse_log(FUSE_LOG_DEBUG, "   time_gran=%u\n", outarg.time_gran);
+ 
+     send_reply_ok(req, &outarg, outargsize);
+ }
+@@ -2407,14 +2395,11 @@ void fuse_session_process_buf_int(struct fuse_session *se,
+     in = fuse_mbuf_iter_advance(&iter, sizeof(*in));
+     assert(in); /* caller guarantees the input buffer is large enough */
+ 
+-    if (se->debug) {
+-        fuse_log(FUSE_LOG_DEBUG,
+-                 "unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, "
+-                 "pid: %u\n",
+-                 (unsigned long long)in->unique,
+-                 opname((enum fuse_opcode)in->opcode), in->opcode,
+-                 (unsigned long long)in->nodeid, buf->size, in->pid);
+-    }
++    fuse_log(
++        FUSE_LOG_DEBUG,
++        "unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n",
++        (unsigned long long)in->unique, opname((enum fuse_opcode)in->opcode),
++        in->opcode, (unsigned long long)in->nodeid, buf->size, in->pid);
+ 
+     req = fuse_ll_alloc_req(se);
+     if (req == NULL) {
+diff --git a/tools/virtiofsd/fuse_lowlevel.h b/tools/virtiofsd/fuse_lowlevel.h
+index f2750bc189..138041e5f1 100644
+--- a/tools/virtiofsd/fuse_lowlevel.h
++++ b/tools/virtiofsd/fuse_lowlevel.h
+@@ -1796,6 +1796,7 @@ struct fuse_cmdline_opts {
+     int show_help;
+     int print_capabilities;
+     int syslog;
++    int log_level;
+     unsigned int max_idle_threads;
+ };
+ 
+diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
+index 9692ef9f1f..6d50a46a7e 100644
+--- a/tools/virtiofsd/helper.c
++++ b/tools/virtiofsd/helper.c
+@@ -34,7 +34,6 @@
+         t, offsetof(struct fuse_cmdline_opts, p), v \
+     }
+ 
+-
+ static const struct fuse_opt fuse_helper_opts[] = {
+     FUSE_HELPER_OPT("-h", show_help),
+     FUSE_HELPER_OPT("--help", show_help),
+@@ -55,6 +54,10 @@ static const struct fuse_opt fuse_helper_opts[] = {
+     FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP),
+     FUSE_HELPER_OPT("max_idle_threads=%u", max_idle_threads),
+     FUSE_HELPER_OPT("--syslog", syslog),
++    FUSE_HELPER_OPT_VALUE("log_level=debug", log_level, FUSE_LOG_DEBUG),
++    FUSE_HELPER_OPT_VALUE("log_level=info", log_level, FUSE_LOG_INFO),
++    FUSE_HELPER_OPT_VALUE("log_level=warn", log_level, FUSE_LOG_WARNING),
++    FUSE_HELPER_OPT_VALUE("log_level=err", log_level, FUSE_LOG_ERR),
+     FUSE_OPT_END
+ };
+ 
+@@ -142,6 +145,9 @@ void fuse_cmdline_help(void)
+            "    --syslog                   log to syslog (default stderr)\n"
+            "    -f                         foreground operation\n"
+            "    --daemonize                run in background\n"
++           "    -o log_level=<level>       log level, default to \"info\"\n"
++           "                               level could be one of \"debug, "
++           "info, warn, err\"\n"
+            "    -o max_idle_threads        the maximum number of idle worker "
+            "threads\n"
+            "                               allowed (default: 10)\n"
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 0372aca143..ff6910fd73 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -37,6 +37,7 @@
+ 
+ #include "qemu/osdep.h"
+ #include "fuse_virtio.h"
++#include "fuse_log.h"
+ #include "fuse_lowlevel.h"
+ #include <assert.h>
+ #include <cap-ng.h>
+@@ -140,6 +141,7 @@ static const struct fuse_opt lo_opts[] = {
+     FUSE_OPT_END
+ };
+ static bool use_syslog = false;
++static int current_log_level;
+ 
+ static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n);
+ 
+@@ -458,11 +460,6 @@ static int lo_fd(fuse_req_t req, fuse_ino_t ino)
+     return inode ? inode->fd : -1;
+ }
+ 
+-static bool lo_debug(fuse_req_t req)
+-{
+-    return lo_data(req)->debug != 0;
+-}
+-
+ static void lo_init(void *userdata, struct fuse_conn_info *conn)
+ {
+     struct lo_data *lo = (struct lo_data *)userdata;
+@@ -472,15 +469,11 @@ static void lo_init(void *userdata, struct fuse_conn_info *conn)
+     }
+ 
+     if (lo->writeback && conn->capable & FUSE_CAP_WRITEBACK_CACHE) {
+-        if (lo->debug) {
+-            fuse_log(FUSE_LOG_DEBUG, "lo_init: activating writeback\n");
+-        }
++        fuse_log(FUSE_LOG_DEBUG, "lo_init: activating writeback\n");
+         conn->want |= FUSE_CAP_WRITEBACK_CACHE;
+     }
+     if (lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) {
+-        if (lo->debug) {
+-            fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
+-        }
++        fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
+         conn->want |= FUSE_CAP_FLOCK_LOCKS;
+     }
+ }
+@@ -823,10 +816,8 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+     }
+     e->ino = inode->fuse_ino;
+ 
+-    if (lo_debug(req)) {
+-        fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
+-                 (unsigned long long)parent, name, (unsigned long long)e->ino);
+-    }
++    fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n", (unsigned long long)parent,
++             name, (unsigned long long)e->ino);
+ 
+     return 0;
+ 
+@@ -843,10 +834,8 @@ static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
+     struct fuse_entry_param e;
+     int err;
+ 
+-    if (lo_debug(req)) {
+-        fuse_log(FUSE_LOG_DEBUG, "lo_lookup(parent=%" PRIu64 ", name=%s)\n",
+-                 parent, name);
+-    }
++    fuse_log(FUSE_LOG_DEBUG, "lo_lookup(parent=%" PRIu64 ", name=%s)\n", parent,
++             name);
+ 
+     /*
+      * Don't use is_safe_path_component(), allow "." and ".." for NFS export
+@@ -971,10 +960,8 @@ static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent,
+         goto out;
+     }
+ 
+-    if (lo_debug(req)) {
+-        fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
+-                 (unsigned long long)parent, name, (unsigned long long)e.ino);
+-    }
++    fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n", (unsigned long long)parent,
++             name, (unsigned long long)e.ino);
+ 
+     fuse_reply_entry(req, &e);
+     return;
+@@ -1074,10 +1061,8 @@ static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
+     pthread_mutex_unlock(&lo->mutex);
+     e.ino = inode->fuse_ino;
+ 
+-    if (lo_debug(req)) {
+-        fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
+-                 (unsigned long long)parent, name, (unsigned long long)e.ino);
+-    }
++    fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n", (unsigned long long)parent,
++             name, (unsigned long long)e.ino);
+ 
+     fuse_reply_entry(req, &e);
+     return;
+@@ -1171,11 +1156,9 @@ static void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
+         return;
+     }
+ 
+-    if (lo_debug(req)) {
+-        fuse_log(FUSE_LOG_DEBUG, "  forget %lli %lli -%lli\n",
+-                 (unsigned long long)ino, (unsigned long long)inode->refcount,
+-                 (unsigned long long)nlookup);
+-    }
++    fuse_log(FUSE_LOG_DEBUG, "  forget %lli %lli -%lli\n",
++             (unsigned long long)ino, (unsigned long long)inode->refcount,
++             (unsigned long long)nlookup);
+ 
+     unref_inode(lo, inode, nlookup);
+ }
+@@ -1445,10 +1428,8 @@ static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
+     int err;
+     struct lo_cred old = {};
+ 
+-    if (lo_debug(req)) {
+-        fuse_log(FUSE_LOG_DEBUG, "lo_create(parent=%" PRIu64 ", name=%s)\n",
+-                 parent, name);
+-    }
++    fuse_log(FUSE_LOG_DEBUG, "lo_create(parent=%" PRIu64 ", name=%s)\n", parent,
++             name);
+ 
+     if (!is_safe_path_component(name)) {
+         fuse_reply_err(req, EINVAL);
+@@ -1525,10 +1506,8 @@ static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+     char buf[64];
+     struct lo_data *lo = lo_data(req);
+ 
+-    if (lo_debug(req)) {
+-        fuse_log(FUSE_LOG_DEBUG, "lo_open(ino=%" PRIu64 ", flags=%d)\n", ino,
+-                 fi->flags);
+-    }
++    fuse_log(FUSE_LOG_DEBUG, "lo_open(ino=%" PRIu64 ", flags=%d)\n", ino,
++             fi->flags);
+ 
+     /*
+      * With writeback cache, kernel may send read requests even
+@@ -1644,12 +1623,10 @@ static void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset,
+ {
+     struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size);
+ 
+-    if (lo_debug(req)) {
+-        fuse_log(FUSE_LOG_DEBUG,
+-                 "lo_read(ino=%" PRIu64 ", size=%zd, "
+-                 "off=%lu)\n",
+-                 ino, size, (unsigned long)offset);
+-    }
++    fuse_log(FUSE_LOG_DEBUG,
++             "lo_read(ino=%" PRIu64 ", size=%zd, "
++             "off=%lu)\n",
++             ino, size, (unsigned long)offset);
+ 
+     buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
+     buf.buf[0].fd = lo_fi_fd(req, fi);
+@@ -1671,11 +1648,9 @@ static void lo_write_buf(fuse_req_t req, fuse_ino_t ino,
+     out_buf.buf[0].fd = lo_fi_fd(req, fi);
+     out_buf.buf[0].pos = off;
+ 
+-    if (lo_debug(req)) {
+-        fuse_log(FUSE_LOG_DEBUG,
+-                 "lo_write(ino=%" PRIu64 ", size=%zd, off=%lu)\n", ino,
+-                 out_buf.buf[0].size, (unsigned long)off);
+-    }
++    fuse_log(FUSE_LOG_DEBUG,
++             "lo_write_buf(ino=%" PRIu64 ", size=%zd, off=%lu)\n", ino,
++             out_buf.buf[0].size, (unsigned long)off);
+ 
+     /*
+      * If kill_priv is set, drop CAP_FSETID which should lead to kernel
+@@ -1774,11 +1749,8 @@ static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+         goto out;
+     }
+ 
+-    if (lo_debug(req)) {
+-        fuse_log(FUSE_LOG_DEBUG,
+-                 "lo_getxattr(ino=%" PRIu64 ", name=%s size=%zd)\n", ino, name,
+-                 size);
+-    }
++    fuse_log(FUSE_LOG_DEBUG, "lo_getxattr(ino=%" PRIu64 ", name=%s size=%zd)\n",
++             ino, name, size);
+ 
+     if (inode->is_symlink) {
+         /* Sorry, no race free way to getxattr on symlink. */
+@@ -1852,10 +1824,8 @@ static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
+         goto out;
+     }
+ 
+-    if (lo_debug(req)) {
+-        fuse_log(FUSE_LOG_DEBUG, "lo_listxattr(ino=%" PRIu64 ", size=%zd)\n",
+-                 ino, size);
+-    }
++    fuse_log(FUSE_LOG_DEBUG, "lo_listxattr(ino=%" PRIu64 ", size=%zd)\n", ino,
++             size);
+ 
+     if (inode->is_symlink) {
+         /* Sorry, no race free way to listxattr on symlink. */
+@@ -1929,11 +1899,8 @@ static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+         goto out;
+     }
+ 
+-    if (lo_debug(req)) {
+-        fuse_log(FUSE_LOG_DEBUG,
+-                 "lo_setxattr(ino=%" PRIu64 ", name=%s value=%s size=%zd)\n",
+-                 ino, name, value, size);
+-    }
++    fuse_log(FUSE_LOG_DEBUG, "lo_setxattr(ino=%" PRIu64
++             ", name=%s value=%s size=%zd)\n", ino, name, value, size);
+ 
+     if (inode->is_symlink) {
+         /* Sorry, no race free way to setxattr on symlink. */
+@@ -1978,10 +1945,8 @@ static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
+         goto out;
+     }
+ 
+-    if (lo_debug(req)) {
+-        fuse_log(FUSE_LOG_DEBUG, "lo_removexattr(ino=%" PRIu64 ", name=%s)\n",
+-                 ino, name);
+-    }
++    fuse_log(FUSE_LOG_DEBUG, "lo_removexattr(ino=%" PRIu64 ", name=%s)\n", ino,
++             name);
+ 
+     if (inode->is_symlink) {
+         /* Sorry, no race free way to setxattr on symlink. */
+@@ -2303,6 +2268,10 @@ static void setup_nofile_rlimit(void)
+ 
+ static void log_func(enum fuse_log_level level, const char *fmt, va_list ap)
+ {
++    if (current_log_level < level) {
++        return;
++    }
++
+     if (use_syslog) {
+         int priority = LOG_ERR;
+         switch (level) {
+@@ -2401,8 +2370,19 @@ int main(int argc, char *argv[])
+         return 1;
+     }
+ 
++    /*
++     * log_level is 0 if not configured via cmd options (0 is LOG_EMERG,
++     * and we don't use this log level).
++     */
++    if (opts.log_level != 0) {
++        current_log_level = opts.log_level;
++    }
+     lo.debug = opts.debug;
++    if (lo.debug) {
++        current_log_level = FUSE_LOG_DEBUG;
++    }
+     lo.root.refcount = 2;
++
+     if (lo.source) {
+         struct stat stat;
+         int res;
diff --git a/0069-virtiofsd-Add-ID-to-the-log-with-FUSE_LOG_DEBUG-leve.patch b/0069-virtiofsd-Add-ID-to-the-log-with-FUSE_LOG_DEBUG-leve.patch
new file mode 100644
index 0000000..e3aaef9
--- /dev/null
+++ b/0069-virtiofsd-Add-ID-to-the-log-with-FUSE_LOG_DEBUG-leve.patch
@@ -0,0 +1,68 @@
+From: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+Date: Mon, 27 Jan 2020 19:01:38 +0000
+Subject: [PATCH] virtiofsd: Add ID to the log with FUSE_LOG_DEBUG level
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+virtiofsd has some threads, so we see a lot of logs with debug option.
+It would be useful for debugging if we can identify the specific thread
+from the log.
+
+Add ID, which is got by gettid(), to the log with FUSE_LOG_DEBUG level
+so that we can grep the specific thread.
+
+The log is like as:
+
+  ]# ./virtiofsd -d -o vhost_user_socket=/tmp/vhostqemu0 -o source=/tmp/share0 -o cache=auto
+  ...
+  [ID: 00000097]    unique: 12696, success, outsize: 120
+  [ID: 00000097] virtio_send_msg: elem 18: with 2 in desc of length 120
+  [ID: 00000003] fv_queue_thread: Got queue event on Queue 1
+  [ID: 00000003] fv_queue_thread: Queue 1 gave evalue: 1 available: in: 65552 out: 80
+  [ID: 00000003] fv_queue_thread: Waiting for Queue 1 event
+  [ID: 00000071] fv_queue_worker: elem 33: with 2 out desc of length 80 bad_in_num=0 bad_out_num=0
+  [ID: 00000071] unique: 12694, opcode: READ (15), nodeid: 2, insize: 80, pid: 2014
+  [ID: 00000071] lo_read(ino=2, size=65536, off=131072)
+
+Signed-off-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+  added rework as suggested by Daniel P. Berrangé during review
+Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 36f3846902bd41413f6c0bf797dee509028c29f4)
+---
+ tools/virtiofsd/passthrough_ll.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index ff6910fd73..f08324f000 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -43,6 +43,7 @@
+ #include <cap-ng.h>
+ #include <dirent.h>
+ #include <errno.h>
++#include <glib.h>
+ #include <inttypes.h>
+ #include <limits.h>
+ #include <pthread.h>
+@@ -2268,10 +2269,17 @@ static void setup_nofile_rlimit(void)
+ 
+ static void log_func(enum fuse_log_level level, const char *fmt, va_list ap)
+ {
++    g_autofree char *localfmt = NULL;
++
+     if (current_log_level < level) {
+         return;
+     }
+ 
++    if (current_log_level == FUSE_LOG_DEBUG) {
++        localfmt = g_strdup_printf("[ID: %08ld] %s", syscall(__NR_gettid), fmt);
++        fmt = localfmt;
++    }
++
+     if (use_syslog) {
+         int priority = LOG_ERR;
+         switch (level) {
diff --git a/0070-virtiofsd-Add-timestamp-to-the-log-with-FUSE_LOG_DEB.patch b/0070-virtiofsd-Add-timestamp-to-the-log-with-FUSE_LOG_DEB.patch
new file mode 100644
index 0000000..b58a8c2
--- /dev/null
+++ b/0070-virtiofsd-Add-timestamp-to-the-log-with-FUSE_LOG_DEB.patch
@@ -0,0 +1,56 @@
+From: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+Date: Mon, 27 Jan 2020 19:01:39 +0000
+Subject: [PATCH] virtiofsd: Add timestamp to the log with FUSE_LOG_DEBUG level
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+virtiofsd has some threads, so we see a lot of logs with debug option.
+It would be useful for debugging if we can see the timestamp.
+
+Add nano second timestamp, which got by get_clock(), to the log with
+FUSE_LOG_DEBUG level if the syslog option isn't set.
+
+The log is like as:
+
+  # ./virtiofsd -d -o vhost_user_socket=/tmp/vhostqemu0 -o source=/tmp/share0 -o cache=auto
+  ...
+  [5365943125463727] [ID: 00000002] fv_queue_thread: Start for queue 0 kick_fd 9
+  [5365943125568644] [ID: 00000002] fv_queue_thread: Waiting for Queue 0 event
+  [5365943125573561] [ID: 00000002] fv_queue_thread: Got queue event on Queue 0
+
+Signed-off-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 50fb955aa0e6ede929422146936cf68bf1ca876f)
+---
+ tools/virtiofsd/passthrough_ll.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index f08324f000..98114a3f4a 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -36,6 +36,7 @@
+  */
+ 
+ #include "qemu/osdep.h"
++#include "qemu/timer.h"
+ #include "fuse_virtio.h"
+ #include "fuse_log.h"
+ #include "fuse_lowlevel.h"
+@@ -2276,7 +2277,13 @@ static void log_func(enum fuse_log_level level, const char *fmt, va_list ap)
+     }
+ 
+     if (current_log_level == FUSE_LOG_DEBUG) {
+-        localfmt = g_strdup_printf("[ID: %08ld] %s", syscall(__NR_gettid), fmt);
++        if (!use_syslog) {
++            localfmt = g_strdup_printf("[%" PRId64 "] [ID: %08ld] %s",
++                                       get_clock(), syscall(__NR_gettid), fmt);
++        } else {
++            localfmt = g_strdup_printf("[ID: %08ld] %s", syscall(__NR_gettid),
++                                       fmt);
++        }
+         fmt = localfmt;
+     }
+ 
diff --git a/0071-virtiofsd-Handle-reinit.patch b/0071-virtiofsd-Handle-reinit.patch
new file mode 100644
index 0000000..88c91c7
--- /dev/null
+++ b/0071-virtiofsd-Handle-reinit.patch
@@ -0,0 +1,37 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:40 +0000
+Subject: [PATCH] virtiofsd: Handle reinit
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Allow init->destroy->init  for mount->umount->mount
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit c806d6435fe95fd54b379920aca2f4e3ea1f3258)
+---
+ tools/virtiofsd/fuse_lowlevel.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index a7a19685b5..7d742b5a72 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -2028,6 +2028,7 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid,
+     }
+ 
+     se->got_init = 1;
++    se->got_destroy = 0;
+     if (se->op.init) {
+         se->op.init(se->userdata, &se->conn);
+     }
+@@ -2130,6 +2131,7 @@ static void do_destroy(fuse_req_t req, fuse_ino_t nodeid,
+     (void)iter;
+ 
+     se->got_destroy = 1;
++    se->got_init = 0;
+     if (se->op.destroy) {
+         se->op.destroy(se->userdata);
+     }
diff --git a/0072-virtiofsd-Handle-hard-reboot.patch b/0072-virtiofsd-Handle-hard-reboot.patch
new file mode 100644
index 0000000..c5e2dfd
--- /dev/null
+++ b/0072-virtiofsd-Handle-hard-reboot.patch
@@ -0,0 +1,49 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:41 +0000
+Subject: [PATCH] virtiofsd: Handle hard reboot
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Handle a
+  mount
+  hard reboot (without unmount)
+  mount
+
+we get another 'init' which FUSE doesn't normally expect.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit e8556f49098b5d95634e592d79a97f761b76c96e)
+---
+ tools/virtiofsd/fuse_lowlevel.c | 16 +++++++++++++++-
+ 1 file changed, 15 insertions(+), 1 deletion(-)
+
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 7d742b5a72..65f91dabae 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -2433,7 +2433,21 @@ void fuse_session_process_buf_int(struct fuse_session *se,
+             goto reply_err;
+         }
+     } else if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT) {
+-        goto reply_err;
++        if (fuse_lowlevel_is_virtio(se)) {
++            /*
++             * TODO: This is after a hard reboot typically, we need to do
++             * a destroy, but we can't reply to this request yet so
++             * we can't use do_destroy
++             */
++            fuse_log(FUSE_LOG_DEBUG, "%s: reinit\n", __func__);
++            se->got_destroy = 1;
++            se->got_init = 0;
++            if (se->op.destroy) {
++                se->op.destroy(se->userdata);
++            }
++        } else {
++            goto reply_err;
++        }
+     }
+ 
+     err = EACCES;
diff --git a/0073-virtiofsd-Kill-threads-when-queues-are-stopped.patch b/0073-virtiofsd-Kill-threads-when-queues-are-stopped.patch
new file mode 100644
index 0000000..70d3e7a
--- /dev/null
+++ b/0073-virtiofsd-Kill-threads-when-queues-are-stopped.patch
@@ -0,0 +1,126 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:42 +0000
+Subject: [PATCH] virtiofsd: Kill threads when queues are stopped
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Kill the threads we've started when the queues get stopped.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+With improvements by:
+Signed-off-by: Eryu Guan <eguan@linux.alibaba.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 10477ac47fc57d00a84802ff97c15450cd8021c1)
+---
+ tools/virtiofsd/fuse_virtio.c | 51 ++++++++++++++++++++++++++++++-----
+ 1 file changed, 44 insertions(+), 7 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+index 872968f2c8..7a8774a3ee 100644
+--- a/tools/virtiofsd/fuse_virtio.c
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -41,6 +41,7 @@ struct fv_QueueInfo {
+     /* Our queue index, corresponds to array position */
+     int qidx;
+     int kick_fd;
++    int kill_fd; /* For killing the thread */
+ 
+     /* The element for the command currently being processed */
+     VuVirtqElement *qe;
+@@ -412,14 +413,17 @@ static void *fv_queue_thread(void *opaque)
+     fuse_log(FUSE_LOG_INFO, "%s: Start for queue %d kick_fd %d\n", __func__,
+              qi->qidx, qi->kick_fd);
+     while (1) {
+-        struct pollfd pf[1];
++        struct pollfd pf[2];
+         pf[0].fd = qi->kick_fd;
+         pf[0].events = POLLIN;
+         pf[0].revents = 0;
++        pf[1].fd = qi->kill_fd;
++        pf[1].events = POLLIN;
++        pf[1].revents = 0;
+ 
+         fuse_log(FUSE_LOG_DEBUG, "%s: Waiting for Queue %d event\n", __func__,
+                  qi->qidx);
+-        int poll_res = ppoll(pf, 1, NULL, NULL);
++        int poll_res = ppoll(pf, 2, NULL, NULL);
+ 
+         if (poll_res == -1) {
+             if (errno == EINTR) {
+@@ -430,12 +434,23 @@ static void *fv_queue_thread(void *opaque)
+             fuse_log(FUSE_LOG_ERR, "fv_queue_thread ppoll: %m\n");
+             break;
+         }
+-        assert(poll_res == 1);
++        assert(poll_res >= 1);
+         if (pf[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
+             fuse_log(FUSE_LOG_ERR, "%s: Unexpected poll revents %x Queue %d\n",
+                      __func__, pf[0].revents, qi->qidx);
+             break;
+         }
++        if (pf[1].revents & (POLLERR | POLLHUP | POLLNVAL)) {
++            fuse_log(FUSE_LOG_ERR,
++                     "%s: Unexpected poll revents %x Queue %d killfd\n",
++                     __func__, pf[1].revents, qi->qidx);
++            break;
++        }
++        if (pf[1].revents) {
++            fuse_log(FUSE_LOG_INFO, "%s: kill event on queue %d - quitting\n",
++                     __func__, qi->qidx);
++            break;
++        }
+         assert(pf[0].revents & POLLIN);
+         fuse_log(FUSE_LOG_DEBUG, "%s: Got queue event on Queue %d\n", __func__,
+                  qi->qidx);
+@@ -589,6 +604,28 @@ out:
+     return NULL;
+ }
+ 
++static void fv_queue_cleanup_thread(struct fv_VuDev *vud, int qidx)
++{
++    int ret;
++    struct fv_QueueInfo *ourqi;
++
++    assert(qidx < vud->nqueues);
++    ourqi = vud->qi[qidx];
++
++    /* Kill the thread */
++    if (eventfd_write(ourqi->kill_fd, 1)) {
++        fuse_log(FUSE_LOG_ERR, "Eventfd_write for queue %d: %s\n",
++                 qidx, strerror(errno));
++    }
++    ret = pthread_join(ourqi->thread, NULL);
++    if (ret) {
++        fuse_log(FUSE_LOG_ERR, "%s: Failed to join thread idx %d err %d\n",
++                 __func__, qidx, ret);
++    }
++    close(ourqi->kill_fd);
++    ourqi->kick_fd = -1;
++}
++
+ /* Callback from libvhost-user on start or stop of a queue */
+ static void fv_queue_set_started(VuDev *dev, int qidx, bool started)
+ {
+@@ -633,16 +670,16 @@ static void fv_queue_set_started(VuDev *dev, int qidx, bool started)
+         }
+         ourqi = vud->qi[qidx];
+         ourqi->kick_fd = dev->vq[qidx].kick_fd;
++
++        ourqi->kill_fd = eventfd(0, EFD_CLOEXEC | EFD_SEMAPHORE);
++        assert(ourqi->kill_fd != -1);
+         if (pthread_create(&ourqi->thread, NULL, fv_queue_thread, ourqi)) {
+             fuse_log(FUSE_LOG_ERR, "%s: Failed to create thread for queue %d\n",
+                      __func__, qidx);
+             assert(0);
+         }
+     } else {
+-        /* TODO: Kill the thread */
+-        assert(qidx < vud->nqueues);
+-        ourqi = vud->qi[qidx];
+-        ourqi->kick_fd = -1;
++        fv_queue_cleanup_thread(vud, qidx);
+     }
+ }
+ 
diff --git a/0074-vhost-user-Print-unexpected-slave-message-types.patch b/0074-vhost-user-Print-unexpected-slave-message-types.patch
new file mode 100644
index 0000000..cead453
--- /dev/null
+++ b/0074-vhost-user-Print-unexpected-slave-message-types.patch
@@ -0,0 +1,32 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:43 +0000
+Subject: [PATCH] vhost-user: Print unexpected slave message types
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When we receive an unexpected message type on the slave fd, print
+the type.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 0fdc465d7d5aafeae127eba488f247ac6f58df4c)
+---
+ hw/virtio/vhost-user.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
+index 02a9b25199..e4f46ecf88 100644
+--- a/hw/virtio/vhost-user.c
++++ b/hw/virtio/vhost-user.c
+@@ -1055,7 +1055,7 @@ static void slave_read(void *opaque)
+                                                           fd[0]);
+         break;
+     default:
+-        error_report("Received unexpected msg type.");
++        error_report("Received unexpected msg type: %d.", hdr.request);
+         ret = -EINVAL;
+     }
+ 
diff --git a/0075-contrib-libvhost-user-Protect-slave-fd-with-mutex.patch b/0075-contrib-libvhost-user-Protect-slave-fd-with-mutex.patch
new file mode 100644
index 0000000..2e05ece
--- /dev/null
+++ b/0075-contrib-libvhost-user-Protect-slave-fd-with-mutex.patch
@@ -0,0 +1,118 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:44 +0000
+Subject: [PATCH] contrib/libvhost-user: Protect slave fd with mutex
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+In future patches we'll be performing commands on the slave-fd driven
+by commands on queues, since those queues will be driven by individual
+threads we need to make sure they don't attempt to use the slave-fd
+for multiple commands in parallel.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit c25c02b9e6a196be87a818f459c426556b24770d)
+---
+ contrib/libvhost-user/libvhost-user.c | 24 ++++++++++++++++++++----
+ contrib/libvhost-user/libvhost-user.h |  3 +++
+ 2 files changed, 23 insertions(+), 4 deletions(-)
+
+diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c
+index ec27b78ff1..63e41062a4 100644
+--- a/contrib/libvhost-user/libvhost-user.c
++++ b/contrib/libvhost-user/libvhost-user.c
+@@ -392,26 +392,37 @@ vu_send_reply(VuDev *dev, int conn_fd, VhostUserMsg *vmsg)
+     return vu_message_write(dev, conn_fd, vmsg);
+ }
+ 
++/*
++ * Processes a reply on the slave channel.
++ * Entered with slave_mutex held and releases it before exit.
++ * Returns true on success.
++ */
+ static bool
+ vu_process_message_reply(VuDev *dev, const VhostUserMsg *vmsg)
+ {
+     VhostUserMsg msg_reply;
++    bool result = false;
+ 
+     if ((vmsg->flags & VHOST_USER_NEED_REPLY_MASK) == 0) {
+-        return true;
++        result = true;
++        goto out;
+     }
+ 
+     if (!vu_message_read(dev, dev->slave_fd, &msg_reply)) {
+-        return false;
++        goto out;
+     }
+ 
+     if (msg_reply.request != vmsg->request) {
+         DPRINT("Received unexpected msg type. Expected %d received %d",
+                vmsg->request, msg_reply.request);
+-        return false;
++        goto out;
+     }
+ 
+-    return msg_reply.payload.u64 == 0;
++    result = msg_reply.payload.u64 == 0;
++
++out:
++    pthread_mutex_unlock(&dev->slave_mutex);
++    return result;
+ }
+ 
+ /* Kick the log_call_fd if required. */
+@@ -1105,10 +1116,13 @@ bool vu_set_queue_host_notifier(VuDev *dev, VuVirtq *vq, int fd,
+         return false;
+     }
+ 
++    pthread_mutex_lock(&dev->slave_mutex);
+     if (!vu_message_write(dev, dev->slave_fd, &vmsg)) {
++        pthread_mutex_unlock(&dev->slave_mutex);
+         return false;
+     }
+ 
++    /* Also unlocks the slave_mutex */
+     return vu_process_message_reply(dev, &vmsg);
+ }
+ 
+@@ -1628,6 +1642,7 @@ vu_deinit(VuDev *dev)
+         close(dev->slave_fd);
+         dev->slave_fd = -1;
+     }
++    pthread_mutex_destroy(&dev->slave_mutex);
+ 
+     if (dev->sock != -1) {
+         close(dev->sock);
+@@ -1663,6 +1678,7 @@ vu_init(VuDev *dev,
+     dev->remove_watch = remove_watch;
+     dev->iface = iface;
+     dev->log_call_fd = -1;
++    pthread_mutex_init(&dev->slave_mutex, NULL);
+     dev->slave_fd = -1;
+     dev->max_queues = max_queues;
+ 
+diff --git a/contrib/libvhost-user/libvhost-user.h b/contrib/libvhost-user/libvhost-user.h
+index 46b600799b..1844b6f8d4 100644
+--- a/contrib/libvhost-user/libvhost-user.h
++++ b/contrib/libvhost-user/libvhost-user.h
+@@ -19,6 +19,7 @@
+ #include <stddef.h>
+ #include <sys/poll.h>
+ #include <linux/vhost.h>
++#include <pthread.h>
+ #include "standard-headers/linux/virtio_ring.h"
+ 
+ /* Based on qemu/hw/virtio/vhost-user.c */
+@@ -355,6 +356,8 @@ struct VuDev {
+     VuVirtq *vq;
+     VuDevInflightInfo inflight_info;
+     int log_call_fd;
++    /* Must be held while using slave_fd */
++    pthread_mutex_t slave_mutex;
+     int slave_fd;
+     uint64_t log_size;
+     uint8_t *log_table;
diff --git a/0076-virtiofsd-passthrough_ll-add-renameat2-support.patch b/0076-virtiofsd-passthrough_ll-add-renameat2-support.patch
new file mode 100644
index 0000000..e375310
--- /dev/null
+++ b/0076-virtiofsd-passthrough_ll-add-renameat2-support.patch
@@ -0,0 +1,33 @@
+From: Miklos Szeredi <mszeredi@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:45 +0000
+Subject: [PATCH] virtiofsd: passthrough_ll: add renameat2 support
+
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit f0ab7d6f78a7d3c1c19fd81a91c9b1199f56c4f6)
+---
+ tools/virtiofsd/passthrough_ll.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 98114a3f4a..18d69abcbc 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -1099,7 +1099,17 @@ static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
+     }
+ 
+     if (flags) {
++#ifndef SYS_renameat2
+         fuse_reply_err(req, EINVAL);
++#else
++        res = syscall(SYS_renameat2, lo_fd(req, parent), name,
++                       lo_fd(req, newparent), newname, flags);
++        if (res == -1 && errno == ENOSYS) {
++            fuse_reply_err(req, EINVAL);
++        } else {
++            fuse_reply_err(req, res == -1 ? errno : 0);
++        }
++#endif
+         return;
+     }
+ 
diff --git a/0077-virtiofsd-passthrough_ll-disable-readdirplus-on-cach.patch b/0077-virtiofsd-passthrough_ll-disable-readdirplus-on-cach.patch
new file mode 100644
index 0000000..d4dbb58
--- /dev/null
+++ b/0077-virtiofsd-passthrough_ll-disable-readdirplus-on-cach.patch
@@ -0,0 +1,33 @@
+From: Miklos Szeredi <mszeredi@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:46 +0000
+Subject: [PATCH] virtiofsd: passthrough_ll: disable readdirplus on cache=never
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+...because the attributes sent in the READDIRPLUS reply would be discarded
+anyway.
+
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit ddcbabcb0ea177be3ec3500726b699c7c26ffd93)
+---
+ tools/virtiofsd/passthrough_ll.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 18d69abcbc..6480c517dc 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -478,6 +478,10 @@ static void lo_init(void *userdata, struct fuse_conn_info *conn)
+         fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
+         conn->want |= FUSE_CAP_FLOCK_LOCKS;
+     }
++    if (lo->cache == CACHE_NEVER) {
++        fuse_log(FUSE_LOG_DEBUG, "lo_init: disabling readdirplus\n");
++        conn->want &= ~FUSE_CAP_READDIRPLUS;
++    }
+ }
+ 
+ static void lo_getattr(fuse_req_t req, fuse_ino_t ino,
diff --git a/0078-virtiofsd-passthrough_ll-control-readdirplus.patch b/0078-virtiofsd-passthrough_ll-control-readdirplus.patch
new file mode 100644
index 0000000..d40c6f6
--- /dev/null
+++ b/0078-virtiofsd-passthrough_ll-control-readdirplus.patch
@@ -0,0 +1,60 @@
+From: Miklos Szeredi <mszeredi@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:47 +0000
+Subject: [PATCH] virtiofsd: passthrough_ll: control readdirplus
+
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Reviewed-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 59aef494be2d8d91055ff3f3a8eb13d9f32873d8)
+---
+ tools/virtiofsd/helper.c         | 4 ++++
+ tools/virtiofsd/passthrough_ll.c | 7 ++++++-
+ 2 files changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
+index 6d50a46a7e..14f5d70c10 100644
+--- a/tools/virtiofsd/helper.c
++++ b/tools/virtiofsd/helper.c
+@@ -153,6 +153,10 @@ void fuse_cmdline_help(void)
+            "                               allowed (default: 10)\n"
+            "    -o norace                  disable racy fallback\n"
+            "                               default: false\n"
++           "    -o readdirplus|no_readdirplus\n"
++           "                               enable/disable readirplus\n"
++           "                               default: readdirplus except with "
++           "cache=never\n"
+           );
+ }
+ 
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 6480c517dc..8b1784ff7b 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -117,6 +117,8 @@ struct lo_data {
+     double timeout;
+     int cache;
+     int timeout_set;
++    int readdirplus_set;
++    int readdirplus_clear;
+     struct lo_inode root; /* protected by lo->mutex */
+     struct lo_map ino_map; /* protected by lo->mutex */
+     struct lo_map dirp_map; /* protected by lo->mutex */
+@@ -140,6 +142,8 @@ static const struct fuse_opt lo_opts[] = {
+     { "cache=auto", offsetof(struct lo_data, cache), CACHE_NORMAL },
+     { "cache=always", offsetof(struct lo_data, cache), CACHE_ALWAYS },
+     { "norace", offsetof(struct lo_data, norace), 1 },
++    { "readdirplus", offsetof(struct lo_data, readdirplus_set), 1 },
++    { "no_readdirplus", offsetof(struct lo_data, readdirplus_clear), 1 },
+     FUSE_OPT_END
+ };
+ static bool use_syslog = false;
+@@ -478,7 +482,8 @@ static void lo_init(void *userdata, struct fuse_conn_info *conn)
+         fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
+         conn->want |= FUSE_CAP_FLOCK_LOCKS;
+     }
+-    if (lo->cache == CACHE_NEVER) {
++    if ((lo->cache == CACHE_NEVER && !lo->readdirplus_set) ||
++        lo->readdirplus_clear) {
+         fuse_log(FUSE_LOG_DEBUG, "lo_init: disabling readdirplus\n");
+         conn->want &= ~FUSE_CAP_READDIRPLUS;
+     }
diff --git a/0079-virtiofsd-rename-unref_inode-to-unref_inode_lolocked.patch b/0079-virtiofsd-rename-unref_inode-to-unref_inode_lolocked.patch
new file mode 100644
index 0000000..90fc806
--- /dev/null
+++ b/0079-virtiofsd-rename-unref_inode-to-unref_inode_lolocked.patch
@@ -0,0 +1,77 @@
+From: Miklos Szeredi <mszeredi@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:48 +0000
+Subject: [PATCH] virtiofsd: rename unref_inode() to unref_inode_lolocked()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 95d2715791c60b5dc2d22e4eb7b83217273296fa)
+---
+ tools/virtiofsd/passthrough_ll.c | 15 ++++++++-------
+ 1 file changed, 8 insertions(+), 7 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 8b1784ff7b..de12e75a9e 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -148,8 +148,8 @@ static const struct fuse_opt lo_opts[] = {
+ };
+ static bool use_syslog = false;
+ static int current_log_level;
+-
+-static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n);
++static void unref_inode_lolocked(struct lo_data *lo, struct lo_inode *inode,
++                                 uint64_t n);
+ 
+ static struct {
+     pthread_mutex_t mutex;
+@@ -586,7 +586,7 @@ retry:
+     return 0;
+ 
+ fail_unref:
+-    unref_inode(lo, p, 1);
++    unref_inode_lolocked(lo, p, 1);
+ fail:
+     if (retries) {
+         retries--;
+@@ -624,7 +624,7 @@ fallback:
+     res = lo_parent_and_name(lo, inode, path, &parent);
+     if (res != -1) {
+         res = utimensat(parent->fd, path, tv, AT_SYMLINK_NOFOLLOW);
+-        unref_inode(lo, parent, 1);
++        unref_inode_lolocked(lo, parent, 1);
+     }
+ 
+     return res;
+@@ -1027,7 +1027,7 @@ fallback:
+     res = lo_parent_and_name(lo, inode, path, &parent);
+     if (res != -1) {
+         res = linkat(parent->fd, path, dfd, name, 0);
+-        unref_inode(lo, parent, 1);
++        unref_inode_lolocked(lo, parent, 1);
+     }
+ 
+     return res;
+@@ -1141,7 +1141,8 @@ static void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
+     fuse_reply_err(req, res == -1 ? errno : 0);
+ }
+ 
+-static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n)
++static void unref_inode_lolocked(struct lo_data *lo, struct lo_inode *inode,
++                                 uint64_t n)
+ {
+     if (!inode) {
+         return;
+@@ -1181,7 +1182,7 @@ static void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
+              (unsigned long long)ino, (unsigned long long)inode->refcount,
+              (unsigned long long)nlookup);
+ 
+-    unref_inode(lo, inode, nlookup);
++    unref_inode_lolocked(lo, inode, nlookup);
+ }
+ 
+ static void lo_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
diff --git a/0080-virtiofsd-fail-when-parent-inode-isn-t-known-in-lo_d.patch b/0080-virtiofsd-fail-when-parent-inode-isn-t-known-in-lo_d.patch
new file mode 100644
index 0000000..cc729ce
--- /dev/null
+++ b/0080-virtiofsd-fail-when-parent-inode-isn-t-known-in-lo_d.patch
@@ -0,0 +1,66 @@
+From: Miklos Szeredi <mszeredi@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:49 +0000
+Subject: [PATCH] virtiofsd: fail when parent inode isn't known in
+ lo_do_lookup()
+
+The Linux file handle APIs (struct export_operations) can access inodes
+that are not attached to parents because path name traversal is not
+performed.  Refuse if there is no parent in lo_do_lookup().
+
+Also clean up lo_do_lookup() while we're here.
+
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 9de4fab5995d115f8ebfb41d8d94a866d80a1708)
+---
+ tools/virtiofsd/passthrough_ll.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index de12e75a9e..33bfb4d1f4 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -777,6 +777,15 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+     struct lo_data *lo = lo_data(req);
+     struct lo_inode *inode, *dir = lo_inode(req, parent);
+ 
++    /*
++     * name_to_handle_at() and open_by_handle_at() can reach here with fuse
++     * mount point in guest, but we don't have its inode info in the
++     * ino_map.
++     */
++    if (!dir) {
++        return ENOENT;
++    }
++
+     memset(e, 0, sizeof(*e));
+     e->attr_timeout = lo->timeout;
+     e->entry_timeout = lo->timeout;
+@@ -786,7 +795,7 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+         name = ".";
+     }
+ 
+-    newfd = openat(lo_fd(req, parent), name, O_PATH | O_NOFOLLOW);
++    newfd = openat(dir->fd, name, O_PATH | O_NOFOLLOW);
+     if (newfd == -1) {
+         goto out_err;
+     }
+@@ -796,7 +805,7 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+         goto out_err;
+     }
+ 
+-    inode = lo_find(lo_data(req), &e->attr);
++    inode = lo_find(lo, &e->attr);
+     if (inode) {
+         close(newfd);
+         newfd = -1;
+@@ -812,6 +821,7 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+         inode->is_symlink = S_ISLNK(e->attr.st_mode);
+         inode->refcount = 1;
+         inode->fd = newfd;
++        newfd = -1;
+         inode->ino = e->attr.st_ino;
+         inode->dev = e->attr.st_dev;
+ 
diff --git a/0081-virtiofsd-extract-root-inode-init-into-setup_root.patch b/0081-virtiofsd-extract-root-inode-init-into-setup_root.patch
new file mode 100644
index 0000000..f88349d
--- /dev/null
+++ b/0081-virtiofsd-extract-root-inode-init-into-setup_root.patch
@@ -0,0 +1,91 @@
+From: Miklos Szeredi <mszeredi@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:50 +0000
+Subject: [PATCH] virtiofsd: extract root inode init into setup_root()
+
+Inititialize the root inode in a single place.
+
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+dgilbert:
+with fix suggested by Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Reviewed-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 3ca8a2b1c83eb185c232a4e87abbb65495263756)
+---
+ tools/virtiofsd/passthrough_ll.c | 35 +++++++++++++++++++++++---------
+ 1 file changed, 25 insertions(+), 10 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 33bfb4d1f4..9e7191eb75 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -2351,6 +2351,30 @@ static void log_func(enum fuse_log_level level, const char *fmt, va_list ap)
+     }
+ }
+ 
++static void setup_root(struct lo_data *lo, struct lo_inode *root)
++{
++    int fd, res;
++    struct stat stat;
++
++    fd = open("/", O_PATH);
++    if (fd == -1) {
++        fuse_log(FUSE_LOG_ERR, "open(%s, O_PATH): %m\n", lo->source);
++        exit(1);
++    }
++
++    res = fstatat(fd, "", &stat, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
++    if (res == -1) {
++        fuse_log(FUSE_LOG_ERR, "fstatat(%s): %m\n", lo->source);
++        exit(1);
++    }
++
++    root->is_symlink = false;
++    root->fd = fd;
++    root->ino = stat.st_ino;
++    root->dev = stat.st_dev;
++    root->refcount = 2;
++}
++
+ int main(int argc, char *argv[])
+ {
+     struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+@@ -2426,8 +2450,6 @@ int main(int argc, char *argv[])
+     if (lo.debug) {
+         current_log_level = FUSE_LOG_DEBUG;
+     }
+-    lo.root.refcount = 2;
+-
+     if (lo.source) {
+         struct stat stat;
+         int res;
+@@ -2446,7 +2468,6 @@ int main(int argc, char *argv[])
+     } else {
+         lo.source = "/";
+     }
+-    lo.root.is_symlink = false;
+     if (!lo.timeout_set) {
+         switch (lo.cache) {
+         case CACHE_NEVER:
+@@ -2466,13 +2487,6 @@ int main(int argc, char *argv[])
+         exit(1);
+     }
+ 
+-    lo.root.fd = open(lo.source, O_PATH);
+-
+-    if (lo.root.fd == -1) {
+-        fuse_log(FUSE_LOG_ERR, "open(\"%s\", O_PATH): %m\n", lo.source);
+-        exit(1);
+-    }
+-
+     se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo);
+     if (se == NULL) {
+         goto err_out1;
+@@ -2495,6 +2509,7 @@ int main(int argc, char *argv[])
+ 
+     setup_sandbox(&lo, se, opts.syslog);
+ 
++    setup_root(&lo, &lo.root);
+     /* Block until ctrl+c or fusermount -u */
+     ret = virtio_loop(se);
+ 
diff --git a/0082-virtiofsd-passthrough_ll-clean-up-cache-related-opti.patch b/0082-virtiofsd-passthrough_ll-clean-up-cache-related-opti.patch
new file mode 100644
index 0000000..57a2381
--- /dev/null
+++ b/0082-virtiofsd-passthrough_ll-clean-up-cache-related-opti.patch
@@ -0,0 +1,121 @@
+From: Miklos Szeredi <mszeredi@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:51 +0000
+Subject: [PATCH] virtiofsd: passthrough_ll: clean up cache related options
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+ - Rename "cache=never" to "cache=none" to match 9p's similar option.
+
+ - Rename CACHE_NORMAL constant to CACHE_AUTO to match the "cache=auto"
+   option.
+
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 230e777b5e250759ee0480fcc0e9ccfa2b082fba)
+---
+ tools/virtiofsd/helper.c         |  5 ++++-
+ tools/virtiofsd/passthrough_ll.c | 20 ++++++++++----------
+ 2 files changed, 14 insertions(+), 11 deletions(-)
+
+diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
+index 14f5d70c10..567202444a 100644
+--- a/tools/virtiofsd/helper.c
++++ b/tools/virtiofsd/helper.c
+@@ -145,6 +145,9 @@ void fuse_cmdline_help(void)
+            "    --syslog                   log to syslog (default stderr)\n"
+            "    -f                         foreground operation\n"
+            "    --daemonize                run in background\n"
++           "    -o cache=<mode>            cache mode. could be one of \"auto, "
++           "always, none\"\n"
++           "                               default: auto\n"
+            "    -o log_level=<level>       log level, default to \"info\"\n"
+            "                               level could be one of \"debug, "
+            "info, warn, err\"\n"
+@@ -156,7 +159,7 @@ void fuse_cmdline_help(void)
+            "    -o readdirplus|no_readdirplus\n"
+            "                               enable/disable readirplus\n"
+            "                               default: readdirplus except with "
+-           "cache=never\n"
++           "cache=none\n"
+           );
+ }
+ 
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 9e7191eb75..b40f2874a7 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -101,8 +101,8 @@ struct lo_cred {
+ };
+ 
+ enum {
+-    CACHE_NEVER,
+-    CACHE_NORMAL,
++    CACHE_NONE,
++    CACHE_AUTO,
+     CACHE_ALWAYS,
+ };
+ 
+@@ -138,8 +138,8 @@ static const struct fuse_opt lo_opts[] = {
+     { "no_xattr", offsetof(struct lo_data, xattr), 0 },
+     { "timeout=%lf", offsetof(struct lo_data, timeout), 0 },
+     { "timeout=", offsetof(struct lo_data, timeout_set), 1 },
+-    { "cache=never", offsetof(struct lo_data, cache), CACHE_NEVER },
+-    { "cache=auto", offsetof(struct lo_data, cache), CACHE_NORMAL },
++    { "cache=none", offsetof(struct lo_data, cache), CACHE_NONE },
++    { "cache=auto", offsetof(struct lo_data, cache), CACHE_AUTO },
+     { "cache=always", offsetof(struct lo_data, cache), CACHE_ALWAYS },
+     { "norace", offsetof(struct lo_data, norace), 1 },
+     { "readdirplus", offsetof(struct lo_data, readdirplus_set), 1 },
+@@ -482,7 +482,7 @@ static void lo_init(void *userdata, struct fuse_conn_info *conn)
+         fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
+         conn->want |= FUSE_CAP_FLOCK_LOCKS;
+     }
+-    if ((lo->cache == CACHE_NEVER && !lo->readdirplus_set) ||
++    if ((lo->cache == CACHE_NONE && !lo->readdirplus_set) ||
+         lo->readdirplus_clear) {
+         fuse_log(FUSE_LOG_DEBUG, "lo_init: disabling readdirplus\n");
+         conn->want &= ~FUSE_CAP_READDIRPLUS;
+@@ -1493,7 +1493,7 @@ static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
+         fi->fh = fh;
+         err = lo_do_lookup(req, parent, name, &e);
+     }
+-    if (lo->cache == CACHE_NEVER) {
++    if (lo->cache == CACHE_NONE) {
+         fi->direct_io = 1;
+     } else if (lo->cache == CACHE_ALWAYS) {
+         fi->keep_cache = 1;
+@@ -1578,7 +1578,7 @@ static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+     }
+ 
+     fi->fh = fh;
+-    if (lo->cache == CACHE_NEVER) {
++    if (lo->cache == CACHE_NONE) {
+         fi->direct_io = 1;
+     } else if (lo->cache == CACHE_ALWAYS) {
+         fi->keep_cache = 1;
+@@ -2395,7 +2395,7 @@ int main(int argc, char *argv[])
+     lo.root.next = lo.root.prev = &lo.root;
+     lo.root.fd = -1;
+     lo.root.fuse_ino = FUSE_ROOT_ID;
+-    lo.cache = CACHE_NORMAL;
++    lo.cache = CACHE_AUTO;
+ 
+     /*
+      * Set up the ino map like this:
+@@ -2470,11 +2470,11 @@ int main(int argc, char *argv[])
+     }
+     if (!lo.timeout_set) {
+         switch (lo.cache) {
+-        case CACHE_NEVER:
++        case CACHE_NONE:
+             lo.timeout = 0.0;
+             break;
+ 
+-        case CACHE_NORMAL:
++        case CACHE_AUTO:
+             lo.timeout = 1.0;
+             break;
+ 
diff --git a/0083-virtiofsd-passthrough_ll-use-hashtable.patch b/0083-virtiofsd-passthrough_ll-use-hashtable.patch
new file mode 100644
index 0000000..0780206
--- /dev/null
+++ b/0083-virtiofsd-passthrough_ll-use-hashtable.patch
@@ -0,0 +1,195 @@
+From: Miklos Szeredi <mszeredi@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:52 +0000
+Subject: [PATCH] virtiofsd: passthrough_ll: use hashtable
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Improve performance of inode lookup by using a hash table.
+
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Signed-off-by: Liu Bo <bo.liu@linux.alibaba.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit bfc50a6e06b10b2f9dbaf6c1a89dd523322e016f)
+---
+ tools/virtiofsd/passthrough_ll.c | 81 ++++++++++++++++++--------------
+ 1 file changed, 45 insertions(+), 36 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index b40f2874a7..b176a314d6 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -84,13 +84,15 @@ struct lo_map {
+     ssize_t freelist;
+ };
+ 
++struct lo_key {
++    ino_t ino;
++    dev_t dev;
++};
++
+ struct lo_inode {
+-    struct lo_inode *next; /* protected by lo->mutex */
+-    struct lo_inode *prev; /* protected by lo->mutex */
+     int fd;
+     bool is_symlink;
+-    ino_t ino;
+-    dev_t dev;
++    struct lo_key key;
+     uint64_t refcount; /* protected by lo->mutex */
+     fuse_ino_t fuse_ino;
+ };
+@@ -119,7 +121,8 @@ struct lo_data {
+     int timeout_set;
+     int readdirplus_set;
+     int readdirplus_clear;
+-    struct lo_inode root; /* protected by lo->mutex */
++    struct lo_inode root;
++    GHashTable *inodes; /* protected by lo->mutex */
+     struct lo_map ino_map; /* protected by lo->mutex */
+     struct lo_map dirp_map; /* protected by lo->mutex */
+     struct lo_map fd_map; /* protected by lo->mutex */
+@@ -573,7 +576,7 @@ retry:
+         }
+         goto fail_unref;
+     }
+-    if (stat.st_dev != inode->dev || stat.st_ino != inode->ino) {
++    if (stat.st_dev != inode->key.dev || stat.st_ino != inode->key.ino) {
+         if (!retries) {
+             fuse_log(FUSE_LOG_WARNING,
+                      "%s: failed to match last\n", __func__);
+@@ -753,19 +756,20 @@ out_err:
+ static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st)
+ {
+     struct lo_inode *p;
+-    struct lo_inode *ret = NULL;
++    struct lo_key key = {
++        .ino = st->st_ino,
++        .dev = st->st_dev,
++    };
+ 
+     pthread_mutex_lock(&lo->mutex);
+-    for (p = lo->root.next; p != &lo->root; p = p->next) {
+-        if (p->ino == st->st_ino && p->dev == st->st_dev) {
+-            assert(p->refcount > 0);
+-            ret = p;
+-            ret->refcount++;
+-            break;
+-        }
++    p = g_hash_table_lookup(lo->inodes, &key);
++    if (p) {
++        assert(p->refcount > 0);
++        p->refcount++;
+     }
+     pthread_mutex_unlock(&lo->mutex);
+-    return ret;
++
++    return p;
+ }
+ 
+ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+@@ -810,8 +814,6 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+         close(newfd);
+         newfd = -1;
+     } else {
+-        struct lo_inode *prev, *next;
+-
+         saverr = ENOMEM;
+         inode = calloc(1, sizeof(struct lo_inode));
+         if (!inode) {
+@@ -822,17 +824,12 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+         inode->refcount = 1;
+         inode->fd = newfd;
+         newfd = -1;
+-        inode->ino = e->attr.st_ino;
+-        inode->dev = e->attr.st_dev;
++        inode->key.ino = e->attr.st_ino;
++        inode->key.dev = e->attr.st_dev;
+ 
+         pthread_mutex_lock(&lo->mutex);
+         inode->fuse_ino = lo_add_inode_mapping(req, inode);
+-        prev = &lo->root;
+-        next = prev->next;
+-        next->prev = inode;
+-        inode->next = next;
+-        inode->prev = prev;
+-        prev->next = inode;
++        g_hash_table_insert(lo->inodes, &inode->key, inode);
+         pthread_mutex_unlock(&lo->mutex);
+     }
+     e->ino = inode->fuse_ino;
+@@ -1162,14 +1159,8 @@ static void unref_inode_lolocked(struct lo_data *lo, struct lo_inode *inode,
+     assert(inode->refcount >= n);
+     inode->refcount -= n;
+     if (!inode->refcount) {
+-        struct lo_inode *prev, *next;
+-
+-        prev = inode->prev;
+-        next = inode->next;
+-        next->prev = prev;
+-        prev->next = next;
+-
+         lo_map_remove(&lo->ino_map, inode->fuse_ino);
++        g_hash_table_remove(lo->inodes, &inode->key);
+         pthread_mutex_unlock(&lo->mutex);
+         close(inode->fd);
+         free(inode);
+@@ -1369,7 +1360,7 @@ static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
+ 
+         /* Hide root's parent directory */
+         if (dinode == &lo->root && strcmp(name, "..") == 0) {
+-            e.attr.st_ino = lo->root.ino;
++            e.attr.st_ino = lo->root.key.ino;
+             e.attr.st_mode = DT_DIR << 12;
+         }
+ 
+@@ -2370,11 +2361,26 @@ static void setup_root(struct lo_data *lo, struct lo_inode *root)
+ 
+     root->is_symlink = false;
+     root->fd = fd;
+-    root->ino = stat.st_ino;
+-    root->dev = stat.st_dev;
++    root->key.ino = stat.st_ino;
++    root->key.dev = stat.st_dev;
+     root->refcount = 2;
+ }
+ 
++static guint lo_key_hash(gconstpointer key)
++{
++    const struct lo_key *lkey = key;
++
++    return (guint)lkey->ino + (guint)lkey->dev;
++}
++
++static gboolean lo_key_equal(gconstpointer a, gconstpointer b)
++{
++    const struct lo_key *la = a;
++    const struct lo_key *lb = b;
++
++    return la->ino == lb->ino && la->dev == lb->dev;
++}
++
+ int main(int argc, char *argv[])
+ {
+     struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+@@ -2392,7 +2398,7 @@ int main(int argc, char *argv[])
+     umask(0);
+ 
+     pthread_mutex_init(&lo.mutex, NULL);
+-    lo.root.next = lo.root.prev = &lo.root;
++    lo.inodes = g_hash_table_new(lo_key_hash, lo_key_equal);
+     lo.root.fd = -1;
+     lo.root.fuse_ino = FUSE_ROOT_ID;
+     lo.cache = CACHE_AUTO;
+@@ -2522,6 +2528,9 @@ err_out2:
+ err_out1:
+     fuse_opt_free_args(&args);
+ 
++    if (lo.inodes) {
++        g_hash_table_destroy(lo.inodes);
++    }
+     lo_map_destroy(&lo.fd_map);
+     lo_map_destroy(&lo.dirp_map);
+     lo_map_destroy(&lo.ino_map);
diff --git a/0084-virtiofsd-Clean-up-inodes-on-destroy.patch b/0084-virtiofsd-Clean-up-inodes-on-destroy.patch
new file mode 100644
index 0000000..48b65d5
--- /dev/null
+++ b/0084-virtiofsd-Clean-up-inodes-on-destroy.patch
@@ -0,0 +1,69 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:01:53 +0000
+Subject: [PATCH] virtiofsd: Clean up inodes on destroy
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Clear out our inodes and fd's on a 'destroy' - so we get rid
+of them if we reboot the guest.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 771b01eb76ff480fee984bd1d21727147cc3e702)
+---
+ tools/virtiofsd/passthrough_ll.c | 26 ++++++++++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index b176a314d6..9ed77a17fd 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -1169,6 +1169,25 @@ static void unref_inode_lolocked(struct lo_data *lo, struct lo_inode *inode,
+     }
+ }
+ 
++static int unref_all_inodes_cb(gpointer key, gpointer value, gpointer user_data)
++{
++    struct lo_inode *inode = value;
++    struct lo_data *lo = user_data;
++
++    inode->refcount = 0;
++    lo_map_remove(&lo->ino_map, inode->fuse_ino);
++    close(inode->fd);
++
++    return TRUE;
++}
++
++static void unref_all_inodes(struct lo_data *lo)
++{
++    pthread_mutex_lock(&lo->mutex);
++    g_hash_table_foreach_remove(lo->inodes, unref_all_inodes_cb, lo);
++    pthread_mutex_unlock(&lo->mutex);
++}
++
+ static void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
+ {
+     struct lo_data *lo = lo_data(req);
+@@ -2035,6 +2054,12 @@ static void lo_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
+     }
+ }
+ 
++static void lo_destroy(void *userdata)
++{
++    struct lo_data *lo = (struct lo_data *)userdata;
++    unref_all_inodes(lo);
++}
++
+ static struct fuse_lowlevel_ops lo_oper = {
+     .init = lo_init,
+     .lookup = lo_lookup,
+@@ -2073,6 +2098,7 @@ static struct fuse_lowlevel_ops lo_oper = {
+     .copy_file_range = lo_copy_file_range,
+ #endif
+     .lseek = lo_lseek,
++    .destroy = lo_destroy,
+ };
+ 
+ /* Print vhost-user.json backend program capabilities */
diff --git a/0085-virtiofsd-support-nanosecond-resolution-for-file-tim.patch b/0085-virtiofsd-support-nanosecond-resolution-for-file-tim.patch
new file mode 100644
index 0000000..59996ef
--- /dev/null
+++ b/0085-virtiofsd-support-nanosecond-resolution-for-file-tim.patch
@@ -0,0 +1,66 @@
+From: Jiufei Xue <jiufei.xue@linux.alibaba.com>
+Date: Mon, 27 Jan 2020 19:01:54 +0000
+Subject: [PATCH] virtiofsd: support nanosecond resolution for file timestamp
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Define HAVE_STRUCT_STAT_ST_ATIM to 1 if `st_atim' is member of `struct
+stat' which means support nanosecond resolution for the file timestamp
+fields.
+
+Signed-off-by: Jiufei Xue <jiufei.xue@linux.alibaba.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 8a792b034d4b315251fd842bb4c73a133aa1368f)
+---
+ configure                   | 16 ++++++++++++++++
+ tools/virtiofsd/fuse_misc.h |  1 +
+ 2 files changed, 17 insertions(+)
+
+diff --git a/configure b/configure
+index afe9393f04..dd50b03b01 100755
+--- a/configure
++++ b/configure
+@@ -5217,6 +5217,19 @@ if compile_prog "" "" ; then
+     strchrnul=yes
+ fi
+ 
++#########################################
++# check if we have st_atim
++
++st_atim=no
++cat > $TMPC << EOF
++#include <sys/stat.h>
++#include <stddef.h>
++int main(void) { return offsetof(struct stat, st_atim); }
++EOF
++if compile_prog "" "" ; then
++    st_atim=yes
++fi
++
+ ##########################################
+ # check if trace backend exists
+ 
+@@ -6918,6 +6931,9 @@ fi
+ if test "$strchrnul" = "yes" ; then
+   echo "HAVE_STRCHRNUL=y" >> $config_host_mak
+ fi
++if test "$st_atim" = "yes" ; then
++  echo "HAVE_STRUCT_STAT_ST_ATIM=y" >> $config_host_mak
++fi
+ if test "$byteswap_h" = "yes" ; then
+   echo "CONFIG_BYTESWAP_H=y" >> $config_host_mak
+ fi
+diff --git a/tools/virtiofsd/fuse_misc.h b/tools/virtiofsd/fuse_misc.h
+index f252baa752..5c618ce21f 100644
+--- a/tools/virtiofsd/fuse_misc.h
++++ b/tools/virtiofsd/fuse_misc.h
+@@ -7,6 +7,7 @@
+  */
+ 
+ #include <pthread.h>
++#include "config-host.h"
+ 
+ /*
+  * Versioned symbols cannot be used in some cases because it
diff --git a/0086-virtiofsd-fix-error-handling-in-main.patch b/0086-virtiofsd-fix-error-handling-in-main.patch
new file mode 100644
index 0000000..3828cef
--- /dev/null
+++ b/0086-virtiofsd-fix-error-handling-in-main.patch
@@ -0,0 +1,47 @@
+From: Liu Bo <bo.liu@linux.alibaba.com>
+Date: Mon, 27 Jan 2020 19:01:55 +0000
+Subject: [PATCH] virtiofsd: fix error handling in main()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Neither fuse_parse_cmdline() nor fuse_opt_parse() goes to the right place
+to do cleanup.
+
+Signed-off-by: Liu Bo <bo.liu@linux.alibaba.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit c6de804670f2255ce776263124c37f3370dc5ac1)
+---
+ tools/virtiofsd/passthrough_ll.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 9ed77a17fd..af050c6d97 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -2443,13 +2443,14 @@ int main(int argc, char *argv[])
+     lo_map_init(&lo.fd_map);
+ 
+     if (fuse_parse_cmdline(&args, &opts) != 0) {
+-        return 1;
++        goto err_out1;
+     }
+     fuse_set_log_func(log_func);
+     use_syslog = opts.syslog;
+     if (use_syslog) {
+         openlog("virtiofsd", LOG_PID, LOG_DAEMON);
+     }
++
+     if (opts.show_help) {
+         printf("usage: %s [options]\n\n", argv[0]);
+         fuse_cmdline_help();
+@@ -2468,7 +2469,7 @@ int main(int argc, char *argv[])
+     }
+ 
+     if (fuse_opt_parse(&args, &lo, lo_opts, NULL) == -1) {
+-        return 1;
++        goto err_out1;
+     }
+ 
+     /*
diff --git a/0087-virtiofsd-cleanup-allocated-resource-in-se.patch b/0087-virtiofsd-cleanup-allocated-resource-in-se.patch
new file mode 100644
index 0000000..cf1ddb1
--- /dev/null
+++ b/0087-virtiofsd-cleanup-allocated-resource-in-se.patch
@@ -0,0 +1,66 @@
+From: Liu Bo <bo.liu@linux.alibaba.com>
+Date: Mon, 27 Jan 2020 19:01:56 +0000
+Subject: [PATCH] virtiofsd: cleanup allocated resource in se
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This cleans up unfreed resources in se on quiting, including
+se->virtio_dev, se->vu_socket_path, se->vu_socketfd.
+
+Signed-off-by: Liu Bo <bo.liu@linux.alibaba.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 61cfc44982e566c33b9d5df17858e4d5ae373873)
+---
+ tools/virtiofsd/fuse_lowlevel.c | 7 +++++++
+ tools/virtiofsd/fuse_virtio.c   | 7 +++++++
+ tools/virtiofsd/fuse_virtio.h   | 2 +-
+ 3 files changed, 15 insertions(+), 1 deletion(-)
+
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 65f91dabae..440508a6ec 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -2532,6 +2532,13 @@ void fuse_session_destroy(struct fuse_session *se)
+     if (se->fd != -1) {
+         close(se->fd);
+     }
++
++    if (se->vu_socket_path) {
++        virtio_session_close(se);
++        free(se->vu_socket_path);
++        se->vu_socket_path = NULL;
++    }
++
+     free(se);
+ }
+ 
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+index 7a8774a3ee..e7bd772805 100644
+--- a/tools/virtiofsd/fuse_virtio.c
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -833,3 +833,10 @@ int virtio_session_mount(struct fuse_session *se)
+ 
+     return 0;
+ }
++
++void virtio_session_close(struct fuse_session *se)
++{
++    close(se->vu_socketfd);
++    free(se->virtio_dev);
++    se->virtio_dev = NULL;
++}
+diff --git a/tools/virtiofsd/fuse_virtio.h b/tools/virtiofsd/fuse_virtio.h
+index cc676b9193..111684032c 100644
+--- a/tools/virtiofsd/fuse_virtio.h
++++ b/tools/virtiofsd/fuse_virtio.h
+@@ -19,7 +19,7 @@
+ struct fuse_session;
+ 
+ int virtio_session_mount(struct fuse_session *se);
+-
++void virtio_session_close(struct fuse_session *se);
+ int virtio_loop(struct fuse_session *se);
+ 
+ 
diff --git a/0088-virtiofsd-fix-memory-leak-on-lo.source.patch b/0088-virtiofsd-fix-memory-leak-on-lo.source.patch
new file mode 100644
index 0000000..3c509a7
--- /dev/null
+++ b/0088-virtiofsd-fix-memory-leak-on-lo.source.patch
@@ -0,0 +1,47 @@
+From: Liu Bo <bo.liu@linux.alibaba.com>
+Date: Mon, 27 Jan 2020 19:01:57 +0000
+Subject: [PATCH] virtiofsd: fix memory leak on lo.source
+
+valgrind reported that lo.source is leaked on quiting, but it was defined
+as (const char*) as it may point to a const string "/".
+
+Signed-off-by: Liu Bo <bo.liu@linux.alibaba.com>
+Reviewed-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit eb68a33b5fc5dde87bd9b99b94e7c33a5d8ea82e)
+---
+ tools/virtiofsd/passthrough_ll.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index af050c6d97..056ebe8556 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -115,7 +115,7 @@ struct lo_data {
+     int writeback;
+     int flock;
+     int xattr;
+-    const char *source;
++    char *source;
+     double timeout;
+     int cache;
+     int timeout_set;
+@@ -2497,9 +2497,8 @@ int main(int argc, char *argv[])
+             fuse_log(FUSE_LOG_ERR, "source is not a directory\n");
+             exit(1);
+         }
+-
+     } else {
+-        lo.source = "/";
++        lo.source = strdup("/");
+     }
+     if (!lo.timeout_set) {
+         switch (lo.cache) {
+@@ -2570,5 +2569,7 @@ err_out1:
+         close(lo.root.fd);
+     }
+ 
++    free(lo.source);
++
+     return ret ? 1 : 0;
+ }
diff --git a/0089-virtiofsd-add-helper-for-lo_data-cleanup.patch b/0089-virtiofsd-add-helper-for-lo_data-cleanup.patch
new file mode 100644
index 0000000..2cdf880
--- /dev/null
+++ b/0089-virtiofsd-add-helper-for-lo_data-cleanup.patch
@@ -0,0 +1,72 @@
+From: Liu Bo <bo.liu@linux.alibaba.com>
+Date: Mon, 27 Jan 2020 19:01:58 +0000
+Subject: [PATCH] virtiofsd: add helper for lo_data cleanup
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This offers an helper function for lo_data's cleanup.
+
+Signed-off-by: Liu Bo <bo.liu@linux.alibaba.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 18a69cbbb6a4caa7c2040c6db4a33b044a32be7e)
+---
+ tools/virtiofsd/passthrough_ll.c | 37 ++++++++++++++++++--------------
+ 1 file changed, 21 insertions(+), 16 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 056ebe8556..e8dc5c7320 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -2407,6 +2407,26 @@ static gboolean lo_key_equal(gconstpointer a, gconstpointer b)
+     return la->ino == lb->ino && la->dev == lb->dev;
+ }
+ 
++static void fuse_lo_data_cleanup(struct lo_data *lo)
++{
++    if (lo->inodes) {
++        g_hash_table_destroy(lo->inodes);
++    }
++    lo_map_destroy(&lo->fd_map);
++    lo_map_destroy(&lo->dirp_map);
++    lo_map_destroy(&lo->ino_map);
++
++    if (lo->proc_self_fd >= 0) {
++        close(lo->proc_self_fd);
++    }
++
++    if (lo->root.fd >= 0) {
++        close(lo->root.fd);
++    }
++
++    free(lo->source);
++}
++
+ int main(int argc, char *argv[])
+ {
+     struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+@@ -2554,22 +2574,7 @@ err_out2:
+ err_out1:
+     fuse_opt_free_args(&args);
+ 
+-    if (lo.inodes) {
+-        g_hash_table_destroy(lo.inodes);
+-    }
+-    lo_map_destroy(&lo.fd_map);
+-    lo_map_destroy(&lo.dirp_map);
+-    lo_map_destroy(&lo.ino_map);
+-
+-    if (lo.proc_self_fd >= 0) {
+-        close(lo.proc_self_fd);
+-    }
+-
+-    if (lo.root.fd >= 0) {
+-        close(lo.root.fd);
+-    }
+-
+-    free(lo.source);
++    fuse_lo_data_cleanup(&lo);
+ 
+     return ret ? 1 : 0;
+ }
diff --git a/0090-virtiofsd-Prevent-multiply-running-with-same-vhost_u.patch b/0090-virtiofsd-Prevent-multiply-running-with-same-vhost_u.patch
new file mode 100644
index 0000000..d3f2ebc
--- /dev/null
+++ b/0090-virtiofsd-Prevent-multiply-running-with-same-vhost_u.patch
@@ -0,0 +1,127 @@
+From: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+Date: Mon, 27 Jan 2020 19:01:59 +0000
+Subject: [PATCH] virtiofsd: Prevent multiply running with same
+ vhost_user_socket
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+virtiofsd can run multiply even if the vhost_user_socket is same path.
+
+  ]# ./virtiofsd -o vhost_user_socket=/tmp/vhostqemu -o source=/tmp/share &
+  [1] 244965
+  virtio_session_mount: Waiting for vhost-user socket connection...
+  ]# ./virtiofsd -o vhost_user_socket=/tmp/vhostqemu -o source=/tmp/share &
+  [2] 244966
+  virtio_session_mount: Waiting for vhost-user socket connection...
+  ]#
+
+The user will get confused about the situation and maybe the cause of the
+unexpected problem. So it's better to prevent the multiple running.
+
+Create a regular file under localstatedir directory to exclude the
+vhost_user_socket. To create and lock the file, use qemu_write_pidfile()
+because the API has some sanity checks and file lock.
+
+Signed-off-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+  Applied fixes from Stefan's review and moved osdep include
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 96814800d2b49d18737c36e021c387697ec40c62)
+---
+ tools/virtiofsd/fuse_lowlevel.c |  1 +
+ tools/virtiofsd/fuse_virtio.c   | 49 ++++++++++++++++++++++++++++++++-
+ 2 files changed, 49 insertions(+), 1 deletion(-)
+
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 440508a6ec..aac282f278 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -18,6 +18,7 @@
+ 
+ #include <assert.h>
+ #include <errno.h>
++#include <glib.h>
+ #include <limits.h>
+ #include <stdbool.h>
+ #include <stddef.h>
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+index e7bd772805..b7948def27 100644
+--- a/tools/virtiofsd/fuse_virtio.c
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -13,11 +13,12 @@
+ 
+ #include "qemu/osdep.h"
+ #include "qemu/iov.h"
+-#include "fuse_virtio.h"
++#include "qapi/error.h"
+ #include "fuse_i.h"
+ #include "standard-headers/linux/fuse.h"
+ #include "fuse_misc.h"
+ #include "fuse_opt.h"
++#include "fuse_virtio.h"
+ 
+ #include <assert.h>
+ #include <errno.h>
+@@ -743,6 +744,42 @@ int virtio_loop(struct fuse_session *se)
+     return 0;
+ }
+ 
++static void strreplace(char *s, char old, char new)
++{
++    for (; *s; ++s) {
++        if (*s == old) {
++            *s = new;
++        }
++    }
++}
++
++static bool fv_socket_lock(struct fuse_session *se)
++{
++    g_autofree gchar *sk_name = NULL;
++    g_autofree gchar *pidfile = NULL;
++    g_autofree gchar *dir = NULL;
++    Error *local_err = NULL;
++
++    dir = qemu_get_local_state_pathname("run/virtiofsd");
++
++    if (g_mkdir_with_parents(dir, S_IRWXU) < 0) {
++        fuse_log(FUSE_LOG_ERR, "%s: Failed to create directory %s: %s",
++                 __func__, dir, strerror(errno));
++        return false;
++    }
++
++    sk_name = g_strdup(se->vu_socket_path);
++    strreplace(sk_name, '/', '.');
++    pidfile = g_strdup_printf("%s/%s.pid", dir, sk_name);
++
++    if (!qemu_write_pidfile(pidfile, &local_err)) {
++        error_report_err(local_err);
++        return false;
++    }
++
++    return true;
++}
++
+ static int fv_create_listen_socket(struct fuse_session *se)
+ {
+     struct sockaddr_un un;
+@@ -758,6 +795,16 @@ static int fv_create_listen_socket(struct fuse_session *se)
+         return -1;
+     }
+ 
++    if (!strlen(se->vu_socket_path)) {
++        fuse_log(FUSE_LOG_ERR, "Socket path is empty\n");
++        return -1;
++    }
++
++    /* Check the vu_socket_path is already used */
++    if (!fv_socket_lock(se)) {
++        return -1;
++    }
++
+     /*
+      * Create the Unix socket to communicate with qemu
+      * based on QEMU's vhost-user-bridge
diff --git a/0091-virtiofsd-enable-PARALLEL_DIROPS-during-INIT.patch b/0091-virtiofsd-enable-PARALLEL_DIROPS-during-INIT.patch
new file mode 100644
index 0000000..dfdd3b3
--- /dev/null
+++ b/0091-virtiofsd-enable-PARALLEL_DIROPS-during-INIT.patch
@@ -0,0 +1,31 @@
+From: Liu Bo <bo.liu@linux.alibaba.com>
+Date: Mon, 27 Jan 2020 19:02:00 +0000
+Subject: [PATCH] virtiofsd: enable PARALLEL_DIROPS during INIT
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+lookup is a RO operations, PARALLEL_DIROPS can be enabled.
+
+Signed-off-by: Liu Bo <bo.liu@linux.alibaba.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit b7ed733a3841c4d489d3bd6ca7ed23c84db119c2)
+---
+ tools/virtiofsd/fuse_lowlevel.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index aac282f278..70568d22a4 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -2062,6 +2062,9 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid,
+     if (se->conn.want & FUSE_CAP_ASYNC_READ) {
+         outarg.flags |= FUSE_ASYNC_READ;
+     }
++    if (se->conn.want & FUSE_CAP_PARALLEL_DIROPS) {
++        outarg.flags |= FUSE_PARALLEL_DIROPS;
++    }
+     if (se->conn.want & FUSE_CAP_POSIX_LOCKS) {
+         outarg.flags |= FUSE_POSIX_LOCKS;
+     }
diff --git a/0092-virtiofsd-fix-incorrect-error-handling-in-lo_do_look.patch b/0092-virtiofsd-fix-incorrect-error-handling-in-lo_do_look.patch
new file mode 100644
index 0000000..fa99bf8
--- /dev/null
+++ b/0092-virtiofsd-fix-incorrect-error-handling-in-lo_do_look.patch
@@ -0,0 +1,27 @@
+From: Eric Ren <renzhen@linux.alibaba.com>
+Date: Mon, 27 Jan 2020 19:02:01 +0000
+Subject: [PATCH] virtiofsd: fix incorrect error handling in lo_do_lookup
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Eric Ren <renzhen@linux.alibaba.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit fc3f0041b43b6c64aa97b3558a6abe1a10028354)
+---
+ tools/virtiofsd/passthrough_ll.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index e8dc5c7320..05b5f898db 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -814,7 +814,6 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+         close(newfd);
+         newfd = -1;
+     } else {
+-        saverr = ENOMEM;
+         inode = calloc(1, sizeof(struct lo_inode));
+         if (!inode) {
+             goto out_err;
diff --git a/0093-Virtiofsd-fix-memory-leak-on-fuse-queueinfo.patch b/0093-Virtiofsd-fix-memory-leak-on-fuse-queueinfo.patch
new file mode 100644
index 0000000..bef1ac0
--- /dev/null
+++ b/0093-Virtiofsd-fix-memory-leak-on-fuse-queueinfo.patch
@@ -0,0 +1,44 @@
+From: Liu Bo <bo.liu@linux.alibaba.com>
+Date: Mon, 27 Jan 2020 19:02:02 +0000
+Subject: [PATCH] Virtiofsd: fix memory leak on fuse queueinfo
+
+For fuse's queueinfo, both queueinfo array and queueinfos are allocated in
+fv_queue_set_started() but not cleaned up when the daemon process quits.
+
+This fixes the leak in proper places.
+
+Signed-off-by: Liu Bo <bo.liu@linux.alibaba.com>
+Signed-off-by: Eric Ren <renzhen@linux.alibaba.com>
+Reviewed-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 740b0b700a6338a1cf60c26229651ac5f6724944)
+---
+ tools/virtiofsd/fuse_virtio.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+index b7948def27..fb8d6d1379 100644
+--- a/tools/virtiofsd/fuse_virtio.c
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -625,6 +625,8 @@ static void fv_queue_cleanup_thread(struct fv_VuDev *vud, int qidx)
+     }
+     close(ourqi->kill_fd);
+     ourqi->kick_fd = -1;
++    free(vud->qi[qidx]);
++    vud->qi[qidx] = NULL;
+ }
+ 
+ /* Callback from libvhost-user on start or stop of a queue */
+@@ -884,6 +886,12 @@ int virtio_session_mount(struct fuse_session *se)
+ void virtio_session_close(struct fuse_session *se)
+ {
+     close(se->vu_socketfd);
++
++    if (!se->virtio_dev) {
++        return;
++    }
++
++    free(se->virtio_dev->qi);
+     free(se->virtio_dev);
+     se->virtio_dev = NULL;
+ }
diff --git a/0094-virtiofsd-Support-remote-posix-locks.patch b/0094-virtiofsd-Support-remote-posix-locks.patch
new file mode 100644
index 0000000..83b237c
--- /dev/null
+++ b/0094-virtiofsd-Support-remote-posix-locks.patch
@@ -0,0 +1,336 @@
+From: Vivek Goyal <vgoyal@redhat.com>
+Date: Mon, 27 Jan 2020 19:02:03 +0000
+Subject: [PATCH] virtiofsd: Support remote posix locks
+
+Doing posix locks with-in guest kernel are not sufficient if a file/dir
+is being shared by multiple guests. So we need the notion of daemon doing
+the locks which are visible to rest of the guests.
+
+Given posix locks are per process, one can not call posix lock API on host,
+otherwise bunch of basic posix locks properties are broken. For example,
+If two processes (A and B) in guest open the file and take locks on different
+sections of file, if one of the processes closes the fd, it will close
+fd on virtiofsd and all posix locks on file will go away. This means if
+process A closes the fd, then locks of process B will go away too.
+
+Similar other problems exist too.
+
+This patch set tries to emulate posix locks while using open file
+description locks provided on Linux.
+
+Daemon provides two options (-o posix_lock, -o no_posix_lock) to enable
+or disable posix locking in daemon. By default it is enabled.
+
+There are few issues though.
+
+- GETLK() returns pid of process holding lock. As we are emulating locks
+  using OFD, and these locks are not per process and don't return pid
+  of process, so GETLK() in guest does not reuturn process pid.
+
+- As of now only F_SETLK is supported and not F_SETLKW. We can't block
+  the thread in virtiofsd for arbitrary long duration as there is only
+  one thread serving the queue. That means unlock request will not make
+  it to daemon and F_SETLKW will block infinitely and bring virtio-fs
+  to a halt. This is a solvable problem though and will require significant
+  changes in virtiofsd and kernel. Left as a TODO item for now.
+
+Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
+Reviewed-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 0e81414c54161296212f6bc8a1c70526c4a9755a)
+---
+ tools/virtiofsd/helper.c         |   3 +
+ tools/virtiofsd/passthrough_ll.c | 189 +++++++++++++++++++++++++++++++
+ 2 files changed, 192 insertions(+)
+
+diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
+index 567202444a..33749bfcb7 100644
+--- a/tools/virtiofsd/helper.c
++++ b/tools/virtiofsd/helper.c
+@@ -156,6 +156,9 @@ void fuse_cmdline_help(void)
+            "                               allowed (default: 10)\n"
+            "    -o norace                  disable racy fallback\n"
+            "                               default: false\n"
++           "    -o posix_lock|no_posix_lock\n"
++           "                               enable/disable remote posix lock\n"
++           "                               default: posix_lock\n"
+            "    -o readdirplus|no_readdirplus\n"
+            "                               enable/disable readirplus\n"
+            "                               default: readdirplus except with "
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 05b5f898db..9414935b52 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -67,6 +67,12 @@
+ #include "passthrough_helpers.h"
+ #include "seccomp.h"
+ 
++/* Keep track of inode posix locks for each owner. */
++struct lo_inode_plock {
++    uint64_t lock_owner;
++    int fd; /* fd for OFD locks */
++};
++
+ struct lo_map_elem {
+     union {
+         struct lo_inode *inode;
+@@ -95,6 +101,8 @@ struct lo_inode {
+     struct lo_key key;
+     uint64_t refcount; /* protected by lo->mutex */
+     fuse_ino_t fuse_ino;
++    pthread_mutex_t plock_mutex;
++    GHashTable *posix_locks; /* protected by lo_inode->plock_mutex */
+ };
+ 
+ struct lo_cred {
+@@ -114,6 +122,7 @@ struct lo_data {
+     int norace;
+     int writeback;
+     int flock;
++    int posix_lock;
+     int xattr;
+     char *source;
+     double timeout;
+@@ -137,6 +146,8 @@ static const struct fuse_opt lo_opts[] = {
+     { "source=%s", offsetof(struct lo_data, source), 0 },
+     { "flock", offsetof(struct lo_data, flock), 1 },
+     { "no_flock", offsetof(struct lo_data, flock), 0 },
++    { "posix_lock", offsetof(struct lo_data, posix_lock), 1 },
++    { "no_posix_lock", offsetof(struct lo_data, posix_lock), 0 },
+     { "xattr", offsetof(struct lo_data, xattr), 1 },
+     { "no_xattr", offsetof(struct lo_data, xattr), 0 },
+     { "timeout=%lf", offsetof(struct lo_data, timeout), 0 },
+@@ -485,6 +496,17 @@ static void lo_init(void *userdata, struct fuse_conn_info *conn)
+         fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
+         conn->want |= FUSE_CAP_FLOCK_LOCKS;
+     }
++
++    if (conn->capable & FUSE_CAP_POSIX_LOCKS) {
++        if (lo->posix_lock) {
++            fuse_log(FUSE_LOG_DEBUG, "lo_init: activating posix locks\n");
++            conn->want |= FUSE_CAP_POSIX_LOCKS;
++        } else {
++            fuse_log(FUSE_LOG_DEBUG, "lo_init: disabling posix locks\n");
++            conn->want &= ~FUSE_CAP_POSIX_LOCKS;
++        }
++    }
++
+     if ((lo->cache == CACHE_NONE && !lo->readdirplus_set) ||
+         lo->readdirplus_clear) {
+         fuse_log(FUSE_LOG_DEBUG, "lo_init: disabling readdirplus\n");
+@@ -772,6 +794,19 @@ static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st)
+     return p;
+ }
+ 
++/* value_destroy_func for posix_locks GHashTable */
++static void posix_locks_value_destroy(gpointer data)
++{
++    struct lo_inode_plock *plock = data;
++
++    /*
++     * We had used open() for locks and had only one fd. So
++     * closing this fd should release all OFD locks.
++     */
++    close(plock->fd);
++    free(plock);
++}
++
+ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+                         struct fuse_entry_param *e)
+ {
+@@ -825,6 +860,9 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+         newfd = -1;
+         inode->key.ino = e->attr.st_ino;
+         inode->key.dev = e->attr.st_dev;
++        pthread_mutex_init(&inode->plock_mutex, NULL);
++        inode->posix_locks = g_hash_table_new_full(
++            g_direct_hash, g_direct_equal, NULL, posix_locks_value_destroy);
+ 
+         pthread_mutex_lock(&lo->mutex);
+         inode->fuse_ino = lo_add_inode_mapping(req, inode);
+@@ -1160,6 +1198,11 @@ static void unref_inode_lolocked(struct lo_data *lo, struct lo_inode *inode,
+     if (!inode->refcount) {
+         lo_map_remove(&lo->ino_map, inode->fuse_ino);
+         g_hash_table_remove(lo->inodes, &inode->key);
++        if (g_hash_table_size(inode->posix_locks)) {
++            fuse_log(FUSE_LOG_WARNING, "Hash table is not empty\n");
++        }
++        g_hash_table_destroy(inode->posix_locks);
++        pthread_mutex_destroy(&inode->plock_mutex);
+         pthread_mutex_unlock(&lo->mutex);
+         close(inode->fd);
+         free(inode);
+@@ -1516,6 +1559,136 @@ out:
+     }
+ }
+ 
++/* Should be called with inode->plock_mutex held */
++static struct lo_inode_plock *lookup_create_plock_ctx(struct lo_data *lo,
++                                                      struct lo_inode *inode,
++                                                      uint64_t lock_owner,
++                                                      pid_t pid, int *err)
++{
++    struct lo_inode_plock *plock;
++    char procname[64];
++    int fd;
++
++    plock =
++        g_hash_table_lookup(inode->posix_locks, GUINT_TO_POINTER(lock_owner));
++
++    if (plock) {
++        return plock;
++    }
++
++    plock = malloc(sizeof(struct lo_inode_plock));
++    if (!plock) {
++        *err = ENOMEM;
++        return NULL;
++    }
++
++    /* Open another instance of file which can be used for ofd locks. */
++    sprintf(procname, "%i", inode->fd);
++
++    /* TODO: What if file is not writable? */
++    fd = openat(lo->proc_self_fd, procname, O_RDWR);
++    if (fd == -1) {
++        *err = errno;
++        free(plock);
++        return NULL;
++    }
++
++    plock->lock_owner = lock_owner;
++    plock->fd = fd;
++    g_hash_table_insert(inode->posix_locks, GUINT_TO_POINTER(plock->lock_owner),
++                        plock);
++    return plock;
++}
++
++static void lo_getlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
++                     struct flock *lock)
++{
++    struct lo_data *lo = lo_data(req);
++    struct lo_inode *inode;
++    struct lo_inode_plock *plock;
++    int ret, saverr = 0;
++
++    fuse_log(FUSE_LOG_DEBUG,
++             "lo_getlk(ino=%" PRIu64 ", flags=%d)"
++             " owner=0x%lx, l_type=%d l_start=0x%lx"
++             " l_len=0x%lx\n",
++             ino, fi->flags, fi->lock_owner, lock->l_type, lock->l_start,
++             lock->l_len);
++
++    inode = lo_inode(req, ino);
++    if (!inode) {
++        fuse_reply_err(req, EBADF);
++        return;
++    }
++
++    pthread_mutex_lock(&inode->plock_mutex);
++    plock =
++        lookup_create_plock_ctx(lo, inode, fi->lock_owner, lock->l_pid, &ret);
++    if (!plock) {
++        pthread_mutex_unlock(&inode->plock_mutex);
++        fuse_reply_err(req, ret);
++        return;
++    }
++
++    ret = fcntl(plock->fd, F_OFD_GETLK, lock);
++    if (ret == -1) {
++        saverr = errno;
++    }
++    pthread_mutex_unlock(&inode->plock_mutex);
++
++    if (saverr) {
++        fuse_reply_err(req, saverr);
++    } else {
++        fuse_reply_lock(req, lock);
++    }
++}
++
++static void lo_setlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
++                     struct flock *lock, int sleep)
++{
++    struct lo_data *lo = lo_data(req);
++    struct lo_inode *inode;
++    struct lo_inode_plock *plock;
++    int ret, saverr = 0;
++
++    fuse_log(FUSE_LOG_DEBUG,
++             "lo_setlk(ino=%" PRIu64 ", flags=%d)"
++             " cmd=%d pid=%d owner=0x%lx sleep=%d l_whence=%d"
++             " l_start=0x%lx l_len=0x%lx\n",
++             ino, fi->flags, lock->l_type, lock->l_pid, fi->lock_owner, sleep,
++             lock->l_whence, lock->l_start, lock->l_len);
++
++    if (sleep) {
++        fuse_reply_err(req, EOPNOTSUPP);
++        return;
++    }
++
++    inode = lo_inode(req, ino);
++    if (!inode) {
++        fuse_reply_err(req, EBADF);
++        return;
++    }
++
++    pthread_mutex_lock(&inode->plock_mutex);
++    plock =
++        lookup_create_plock_ctx(lo, inode, fi->lock_owner, lock->l_pid, &ret);
++
++    if (!plock) {
++        pthread_mutex_unlock(&inode->plock_mutex);
++        fuse_reply_err(req, ret);
++        return;
++    }
++
++    /* TODO: Is it alright to modify flock? */
++    lock->l_pid = 0;
++    ret = fcntl(plock->fd, F_OFD_SETLK, lock);
++    if (ret == -1) {
++        saverr = errno;
++    }
++    pthread_mutex_unlock(&inode->plock_mutex);
++    fuse_reply_err(req, saverr);
++}
++
+ static void lo_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
+                         struct fuse_file_info *fi)
+ {
+@@ -1617,6 +1790,19 @@ static void lo_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+ {
+     int res;
+     (void)ino;
++    struct lo_inode *inode;
++
++    inode = lo_inode(req, ino);
++    if (!inode) {
++        fuse_reply_err(req, EBADF);
++        return;
++    }
++
++    /* An fd is going away. Cleanup associated posix locks */
++    pthread_mutex_lock(&inode->plock_mutex);
++    g_hash_table_remove(inode->posix_locks, GUINT_TO_POINTER(fi->lock_owner));
++    pthread_mutex_unlock(&inode->plock_mutex);
++
+     res = close(dup(lo_fi_fd(req, fi)));
+     fuse_reply_err(req, res == -1 ? errno : 0);
+ }
+@@ -2080,6 +2266,8 @@ static struct fuse_lowlevel_ops lo_oper = {
+     .releasedir = lo_releasedir,
+     .fsyncdir = lo_fsyncdir,
+     .create = lo_create,
++    .getlk = lo_getlk,
++    .setlk = lo_setlk,
+     .open = lo_open,
+     .release = lo_release,
+     .flush = lo_flush,
+@@ -2434,6 +2622,7 @@ int main(int argc, char *argv[])
+     struct lo_data lo = {
+         .debug = 0,
+         .writeback = 0,
++        .posix_lock = 1,
+         .proc_self_fd = -1,
+     };
+     struct lo_map_elem *root_elem;
diff --git a/0095-virtiofsd-use-fuse_lowlevel_is_virtio-in-fuse_sessio.patch b/0095-virtiofsd-use-fuse_lowlevel_is_virtio-in-fuse_sessio.patch
new file mode 100644
index 0000000..357130e
--- /dev/null
+++ b/0095-virtiofsd-use-fuse_lowlevel_is_virtio-in-fuse_sessio.patch
@@ -0,0 +1,40 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:02:04 +0000
+Subject: [PATCH] virtiofsd: use fuse_lowlevel_is_virtio() in
+ fuse_session_destroy()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+vu_socket_path is NULL when --fd=FDNUM was used.  Use
+fuse_lowlevel_is_virtio() instead.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 620e9d8d9cee6df7fe71168dea950dba0cc21a4a)
+---
+ tools/virtiofsd/fuse_lowlevel.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 70568d22a4..dab6a31e08 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -2537,12 +2537,13 @@ void fuse_session_destroy(struct fuse_session *se)
+         close(se->fd);
+     }
+ 
+-    if (se->vu_socket_path) {
++    if (fuse_lowlevel_is_virtio(se)) {
+         virtio_session_close(se);
+-        free(se->vu_socket_path);
+-        se->vu_socket_path = NULL;
+     }
+ 
++    free(se->vu_socket_path);
++    se->vu_socket_path = NULL;
++
+     free(se);
+ }
+ 
diff --git a/0096-virtiofsd-prevent-fv_queue_thread-vs-virtio_loop-rac.patch b/0096-virtiofsd-prevent-fv_queue_thread-vs-virtio_loop-rac.patch
new file mode 100644
index 0000000..0129a03
--- /dev/null
+++ b/0096-virtiofsd-prevent-fv_queue_thread-vs-virtio_loop-rac.patch
@@ -0,0 +1,132 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:02:05 +0000
+Subject: [PATCH] virtiofsd: prevent fv_queue_thread() vs virtio_loop() races
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We call into libvhost-user from the virtqueue handler thread and the
+vhost-user message processing thread without a lock.  There is nothing
+protecting the virtqueue handler thread if the vhost-user message
+processing thread changes the virtqueue or memory table while it is
+running.
+
+This patch introduces a read-write lock.  Virtqueue handler threads are
+readers.  The vhost-user message processing thread is a writer.  This
+will allow concurrency for multiqueue in the future while protecting
+against fv_queue_thread() vs virtio_loop() races.
+
+Note that the critical sections could be made smaller but it would be
+more invasive and require libvhost-user changes.  Let's start simple and
+improve performance later, if necessary.  Another option would be an
+RCU-style approach with lighter-weight primitives.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit e7b337326d594b71b07cd6dbb332c49c122c80a4)
+---
+ tools/virtiofsd/fuse_virtio.c | 34 +++++++++++++++++++++++++++++++++-
+ 1 file changed, 33 insertions(+), 1 deletion(-)
+
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+index fb8d6d1379..f6242f9338 100644
+--- a/tools/virtiofsd/fuse_virtio.c
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -58,6 +58,18 @@ struct fv_VuDev {
+     VuDev dev;
+     struct fuse_session *se;
+ 
++    /*
++     * Either handle virtqueues or vhost-user protocol messages.  Don't do
++     * both at the same time since that could lead to race conditions if
++     * virtqueues or memory tables change while another thread is accessing
++     * them.
++     *
++     * The assumptions are:
++     * 1. fv_queue_thread() reads/writes to virtqueues and only reads VuDev.
++     * 2. virtio_loop() reads/writes virtqueues and VuDev.
++     */
++    pthread_rwlock_t vu_dispatch_rwlock;
++
+     /*
+      * The following pair of fields are only accessed in the main
+      * virtio_loop
+@@ -415,6 +427,8 @@ static void *fv_queue_thread(void *opaque)
+              qi->qidx, qi->kick_fd);
+     while (1) {
+         struct pollfd pf[2];
++        int ret;
++
+         pf[0].fd = qi->kick_fd;
+         pf[0].events = POLLIN;
+         pf[0].revents = 0;
+@@ -461,6 +475,9 @@ static void *fv_queue_thread(void *opaque)
+             fuse_log(FUSE_LOG_ERR, "Eventfd_read for queue: %m\n");
+             break;
+         }
++        /* Mutual exclusion with virtio_loop() */
++        ret = pthread_rwlock_rdlock(&qi->virtio_dev->vu_dispatch_rwlock);
++        assert(ret == 0); /* there is no possible error case */
+         /* out is from guest, in is too guest */
+         unsigned int in_bytes, out_bytes;
+         vu_queue_get_avail_bytes(dev, q, &in_bytes, &out_bytes, ~0, ~0);
+@@ -469,6 +486,7 @@ static void *fv_queue_thread(void *opaque)
+                  "%s: Queue %d gave evalue: %zx available: in: %u out: %u\n",
+                  __func__, qi->qidx, (size_t)evalue, in_bytes, out_bytes);
+ 
++
+         while (1) {
+             bool allocated_bufv = false;
+             struct fuse_bufvec bufv;
+@@ -597,6 +615,8 @@ static void *fv_queue_thread(void *opaque)
+             free(elem);
+             elem = NULL;
+         }
++
++        pthread_rwlock_unlock(&qi->virtio_dev->vu_dispatch_rwlock);
+     }
+ out:
+     pthread_mutex_destroy(&ch.lock);
+@@ -711,6 +731,8 @@ int virtio_loop(struct fuse_session *se)
+ 
+     while (!fuse_session_exited(se)) {
+         struct pollfd pf[1];
++        bool ok;
++        int ret;
+         pf[0].fd = se->vu_socketfd;
+         pf[0].events = POLLIN;
+         pf[0].revents = 0;
+@@ -735,7 +757,15 @@ int virtio_loop(struct fuse_session *se)
+         }
+         assert(pf[0].revents & POLLIN);
+         fuse_log(FUSE_LOG_DEBUG, "%s: Got VU event\n", __func__);
+-        if (!vu_dispatch(&se->virtio_dev->dev)) {
++        /* Mutual exclusion with fv_queue_thread() */
++        ret = pthread_rwlock_wrlock(&se->virtio_dev->vu_dispatch_rwlock);
++        assert(ret == 0); /* there is no possible error case */
++
++        ok = vu_dispatch(&se->virtio_dev->dev);
++
++        pthread_rwlock_unlock(&se->virtio_dev->vu_dispatch_rwlock);
++
++        if (!ok) {
+             fuse_log(FUSE_LOG_ERR, "%s: vu_dispatch failed\n", __func__);
+             break;
+         }
+@@ -877,6 +907,7 @@ int virtio_session_mount(struct fuse_session *se)
+ 
+     se->vu_socketfd = data_sock;
+     se->virtio_dev->se = se;
++    pthread_rwlock_init(&se->virtio_dev->vu_dispatch_rwlock, NULL);
+     vu_init(&se->virtio_dev->dev, 2, se->vu_socketfd, fv_panic, fv_set_watch,
+             fv_remove_watch, &fv_iface);
+ 
+@@ -892,6 +923,7 @@ void virtio_session_close(struct fuse_session *se)
+     }
+ 
+     free(se->virtio_dev->qi);
++    pthread_rwlock_destroy(&se->virtio_dev->vu_dispatch_rwlock);
+     free(se->virtio_dev);
+     se->virtio_dev = NULL;
+ }
diff --git a/0097-virtiofsd-make-lo_release-atomic.patch b/0097-virtiofsd-make-lo_release-atomic.patch
new file mode 100644
index 0000000..8f75b74
--- /dev/null
+++ b/0097-virtiofsd-make-lo_release-atomic.patch
@@ -0,0 +1,46 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:02:06 +0000
+Subject: [PATCH] virtiofsd: make lo_release() atomic
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Hold the lock across both lo_map_get() and lo_map_remove() to prevent
+races between two FUSE_RELEASE requests.  In this case I don't see a
+serious bug but it's safer to do things atomically.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit baed65c060c0e524530bc243eec427fb408bd477)
+---
+ tools/virtiofsd/passthrough_ll.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 9414935b52..690edbc4c5 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -1772,14 +1772,18 @@ static void lo_release(fuse_req_t req, fuse_ino_t ino,
+                        struct fuse_file_info *fi)
+ {
+     struct lo_data *lo = lo_data(req);
+-    int fd;
++    struct lo_map_elem *elem;
++    int fd = -1;
+ 
+     (void)ino;
+ 
+-    fd = lo_fi_fd(req, fi);
+-
+     pthread_mutex_lock(&lo->mutex);
+-    lo_map_remove(&lo->fd_map, fi->fh);
++    elem = lo_map_get(&lo->fd_map, fi->fh);
++    if (elem) {
++        fd = elem->fd;
++        elem = NULL;
++        lo_map_remove(&lo->fd_map, fi->fh);
++    }
+     pthread_mutex_unlock(&lo->mutex);
+ 
+     close(fd);
diff --git a/0098-virtiofsd-prevent-races-with-lo_dirp_put.patch b/0098-virtiofsd-prevent-races-with-lo_dirp_put.patch
new file mode 100644
index 0000000..a900bc8
--- /dev/null
+++ b/0098-virtiofsd-prevent-races-with-lo_dirp_put.patch
@@ -0,0 +1,131 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:02:07 +0000
+Subject: [PATCH] virtiofsd: prevent races with lo_dirp_put()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Introduce lo_dirp_put() so that FUSE_RELEASEDIR does not cause
+use-after-free races with other threads that are accessing lo_dirp.
+
+Also make lo_releasedir() atomic to prevent FUSE_RELEASEDIR racing with
+itself.  This prevents double-frees.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit acefdde73b403576a241ebd8dbe8431ddc0d9442)
+---
+ tools/virtiofsd/passthrough_ll.c | 41 +++++++++++++++++++++++++++-----
+ 1 file changed, 35 insertions(+), 6 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 690edbc4c5..2d703b57e5 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -1284,11 +1284,28 @@ static void lo_readlink(fuse_req_t req, fuse_ino_t ino)
+ }
+ 
+ struct lo_dirp {
++    gint refcount;
+     DIR *dp;
+     struct dirent *entry;
+     off_t offset;
+ };
+ 
++static void lo_dirp_put(struct lo_dirp **dp)
++{
++    struct lo_dirp *d = *dp;
++
++    if (!d) {
++        return;
++    }
++    *dp = NULL;
++
++    if (g_atomic_int_dec_and_test(&d->refcount)) {
++        closedir(d->dp);
++        free(d);
++    }
++}
++
++/* Call lo_dirp_put() on the return value when no longer needed */
+ static struct lo_dirp *lo_dirp(fuse_req_t req, struct fuse_file_info *fi)
+ {
+     struct lo_data *lo = lo_data(req);
+@@ -1296,6 +1313,9 @@ static struct lo_dirp *lo_dirp(fuse_req_t req, struct fuse_file_info *fi)
+ 
+     pthread_mutex_lock(&lo->mutex);
+     elem = lo_map_get(&lo->dirp_map, fi->fh);
++    if (elem) {
++        g_atomic_int_inc(&elem->dirp->refcount);
++    }
+     pthread_mutex_unlock(&lo->mutex);
+     if (!elem) {
+         return NULL;
+@@ -1331,6 +1351,7 @@ static void lo_opendir(fuse_req_t req, fuse_ino_t ino,
+     d->offset = 0;
+     d->entry = NULL;
+ 
++    g_atomic_int_set(&d->refcount, 1); /* paired with lo_releasedir() */
+     pthread_mutex_lock(&lo->mutex);
+     fh = lo_add_dirp_mapping(req, d);
+     pthread_mutex_unlock(&lo->mutex);
+@@ -1364,7 +1385,7 @@ static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
+                           off_t offset, struct fuse_file_info *fi, int plus)
+ {
+     struct lo_data *lo = lo_data(req);
+-    struct lo_dirp *d;
++    struct lo_dirp *d = NULL;
+     struct lo_inode *dinode;
+     char *buf = NULL;
+     char *p;
+@@ -1454,6 +1475,8 @@ static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
+ 
+     err = 0;
+ error:
++    lo_dirp_put(&d);
++
+     /*
+      * If there's an error, we can only signal it if we haven't stored
+      * any entries yet - otherwise we'd end up with wrong lookup
+@@ -1484,22 +1507,25 @@ static void lo_releasedir(fuse_req_t req, fuse_ino_t ino,
+                           struct fuse_file_info *fi)
+ {
+     struct lo_data *lo = lo_data(req);
++    struct lo_map_elem *elem;
+     struct lo_dirp *d;
+ 
+     (void)ino;
+ 
+-    d = lo_dirp(req, fi);
+-    if (!d) {
++    pthread_mutex_lock(&lo->mutex);
++    elem = lo_map_get(&lo->dirp_map, fi->fh);
++    if (!elem) {
++        pthread_mutex_unlock(&lo->mutex);
+         fuse_reply_err(req, EBADF);
+         return;
+     }
+ 
+-    pthread_mutex_lock(&lo->mutex);
++    d = elem->dirp;
+     lo_map_remove(&lo->dirp_map, fi->fh);
+     pthread_mutex_unlock(&lo->mutex);
+ 
+-    closedir(d->dp);
+-    free(d);
++    lo_dirp_put(&d); /* paired with lo_opendir() */
++
+     fuse_reply_err(req, 0);
+ }
+ 
+@@ -1710,6 +1736,9 @@ static void lo_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
+     } else {
+         res = fsync(fd);
+     }
++
++    lo_dirp_put(&d);
++
+     fuse_reply_err(req, res == -1 ? errno : 0);
+ }
+ 
diff --git a/0099-virtiofsd-rename-inode-refcount-to-inode-nlookup.patch b/0099-virtiofsd-rename-inode-refcount-to-inode-nlookup.patch
new file mode 100644
index 0000000..2025112
--- /dev/null
+++ b/0099-virtiofsd-rename-inode-refcount-to-inode-nlookup.patch
@@ -0,0 +1,123 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:02:08 +0000
+Subject: [PATCH] virtiofsd: rename inode->refcount to inode->nlookup
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This reference counter plays a specific role in the FUSE protocol.  It's
+not a generic object reference counter and the FUSE kernel code calls it
+"nlookup".
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 1222f015558fc34cea02aa3a5a92de608c82cec8)
+---
+ tools/virtiofsd/passthrough_ll.c | 37 +++++++++++++++++++++-----------
+ 1 file changed, 25 insertions(+), 12 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 2d703b57e5..c819b5f782 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -99,7 +99,20 @@ struct lo_inode {
+     int fd;
+     bool is_symlink;
+     struct lo_key key;
+-    uint64_t refcount; /* protected by lo->mutex */
++
++    /*
++     * This counter keeps the inode alive during the FUSE session.
++     * Incremented when the FUSE inode number is sent in a reply
++     * (FUSE_LOOKUP, FUSE_READDIRPLUS, etc).  Decremented when an inode is
++     * released by requests like FUSE_FORGET, FUSE_RMDIR, FUSE_RENAME, etc.
++     *
++     * Note that this value is untrusted because the client can manipulate
++     * it arbitrarily using FUSE_FORGET requests.
++     *
++     * Protected by lo->mutex.
++     */
++    uint64_t nlookup;
++
+     fuse_ino_t fuse_ino;
+     pthread_mutex_t plock_mutex;
+     GHashTable *posix_locks; /* protected by lo_inode->plock_mutex */
+@@ -568,7 +581,7 @@ retry:
+     if (last == path) {
+         p = &lo->root;
+         pthread_mutex_lock(&lo->mutex);
+-        p->refcount++;
++        p->nlookup++;
+         pthread_mutex_unlock(&lo->mutex);
+     } else {
+         *last = '\0';
+@@ -786,8 +799,8 @@ static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st)
+     pthread_mutex_lock(&lo->mutex);
+     p = g_hash_table_lookup(lo->inodes, &key);
+     if (p) {
+-        assert(p->refcount > 0);
+-        p->refcount++;
++        assert(p->nlookup > 0);
++        p->nlookup++;
+     }
+     pthread_mutex_unlock(&lo->mutex);
+ 
+@@ -855,7 +868,7 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+         }
+ 
+         inode->is_symlink = S_ISLNK(e->attr.st_mode);
+-        inode->refcount = 1;
++        inode->nlookup = 1;
+         inode->fd = newfd;
+         newfd = -1;
+         inode->key.ino = e->attr.st_ino;
+@@ -1112,7 +1125,7 @@ static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
+     }
+ 
+     pthread_mutex_lock(&lo->mutex);
+-    inode->refcount++;
++    inode->nlookup++;
+     pthread_mutex_unlock(&lo->mutex);
+     e.ino = inode->fuse_ino;
+ 
+@@ -1193,9 +1206,9 @@ static void unref_inode_lolocked(struct lo_data *lo, struct lo_inode *inode,
+     }
+ 
+     pthread_mutex_lock(&lo->mutex);
+-    assert(inode->refcount >= n);
+-    inode->refcount -= n;
+-    if (!inode->refcount) {
++    assert(inode->nlookup >= n);
++    inode->nlookup -= n;
++    if (!inode->nlookup) {
+         lo_map_remove(&lo->ino_map, inode->fuse_ino);
+         g_hash_table_remove(lo->inodes, &inode->key);
+         if (g_hash_table_size(inode->posix_locks)) {
+@@ -1216,7 +1229,7 @@ static int unref_all_inodes_cb(gpointer key, gpointer value, gpointer user_data)
+     struct lo_inode *inode = value;
+     struct lo_data *lo = user_data;
+ 
+-    inode->refcount = 0;
++    inode->nlookup = 0;
+     lo_map_remove(&lo->ino_map, inode->fuse_ino);
+     close(inode->fd);
+ 
+@@ -1241,7 +1254,7 @@ static void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
+     }
+ 
+     fuse_log(FUSE_LOG_DEBUG, "  forget %lli %lli -%lli\n",
+-             (unsigned long long)ino, (unsigned long long)inode->refcount,
++             (unsigned long long)ino, (unsigned long long)inode->nlookup,
+              (unsigned long long)nlookup);
+ 
+     unref_inode_lolocked(lo, inode, nlookup);
+@@ -2609,7 +2622,7 @@ static void setup_root(struct lo_data *lo, struct lo_inode *root)
+     root->fd = fd;
+     root->key.ino = stat.st_ino;
+     root->key.dev = stat.st_dev;
+-    root->refcount = 2;
++    root->nlookup = 2;
+ }
+ 
+ static guint lo_key_hash(gconstpointer key)
diff --git a/0100-libvhost-user-Fix-some-memtable-remap-cases.patch b/0100-libvhost-user-Fix-some-memtable-remap-cases.patch
new file mode 100644
index 0000000..da82476
--- /dev/null
+++ b/0100-libvhost-user-Fix-some-memtable-remap-cases.patch
@@ -0,0 +1,98 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:02:09 +0000
+Subject: [PATCH] libvhost-user: Fix some memtable remap cases
+
+If a new setmemtable command comes in once the vhost threads are
+running, it will remap the guests address space and the threads
+will now be looking in the wrong place.
+
+Fortunately we're running this command under lock, so we can
+update the queue mappings so that threads will look in the new-right
+place.
+
+Note: This doesn't fix things that the threads might be doing
+without a lock (e.g. a readv/writev!)  That's for another time.
+
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 49e9ec749d4db62ae51f76354143cee183912a1d)
+---
+ contrib/libvhost-user/libvhost-user.c | 33 ++++++++++++++++++++-------
+ contrib/libvhost-user/libvhost-user.h |  3 +++
+ 2 files changed, 28 insertions(+), 8 deletions(-)
+
+diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c
+index 63e41062a4..b89bf18501 100644
+--- a/contrib/libvhost-user/libvhost-user.c
++++ b/contrib/libvhost-user/libvhost-user.c
+@@ -564,6 +564,21 @@ vu_reset_device_exec(VuDev *dev, VhostUserMsg *vmsg)
+     return false;
+ }
+ 
++static bool
++map_ring(VuDev *dev, VuVirtq *vq)
++{
++    vq->vring.desc = qva_to_va(dev, vq->vra.desc_user_addr);
++    vq->vring.used = qva_to_va(dev, vq->vra.used_user_addr);
++    vq->vring.avail = qva_to_va(dev, vq->vra.avail_user_addr);
++
++    DPRINT("Setting virtq addresses:\n");
++    DPRINT("    vring_desc  at %p\n", vq->vring.desc);
++    DPRINT("    vring_used  at %p\n", vq->vring.used);
++    DPRINT("    vring_avail at %p\n", vq->vring.avail);
++
++    return !(vq->vring.desc && vq->vring.used && vq->vring.avail);
++}
++
+ static bool
+ vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg)
+ {
+@@ -767,6 +782,14 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg)
+         close(vmsg->fds[i]);
+     }
+ 
++    for (i = 0; i < dev->max_queues; i++) {
++        if (dev->vq[i].vring.desc) {
++            if (map_ring(dev, &dev->vq[i])) {
++                vu_panic(dev, "remaping queue %d during setmemtable", i);
++            }
++        }
++    }
++
+     return false;
+ }
+ 
+@@ -853,18 +876,12 @@ vu_set_vring_addr_exec(VuDev *dev, VhostUserMsg *vmsg)
+     DPRINT("    avail_user_addr:  0x%016" PRIx64 "\n", vra->avail_user_addr);
+     DPRINT("    log_guest_addr:   0x%016" PRIx64 "\n", vra->log_guest_addr);
+ 
++    vq->vra = *vra;
+     vq->vring.flags = vra->flags;
+-    vq->vring.desc = qva_to_va(dev, vra->desc_user_addr);
+-    vq->vring.used = qva_to_va(dev, vra->used_user_addr);
+-    vq->vring.avail = qva_to_va(dev, vra->avail_user_addr);
+     vq->vring.log_guest_addr = vra->log_guest_addr;
+ 
+-    DPRINT("Setting virtq addresses:\n");
+-    DPRINT("    vring_desc  at %p\n", vq->vring.desc);
+-    DPRINT("    vring_used  at %p\n", vq->vring.used);
+-    DPRINT("    vring_avail at %p\n", vq->vring.avail);
+ 
+-    if (!(vq->vring.desc && vq->vring.used && vq->vring.avail)) {
++    if (map_ring(dev, vq)) {
+         vu_panic(dev, "Invalid vring_addr message");
+         return false;
+     }
+diff --git a/contrib/libvhost-user/libvhost-user.h b/contrib/libvhost-user/libvhost-user.h
+index 1844b6f8d4..5cb7708559 100644
+--- a/contrib/libvhost-user/libvhost-user.h
++++ b/contrib/libvhost-user/libvhost-user.h
+@@ -327,6 +327,9 @@ typedef struct VuVirtq {
+     int err_fd;
+     unsigned int enable;
+     bool started;
++
++    /* Guest addresses of our ring */
++    struct vhost_vring_addr vra;
+ } VuVirtq;
+ 
+ enum VuWatchCondtion {
diff --git a/0101-virtiofsd-passthrough_ll-fix-refcounting-on-remove-r.patch b/0101-virtiofsd-passthrough_ll-fix-refcounting-on-remove-r.patch
new file mode 100644
index 0000000..e8ba18f
--- /dev/null
+++ b/0101-virtiofsd-passthrough_ll-fix-refcounting-on-remove-r.patch
@@ -0,0 +1,123 @@
+From: Miklos Szeredi <mszeredi@redhat.com>
+Date: Mon, 27 Jan 2020 19:02:10 +0000
+Subject: [PATCH] virtiofsd: passthrough_ll: fix refcounting on remove/rename
+
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Reviewed-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 9257e514d861afa759c36704e1904d43ca3fec88)
+---
+ tools/virtiofsd/passthrough_ll.c | 50 +++++++++++++++++++++++++++++++-
+ 1 file changed, 49 insertions(+), 1 deletion(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index c819b5f782..e3a6d6b611 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -1140,17 +1140,42 @@ out_err:
+     fuse_reply_err(req, saverr);
+ }
+ 
++static struct lo_inode *lookup_name(fuse_req_t req, fuse_ino_t parent,
++                                    const char *name)
++{
++    int res;
++    struct stat attr;
++
++    res = fstatat(lo_fd(req, parent), name, &attr,
++                  AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
++    if (res == -1) {
++        return NULL;
++    }
++
++    return lo_find(lo_data(req), &attr);
++}
++
+ static void lo_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
+ {
+     int res;
++    struct lo_inode *inode;
++    struct lo_data *lo = lo_data(req);
++
+     if (!is_safe_path_component(name)) {
+         fuse_reply_err(req, EINVAL);
+         return;
+     }
+ 
++    inode = lookup_name(req, parent, name);
++    if (!inode) {
++        fuse_reply_err(req, EIO);
++        return;
++    }
++
+     res = unlinkat(lo_fd(req, parent), name, AT_REMOVEDIR);
+ 
+     fuse_reply_err(req, res == -1 ? errno : 0);
++    unref_inode_lolocked(lo, inode, 1);
+ }
+ 
+ static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
+@@ -1158,12 +1183,23 @@ static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
+                       unsigned int flags)
+ {
+     int res;
++    struct lo_inode *oldinode;
++    struct lo_inode *newinode;
++    struct lo_data *lo = lo_data(req);
+ 
+     if (!is_safe_path_component(name) || !is_safe_path_component(newname)) {
+         fuse_reply_err(req, EINVAL);
+         return;
+     }
+ 
++    oldinode = lookup_name(req, parent, name);
++    newinode = lookup_name(req, newparent, newname);
++
++    if (!oldinode) {
++        fuse_reply_err(req, EIO);
++        goto out;
++    }
++
+     if (flags) {
+ #ifndef SYS_renameat2
+         fuse_reply_err(req, EINVAL);
+@@ -1176,26 +1212,38 @@ static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
+             fuse_reply_err(req, res == -1 ? errno : 0);
+         }
+ #endif
+-        return;
++        goto out;
+     }
+ 
+     res = renameat(lo_fd(req, parent), name, lo_fd(req, newparent), newname);
+ 
+     fuse_reply_err(req, res == -1 ? errno : 0);
++out:
++    unref_inode_lolocked(lo, oldinode, 1);
++    unref_inode_lolocked(lo, newinode, 1);
+ }
+ 
+ static void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
+ {
+     int res;
++    struct lo_inode *inode;
++    struct lo_data *lo = lo_data(req);
+ 
+     if (!is_safe_path_component(name)) {
+         fuse_reply_err(req, EINVAL);
+         return;
+     }
+ 
++    inode = lookup_name(req, parent, name);
++    if (!inode) {
++        fuse_reply_err(req, EIO);
++        return;
++    }
++
+     res = unlinkat(lo_fd(req, parent), name, 0);
+ 
+     fuse_reply_err(req, res == -1 ? errno : 0);
++    unref_inode_lolocked(lo, inode, 1);
+ }
+ 
+ static void unref_inode_lolocked(struct lo_data *lo, struct lo_inode *inode,
diff --git a/0102-virtiofsd-introduce-inode-refcount-to-prevent-use-af.patch b/0102-virtiofsd-introduce-inode-refcount-to-prevent-use-af.patch
new file mode 100644
index 0000000..25e6f71
--- /dev/null
+++ b/0102-virtiofsd-introduce-inode-refcount-to-prevent-use-af.patch
@@ -0,0 +1,569 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:02:11 +0000
+Subject: [PATCH] virtiofsd: introduce inode refcount to prevent use-after-free
+
+If thread A is using an inode it must not be deleted by thread B when
+processing a FUSE_FORGET request.
+
+The FUSE protocol itself already has a counter called nlookup that is
+used in FUSE_FORGET messages.  We cannot trust this counter since the
+untrusted client can manipulate it via FUSE_FORGET messages.
+
+Introduce a new refcount to keep inodes alive for the required lifespan.
+lo_inode_put() must be called to release a reference.  FUSE's nlookup
+counter holds exactly one reference so that the inode stays alive as
+long as the client still wants to remember it.
+
+Note that the lo_inode->is_symlink field is moved to avoid creating a
+hole in the struct due to struct field alignment.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Reviewed-by: Sergio Lopez <slp@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit c241aa9457d88c6a0d027f48fadfed131646bce3)
+---
+ tools/virtiofsd/passthrough_ll.c | 169 ++++++++++++++++++++++++++-----
+ 1 file changed, 146 insertions(+), 23 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index e3a6d6b611..ab1613586e 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -97,7 +97,13 @@ struct lo_key {
+ 
+ struct lo_inode {
+     int fd;
+-    bool is_symlink;
++
++    /*
++     * Atomic reference count for this object.  The nlookup field holds a
++     * reference and release it when nlookup reaches 0.
++     */
++    gint refcount;
++
+     struct lo_key key;
+ 
+     /*
+@@ -116,6 +122,8 @@ struct lo_inode {
+     fuse_ino_t fuse_ino;
+     pthread_mutex_t plock_mutex;
+     GHashTable *posix_locks; /* protected by lo_inode->plock_mutex */
++
++    bool is_symlink;
+ };
+ 
+ struct lo_cred {
+@@ -471,6 +479,23 @@ static ssize_t lo_add_inode_mapping(fuse_req_t req, struct lo_inode *inode)
+     return elem - lo_data(req)->ino_map.elems;
+ }
+ 
++static void lo_inode_put(struct lo_data *lo, struct lo_inode **inodep)
++{
++    struct lo_inode *inode = *inodep;
++
++    if (!inode) {
++        return;
++    }
++
++    *inodep = NULL;
++
++    if (g_atomic_int_dec_and_test(&inode->refcount)) {
++        close(inode->fd);
++        free(inode);
++    }
++}
++
++/* Caller must release refcount using lo_inode_put() */
+ static struct lo_inode *lo_inode(fuse_req_t req, fuse_ino_t ino)
+ {
+     struct lo_data *lo = lo_data(req);
+@@ -478,6 +503,9 @@ static struct lo_inode *lo_inode(fuse_req_t req, fuse_ino_t ino)
+ 
+     pthread_mutex_lock(&lo->mutex);
+     elem = lo_map_get(&lo->ino_map, ino);
++    if (elem) {
++        g_atomic_int_inc(&elem->inode->refcount);
++    }
+     pthread_mutex_unlock(&lo->mutex);
+ 
+     if (!elem) {
+@@ -487,10 +515,23 @@ static struct lo_inode *lo_inode(fuse_req_t req, fuse_ino_t ino)
+     return elem->inode;
+ }
+ 
++/*
++ * TODO Remove this helper and force callers to hold an inode refcount until
++ * they are done with the fd.  This will be done in a later patch to make
++ * review easier.
++ */
+ static int lo_fd(fuse_req_t req, fuse_ino_t ino)
+ {
+     struct lo_inode *inode = lo_inode(req, ino);
+-    return inode ? inode->fd : -1;
++    int fd;
++
++    if (!inode) {
++        return -1;
++    }
++
++    fd = inode->fd;
++    lo_inode_put(lo_data(req), &inode);
++    return fd;
+ }
+ 
+ static void lo_init(void *userdata, struct fuse_conn_info *conn)
+@@ -545,6 +586,10 @@ static void lo_getattr(fuse_req_t req, fuse_ino_t ino,
+     fuse_reply_attr(req, &buf, lo->timeout);
+ }
+ 
++/*
++ * Increments parent->nlookup and caller must release refcount using
++ * lo_inode_put(&parent).
++ */
+ static int lo_parent_and_name(struct lo_data *lo, struct lo_inode *inode,
+                               char path[PATH_MAX], struct lo_inode **parent)
+ {
+@@ -582,6 +627,7 @@ retry:
+         p = &lo->root;
+         pthread_mutex_lock(&lo->mutex);
+         p->nlookup++;
++        g_atomic_int_inc(&p->refcount);
+         pthread_mutex_unlock(&lo->mutex);
+     } else {
+         *last = '\0';
+@@ -625,6 +671,7 @@ retry:
+ 
+ fail_unref:
+     unref_inode_lolocked(lo, p, 1);
++    lo_inode_put(lo, &p);
+ fail:
+     if (retries) {
+         retries--;
+@@ -663,6 +710,7 @@ fallback:
+     if (res != -1) {
+         res = utimensat(parent->fd, path, tv, AT_SYMLINK_NOFOLLOW);
+         unref_inode_lolocked(lo, parent, 1);
++        lo_inode_put(lo, &parent);
+     }
+ 
+     return res;
+@@ -780,11 +828,13 @@ static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+             goto out_err;
+         }
+     }
++    lo_inode_put(lo, &inode);
+ 
+     return lo_getattr(req, ino, fi);
+ 
+ out_err:
+     saverr = errno;
++    lo_inode_put(lo, &inode);
+     fuse_reply_err(req, saverr);
+ }
+ 
+@@ -801,6 +851,7 @@ static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st)
+     if (p) {
+         assert(p->nlookup > 0);
+         p->nlookup++;
++        g_atomic_int_inc(&p->refcount);
+     }
+     pthread_mutex_unlock(&lo->mutex);
+ 
+@@ -820,6 +871,10 @@ static void posix_locks_value_destroy(gpointer data)
+     free(plock);
+ }
+ 
++/*
++ * Increments nlookup and caller must release refcount using
++ * lo_inode_put(&parent).
++ */
+ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+                         struct fuse_entry_param *e)
+ {
+@@ -827,7 +882,8 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+     int res;
+     int saverr;
+     struct lo_data *lo = lo_data(req);
+-    struct lo_inode *inode, *dir = lo_inode(req, parent);
++    struct lo_inode *inode = NULL;
++    struct lo_inode *dir = lo_inode(req, parent);
+ 
+     /*
+      * name_to_handle_at() and open_by_handle_at() can reach here with fuse
+@@ -868,6 +924,13 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+         }
+ 
+         inode->is_symlink = S_ISLNK(e->attr.st_mode);
++
++        /*
++         * One for the caller and one for nlookup (released in
++         * unref_inode_lolocked())
++         */
++        g_atomic_int_set(&inode->refcount, 2);
++
+         inode->nlookup = 1;
+         inode->fd = newfd;
+         newfd = -1;
+@@ -883,6 +946,8 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+         pthread_mutex_unlock(&lo->mutex);
+     }
+     e->ino = inode->fuse_ino;
++    lo_inode_put(lo, &inode);
++    lo_inode_put(lo, &dir);
+ 
+     fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n", (unsigned long long)parent,
+              name, (unsigned long long)e->ino);
+@@ -894,6 +959,8 @@ out_err:
+     if (newfd != -1) {
+         close(newfd);
+     }
++    lo_inode_put(lo, &inode);
++    lo_inode_put(lo, &dir);
+     return saverr;
+ }
+ 
+@@ -991,6 +1058,7 @@ static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent,
+ {
+     int res;
+     int saverr;
++    struct lo_data *lo = lo_data(req);
+     struct lo_inode *dir;
+     struct fuse_entry_param e;
+     struct lo_cred old = {};
+@@ -1032,9 +1100,11 @@ static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent,
+              name, (unsigned long long)e.ino);
+ 
+     fuse_reply_entry(req, &e);
++    lo_inode_put(lo, &dir);
+     return;
+ 
+ out:
++    lo_inode_put(lo, &dir);
+     fuse_reply_err(req, saverr);
+ }
+ 
+@@ -1085,6 +1155,7 @@ fallback:
+     if (res != -1) {
+         res = linkat(parent->fd, path, dfd, name, 0);
+         unref_inode_lolocked(lo, parent, 1);
++        lo_inode_put(lo, &parent);
+     }
+ 
+     return res;
+@@ -1095,6 +1166,7 @@ static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
+ {
+     int res;
+     struct lo_data *lo = lo_data(req);
++    struct lo_inode *parent_inode;
+     struct lo_inode *inode;
+     struct fuse_entry_param e;
+     int saverr;
+@@ -1104,17 +1176,18 @@ static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
+         return;
+     }
+ 
++    parent_inode = lo_inode(req, parent);
+     inode = lo_inode(req, ino);
+-    if (!inode) {
+-        fuse_reply_err(req, EBADF);
+-        return;
++    if (!parent_inode || !inode) {
++        errno = EBADF;
++        goto out_err;
+     }
+ 
+     memset(&e, 0, sizeof(struct fuse_entry_param));
+     e.attr_timeout = lo->timeout;
+     e.entry_timeout = lo->timeout;
+ 
+-    res = linkat_empty_nofollow(lo, inode, lo_fd(req, parent), name);
++    res = linkat_empty_nofollow(lo, inode, parent_inode->fd, name);
+     if (res == -1) {
+         goto out_err;
+     }
+@@ -1133,13 +1206,18 @@ static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
+              name, (unsigned long long)e.ino);
+ 
+     fuse_reply_entry(req, &e);
++    lo_inode_put(lo, &parent_inode);
++    lo_inode_put(lo, &inode);
+     return;
+ 
+ out_err:
+     saverr = errno;
++    lo_inode_put(lo, &parent_inode);
++    lo_inode_put(lo, &inode);
+     fuse_reply_err(req, saverr);
+ }
+ 
++/* Increments nlookup and caller must release refcount using lo_inode_put() */
+ static struct lo_inode *lookup_name(fuse_req_t req, fuse_ino_t parent,
+                                     const char *name)
+ {
+@@ -1176,6 +1254,7 @@ static void lo_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
+ 
+     fuse_reply_err(req, res == -1 ? errno : 0);
+     unref_inode_lolocked(lo, inode, 1);
++    lo_inode_put(lo, &inode);
+ }
+ 
+ static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
+@@ -1183,8 +1262,10 @@ static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
+                       unsigned int flags)
+ {
+     int res;
+-    struct lo_inode *oldinode;
+-    struct lo_inode *newinode;
++    struct lo_inode *parent_inode;
++    struct lo_inode *newparent_inode;
++    struct lo_inode *oldinode = NULL;
++    struct lo_inode *newinode = NULL;
+     struct lo_data *lo = lo_data(req);
+ 
+     if (!is_safe_path_component(name) || !is_safe_path_component(newname)) {
+@@ -1192,6 +1273,13 @@ static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
+         return;
+     }
+ 
++    parent_inode = lo_inode(req, parent);
++    newparent_inode = lo_inode(req, newparent);
++    if (!parent_inode || !newparent_inode) {
++        fuse_reply_err(req, EBADF);
++        goto out;
++    }
++
+     oldinode = lookup_name(req, parent, name);
+     newinode = lookup_name(req, newparent, newname);
+ 
+@@ -1204,8 +1292,8 @@ static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
+ #ifndef SYS_renameat2
+         fuse_reply_err(req, EINVAL);
+ #else
+-        res = syscall(SYS_renameat2, lo_fd(req, parent), name,
+-                       lo_fd(req, newparent), newname, flags);
++        res = syscall(SYS_renameat2, parent_inode->fd, name,
++                        newparent_inode->fd, newname, flags);
+         if (res == -1 && errno == ENOSYS) {
+             fuse_reply_err(req, EINVAL);
+         } else {
+@@ -1215,12 +1303,16 @@ static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
+         goto out;
+     }
+ 
+-    res = renameat(lo_fd(req, parent), name, lo_fd(req, newparent), newname);
++    res = renameat(parent_inode->fd, name, newparent_inode->fd, newname);
+ 
+     fuse_reply_err(req, res == -1 ? errno : 0);
+ out:
+     unref_inode_lolocked(lo, oldinode, 1);
+     unref_inode_lolocked(lo, newinode, 1);
++    lo_inode_put(lo, &oldinode);
++    lo_inode_put(lo, &newinode);
++    lo_inode_put(lo, &parent_inode);
++    lo_inode_put(lo, &newparent_inode);
+ }
+ 
+ static void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
+@@ -1244,6 +1336,7 @@ static void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
+ 
+     fuse_reply_err(req, res == -1 ? errno : 0);
+     unref_inode_lolocked(lo, inode, 1);
++    lo_inode_put(lo, &inode);
+ }
+ 
+ static void unref_inode_lolocked(struct lo_data *lo, struct lo_inode *inode,
+@@ -1265,8 +1358,9 @@ static void unref_inode_lolocked(struct lo_data *lo, struct lo_inode *inode,
+         g_hash_table_destroy(inode->posix_locks);
+         pthread_mutex_destroy(&inode->plock_mutex);
+         pthread_mutex_unlock(&lo->mutex);
+-        close(inode->fd);
+-        free(inode);
++
++        /* Drop our refcount from lo_do_lookup() */
++        lo_inode_put(lo, &inode);
+     } else {
+         pthread_mutex_unlock(&lo->mutex);
+     }
+@@ -1280,6 +1374,7 @@ static int unref_all_inodes_cb(gpointer key, gpointer value, gpointer user_data)
+     inode->nlookup = 0;
+     lo_map_remove(&lo->ino_map, inode->fuse_ino);
+     close(inode->fd);
++    lo_inode_put(lo, &inode); /* Drop our refcount from lo_do_lookup() */
+ 
+     return TRUE;
+ }
+@@ -1306,6 +1401,7 @@ static void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
+              (unsigned long long)nlookup);
+ 
+     unref_inode_lolocked(lo, inode, nlookup);
++    lo_inode_put(lo, &inode);
+ }
+ 
+ static void lo_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
+@@ -1537,6 +1633,7 @@ static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
+     err = 0;
+ error:
+     lo_dirp_put(&d);
++    lo_inode_put(lo, &dinode);
+ 
+     /*
+      * If there's an error, we can only signal it if we haven't stored
+@@ -1595,6 +1692,7 @@ static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
+ {
+     int fd;
+     struct lo_data *lo = lo_data(req);
++    struct lo_inode *parent_inode;
+     struct fuse_entry_param e;
+     int err;
+     struct lo_cred old = {};
+@@ -1607,12 +1705,18 @@ static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
+         return;
+     }
+ 
++    parent_inode = lo_inode(req, parent);
++    if (!parent_inode) {
++        fuse_reply_err(req, EBADF);
++        return;
++    }
++
+     err = lo_change_cred(req, &old);
+     if (err) {
+         goto out;
+     }
+ 
+-    fd = openat(lo_fd(req, parent), name, (fi->flags | O_CREAT) & ~O_NOFOLLOW,
++    fd = openat(parent_inode->fd, name, (fi->flags | O_CREAT) & ~O_NOFOLLOW,
+                 mode);
+     err = fd == -1 ? errno : 0;
+     lo_restore_cred(&old);
+@@ -1625,8 +1729,8 @@ static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
+         pthread_mutex_unlock(&lo->mutex);
+         if (fh == -1) {
+             close(fd);
+-            fuse_reply_err(req, ENOMEM);
+-            return;
++            err = ENOMEM;
++            goto out;
+         }
+ 
+         fi->fh = fh;
+@@ -1639,6 +1743,8 @@ static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
+     }
+ 
+ out:
++    lo_inode_put(lo, &parent_inode);
++
+     if (err) {
+         fuse_reply_err(req, err);
+     } else {
+@@ -1712,16 +1818,18 @@ static void lo_getlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
+     plock =
+         lookup_create_plock_ctx(lo, inode, fi->lock_owner, lock->l_pid, &ret);
+     if (!plock) {
+-        pthread_mutex_unlock(&inode->plock_mutex);
+-        fuse_reply_err(req, ret);
+-        return;
++        saverr = ret;
++        goto out;
+     }
+ 
+     ret = fcntl(plock->fd, F_OFD_GETLK, lock);
+     if (ret == -1) {
+         saverr = errno;
+     }
++
++out:
+     pthread_mutex_unlock(&inode->plock_mutex);
++    lo_inode_put(lo, &inode);
+ 
+     if (saverr) {
+         fuse_reply_err(req, saverr);
+@@ -1761,9 +1869,8 @@ static void lo_setlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
+         lookup_create_plock_ctx(lo, inode, fi->lock_owner, lock->l_pid, &ret);
+ 
+     if (!plock) {
+-        pthread_mutex_unlock(&inode->plock_mutex);
+-        fuse_reply_err(req, ret);
+-        return;
++        saverr = ret;
++        goto out;
+     }
+ 
+     /* TODO: Is it alright to modify flock? */
+@@ -1772,7 +1879,11 @@ static void lo_setlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
+     if (ret == -1) {
+         saverr = errno;
+     }
++
++out:
+     pthread_mutex_unlock(&inode->plock_mutex);
++    lo_inode_put(lo, &inode);
++
+     fuse_reply_err(req, saverr);
+ }
+ 
+@@ -1898,6 +2009,7 @@ static void lo_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+     pthread_mutex_unlock(&inode->plock_mutex);
+ 
+     res = close(dup(lo_fi_fd(req, fi)));
++    lo_inode_put(lo_data(req), &inode);
+     fuse_reply_err(req, res == -1 ? errno : 0);
+ }
+ 
+@@ -2115,11 +2227,14 @@ out_free:
+     if (fd >= 0) {
+         close(fd);
+     }
++
++    lo_inode_put(lo, &inode);
+     return;
+ 
+ out_err:
+     saverr = errno;
+ out:
++    lo_inode_put(lo, &inode);
+     fuse_reply_err(req, saverr);
+     goto out_free;
+ }
+@@ -2190,11 +2305,14 @@ out_free:
+     if (fd >= 0) {
+         close(fd);
+     }
++
++    lo_inode_put(lo, &inode);
+     return;
+ 
+ out_err:
+     saverr = errno;
+ out:
++    lo_inode_put(lo, &inode);
+     fuse_reply_err(req, saverr);
+     goto out_free;
+ }
+@@ -2243,6 +2361,8 @@ out:
+     if (fd >= 0) {
+         close(fd);
+     }
++
++    lo_inode_put(lo, &inode);
+     fuse_reply_err(req, saverr);
+ }
+ 
+@@ -2289,6 +2409,8 @@ out:
+     if (fd >= 0) {
+         close(fd);
+     }
++
++    lo_inode_put(lo, &inode);
+     fuse_reply_err(req, saverr);
+ }
+ 
+@@ -2671,6 +2793,7 @@ static void setup_root(struct lo_data *lo, struct lo_inode *root)
+     root->key.ino = stat.st_ino;
+     root->key.dev = stat.st_dev;
+     root->nlookup = 2;
++    g_atomic_int_set(&root->refcount, 2);
+ }
+ 
+ static guint lo_key_hash(gconstpointer key)
diff --git a/0103-virtiofsd-do-not-always-set-FUSE_FLOCK_LOCKS.patch b/0103-virtiofsd-do-not-always-set-FUSE_FLOCK_LOCKS.patch
new file mode 100644
index 0000000..ae53c17
--- /dev/null
+++ b/0103-virtiofsd-do-not-always-set-FUSE_FLOCK_LOCKS.patch
@@ -0,0 +1,38 @@
+From: Peng Tao <tao.peng@linux.alibaba.com>
+Date: Mon, 27 Jan 2020 19:02:12 +0000
+Subject: [PATCH] virtiofsd: do not always set FUSE_FLOCK_LOCKS
+
+Right now we always enable it regardless of given commandlines.
+Fix it by setting the flag relying on the lo->flock bit.
+
+Signed-off-by: Peng Tao <tao.peng@linux.alibaba.com>
+Reviewed-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Reviewed-by: Sergio Lopez <slp@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit e468d4af5f5192ab33283464a9f6933044ce47f7)
+---
+ tools/virtiofsd/passthrough_ll.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index ab1613586e..ccbbec18b0 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -546,9 +546,14 @@ static void lo_init(void *userdata, struct fuse_conn_info *conn)
+         fuse_log(FUSE_LOG_DEBUG, "lo_init: activating writeback\n");
+         conn->want |= FUSE_CAP_WRITEBACK_CACHE;
+     }
+-    if (lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) {
+-        fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
+-        conn->want |= FUSE_CAP_FLOCK_LOCKS;
++    if (conn->capable & FUSE_CAP_FLOCK_LOCKS) {
++        if (lo->flock) {
++            fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
++            conn->want |= FUSE_CAP_FLOCK_LOCKS;
++        } else {
++            fuse_log(FUSE_LOG_DEBUG, "lo_init: disabling flock locks\n");
++            conn->want &= ~FUSE_CAP_FLOCK_LOCKS;
++        }
+     }
+ 
+     if (conn->capable & FUSE_CAP_POSIX_LOCKS) {
diff --git a/0104-virtiofsd-convert-more-fprintf-and-perror-to-use-fus.patch b/0104-virtiofsd-convert-more-fprintf-and-perror-to-use-fus.patch
new file mode 100644
index 0000000..aabec08
--- /dev/null
+++ b/0104-virtiofsd-convert-more-fprintf-and-perror-to-use-fus.patch
@@ -0,0 +1,83 @@
+From: Eryu Guan <eguan@linux.alibaba.com>
+Date: Mon, 27 Jan 2020 19:02:13 +0000
+Subject: [PATCH] virtiofsd: convert more fprintf and perror to use fuse log
+ infra
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Eryu Guan <eguan@linux.alibaba.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Reviewed-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit fc1aed0bf96259d0b46b1cfea7497b7762c4ee3d)
+---
+ tools/virtiofsd/fuse_signals.c | 7 +++++--
+ tools/virtiofsd/helper.c       | 9 ++++++---
+ 2 files changed, 11 insertions(+), 5 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_signals.c b/tools/virtiofsd/fuse_signals.c
+index dc7c8ac025..f18625b6e2 100644
+--- a/tools/virtiofsd/fuse_signals.c
++++ b/tools/virtiofsd/fuse_signals.c
+@@ -12,6 +12,7 @@
+ #include "fuse_i.h"
+ #include "fuse_lowlevel.h"
+ 
++#include <errno.h>
+ #include <signal.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+@@ -47,13 +48,15 @@ static int set_one_signal_handler(int sig, void (*handler)(int), int remove)
+     sa.sa_flags = 0;
+ 
+     if (sigaction(sig, NULL, &old_sa) == -1) {
+-        perror("fuse: cannot get old signal handler");
++        fuse_log(FUSE_LOG_ERR, "fuse: cannot get old signal handler: %s\n",
++                 strerror(errno));
+         return -1;
+     }
+ 
+     if (old_sa.sa_handler == (remove ? handler : SIG_DFL) &&
+         sigaction(sig, &sa, NULL) == -1) {
+-        perror("fuse: cannot set signal handler");
++        fuse_log(FUSE_LOG_ERR, "fuse: cannot set signal handler: %s\n",
++                 strerror(errno));
+         return -1;
+     }
+     return 0;
+diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
+index 33749bfcb7..f98d8f2eb2 100644
+--- a/tools/virtiofsd/helper.c
++++ b/tools/virtiofsd/helper.c
+@@ -208,7 +208,8 @@ int fuse_daemonize(int foreground)
+         char completed;
+ 
+         if (pipe(waiter)) {
+-            perror("fuse_daemonize: pipe");
++            fuse_log(FUSE_LOG_ERR, "fuse_daemonize: pipe: %s\n",
++                     strerror(errno));
+             return -1;
+         }
+ 
+@@ -218,7 +219,8 @@ int fuse_daemonize(int foreground)
+          */
+         switch (fork()) {
+         case -1:
+-            perror("fuse_daemonize: fork");
++            fuse_log(FUSE_LOG_ERR, "fuse_daemonize: fork: %s\n",
++                     strerror(errno));
+             return -1;
+         case 0:
+             break;
+@@ -228,7 +230,8 @@ int fuse_daemonize(int foreground)
+         }
+ 
+         if (setsid() == -1) {
+-            perror("fuse_daemonize: setsid");
++            fuse_log(FUSE_LOG_ERR, "fuse_daemonize: setsid: %s\n",
++                     strerror(errno));
+             return -1;
+         }
+ 
diff --git a/0105-virtiofsd-Reset-O_DIRECT-flag-during-file-open.patch b/0105-virtiofsd-Reset-O_DIRECT-flag-during-file-open.patch
new file mode 100644
index 0000000..bbd90a3
--- /dev/null
+++ b/0105-virtiofsd-Reset-O_DIRECT-flag-during-file-open.patch
@@ -0,0 +1,56 @@
+From: Vivek Goyal <vgoyal@redhat.com>
+Date: Mon, 27 Jan 2020 19:02:14 +0000
+Subject: [PATCH] virtiofsd: Reset O_DIRECT flag during file open
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+If an application wants to do direct IO and opens a file with O_DIRECT
+in guest, that does not necessarily mean that we need to bypass page
+cache on host as well. So reset this flag on host.
+
+If somebody needs to bypass page cache on host as well (and it is safe to
+do so), we can add a knob in daemon later to control this behavior.
+
+I check virtio-9p and they do reset O_DIRECT flag.
+
+Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 65da4539803373ec4eec97ffc49ee90083e56efd)
+---
+ tools/virtiofsd/passthrough_ll.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index ccbbec18b0..948cb19c77 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -1721,6 +1721,13 @@ static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
+         goto out;
+     }
+ 
++    /*
++     * O_DIRECT in guest should not necessarily mean bypassing page
++     * cache on host as well. If somebody needs that behavior, it
++     * probably should be a configuration knob in daemon.
++     */
++    fi->flags &= ~O_DIRECT;
++
+     fd = openat(parent_inode->fd, name, (fi->flags | O_CREAT) & ~O_NOFOLLOW,
+                 mode);
+     err = fd == -1 ? errno : 0;
+@@ -1950,6 +1957,13 @@ static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+         fi->flags &= ~O_APPEND;
+     }
+ 
++    /*
++     * O_DIRECT in guest should not necessarily mean bypassing page
++     * cache on host as well. If somebody needs that behavior, it
++     * probably should be a configuration knob in daemon.
++     */
++    fi->flags &= ~O_DIRECT;
++
+     sprintf(buf, "%i", lo_fd(req, ino));
+     fd = openat(lo->proc_self_fd, buf, fi->flags & ~O_NOFOLLOW);
+     if (fd == -1) {
diff --git a/0106-virtiofsd-Fix-data-corruption-with-O_APPEND-write-in.patch b/0106-virtiofsd-Fix-data-corruption-with-O_APPEND-write-in.patch
new file mode 100644
index 0000000..ec53bd4
--- /dev/null
+++ b/0106-virtiofsd-Fix-data-corruption-with-O_APPEND-write-in.patch
@@ -0,0 +1,120 @@
+From: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Date: Mon, 27 Jan 2020 19:02:15 +0000
+Subject: [PATCH] virtiofsd: Fix data corruption with O_APPEND write in
+ writeback mode
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When writeback mode is enabled (-o writeback), O_APPEND handling is
+done in kernel. Therefore virtiofsd clears O_APPEND flag when open.
+Otherwise O_APPEND flag takes precedence over pwrite() and write
+data may corrupt.
+
+Currently clearing O_APPEND flag is done in lo_open(), but we also
+need the same operation in lo_create(). So, factor out the flag
+update operation in lo_open() to update_open_flags() and call it
+in both lo_open() and lo_create().
+
+This fixes the failure of xfstest generic/069 in writeback mode
+(which tests O_APPEND write data integrity).
+
+Signed-off-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 8e4e41e39eac5ee5f378d66f069a2f70a1734317)
+---
+ tools/virtiofsd/passthrough_ll.c | 66 ++++++++++++++++----------------
+ 1 file changed, 33 insertions(+), 33 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 948cb19c77..4c61ac5065 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -1692,6 +1692,37 @@ static void lo_releasedir(fuse_req_t req, fuse_ino_t ino,
+     fuse_reply_err(req, 0);
+ }
+ 
++static void update_open_flags(int writeback, struct fuse_file_info *fi)
++{
++    /*
++     * With writeback cache, kernel may send read requests even
++     * when userspace opened write-only
++     */
++    if (writeback && (fi->flags & O_ACCMODE) == O_WRONLY) {
++        fi->flags &= ~O_ACCMODE;
++        fi->flags |= O_RDWR;
++    }
++
++    /*
++     * With writeback cache, O_APPEND is handled by the kernel.
++     * This breaks atomicity (since the file may change in the
++     * underlying filesystem, so that the kernel's idea of the
++     * end of the file isn't accurate anymore). In this example,
++     * we just accept that. A more rigorous filesystem may want
++     * to return an error here
++     */
++    if (writeback && (fi->flags & O_APPEND)) {
++        fi->flags &= ~O_APPEND;
++    }
++
++    /*
++     * O_DIRECT in guest should not necessarily mean bypassing page
++     * cache on host as well. If somebody needs that behavior, it
++     * probably should be a configuration knob in daemon.
++     */
++    fi->flags &= ~O_DIRECT;
++}
++
+ static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
+                       mode_t mode, struct fuse_file_info *fi)
+ {
+@@ -1721,12 +1752,7 @@ static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
+         goto out;
+     }
+ 
+-    /*
+-     * O_DIRECT in guest should not necessarily mean bypassing page
+-     * cache on host as well. If somebody needs that behavior, it
+-     * probably should be a configuration knob in daemon.
+-     */
+-    fi->flags &= ~O_DIRECT;
++    update_open_flags(lo->writeback, fi);
+ 
+     fd = openat(parent_inode->fd, name, (fi->flags | O_CREAT) & ~O_NOFOLLOW,
+                 mode);
+@@ -1936,33 +1962,7 @@ static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+     fuse_log(FUSE_LOG_DEBUG, "lo_open(ino=%" PRIu64 ", flags=%d)\n", ino,
+              fi->flags);
+ 
+-    /*
+-     * With writeback cache, kernel may send read requests even
+-     * when userspace opened write-only
+-     */
+-    if (lo->writeback && (fi->flags & O_ACCMODE) == O_WRONLY) {
+-        fi->flags &= ~O_ACCMODE;
+-        fi->flags |= O_RDWR;
+-    }
+-
+-    /*
+-     * With writeback cache, O_APPEND is handled by the kernel.
+-     * This breaks atomicity (since the file may change in the
+-     * underlying filesystem, so that the kernel's idea of the
+-     * end of the file isn't accurate anymore). In this example,
+-     * we just accept that. A more rigorous filesystem may want
+-     * to return an error here
+-     */
+-    if (lo->writeback && (fi->flags & O_APPEND)) {
+-        fi->flags &= ~O_APPEND;
+-    }
+-
+-    /*
+-     * O_DIRECT in guest should not necessarily mean bypassing page
+-     * cache on host as well. If somebody needs that behavior, it
+-     * probably should be a configuration knob in daemon.
+-     */
+-    fi->flags &= ~O_DIRECT;
++    update_open_flags(lo->writeback, fi);
+ 
+     sprintf(buf, "%i", lo_fd(req, ino));
+     fd = openat(lo->proc_self_fd, buf, fi->flags & ~O_NOFOLLOW);
diff --git a/0107-virtiofsd-passthrough_ll-Use-cache_readdir-for-direc.patch b/0107-virtiofsd-passthrough_ll-Use-cache_readdir-for-direc.patch
new file mode 100644
index 0000000..d78ba2f
--- /dev/null
+++ b/0107-virtiofsd-passthrough_ll-Use-cache_readdir-for-direc.patch
@@ -0,0 +1,29 @@
+From: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Date: Mon, 27 Jan 2020 19:02:16 +0000
+Subject: [PATCH] virtiofsd: passthrough_ll: Use cache_readdir for directory
+ open
+
+Since keep_cache(FOPEN_KEEP_CACHE) has no effect for directory as
+described in fuse_common.h, use cache_readdir(FOPNE_CACHE_DIR) for
+diretory open when cache=always mode.
+
+Signed-off-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 9b610b09b49b1aada256097b338d49da805da6ae)
+---
+ tools/virtiofsd/passthrough_ll.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 4c61ac5065..79b8b71a4f 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -1523,7 +1523,7 @@ static void lo_opendir(fuse_req_t req, fuse_ino_t ino,
+ 
+     fi->fh = fh;
+     if (lo->cache == CACHE_ALWAYS) {
+-        fi->keep_cache = 1;
++        fi->cache_readdir = 1;
+     }
+     fuse_reply_open(req, fi);
+     return;
diff --git a/0108-virtiofsd-add-definition-of-fuse_buf_writev.patch b/0108-virtiofsd-add-definition-of-fuse_buf_writev.patch
new file mode 100644
index 0000000..34925c1
--- /dev/null
+++ b/0108-virtiofsd-add-definition-of-fuse_buf_writev.patch
@@ -0,0 +1,77 @@
+From: piaojun <piaojun@huawei.com>
+Date: Mon, 27 Jan 2020 19:02:17 +0000
+Subject: [PATCH] virtiofsd: add definition of fuse_buf_writev()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Define fuse_buf_writev() which use pwritev and writev to improve io
+bandwidth. Especially, the src bufs with 0 size should be skipped as
+their mems are not *block_size* aligned which will cause writev failed
+in direct io mode.
+
+Signed-off-by: Jun Piao <piaojun@huawei.com>
+Suggested-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 9ceaaa15cf21073c2b23058c374f61c30cd39c31)
+---
+ tools/virtiofsd/buffer.c | 38 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 38 insertions(+)
+
+diff --git a/tools/virtiofsd/buffer.c b/tools/virtiofsd/buffer.c
+index 42a608f6bd..37befebac2 100644
+--- a/tools/virtiofsd/buffer.c
++++ b/tools/virtiofsd/buffer.c
+@@ -14,6 +14,7 @@
+ #include "fuse_lowlevel.h"
+ #include <assert.h>
+ #include <errno.h>
++#include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
+ 
+@@ -33,6 +34,43 @@ size_t fuse_buf_size(const struct fuse_bufvec *bufv)
+     return size;
+ }
+ 
++__attribute__((unused))
++static ssize_t fuse_buf_writev(struct fuse_buf *out_buf,
++                               struct fuse_bufvec *in_buf)
++{
++    ssize_t res, i, j;
++    size_t iovcnt = in_buf->count;
++    struct iovec *iov;
++    int fd = out_buf->fd;
++
++    iov = calloc(iovcnt, sizeof(struct iovec));
++    if (!iov) {
++        return -ENOMEM;
++    }
++
++    for (i = 0, j = 0; i < iovcnt; i++) {
++        /* Skip the buf with 0 size */
++        if (in_buf->buf[i].size) {
++            iov[j].iov_base = in_buf->buf[i].mem;
++            iov[j].iov_len = in_buf->buf[i].size;
++            j++;
++        }
++    }
++
++    if (out_buf->flags & FUSE_BUF_FD_SEEK) {
++        res = pwritev(fd, iov, iovcnt, out_buf->pos);
++    } else {
++        res = writev(fd, iov, iovcnt);
++    }
++
++    if (res == -1) {
++        res = -errno;
++    }
++
++    free(iov);
++    return res;
++}
++
+ static size_t min_size(size_t s1, size_t s2)
+ {
+     return s1 < s2 ? s1 : s2;
diff --git a/0109-virtiofsd-use-fuse_buf_writev-to-replace-fuse_buf_wr.patch b/0109-virtiofsd-use-fuse_buf_writev-to-replace-fuse_buf_wr.patch
new file mode 100644
index 0000000..4ed2da4
--- /dev/null
+++ b/0109-virtiofsd-use-fuse_buf_writev-to-replace-fuse_buf_wr.patch
@@ -0,0 +1,66 @@
+From: piaojun <piaojun@huawei.com>
+Date: Mon, 27 Jan 2020 19:02:18 +0000
+Subject: [PATCH] virtiofsd: use fuse_buf_writev to replace fuse_buf_write for
+ better performance
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+fuse_buf_writev() only handles the normal write in which src is buffer
+and dest is fd. Specially if src buffer represents guest physical
+address that can't be mapped by the daemon process, IO must be bounced
+back to the VMM to do it by fuse_buf_copy().
+
+Signed-off-by: Jun Piao <piaojun@huawei.com>
+Suggested-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Suggested-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit c465bba2c90a810f6e71e4f2646b1b4ee4b478de)
+---
+ tools/virtiofsd/buffer.c | 20 ++++++++++++++++++--
+ 1 file changed, 18 insertions(+), 2 deletions(-)
+
+diff --git a/tools/virtiofsd/buffer.c b/tools/virtiofsd/buffer.c
+index 37befebac2..27c1377f22 100644
+--- a/tools/virtiofsd/buffer.c
++++ b/tools/virtiofsd/buffer.c
+@@ -34,7 +34,6 @@ size_t fuse_buf_size(const struct fuse_bufvec *bufv)
+     return size;
+ }
+ 
+-__attribute__((unused))
+ static ssize_t fuse_buf_writev(struct fuse_buf *out_buf,
+                                struct fuse_bufvec *in_buf)
+ {
+@@ -262,12 +261,29 @@ static int fuse_bufvec_advance(struct fuse_bufvec *bufv, size_t len)
+ 
+ ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv)
+ {
+-    size_t copied = 0;
++    size_t copied = 0, i;
+ 
+     if (dstv == srcv) {
+         return fuse_buf_size(dstv);
+     }
+ 
++    /*
++     * use writev to improve bandwidth when all the
++     * src buffers already mapped by the daemon
++     * process
++     */
++    for (i = 0; i < srcv->count; i++) {
++        if (srcv->buf[i].flags & FUSE_BUF_IS_FD) {
++            break;
++        }
++    }
++    if ((i == srcv->count) && (dstv->count == 1) &&
++        (dstv->idx == 0) &&
++        (dstv->buf[0].flags & FUSE_BUF_IS_FD)) {
++        dstv->buf[0].pos += dstv->off;
++        return fuse_buf_writev(&dstv->buf[0], srcv);
++    }
++
+     for (;;) {
+         const struct fuse_buf *src = fuse_bufvec_current(srcv);
+         const struct fuse_buf *dst = fuse_bufvec_current(dstv);
diff --git a/0110-virtiofsd-process-requests-in-a-thread-pool.patch b/0110-virtiofsd-process-requests-in-a-thread-pool.patch
new file mode 100644
index 0000000..b83ae83
--- /dev/null
+++ b/0110-virtiofsd-process-requests-in-a-thread-pool.patch
@@ -0,0 +1,514 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:02:19 +0000
+Subject: [PATCH] virtiofsd: process requests in a thread pool
+
+Introduce a thread pool so that fv_queue_thread() just pops
+VuVirtqElements and hands them to the thread pool.  For the time being
+only one worker thread is allowed since passthrough_ll.c is not
+thread-safe yet.  Future patches will lift this restriction so that
+multiple FUSE requests can be processed in parallel.
+
+The main new concept is struct FVRequest, which contains both
+VuVirtqElement and struct fuse_chan.  We now have fv_VuDev for a device,
+fv_QueueInfo for a virtqueue, and FVRequest for a request.  Some of
+fv_QueueInfo's fields are moved into FVRequest because they are
+per-request.  The name FVRequest conforms to QEMU coding style and I
+expect the struct fv_* types will be renamed in a future refactoring.
+
+This patch series is not optimal.  fbuf reuse is dropped so each request
+does malloc(se->bufsize), but there is no clean and cheap way to keep
+this with a thread pool.  The vq_lock mutex is held for longer than
+necessary, especially during the eventfd_write() syscall.  Performance
+can be improved in the future.
+
+prctl(2) had to be added to the seccomp whitelist because glib invokes
+it.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit a3d756c5aecccc4c0e51060a7e2f1c87bf8f1180)
+---
+ tools/virtiofsd/fuse_virtio.c | 359 +++++++++++++++++++---------------
+ 1 file changed, 201 insertions(+), 158 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+index f6242f9338..0dcf2ef57a 100644
+--- a/tools/virtiofsd/fuse_virtio.c
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -22,6 +22,7 @@
+ 
+ #include <assert.h>
+ #include <errno.h>
++#include <glib.h>
+ #include <stdint.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+@@ -37,17 +38,28 @@
+ struct fv_VuDev;
+ struct fv_QueueInfo {
+     pthread_t thread;
++    /*
++     * This lock protects the VuVirtq preventing races between
++     * fv_queue_thread() and fv_queue_worker().
++     */
++    pthread_mutex_t vq_lock;
++
+     struct fv_VuDev *virtio_dev;
+ 
+     /* Our queue index, corresponds to array position */
+     int qidx;
+     int kick_fd;
+     int kill_fd; /* For killing the thread */
++};
+ 
+-    /* The element for the command currently being processed */
+-    VuVirtqElement *qe;
++/* A FUSE request */
++typedef struct {
++    VuVirtqElement elem;
++    struct fuse_chan ch;
++
++    /* Used to complete requests that involve no reply */
+     bool reply_sent;
+-};
++} FVRequest;
+ 
+ /*
+  * We pass the dev element into libvhost-user
+@@ -191,8 +203,11 @@ static void copy_iov(struct iovec *src_iov, int src_count,
+ int virtio_send_msg(struct fuse_session *se, struct fuse_chan *ch,
+                     struct iovec *iov, int count)
+ {
+-    VuVirtqElement *elem;
+-    VuVirtq *q;
++    FVRequest *req = container_of(ch, FVRequest, ch);
++    struct fv_QueueInfo *qi = ch->qi;
++    VuDev *dev = &se->virtio_dev->dev;
++    VuVirtq *q = vu_get_queue(dev, qi->qidx);
++    VuVirtqElement *elem = &req->elem;
+     int ret = 0;
+ 
+     assert(count >= 1);
+@@ -205,11 +220,7 @@ int virtio_send_msg(struct fuse_session *se, struct fuse_chan *ch,
+ 
+     /* unique == 0 is notification, which we don't support */
+     assert(out->unique);
+-    /* For virtio we always have ch */
+-    assert(ch);
+-    assert(!ch->qi->reply_sent);
+-    elem = ch->qi->qe;
+-    q = &ch->qi->virtio_dev->dev.vq[ch->qi->qidx];
++    assert(!req->reply_sent);
+ 
+     /* The 'in' part of the elem is to qemu */
+     unsigned int in_num = elem->in_num;
+@@ -236,9 +247,15 @@ int virtio_send_msg(struct fuse_session *se, struct fuse_chan *ch,
+     }
+ 
+     copy_iov(iov, count, in_sg, in_num, tosend_len);
+-    vu_queue_push(&se->virtio_dev->dev, q, elem, tosend_len);
+-    vu_queue_notify(&se->virtio_dev->dev, q);
+-    ch->qi->reply_sent = true;
++
++    pthread_rwlock_rdlock(&qi->virtio_dev->vu_dispatch_rwlock);
++    pthread_mutex_lock(&qi->vq_lock);
++    vu_queue_push(dev, q, elem, tosend_len);
++    vu_queue_notify(dev, q);
++    pthread_mutex_unlock(&qi->vq_lock);
++    pthread_rwlock_unlock(&qi->virtio_dev->vu_dispatch_rwlock);
++
++    req->reply_sent = true;
+ 
+ err:
+     return ret;
+@@ -254,9 +271,12 @@ int virtio_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
+                          struct iovec *iov, int count, struct fuse_bufvec *buf,
+                          size_t len)
+ {
++    FVRequest *req = container_of(ch, FVRequest, ch);
++    struct fv_QueueInfo *qi = ch->qi;
++    VuDev *dev = &se->virtio_dev->dev;
++    VuVirtq *q = vu_get_queue(dev, qi->qidx);
++    VuVirtqElement *elem = &req->elem;
+     int ret = 0;
+-    VuVirtqElement *elem;
+-    VuVirtq *q;
+ 
+     assert(count >= 1);
+     assert(iov[0].iov_len >= sizeof(struct fuse_out_header));
+@@ -275,11 +295,7 @@ int virtio_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
+     /* unique == 0 is notification which we don't support */
+     assert(out->unique);
+ 
+-    /* For virtio we always have ch */
+-    assert(ch);
+-    assert(!ch->qi->reply_sent);
+-    elem = ch->qi->qe;
+-    q = &ch->qi->virtio_dev->dev.vq[ch->qi->qidx];
++    assert(!req->reply_sent);
+ 
+     /* The 'in' part of the elem is to qemu */
+     unsigned int in_num = elem->in_num;
+@@ -395,33 +411,175 @@ int virtio_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
+ 
+     ret = 0;
+ 
+-    vu_queue_push(&se->virtio_dev->dev, q, elem, tosend_len);
+-    vu_queue_notify(&se->virtio_dev->dev, q);
++    pthread_rwlock_rdlock(&qi->virtio_dev->vu_dispatch_rwlock);
++    pthread_mutex_lock(&qi->vq_lock);
++    vu_queue_push(dev, q, elem, tosend_len);
++    vu_queue_notify(dev, q);
++    pthread_mutex_unlock(&qi->vq_lock);
++    pthread_rwlock_unlock(&qi->virtio_dev->vu_dispatch_rwlock);
+ 
+ err:
+     if (ret == 0) {
+-        ch->qi->reply_sent = true;
++        req->reply_sent = true;
+     }
+ 
+     return ret;
+ }
+ 
++/* Process one FVRequest in a thread pool */
++static void fv_queue_worker(gpointer data, gpointer user_data)
++{
++    struct fv_QueueInfo *qi = user_data;
++    struct fuse_session *se = qi->virtio_dev->se;
++    struct VuDev *dev = &qi->virtio_dev->dev;
++    FVRequest *req = data;
++    VuVirtqElement *elem = &req->elem;
++    struct fuse_buf fbuf = {};
++    bool allocated_bufv = false;
++    struct fuse_bufvec bufv;
++    struct fuse_bufvec *pbufv;
++
++    assert(se->bufsize > sizeof(struct fuse_in_header));
++
++    /*
++     * An element contains one request and the space to send our response
++     * They're spread over multiple descriptors in a scatter/gather set
++     * and we can't trust the guest to keep them still; so copy in/out.
++     */
++    fbuf.mem = malloc(se->bufsize);
++    assert(fbuf.mem);
++
++    fuse_mutex_init(&req->ch.lock);
++    req->ch.fd = -1;
++    req->ch.qi = qi;
++
++    /* The 'out' part of the elem is from qemu */
++    unsigned int out_num = elem->out_num;
++    struct iovec *out_sg = elem->out_sg;
++    size_t out_len = iov_size(out_sg, out_num);
++    fuse_log(FUSE_LOG_DEBUG,
++             "%s: elem %d: with %d out desc of length %zd\n",
++             __func__, elem->index, out_num, out_len);
++
++    /*
++     * The elem should contain a 'fuse_in_header' (in to fuse)
++     * plus the data based on the len in the header.
++     */
++    if (out_len < sizeof(struct fuse_in_header)) {
++        fuse_log(FUSE_LOG_ERR, "%s: elem %d too short for in_header\n",
++                 __func__, elem->index);
++        assert(0); /* TODO */
++    }
++    if (out_len > se->bufsize) {
++        fuse_log(FUSE_LOG_ERR, "%s: elem %d too large for buffer\n", __func__,
++                 elem->index);
++        assert(0); /* TODO */
++    }
++    /* Copy just the first element and look at it */
++    copy_from_iov(&fbuf, 1, out_sg);
++
++    pbufv = NULL; /* Compiler thinks an unitialised path */
++    if (out_num > 2 &&
++        out_sg[0].iov_len == sizeof(struct fuse_in_header) &&
++        ((struct fuse_in_header *)fbuf.mem)->opcode == FUSE_WRITE &&
++        out_sg[1].iov_len == sizeof(struct fuse_write_in)) {
++        /*
++         * For a write we don't actually need to copy the
++         * data, we can just do it straight out of guest memory
++         * but we must still copy the headers in case the guest
++         * was nasty and changed them while we were using them.
++         */
++        fuse_log(FUSE_LOG_DEBUG, "%s: Write special case\n", __func__);
++
++        /* copy the fuse_write_in header afte rthe fuse_in_header */
++        fbuf.mem += out_sg->iov_len;
++        copy_from_iov(&fbuf, 1, out_sg + 1);
++        fbuf.mem -= out_sg->iov_len;
++        fbuf.size = out_sg[0].iov_len + out_sg[1].iov_len;
++
++        /* Allocate the bufv, with space for the rest of the iov */
++        pbufv = malloc(sizeof(struct fuse_bufvec) +
++                       sizeof(struct fuse_buf) * (out_num - 2));
++        if (!pbufv) {
++            fuse_log(FUSE_LOG_ERR, "%s: pbufv malloc failed\n",
++                    __func__);
++            goto out;
++        }
++
++        allocated_bufv = true;
++        pbufv->count = 1;
++        pbufv->buf[0] = fbuf;
++
++        size_t iovindex, pbufvindex;
++        iovindex = 2; /* 2 headers, separate iovs */
++        pbufvindex = 1; /* 2 headers, 1 fusebuf */
++
++        for (; iovindex < out_num; iovindex++, pbufvindex++) {
++            pbufv->count++;
++            pbufv->buf[pbufvindex].pos = ~0; /* Dummy */
++            pbufv->buf[pbufvindex].flags = 0;
++            pbufv->buf[pbufvindex].mem = out_sg[iovindex].iov_base;
++            pbufv->buf[pbufvindex].size = out_sg[iovindex].iov_len;
++        }
++    } else {
++        /* Normal (non fast write) path */
++
++        /* Copy the rest of the buffer */
++        fbuf.mem += out_sg->iov_len;
++        copy_from_iov(&fbuf, out_num - 1, out_sg + 1);
++        fbuf.mem -= out_sg->iov_len;
++        fbuf.size = out_len;
++
++        /* TODO! Endianness of header */
++
++        /* TODO: Add checks for fuse_session_exited */
++        bufv.buf[0] = fbuf;
++        bufv.count = 1;
++        pbufv = &bufv;
++    }
++    pbufv->idx = 0;
++    pbufv->off = 0;
++    fuse_session_process_buf_int(se, pbufv, &req->ch);
++
++out:
++    if (allocated_bufv) {
++        free(pbufv);
++    }
++
++    /* If the request has no reply, still recycle the virtqueue element */
++    if (!req->reply_sent) {
++        struct VuVirtq *q = vu_get_queue(dev, qi->qidx);
++
++        fuse_log(FUSE_LOG_DEBUG, "%s: elem %d no reply sent\n", __func__,
++                 elem->index);
++
++        pthread_rwlock_rdlock(&qi->virtio_dev->vu_dispatch_rwlock);
++        pthread_mutex_lock(&qi->vq_lock);
++        vu_queue_push(dev, q, elem, 0);
++        vu_queue_notify(dev, q);
++        pthread_mutex_unlock(&qi->vq_lock);
++        pthread_rwlock_unlock(&qi->virtio_dev->vu_dispatch_rwlock);
++    }
++
++    pthread_mutex_destroy(&req->ch.lock);
++    free(fbuf.mem);
++    free(req);
++}
++
+ /* Thread function for individual queues, created when a queue is 'started' */
+ static void *fv_queue_thread(void *opaque)
+ {
+     struct fv_QueueInfo *qi = opaque;
+     struct VuDev *dev = &qi->virtio_dev->dev;
+     struct VuVirtq *q = vu_get_queue(dev, qi->qidx);
+-    struct fuse_session *se = qi->virtio_dev->se;
+-    struct fuse_chan ch;
+-    struct fuse_buf fbuf;
++    GThreadPool *pool;
+ 
+-    fbuf.mem = NULL;
+-    fbuf.flags = 0;
+-
+-    fuse_mutex_init(&ch.lock);
+-    ch.fd = (int)0xdaff0d111;
+-    ch.qi = qi;
++    pool = g_thread_pool_new(fv_queue_worker, qi, 1 /* TODO max_threads */,
++                             TRUE, NULL);
++    if (!pool) {
++        fuse_log(FUSE_LOG_ERR, "%s: g_thread_pool_new failed\n", __func__);
++        return NULL;
++    }
+ 
+     fuse_log(FUSE_LOG_INFO, "%s: Start for queue %d kick_fd %d\n", __func__,
+              qi->qidx, qi->kick_fd);
+@@ -478,6 +636,7 @@ static void *fv_queue_thread(void *opaque)
+         /* Mutual exclusion with virtio_loop() */
+         ret = pthread_rwlock_rdlock(&qi->virtio_dev->vu_dispatch_rwlock);
+         assert(ret == 0); /* there is no possible error case */
++        pthread_mutex_lock(&qi->vq_lock);
+         /* out is from guest, in is too guest */
+         unsigned int in_bytes, out_bytes;
+         vu_queue_get_avail_bytes(dev, q, &in_bytes, &out_bytes, ~0, ~0);
+@@ -486,141 +645,22 @@ static void *fv_queue_thread(void *opaque)
+                  "%s: Queue %d gave evalue: %zx available: in: %u out: %u\n",
+                  __func__, qi->qidx, (size_t)evalue, in_bytes, out_bytes);
+ 
+-
+         while (1) {
+-            bool allocated_bufv = false;
+-            struct fuse_bufvec bufv;
+-            struct fuse_bufvec *pbufv;
+-
+-            /*
+-             * An element contains one request and the space to send our
+-             * response They're spread over multiple descriptors in a
+-             * scatter/gather set and we can't trust the guest to keep them
+-             * still; so copy in/out.
+-             */
+-            VuVirtqElement *elem = vu_queue_pop(dev, q, sizeof(VuVirtqElement));
+-            if (!elem) {
++            FVRequest *req = vu_queue_pop(dev, q, sizeof(FVRequest));
++            if (!req) {
+                 break;
+             }
+ 
+-            qi->qe = elem;
+-            qi->reply_sent = false;
++            req->reply_sent = false;
+ 
+-            if (!fbuf.mem) {
+-                fbuf.mem = malloc(se->bufsize);
+-                assert(fbuf.mem);
+-                assert(se->bufsize > sizeof(struct fuse_in_header));
+-            }
+-            /* The 'out' part of the elem is from qemu */
+-            unsigned int out_num = elem->out_num;
+-            struct iovec *out_sg = elem->out_sg;
+-            size_t out_len = iov_size(out_sg, out_num);
+-            fuse_log(FUSE_LOG_DEBUG,
+-                     "%s: elem %d: with %d out desc of length %zd\n", __func__,
+-                     elem->index, out_num, out_len);
+-
+-            /*
+-             * The elem should contain a 'fuse_in_header' (in to fuse)
+-             * plus the data based on the len in the header.
+-             */
+-            if (out_len < sizeof(struct fuse_in_header)) {
+-                fuse_log(FUSE_LOG_ERR, "%s: elem %d too short for in_header\n",
+-                         __func__, elem->index);
+-                assert(0); /* TODO */
+-            }
+-            if (out_len > se->bufsize) {
+-                fuse_log(FUSE_LOG_ERR, "%s: elem %d too large for buffer\n",
+-                         __func__, elem->index);
+-                assert(0); /* TODO */
+-            }
+-            /* Copy just the first element and look at it */
+-            copy_from_iov(&fbuf, 1, out_sg);
+-
+-            if (out_num > 2 &&
+-                out_sg[0].iov_len == sizeof(struct fuse_in_header) &&
+-                ((struct fuse_in_header *)fbuf.mem)->opcode == FUSE_WRITE &&
+-                out_sg[1].iov_len == sizeof(struct fuse_write_in)) {
+-                /*
+-                 * For a write we don't actually need to copy the
+-                 * data, we can just do it straight out of guest memory
+-                 * but we must still copy the headers in case the guest
+-                 * was nasty and changed them while we were using them.
+-                 */
+-                fuse_log(FUSE_LOG_DEBUG, "%s: Write special case\n", __func__);
+-
+-                /* copy the fuse_write_in header after the fuse_in_header */
+-                fbuf.mem += out_sg->iov_len;
+-                copy_from_iov(&fbuf, 1, out_sg + 1);
+-                fbuf.mem -= out_sg->iov_len;
+-                fbuf.size = out_sg[0].iov_len + out_sg[1].iov_len;
+-
+-                /* Allocate the bufv, with space for the rest of the iov */
+-                allocated_bufv = true;
+-                pbufv = malloc(sizeof(struct fuse_bufvec) +
+-                               sizeof(struct fuse_buf) * (out_num - 2));
+-                if (!pbufv) {
+-                    vu_queue_unpop(dev, q, elem, 0);
+-                    free(elem);
+-                    fuse_log(FUSE_LOG_ERR, "%s: pbufv malloc failed\n",
+-                             __func__);
+-                    goto out;
+-                }
+-
+-                pbufv->count = 1;
+-                pbufv->buf[0] = fbuf;
+-
+-                size_t iovindex, pbufvindex;
+-                iovindex = 2; /* 2 headers, separate iovs */
+-                pbufvindex = 1; /* 2 headers, 1 fusebuf */
+-
+-                for (; iovindex < out_num; iovindex++, pbufvindex++) {
+-                    pbufv->count++;
+-                    pbufv->buf[pbufvindex].pos = ~0; /* Dummy */
+-                    pbufv->buf[pbufvindex].flags = 0;
+-                    pbufv->buf[pbufvindex].mem = out_sg[iovindex].iov_base;
+-                    pbufv->buf[pbufvindex].size = out_sg[iovindex].iov_len;
+-                }
+-            } else {
+-                /* Normal (non fast write) path */
+-
+-                /* Copy the rest of the buffer */
+-                fbuf.mem += out_sg->iov_len;
+-                copy_from_iov(&fbuf, out_num - 1, out_sg + 1);
+-                fbuf.mem -= out_sg->iov_len;
+-                fbuf.size = out_len;
+-
+-                /* TODO! Endianness of header */
+-
+-                /* TODO: Add checks for fuse_session_exited */
+-                bufv.buf[0] = fbuf;
+-                bufv.count = 1;
+-                pbufv = &bufv;
+-            }
+-            pbufv->idx = 0;
+-            pbufv->off = 0;
+-            fuse_session_process_buf_int(se, pbufv, &ch);
+-
+-            if (allocated_bufv) {
+-                free(pbufv);
+-            }
+-
+-            if (!qi->reply_sent) {
+-                fuse_log(FUSE_LOG_DEBUG, "%s: elem %d no reply sent\n",
+-                         __func__, elem->index);
+-                /* I think we've still got to recycle the element */
+-                vu_queue_push(dev, q, elem, 0);
+-                vu_queue_notify(dev, q);
+-            }
+-            qi->qe = NULL;
+-            free(elem);
+-            elem = NULL;
++            g_thread_pool_push(pool, req, NULL);
+         }
+ 
++        pthread_mutex_unlock(&qi->vq_lock);
+         pthread_rwlock_unlock(&qi->virtio_dev->vu_dispatch_rwlock);
+     }
+-out:
+-    pthread_mutex_destroy(&ch.lock);
+-    free(fbuf.mem);
++
++    g_thread_pool_free(pool, FALSE, TRUE);
+ 
+     return NULL;
+ }
+@@ -643,6 +683,7 @@ static void fv_queue_cleanup_thread(struct fv_VuDev *vud, int qidx)
+         fuse_log(FUSE_LOG_ERR, "%s: Failed to join thread idx %d err %d\n",
+                  __func__, qidx, ret);
+     }
++    pthread_mutex_destroy(&ourqi->vq_lock);
+     close(ourqi->kill_fd);
+     ourqi->kick_fd = -1;
+     free(vud->qi[qidx]);
+@@ -696,6 +737,8 @@ static void fv_queue_set_started(VuDev *dev, int qidx, bool started)
+ 
+         ourqi->kill_fd = eventfd(0, EFD_CLOEXEC | EFD_SEMAPHORE);
+         assert(ourqi->kill_fd != -1);
++        pthread_mutex_init(&ourqi->vq_lock, NULL);
++
+         if (pthread_create(&ourqi->thread, NULL, fv_queue_thread, ourqi)) {
+             fuse_log(FUSE_LOG_ERR, "%s: Failed to create thread for queue %d\n",
+                      __func__, qidx);
diff --git a/0111-virtiofsd-prevent-FUSE_INIT-FUSE_DESTROY-races.patch b/0111-virtiofsd-prevent-FUSE_INIT-FUSE_DESTROY-races.patch
new file mode 100644
index 0000000..c2d8e55
--- /dev/null
+++ b/0111-virtiofsd-prevent-FUSE_INIT-FUSE_DESTROY-races.patch
@@ -0,0 +1,84 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:02:20 +0000
+Subject: [PATCH] virtiofsd: prevent FUSE_INIT/FUSE_DESTROY races
+
+When running with multiple threads it can be tricky to handle
+FUSE_INIT/FUSE_DESTROY in parallel with other request types or in
+parallel with themselves.  Serialize FUSE_INIT and FUSE_DESTROY so that
+malicious clients cannot trigger race conditions.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit cdc497c6925be745bc895355bd4674a17a4b2a8b)
+---
+ tools/virtiofsd/fuse_i.h        |  1 +
+ tools/virtiofsd/fuse_lowlevel.c | 18 ++++++++++++++++++
+ 2 files changed, 19 insertions(+)
+
+diff --git a/tools/virtiofsd/fuse_i.h b/tools/virtiofsd/fuse_i.h
+index a20854f1c4..1447d86866 100644
+--- a/tools/virtiofsd/fuse_i.h
++++ b/tools/virtiofsd/fuse_i.h
+@@ -61,6 +61,7 @@ struct fuse_session {
+     struct fuse_req list;
+     struct fuse_req interrupts;
+     pthread_mutex_t lock;
++    pthread_rwlock_t init_rwlock;
+     int got_destroy;
+     int broken_splice_nonblock;
+     uint64_t notify_ctr;
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index dab6a31e08..79a4031266 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -2428,6 +2428,19 @@ void fuse_session_process_buf_int(struct fuse_session *se,
+     req->ctx.pid = in->pid;
+     req->ch = ch;
+ 
++    /*
++     * INIT and DESTROY requests are serialized, all other request types
++     * run in parallel.  This prevents races between FUSE_INIT and ordinary
++     * requests, FUSE_INIT and FUSE_INIT, FUSE_INIT and FUSE_DESTROY, and
++     * FUSE_DESTROY and FUSE_DESTROY.
++     */
++    if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT ||
++        in->opcode == FUSE_DESTROY) {
++        pthread_rwlock_wrlock(&se->init_rwlock);
++    } else {
++        pthread_rwlock_rdlock(&se->init_rwlock);
++    }
++
+     err = EIO;
+     if (!se->got_init) {
+         enum fuse_opcode expected;
+@@ -2485,10 +2498,13 @@ void fuse_session_process_buf_int(struct fuse_session *se,
+     } else {
+         fuse_ll_ops[in->opcode].func(req, in->nodeid, &iter);
+     }
++
++    pthread_rwlock_unlock(&se->init_rwlock);
+     return;
+ 
+ reply_err:
+     fuse_reply_err(req, err);
++    pthread_rwlock_unlock(&se->init_rwlock);
+ }
+ 
+ #define LL_OPTION(n, o, v)                     \
+@@ -2531,6 +2547,7 @@ void fuse_session_destroy(struct fuse_session *se)
+             se->op.destroy(se->userdata);
+         }
+     }
++    pthread_rwlock_destroy(&se->init_rwlock);
+     pthread_mutex_destroy(&se->lock);
+     free(se->cuse_data);
+     if (se->fd != -1) {
+@@ -2610,6 +2627,7 @@ struct fuse_session *fuse_session_new(struct fuse_args *args,
+     list_init_req(&se->list);
+     list_init_req(&se->interrupts);
+     fuse_mutex_init(&se->lock);
++    pthread_rwlock_init(&se->init_rwlock, NULL);
+ 
+     memcpy(&se->op, op, op_size);
+     se->owner = getuid();
diff --git a/0112-virtiofsd-fix-lo_destroy-resource-leaks.patch b/0112-virtiofsd-fix-lo_destroy-resource-leaks.patch
new file mode 100644
index 0000000..20a6143
--- /dev/null
+++ b/0112-virtiofsd-fix-lo_destroy-resource-leaks.patch
@@ -0,0 +1,78 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:02:21 +0000
+Subject: [PATCH] virtiofsd: fix lo_destroy() resource leaks
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Now that lo_destroy() is serialized we can call unref_inode() so that
+all inode resources are freed.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 28f7a3b026f231bfe8de5fed6a18a8d27b1dfcee)
+---
+ tools/virtiofsd/passthrough_ll.c | 41 ++++++++++++++++----------------
+ 1 file changed, 20 insertions(+), 21 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index 79b8b71a4f..eb001b9d1e 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -1371,26 +1371,6 @@ static void unref_inode_lolocked(struct lo_data *lo, struct lo_inode *inode,
+     }
+ }
+ 
+-static int unref_all_inodes_cb(gpointer key, gpointer value, gpointer user_data)
+-{
+-    struct lo_inode *inode = value;
+-    struct lo_data *lo = user_data;
+-
+-    inode->nlookup = 0;
+-    lo_map_remove(&lo->ino_map, inode->fuse_ino);
+-    close(inode->fd);
+-    lo_inode_put(lo, &inode); /* Drop our refcount from lo_do_lookup() */
+-
+-    return TRUE;
+-}
+-
+-static void unref_all_inodes(struct lo_data *lo)
+-{
+-    pthread_mutex_lock(&lo->mutex);
+-    g_hash_table_foreach_remove(lo->inodes, unref_all_inodes_cb, lo);
+-    pthread_mutex_unlock(&lo->mutex);
+-}
+-
+ static void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
+ {
+     struct lo_data *lo = lo_data(req);
+@@ -2477,7 +2457,26 @@ static void lo_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
+ static void lo_destroy(void *userdata)
+ {
+     struct lo_data *lo = (struct lo_data *)userdata;
+-    unref_all_inodes(lo);
++
++    /*
++     * Normally lo->mutex must be taken when traversing lo->inodes but
++     * lo_destroy() is a serialized request so no races are possible here.
++     *
++     * In addition, we cannot acquire lo->mutex since unref_inode() takes it
++     * too and this would result in a recursive lock.
++     */
++    while (true) {
++        GHashTableIter iter;
++        gpointer key, value;
++
++        g_hash_table_iter_init(&iter, lo->inodes);
++        if (!g_hash_table_iter_next(&iter, &key, &value)) {
++            break;
++        }
++
++        struct lo_inode *inode = value;
++        unref_inode_lolocked(lo, inode, inode->nlookup);
++    }
+ }
+ 
+ static struct fuse_lowlevel_ops lo_oper = {
diff --git a/0113-virtiofsd-add-thread-pool-size-NUM-option.patch b/0113-virtiofsd-add-thread-pool-size-NUM-option.patch
new file mode 100644
index 0000000..2cb742c
--- /dev/null
+++ b/0113-virtiofsd-add-thread-pool-size-NUM-option.patch
@@ -0,0 +1,90 @@
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Mon, 27 Jan 2020 19:02:22 +0000
+Subject: [PATCH] virtiofsd: add --thread-pool-size=NUM option
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add an option to control the size of the thread pool.  Requests are now
+processed in parallel by default.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 951b3120dbc971f08681e1d860360e4a1e638902)
+---
+ tools/virtiofsd/fuse_i.h        | 1 +
+ tools/virtiofsd/fuse_lowlevel.c | 7 ++++++-
+ tools/virtiofsd/fuse_virtio.c   | 5 +++--
+ 3 files changed, 10 insertions(+), 3 deletions(-)
+
+diff --git a/tools/virtiofsd/fuse_i.h b/tools/virtiofsd/fuse_i.h
+index 1447d86866..4e47e5880d 100644
+--- a/tools/virtiofsd/fuse_i.h
++++ b/tools/virtiofsd/fuse_i.h
+@@ -72,6 +72,7 @@ struct fuse_session {
+     int   vu_listen_fd;
+     int   vu_socketfd;
+     struct fv_VuDev *virtio_dev;
++    int thread_pool_size;
+ };
+ 
+ struct fuse_chan {
+diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
+index 79a4031266..de2e2e0c65 100644
+--- a/tools/virtiofsd/fuse_lowlevel.c
++++ b/tools/virtiofsd/fuse_lowlevel.c
+@@ -28,6 +28,7 @@
+ #include <sys/file.h>
+ #include <unistd.h>
+ 
++#define THREAD_POOL_SIZE 64
+ 
+ #define OFFSET_MAX 0x7fffffffffffffffLL
+ 
+@@ -2519,6 +2520,7 @@ static const struct fuse_opt fuse_ll_opts[] = {
+     LL_OPTION("allow_root", deny_others, 1),
+     LL_OPTION("--socket-path=%s", vu_socket_path, 0),
+     LL_OPTION("--fd=%d", vu_listen_fd, 0),
++    LL_OPTION("--thread-pool-size=%d", thread_pool_size, 0),
+     FUSE_OPT_END
+ };
+ 
+@@ -2537,7 +2539,9 @@ void fuse_lowlevel_help(void)
+     printf(
+         "    -o allow_root              allow access by root\n"
+         "    --socket-path=PATH         path for the vhost-user socket\n"
+-        "    --fd=FDNUM                 fd number of vhost-user socket\n");
++        "    --fd=FDNUM                 fd number of vhost-user socket\n"
++        "    --thread-pool-size=NUM     thread pool size limit (default %d)\n",
++        THREAD_POOL_SIZE);
+ }
+ 
+ void fuse_session_destroy(struct fuse_session *se)
+@@ -2591,6 +2595,7 @@ struct fuse_session *fuse_session_new(struct fuse_args *args,
+     }
+     se->fd = -1;
+     se->vu_listen_fd = -1;
++    se->thread_pool_size = THREAD_POOL_SIZE;
+     se->conn.max_write = UINT_MAX;
+     se->conn.max_readahead = UINT_MAX;
+ 
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+index 0dcf2ef57a..9f6582343c 100644
+--- a/tools/virtiofsd/fuse_virtio.c
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -572,10 +572,11 @@ static void *fv_queue_thread(void *opaque)
+     struct fv_QueueInfo *qi = opaque;
+     struct VuDev *dev = &qi->virtio_dev->dev;
+     struct VuVirtq *q = vu_get_queue(dev, qi->qidx);
++    struct fuse_session *se = qi->virtio_dev->se;
+     GThreadPool *pool;
+ 
+-    pool = g_thread_pool_new(fv_queue_worker, qi, 1 /* TODO max_threads */,
+-                             TRUE, NULL);
++    pool = g_thread_pool_new(fv_queue_worker, qi, se->thread_pool_size, TRUE,
++                             NULL);
+     if (!pool) {
+         fuse_log(FUSE_LOG_ERR, "%s: g_thread_pool_new failed\n", __func__);
+         return NULL;
diff --git a/0114-virtiofsd-Convert-lo_destroy-to-take-the-lo-mutex-lo.patch b/0114-virtiofsd-Convert-lo_destroy-to-take-the-lo-mutex-lo.patch
new file mode 100644
index 0000000..142429b
--- /dev/null
+++ b/0114-virtiofsd-Convert-lo_destroy-to-take-the-lo-mutex-lo.patch
@@ -0,0 +1,96 @@
+From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
+Date: Mon, 27 Jan 2020 19:02:23 +0000
+Subject: [PATCH] virtiofsd: Convert lo_destroy to take the lo->mutex lock
+ itself
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+lo_destroy was relying on some implicit knowledge of the locking;
+we can avoid this if we create an unref_inode that doesn't take
+the lock and then grab it for the whole of the lo_destroy.
+
+Suggested-by: Vivek Goyal <vgoyal@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit fe4c15798a48143dd6b1f58d2d3cad12206ce211)
+---
+ tools/virtiofsd/passthrough_ll.c | 31 +++++++++++++++++--------------
+ 1 file changed, 17 insertions(+), 14 deletions(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index eb001b9d1e..fc15d61510 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -1344,14 +1344,13 @@ static void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
+     lo_inode_put(lo, &inode);
+ }
+ 
+-static void unref_inode_lolocked(struct lo_data *lo, struct lo_inode *inode,
+-                                 uint64_t n)
++/* To be called with lo->mutex held */
++static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n)
+ {
+     if (!inode) {
+         return;
+     }
+ 
+-    pthread_mutex_lock(&lo->mutex);
+     assert(inode->nlookup >= n);
+     inode->nlookup -= n;
+     if (!inode->nlookup) {
+@@ -1362,15 +1361,24 @@ static void unref_inode_lolocked(struct lo_data *lo, struct lo_inode *inode,
+         }
+         g_hash_table_destroy(inode->posix_locks);
+         pthread_mutex_destroy(&inode->plock_mutex);
+-        pthread_mutex_unlock(&lo->mutex);
+ 
+         /* Drop our refcount from lo_do_lookup() */
+         lo_inode_put(lo, &inode);
+-    } else {
+-        pthread_mutex_unlock(&lo->mutex);
+     }
+ }
+ 
++static void unref_inode_lolocked(struct lo_data *lo, struct lo_inode *inode,
++                                 uint64_t n)
++{
++    if (!inode) {
++        return;
++    }
++
++    pthread_mutex_lock(&lo->mutex);
++    unref_inode(lo, inode, n);
++    pthread_mutex_unlock(&lo->mutex);
++}
++
+ static void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
+ {
+     struct lo_data *lo = lo_data(req);
+@@ -2458,13 +2466,7 @@ static void lo_destroy(void *userdata)
+ {
+     struct lo_data *lo = (struct lo_data *)userdata;
+ 
+-    /*
+-     * Normally lo->mutex must be taken when traversing lo->inodes but
+-     * lo_destroy() is a serialized request so no races are possible here.
+-     *
+-     * In addition, we cannot acquire lo->mutex since unref_inode() takes it
+-     * too and this would result in a recursive lock.
+-     */
++    pthread_mutex_lock(&lo->mutex);
+     while (true) {
+         GHashTableIter iter;
+         gpointer key, value;
+@@ -2475,8 +2477,9 @@ static void lo_destroy(void *userdata)
+         }
+ 
+         struct lo_inode *inode = value;
+-        unref_inode_lolocked(lo, inode, inode->nlookup);
++        unref_inode(lo, inode, inode->nlookup);
+     }
++    pthread_mutex_unlock(&lo->mutex);
+ }
+ 
+ static struct fuse_lowlevel_ops lo_oper = {
diff --git a/0115-virtiofsd-passthrough_ll-Pass-errno-to-fuse_reply_er.patch b/0115-virtiofsd-passthrough_ll-Pass-errno-to-fuse_reply_er.patch
new file mode 100644
index 0000000..91a4062
--- /dev/null
+++ b/0115-virtiofsd-passthrough_ll-Pass-errno-to-fuse_reply_er.patch
@@ -0,0 +1,34 @@
+From: Xiao Yang <yangx.jy@cn.fujitsu.com>
+Date: Mon, 27 Jan 2020 19:02:24 +0000
+Subject: [PATCH] virtiofsd/passthrough_ll: Pass errno to fuse_reply_err()
+
+lo_copy_file_range() passes -errno to fuse_reply_err() and then fuse_reply_err()
+changes it to errno again, so that subsequent fuse_send_reply_iov_nofree() catches
+the wrong errno.(i.e. reports "fuse: bad error value: ...").
+
+Make fuse_send_reply_iov_nofree() accept the correct -errno by passing errno
+directly in lo_copy_file_range().
+
+Signed-off-by: Xiao Yang <yangx.jy@cn.fujitsu.com>
+Reviewed-by: Eryu Guan <eguan@linux.alibaba.com>
+
+dgilbert: Sent upstream and now Merged as aa1185e153f774f1df65
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit a931b6861e59c78d861017e9c6a9c161ff49a163)
+---
+ tools/virtiofsd/passthrough_ll.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
+index fc15d61510..e6f2399efc 100644
+--- a/tools/virtiofsd/passthrough_ll.c
++++ b/tools/virtiofsd/passthrough_ll.c
+@@ -2441,7 +2441,7 @@ static void lo_copy_file_range(fuse_req_t req, fuse_ino_t ino_in, off_t off_in,
+ 
+     res = copy_file_range(in_fd, &off_in, out_fd, &off_out, len, flags);
+     if (res < 0) {
+-        fuse_reply_err(req, -errno);
++        fuse_reply_err(req, errno);
+     } else {
+         fuse_reply_write(req, res);
+     }
diff --git a/0116-virtiofsd-stop-all-queue-threads-on-exit-in-virtio_l.patch b/0116-virtiofsd-stop-all-queue-threads-on-exit-in-virtio_l.patch
new file mode 100644
index 0000000..6769996
--- /dev/null
+++ b/0116-virtiofsd-stop-all-queue-threads-on-exit-in-virtio_l.patch
@@ -0,0 +1,52 @@
+From: Eryu Guan <eguan@linux.alibaba.com>
+Date: Mon, 27 Jan 2020 19:02:25 +0000
+Subject: [PATCH] virtiofsd: stop all queue threads on exit in virtio_loop()
+
+On guest graceful shutdown, virtiofsd receives VHOST_USER_GET_VRING_BASE
+request from VMM and shuts down virtqueues by calling fv_set_started(),
+which joins fv_queue_thread() threads. So when virtio_loop() returns,
+there should be no thread is still accessing data in fuse session and/or
+virtio dev.
+
+But on abnormal exit, e.g. guest got killed for whatever reason,
+vhost-user socket is closed and virtio_loop() breaks out the main loop
+and returns to main(). But it's possible fv_queue_worker()s are still
+working and accessing fuse session and virtio dev, which results in
+crash or use-after-free.
+
+Fix it by stopping fv_queue_thread()s before virtio_loop() returns,
+to make sure there's no-one could access fuse session and virtio dev.
+
+Reported-by: Qingming Su <qingming.su@linux.alibaba.com>
+Signed-off-by: Eryu Guan <eguan@linux.alibaba.com>
+Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 9883df8ccae6d744a0c8d9cbf9d62b1797d70ebd)
+---
+ tools/virtiofsd/fuse_virtio.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
+index 9f6582343c..80a6e929df 100644
+--- a/tools/virtiofsd/fuse_virtio.c
++++ b/tools/virtiofsd/fuse_virtio.c
+@@ -815,6 +815,19 @@ int virtio_loop(struct fuse_session *se)
+         }
+     }
+ 
++    /*
++     * Make sure all fv_queue_thread()s quit on exit, as we're about to
++     * free virtio dev and fuse session, no one should access them anymore.
++     */
++    for (int i = 0; i < se->virtio_dev->nqueues; i++) {
++        if (!se->virtio_dev->qi[i]) {
++            continue;
++        }
++
++        fuse_log(FUSE_LOG_INFO, "%s: Stopping queue %d thread\n", __func__, i);
++        fv_queue_cleanup_thread(se->virtio_dev, i);
++    }
++
+     fuse_log(FUSE_LOG_INFO, "%s: Exit\n", __func__);
+ 
+     return 0;
diff --git a/0117-virtiofsd-add-some-options-to-the-help-message.patch b/0117-virtiofsd-add-some-options-to-the-help-message.patch
new file mode 100644
index 0000000..8fbb062
--- /dev/null
+++ b/0117-virtiofsd-add-some-options-to-the-help-message.patch
@@ -0,0 +1,55 @@
+From: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+Date: Mon, 27 Jan 2020 19:02:26 +0000
+Subject: [PATCH] virtiofsd: add some options to the help message
+
+Add following options to the help message:
+- cache
+- flock|no_flock
+- norace
+- posix_lock|no_posix_lock
+- readdirplus|no_readdirplus
+- timeout
+- writeback|no_writeback
+- xattr|no_xattr
+
+Signed-off-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+
+dgilbert: Split cache, norace, posix_lock, readdirplus off
+  into our own earlier patches that added the options
+
+Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+Reviewed-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
+Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
+(cherry picked from commit 1d59b1b210d7c3b0bdf4b10ebe0bb1fccfcb8b95)
+---
+ tools/virtiofsd/helper.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
+index f98d8f2eb2..0801cf752c 100644
+--- a/tools/virtiofsd/helper.c
++++ b/tools/virtiofsd/helper.c
+@@ -148,6 +148,8 @@ void fuse_cmdline_help(void)
+            "    -o cache=<mode>            cache mode. could be one of \"auto, "
+            "always, none\"\n"
+            "                               default: auto\n"
++           "    -o flock|no_flock          enable/disable flock\n"
++           "                               default: no_flock\n"
+            "    -o log_level=<level>       log level, default to \"info\"\n"
+            "                               level could be one of \"debug, "
+            "info, warn, err\"\n"
+@@ -163,7 +165,13 @@ void fuse_cmdline_help(void)
+            "                               enable/disable readirplus\n"
+            "                               default: readdirplus except with "
+            "cache=none\n"
+-          );
++           "    -o timeout=<number>        I/O timeout (second)\n"
++           "                               default: depends on cache= option.\n"
++           "    -o writeback|no_writeback  enable/disable writeback cache\n"
++           "                               default: no_writeback\n"
++           "    -o xattr|no_xattr          enable/disable xattr\n"
++           "                               default: no_xattr\n"
++           );
+ }
+ 
+ static int fuse_helper_opt_proc(void *data, const char *arg, int key,
diff --git a/qemu.spec b/qemu.spec
index eb965e5..0328d23 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -161,24 +161,13 @@
 Summary: QEMU is a FAST! processor emulator
 Name: qemu
 Version: 4.2.0
-Release: 3%{?rcrel}%{?dist}
+Release: 4%{?rcrel}%{?dist}
 Epoch: 2
 License: GPLv2 and BSD and MIT and CC-BY
 URL: http://www.qemu.org/
 
 Source0: http://wiki.qemu-project.org/download/%{name}-%{version}%{?rcstr}.tar.xz
 
-# Fix a test suite error
-Patch1: 0001-tests-fix-modules-test-duplicate-test-case-error.patch
-
-# Miscellaneous fixes for RISC-V, merged upstream in commit
-# ba2ed84fe6a78f64b2da441750fc6e925d94106a.
-Patch2: 0001-riscv-sifive_u-fix-a-memory-leak-in-soc_realize.patch
-Patch3: 0002-riscv-Set-xPIE-to-1-after-xRET.patch
-Patch4: 0003-target-riscv-Fix-tb-flags-FS-status.patch
-Patch5: 0004-target-riscv-fsd-fsw-doesn-t-dirty-FP-state.patch
-Patch6: 0005-target-riscv-update-mstatus.SD-when-FS-is-set-dirty.patch
-
 # guest agent service
 Source10: qemu-guest-agent.service
 Source17: qemu-ga.sysconfig
@@ -196,6 +185,127 @@ Source20: kvm-x86.modprobe.conf
 # /etc/security/limits.d/95-kvm-ppc64-memlock.conf
 Source21: 95-kvm-ppc64-memlock.conf
 
+# Fix a test suite error
+Patch0001: 0001-tests-fix-modules-test-duplicate-test-case-error.patch
+# Miscellaneous fixes for RISC-V
+Patch0002: 0002-riscv-sifive_u-fix-a-memory-leak-in-soc_realize.patch
+Patch0003: 0003-riscv-Set-xPIE-to-1-after-xRET.patch
+Patch0004: 0004-target-riscv-Fix-tb-flags-FS-status.patch
+Patch0005: 0005-target-riscv-fsd-fsw-doesn-t-dirty-FP-state.patch
+Patch0006: 0006-target-riscv-update-mstatus.SD-when-FS-is-set-dirty.patch
+# virtio-fs support
+Patch0007: 0007-virtio-fs-fix-MSI-X-nvectors-calculation.patch
+Patch0008: 0008-vhost-user-fs-remove-vhostfd-property.patch
+Patch0009: 0009-build-rename-CONFIG_LIBCAP-to-CONFIG_LIBCAP_NG.patch
+Patch0010: 0010-virtiofsd-Pull-in-upstream-headers.patch
+Patch0011: 0011-virtiofsd-Pull-in-kernel-s-fuse.h.patch
+Patch0012: 0012-virtiofsd-Add-auxiliary-.c-s.patch
+Patch0013: 0013-virtiofsd-Add-fuse_lowlevel.c.patch
+Patch0014: 0014-virtiofsd-Add-passthrough_ll.patch
+Patch0015: 0015-virtiofsd-Trim-down-imported-files.patch
+Patch0016: 0016-virtiofsd-Format-imported-files-to-qemu-style.patch
+Patch0017: 0017-virtiofsd-remove-mountpoint-dummy-argument.patch
+Patch0018: 0018-virtiofsd-remove-unused-notify-reply-support.patch
+Patch0019: 0019-virtiofsd-Remove-unused-enum-fuse_buf_copy_flags.patch
+Patch0020: 0020-virtiofsd-Fix-fuse_daemonize-ignored-return-values.patch
+Patch0021: 0021-virtiofsd-Fix-common-header-and-define-for-QEMU-buil.patch
+Patch0022: 0022-virtiofsd-Trim-out-compatibility-code.patch
+Patch0023: 0023-vitriofsd-passthrough_ll-fix-fallocate-ifdefs.patch
+Patch0024: 0024-virtiofsd-Make-fsync-work-even-if-only-inode-is-pass.patch
+Patch0025: 0025-virtiofsd-Add-options-for-virtio.patch
+Patch0026: 0026-virtiofsd-add-o-source-PATH-to-help-output.patch
+Patch0027: 0027-virtiofsd-Open-vhost-connection-instead-of-mounting.patch
+Patch0028: 0028-virtiofsd-Start-wiring-up-vhost-user.patch
+Patch0029: 0029-virtiofsd-Add-main-virtio-loop.patch
+Patch0030: 0030-virtiofsd-get-set-features-callbacks.patch
+Patch0031: 0031-virtiofsd-Start-queue-threads.patch
+Patch0032: 0032-virtiofsd-Poll-kick_fd-for-queue.patch
+Patch0033: 0033-virtiofsd-Start-reading-commands-from-queue.patch
+Patch0034: 0034-virtiofsd-Send-replies-to-messages.patch
+Patch0035: 0035-virtiofsd-Keep-track-of-replies.patch
+Patch0036: 0036-virtiofsd-Add-Makefile-wiring-for-virtiofsd-contrib.patch
+Patch0037: 0037-virtiofsd-Fast-path-for-virtio-read.patch
+Patch0038: 0038-virtiofsd-add-fd-FDNUM-fd-passing-option.patch
+Patch0039: 0039-virtiofsd-make-f-foreground-the-default.patch
+Patch0040: 0040-virtiofsd-add-vhost-user.json-file.patch
+Patch0041: 0041-virtiofsd-add-print-capabilities-option.patch
+Patch0042: 0042-virtiofs-Add-maintainers-entry.patch
+Patch0043: 0043-virtiofsd-passthrough_ll-create-new-files-in-caller-.patch
+Patch0044: 0044-virtiofsd-passthrough_ll-add-lo_map-for-ino-fh-indir.patch
+Patch0045: 0045-virtiofsd-passthrough_ll-add-ino_map-to-hide-lo_inod.patch
+Patch0046: 0046-virtiofsd-passthrough_ll-add-dirp_map-to-hide-lo_dir.patch
+Patch0047: 0047-virtiofsd-passthrough_ll-add-fd_map-to-hide-file-des.patch
+Patch0048: 0048-virtiofsd-passthrough_ll-add-fallback-for-racy-ops.patch
+Patch0049: 0049-virtiofsd-validate-path-components.patch
+Patch0050: 0050-virtiofsd-Plumb-fuse_bufvec-through-to-do_write_buf.patch
+Patch0051: 0051-virtiofsd-Pass-write-iov-s-all-the-way-through.patch
+Patch0052: 0052-virtiofsd-add-fuse_mbuf_iter-API.patch
+Patch0053: 0053-virtiofsd-validate-input-buffer-sizes-in-do_write_bu.patch
+Patch0054: 0054-virtiofsd-check-input-buffer-size-in-fuse_lowlevel.c.patch
+Patch0055: 0055-virtiofsd-prevent-.-escape-in-lo_do_lookup.patch
+Patch0056: 0056-virtiofsd-prevent-.-escape-in-lo_do_readdir.patch
+Patch0057: 0057-virtiofsd-use-proc-self-fd-O_PATH-file-descriptor.patch
+Patch0058: 0058-virtiofsd-sandbox-mount-namespace.patch
+Patch0059: 0059-virtiofsd-move-to-an-empty-network-namespace.patch
+Patch0060: 0060-virtiofsd-move-to-a-new-pid-namespace.patch
+Patch0061: 0061-virtiofsd-add-seccomp-whitelist.patch
+Patch0062: 0062-virtiofsd-Parse-flag-FUSE_WRITE_KILL_PRIV.patch
+Patch0063: 0063-virtiofsd-cap-ng-helpers.patch
+Patch0064: 0064-virtiofsd-Drop-CAP_FSETID-if-client-asked-for-it.patch
+Patch0065: 0065-virtiofsd-set-maximum-RLIMIT_NOFILE-limit.patch
+Patch0066: 0066-virtiofsd-fix-libfuse-information-leaks.patch
+Patch0067: 0067-virtiofsd-add-syslog-command-line-option.patch
+Patch0068: 0068-virtiofsd-print-log-only-when-priority-is-high-enoug.patch
+Patch0069: 0069-virtiofsd-Add-ID-to-the-log-with-FUSE_LOG_DEBUG-leve.patch
+Patch0070: 0070-virtiofsd-Add-timestamp-to-the-log-with-FUSE_LOG_DEB.patch
+Patch0071: 0071-virtiofsd-Handle-reinit.patch
+Patch0072: 0072-virtiofsd-Handle-hard-reboot.patch
+Patch0073: 0073-virtiofsd-Kill-threads-when-queues-are-stopped.patch
+Patch0074: 0074-vhost-user-Print-unexpected-slave-message-types.patch
+Patch0075: 0075-contrib-libvhost-user-Protect-slave-fd-with-mutex.patch
+Patch0076: 0076-virtiofsd-passthrough_ll-add-renameat2-support.patch
+Patch0077: 0077-virtiofsd-passthrough_ll-disable-readdirplus-on-cach.patch
+Patch0078: 0078-virtiofsd-passthrough_ll-control-readdirplus.patch
+Patch0079: 0079-virtiofsd-rename-unref_inode-to-unref_inode_lolocked.patch
+Patch0080: 0080-virtiofsd-fail-when-parent-inode-isn-t-known-in-lo_d.patch
+Patch0081: 0081-virtiofsd-extract-root-inode-init-into-setup_root.patch
+Patch0082: 0082-virtiofsd-passthrough_ll-clean-up-cache-related-opti.patch
+Patch0083: 0083-virtiofsd-passthrough_ll-use-hashtable.patch
+Patch0084: 0084-virtiofsd-Clean-up-inodes-on-destroy.patch
+Patch0085: 0085-virtiofsd-support-nanosecond-resolution-for-file-tim.patch
+Patch0086: 0086-virtiofsd-fix-error-handling-in-main.patch
+Patch0087: 0087-virtiofsd-cleanup-allocated-resource-in-se.patch
+Patch0088: 0088-virtiofsd-fix-memory-leak-on-lo.source.patch
+Patch0089: 0089-virtiofsd-add-helper-for-lo_data-cleanup.patch
+Patch0090: 0090-virtiofsd-Prevent-multiply-running-with-same-vhost_u.patch
+Patch0091: 0091-virtiofsd-enable-PARALLEL_DIROPS-during-INIT.patch
+Patch0092: 0092-virtiofsd-fix-incorrect-error-handling-in-lo_do_look.patch
+Patch0093: 0093-Virtiofsd-fix-memory-leak-on-fuse-queueinfo.patch
+Patch0094: 0094-virtiofsd-Support-remote-posix-locks.patch
+Patch0095: 0095-virtiofsd-use-fuse_lowlevel_is_virtio-in-fuse_sessio.patch
+Patch0096: 0096-virtiofsd-prevent-fv_queue_thread-vs-virtio_loop-rac.patch
+Patch0097: 0097-virtiofsd-make-lo_release-atomic.patch
+Patch0098: 0098-virtiofsd-prevent-races-with-lo_dirp_put.patch
+Patch0099: 0099-virtiofsd-rename-inode-refcount-to-inode-nlookup.patch
+Patch0100: 0100-libvhost-user-Fix-some-memtable-remap-cases.patch
+Patch0101: 0101-virtiofsd-passthrough_ll-fix-refcounting-on-remove-r.patch
+Patch0102: 0102-virtiofsd-introduce-inode-refcount-to-prevent-use-af.patch
+Patch0103: 0103-virtiofsd-do-not-always-set-FUSE_FLOCK_LOCKS.patch
+Patch0104: 0104-virtiofsd-convert-more-fprintf-and-perror-to-use-fus.patch
+Patch0105: 0105-virtiofsd-Reset-O_DIRECT-flag-during-file-open.patch
+Patch0106: 0106-virtiofsd-Fix-data-corruption-with-O_APPEND-write-in.patch
+Patch0107: 0107-virtiofsd-passthrough_ll-Use-cache_readdir-for-direc.patch
+Patch0108: 0108-virtiofsd-add-definition-of-fuse_buf_writev.patch
+Patch0109: 0109-virtiofsd-use-fuse_buf_writev-to-replace-fuse_buf_wr.patch
+Patch0110: 0110-virtiofsd-process-requests-in-a-thread-pool.patch
+Patch0111: 0111-virtiofsd-prevent-FUSE_INIT-FUSE_DESTROY-races.patch
+Patch0112: 0112-virtiofsd-fix-lo_destroy-resource-leaks.patch
+Patch0113: 0113-virtiofsd-add-thread-pool-size-NUM-option.patch
+Patch0114: 0114-virtiofsd-Convert-lo_destroy-to-take-the-lo-mutex-lo.patch
+Patch0115: 0115-virtiofsd-passthrough_ll-Pass-errno-to-fuse_reply_er.patch
+Patch0116: 0116-virtiofsd-stop-all-queue-threads-on-exit-in-virtio_l.patch
+Patch0117: 0117-virtiofsd-add-some-options-to-the-help-message.patch
+
 
 # documentation deps
 BuildRequires: texinfo
@@ -1442,6 +1552,7 @@ getent passwd qemu >/dev/null || \
 %{_datadir}/%{name}/pxe-vmxnet3.rom
 %{_datadir}/%{name}/efi-vmxnet3.rom
 %{_datadir}/%{name}/vhost-user/50-qemu-gpu.json
+%{_datadir}/%{name}/vhost-user/50-qemu-virtiofsd.json
 %{_mandir}/man1/qemu.1*
 %{_mandir}/man1/qemu-trace-stap.1*
 %{_mandir}/man1/virtfs-proxy-helper.1*
@@ -1459,6 +1570,7 @@ getent passwd qemu >/dev/null || \
 %{_unitdir}/qemu-pr-helper.socket
 %attr(4755, root, root) %{_libexecdir}/qemu-bridge-helper
 %{_libexecdir}/vhost-user-gpu
+%{_libexecdir}/virtiofsd
 %config(noreplace) %{_sysconfdir}/sasl2/qemu.conf
 %dir %{_sysconfdir}/qemu
 %config(noreplace) %{_sysconfdir}/qemu/bridge.conf
@@ -1895,7 +2007,10 @@ getent passwd qemu >/dev/null || \
 
 
 %changelog
-* Sat Jan 25 2019 Mohan Boddu <mboddu@bhujji.com> - 4.2.0-3
+* Tue Jan 28 2020 Cole Robinson <crobinso@redhat.com> - 2:4.2.0-4
+- virtio-fs support
+
+* Sat Jan 25 2020 Richard W.M. Jones <rjones@redhat.com> - 4.2.0-3
 - Add miscellaneous fixes for RISC-V (RHBZ#1794902).
 
 * Thu Dec 19 2019 Mohan Boddu <mboddu@bhujji.com> - 4.2.0-2