887953
From fc4bebd605b6a579a4d19c6640aca38057397c77 Mon Sep 17 00:00:00 2001
887953
From: Csaba Henk <csaba@redhat.com>
887953
Date: Tue, 21 Aug 2018 12:44:54 +0200
887953
Subject: [PATCH 527/529] fuse: diagnostic FLUSH interrupt
887953
887953
We add dummy interrupt handling for the FLUSH
887953
fuse message. It can be enabled by the
887953
"--fuse-flush-handle-interrupt" hidden command line
887953
option, or "-ofuse-flush-handle-interrupt=yes"
887953
mount option.
887953
887953
It serves no other than diagnostic & demonstational
887953
purposes -- to exercise the interrupt handling framework
887953
a bit and to give an usage example.
887953
887953
Documentation is also provided that showcases interrupt
887953
handling via FLUSH.
887953
887953
Upstream: https://review.gluster.org/20876
887953
> Change-Id: I522f1e798501d06b74ac3592a5f73c1ab0590c60
887953
> updates: #465
887953
> Signed-off-by: Csaba Henk <csaba@redhat.com>
887953
887953
Change-Id: I510aff8895a3fe5858ab313c47514de7087d08c1
887953
BUG: 1595246
887953
Signed-off-by: Csaba Henk <csaba@redhat.com>
887953
Reviewed-on: https://code.engineering.redhat.com/gerrit/162550
887953
Tested-by: RHGS Build Bot <nigelb@redhat.com>
887953
Reviewed-by: Amar Tumballi Suryanarayan <amarts@redhat.com>
887953
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
887953
---
887953
 doc/developer-guide/Developers-Index.md     |   5 ++
887953
 doc/developer-guide/fuse-interrupt.md       | 130 ++++++++++++++++++++++++++++
887953
 glusterfsd/src/glusterfsd.c                 |  53 +++++++++++-
887953
 glusterfsd/src/glusterfsd.h                 |   1 +
887953
 libglusterfs/src/glusterfs.h                |   2 +
887953
 tests/features/interrupt.t                  |  67 ++++++++++++++
887953
 tests/features/open_and_sleep.c             |  27 ++++++
887953
 xlators/mount/fuse/src/fuse-bridge.c        |  59 +++++++++++++
887953
 xlators/mount/fuse/src/fuse-bridge.h        |   4 +-
887953
 xlators/mount/fuse/utils/mount.glusterfs.in |   7 ++
887953
 10 files changed, 353 insertions(+), 2 deletions(-)
887953
 create mode 100644 doc/developer-guide/fuse-interrupt.md
887953
 create mode 100644 tests/features/interrupt.t
887953
 create mode 100644 tests/features/open_and_sleep.c
887953
887953
diff --git a/doc/developer-guide/Developers-Index.md b/doc/developer-guide/Developers-Index.md
887953
index 4c6346e..6c00a4a 100644
887953
--- a/doc/developer-guide/Developers-Index.md
887953
+++ b/doc/developer-guide/Developers-Index.md
887953
@@ -59,6 +59,11 @@ Translators
887953
 -   [Storage/posix Translator](./posix.md)
887953
 -   [Compression translator](./network_compression.md)
887953
 
887953
+Fuse
887953
+----
887953
+
887953
+-   [Interrupt handling](./fuse-interrupt.md)
887953
+
887953
 Testing/Debugging
887953
 -----------------
887953
 
887953
diff --git a/doc/developer-guide/fuse-interrupt.md b/doc/developer-guide/fuse-interrupt.md
887953
new file mode 100644
887953
index 0000000..f92b553
887953
--- /dev/null
887953
+++ b/doc/developer-guide/fuse-interrupt.md
887953
@@ -0,0 +1,130 @@
887953
+# Fuse interrupt handling
887953
+
887953
+## Conventions followed
887953
+
887953
+- *FUSE* refers to the "wire protocol" between kernel and userspace and
887953
+  related specifications.
887953
+- *fuse* refers to the kernel subsystem and also to the GlusterFs translator.
887953
+
887953
+## FUSE interrupt handling spec
887953
+
887953
+The [Linux kernel FUSE documentation](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/filesystems/fuse.txt?h=v4.18#n148)
887953
+desrcibes how interrupt handling happens in fuse.
887953
+
887953
+## Interrupt handling in the fuse translator
887953
+
887953
+### Declarations
887953
+
887953
+This document describes the internal API in the fuse translator with which
887953
+interrupt can be handled.
887953
+
887953
+The API being internal (to be used only in fuse-bridge.c; the functions are
887953
+not exported to a header file).
887953
+
887953
+```
887953
+enum fuse_interrupt_state {
887953
+    INTERRUPT_NONE,
887953
+    INTERRUPT_SQUELCHED,
887953
+    INTERRUPT_HANDLED,
887953
+};
887953
+typedef enum fuse_interrupt_state fuse_interrupt_state_t;
887953
+struct fuse_interrupt_record;
887953
+typedef struct fuse_interrupt_record fuse_interrupt_record_t;
887953
+typedef void (*fuse_interrupt_handler_t)(xlator_t *this,
887953
+                                         fuse_interrupt_record_t *);
887953
+struct fuse_interrupt_record {
887953
+    fuse_in_header_t fuse_in_header;
887953
+    void *data;
887953
+    /*
887953
+       ...
887953
+     */
887953
+};
887953
+
887953
+fuse_interrupt_record_t *
887953
+fuse_interrupt_record_new(fuse_in_header_t *finh,
887953
+                          fuse_interrupt_handler_t handler);
887953
+
887953
+void
887953
+fuse_interrupt_record_insert(xlator_t *this, fuse_interrupt_record_t *fir);
887953
+
887953
+gf_boolean_t
887953
+fuse_interrupt_finish_fop(call_frame_t *frame, xlator_t *this,
887953
+                          gf_boolean_t sync, void **datap);
887953
+
887953
+void
887953
+fuse_interrupt_finish_interrupt(xlator_t *this, fuse_interrupt_record_t *fir,
887953
+                                fuse_interrupt_state_t intstat,
887953
+                                gf_boolean_t sync, void **datap);
887953
+```
887953
+
887953
+The code demonstrates the usage of the API through `fuse_flush()`. (It's a
887953
+dummy implementation only for demonstration purposes.) Flush is chosen
887953
+because a `FLUSH` interrupt is easy to trigger (see
887953
+*tests/features/interrupt.t*). Interrupt handling for flush is switched on
887953
+by `--fuse-flush-handle-interrupt` (a hidden glusterfs command line flag).
887953
+The flush interrupt handling code is guarded by the
887953
+`flush_handle_interrupt` Boolean member of `fuse_private_t`.
887953
+
887953
+### Usage
887953
+
887953
+A given FUSE fop can be enabled to handle interrupts via the following
887953
+steps:
887953
+
887953
+- Define a handler function (of type `fuse_interrupt_handler_t`).
887953
+  It should implement the interrupt handling logic and in the end
887953
+  call (directly or as async callback) `fuse_interrupt_finish_interrupt()`.
887953
+  The `intstat` argument to `fuse_interrupt_finish_interrupt` should be
887953
+  either `INTERRUPT_SQUELCHED` or `INTERRUPT_HANDLED`.
887953
+    - `INTERRUPT_SQUELCHED` means that we choose not to handle the interrupt
887953
+      and the fop is going on uninterrupted.
887953
+    - `INTERRUPT_HANDLED` means that the interrupt was actually handled. In
887953
+      this case the fop will be answered from interrupt context with errno
887953
+      `EINTR` (that is, the fop should not send a response to the kernel).
887953
+
887953
+  We return to the `sync` and `datap` arguments later.
887953
+- In the `fuse_<FOP>` function create an interrupt record using
887953
+  `fuse_interrupt_record_new()`, passing the incoming `fuse_in_header` and
887953
+  the above handler function to it.
887953
+    - Arbitrary further data can be referred to via the `data` member of the
887953
+      interrupt record that is to be passed on from fop context to
887953
+      interrupt context.
887953
+- When it's set up, pass the interrupt record to
887953
+  `fuse_interrupt_record_insert()`.
887953
+- In `fuse_<FOP>_cbk` call `fuse_interrupt_finish_fop()`.
887953
+    - `fuse_interrupt_finish_fop()` returns a Boolean according to whether the
887953
+      interrupt was handled. If it was, then the fuse request is already
887953
+      answered and the stack gets destroyed in `fuse_interrupt_finish_fop` so
887953
+      `fuse_<FOP>_cbk` can just return (zero). Otherwise follow the standard
887953
+      cbk logic (answer the fuse request and destroy the stack -- these are
887953
+      typically accomplished by `fuse_err_cbk()`).
887953
+- The last two argument of `fuse_interrupt_finish_fop()` and
887953
+  `fuse_interrupt_finish_interrupt()` are `gf_boolean_t sync` and
887953
+  `void **datap`.
887953
+    - `sync` represents the strategy for freeing the interrupt record. The
887953
+      interrupt handler and the fop handler are in race to get at the interrupt
887953
+      record first (interrupt handler for purposes of doing the interrupt
887953
+      handling, fop handler for purposes of deactivating the interrupt record
887953
+      upon completion of the fop handling).
887953
+        - If `sync` is true, then the fop handler will wait for the interrupt
887953
+          handler to finish and it takes care of freeing.
887953
+        - If `sync` is false, the loser of the above race will perform freeing.
887953
+
887953
+      Freeing is done within the respective interrupt finish routines, except
887953
+      for the `data` field of the interrupt record; with respect to that, see
887953
+      the discussion of the `datap` parameter below. The strategy has to be
887953
+      consensual, that is, `fuse_interrupt_finish_fop()` and
887953
+      `fuse_interrupt_finish_interrupt()` must pass the same value for `sync`.
887953
+      If dismantling the resources associated with the interrupt record is
887953
+      simple, `sync = _gf_false` is the suggested choice; `sync = _gf_true` can
887953
+      be useful in the opposite case, when dismantling those resources would
887953
+      be inconvenient to implement in two places or to enact in non-fop context.
887953
+    - If `datap` is `NULL`, the `data` member of the interrupt record will be
887953
+      freed within the interrupt finish routine.  If it points to a valid
887953
+      `void *` pointer, and if caller is doing the cleanup (see `sync` above),
887953
+      then that pointer will be directed to the `data` member of the interrupt
887953
+      record and it's up to the caller what it's doing with it.
887953
+        - If `sync` is true, interrupt handler can use `datap = NULL`, and
887953
+          fop handler will have `datap` set.
887953
+        - If `sync` is false, and handlers pass a pointer to a pointer for
887953
+          `datap`, they should check if the pointed pointer is NULL before
887953
+          attempting to deal with the data.
887953
diff --git a/glusterfsd/src/glusterfsd.c b/glusterfsd/src/glusterfsd.c
887953
index 2e2cd77..9c536cd 100644
887953
--- a/glusterfsd/src/glusterfsd.c
887953
+++ b/glusterfsd/src/glusterfsd.c
887953
@@ -243,6 +243,9 @@ static struct argp_option gf_options[] = {
887953
          OPTION_ARG_OPTIONAL, "disable/enable fuse event-history"},
887953
         {"reader-thread-count", ARGP_READER_THREAD_COUNT_KEY, "INTEGER",
887953
          OPTION_ARG_OPTIONAL, "set fuse reader thread count"},
887953
+        {"fuse-flush-handle-interrupt", ARGP_FUSE_FLUSH_HANDLE_INTERRUPT_KEY,
887953
+         "BOOL", OPTION_ARG_OPTIONAL | OPTION_HIDDEN,
887953
+         "handle interrupt in fuse FLUSH handler"},
887953
         {0, 0, 0, 0, "Miscellaneous Options:"},
887953
         {0, }
887953
 };
887953
@@ -581,6 +584,38 @@ set_fuse_mount_options (glusterfs_ctx_t *ctx, dict_t *options)
887953
                         goto err;
887953
                 }
887953
         }
887953
+        switch (cmd_args->fuse_flush_handle_interrupt) {
887953
+                case GF_OPTION_ENABLE:
887953
+                        ret = dict_set_static_ptr (options,
887953
+                                                   "flush-handle-interrupt",
887953
+                                                   "on");
887953
+                        if (ret < 0) {
887953
+                                gf_msg ("glusterfsd", GF_LOG_ERROR, 0,
887953
+                                        glusterfsd_msg_4,
887953
+                                        "failed to set dict value for key "
887953
+                                        "flush-handle-interrupt");
887953
+                                goto err;
887953
+                        }
887953
+                        break;
887953
+                case GF_OPTION_DISABLE:
887953
+                        ret = dict_set_static_ptr (options,
887953
+                                                   "flush-handle-interrupt",
887953
+                                                   "off");
887953
+                        if (ret < 0) {
887953
+                                gf_msg ("glusterfsd", GF_LOG_ERROR, 0,
887953
+                                        glusterfsd_msg_4,
887953
+                                        "failed to set dict value for key "
887953
+                                         "flush-handle-interrupt");
887953
+                                goto err;
887953
+                        }
887953
+                        break;
887953
+                case GF_OPTION_DEFERRED: /* default */
887953
+                default:
887953
+                        gf_msg_debug ("glusterfsd", 0,
887953
+                                      "fuse-flush-handle-interrupt mode %d",
887953
+                                      cmd_args->fuse_flush_handle_interrupt);
887953
+                        break;
887953
+        }
887953
 
887953
         ret = 0;
887953
 err:
887953
@@ -1352,7 +1387,22 @@ no_oom_api:
887953
                 }
887953
 
887953
                 break;
887953
-	}
887953
+        case ARGP_FUSE_FLUSH_HANDLE_INTERRUPT_KEY:
887953
+                if (!arg)
887953
+                        arg = "yes";
887953
+
887953
+                if (gf_string2boolean(arg, &b) == 0) {
887953
+                        cmd_args->fuse_flush_handle_interrupt = b;
887953
+
887953
+                        break;
887953
+                }
887953
+
887953
+                argp_failure(state, -1, 0,
887953
+                             "unknown fuse flush handle interrupt "
887953
+                             "setting \"%s\"",
887953
+                             arg);
887953
+                break;
887953
+        }
887953
 
887953
         return 0;
887953
 }
887953
@@ -1648,6 +1698,7 @@ glusterfs_ctx_defaults_init (glusterfs_ctx_t *ctx)
887953
         cmd_args->fuse_attribute_timeout = -1;
887953
         cmd_args->fuse_entry_timeout = -1;
887953
 	cmd_args->fopen_keep_cache = GF_OPTION_DEFERRED;
887953
+        cmd_args->fuse_flush_handle_interrupt = GF_OPTION_DEFERRED;
887953
 
887953
         if (ctx->mem_acct_enable)
887953
                 cmd_args->mem_acct = 1;
887953
diff --git a/glusterfsd/src/glusterfsd.h b/glusterfsd/src/glusterfsd.h
887953
index 1550a30..28b514a 100644
887953
--- a/glusterfsd/src/glusterfsd.h
887953
+++ b/glusterfsd/src/glusterfsd.h
887953
@@ -101,6 +101,7 @@ enum argp_option_keys {
887953
         ARGP_FUSE_EVENT_HISTORY_KEY       = 179,
887953
         ARGP_READER_THREAD_COUNT_KEY      = 180,
887953
         ARGP_FUSE_LRU_LIMIT_KEY           = 190,
887953
+        ARGP_FUSE_FLUSH_HANDLE_INTERRUPT_KEY = 191,
887953
 };
887953
 
887953
 struct _gfd_vol_top_priv {
887953
diff --git a/libglusterfs/src/glusterfs.h b/libglusterfs/src/glusterfs.h
887953
index 2690306..9fa066e 100644
887953
--- a/libglusterfs/src/glusterfs.h
887953
+++ b/libglusterfs/src/glusterfs.h
887953
@@ -448,6 +448,8 @@ struct _cmd_args {
887953
 
887953
         char              *event_history;
887953
         uint32_t           reader_thread_count;
887953
+
887953
+        int fuse_flush_handle_interrupt;
887953
 };
887953
 typedef struct _cmd_args cmd_args_t;
887953
 
887953
diff --git a/tests/features/interrupt.t b/tests/features/interrupt.t
887953
new file mode 100644
887953
index 0000000..476d875
887953
--- /dev/null
887953
+++ b/tests/features/interrupt.t
887953
@@ -0,0 +1,67 @@
887953
+#!/bin/bash
887953
+
887953
+##Copy this file to tests/bugs before running run.sh (cp extras/test/bug-920583.t tests/bugs/)
887953
+
887953
+. $(dirname $0)/../include.rc
887953
+. $(dirname $0)/../volume.rc
887953
+
887953
+TESTS_EXPECTED_IN_LOOP=4
887953
+
887953
+cleanup;
887953
+logdir=`gluster --print-logdir`
887953
+
887953
+TEST build_tester $(dirname $0)/open_and_sleep.c
887953
+
887953
+## Start and create a volume
887953
+TEST glusterd;
887953
+TEST pidof glusterd;
887953
+
887953
+TEST $CLI volume create $V0 replica 2 stripe 2 $H0:$B0/${V0}{1,2,3,4,5,6,7,8};
887953
+
887953
+## Verify volume is is created
887953
+EXPECT "$V0" volinfo_field $V0 'Volume Name';
887953
+EXPECT 'Created' volinfo_field $V0 'Status';
887953
+
887953
+## Start volume and verify
887953
+TEST $CLI volume start $V0;
887953
+EXPECT 'Started' volinfo_field $V0 'Status';
887953
+
887953
+function log-file-name()
887953
+{
887953
+    logfilename=$M0".log"
887953
+    echo ${logfilename:1} | tr / -
887953
+}
887953
+
887953
+log_file=$logdir"/"`log-file-name`
887953
+
887953
+function test_interrupt {
887953
+        local handlebool="$1"
887953
+        local logpattern="$2"
887953
+
887953
+        TEST $GFS --volfile-id=$V0 --volfile-server=$H0 --fuse-flush-handle-interrupt=$handlebool --log-level=DEBUG $M0
887953
+
887953
+        # If the test helper fails (which is considered a setup error, not failure of the test
887953
+        # case itself), kill will be invoked without argument, and that will be the actual
887953
+        # error which is caught.
887953
+        TEST "./$(dirname $0)/open_and_sleep $M0/testfile | { sleep 0.1; xargs -n1 kill -INT; }"
887953
+
887953
+        TEST "grep -E '$logpattern' $log_file"
887953
+        # Basic sanity check, making sure filesystem has not crashed.
887953
+        TEST test -f $M0/testfile
887953
+}
887953
+
887953
+# Theoretically FLUSH might finish before INTERRUPT is handled,
887953
+# in which case we'd get the "no handler found" message (but it's unlikely).
887953
+test_interrupt yes 'FLUSH.*interrupt handler triggered|INTERRUPT.*no handler found'
887953
+EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0
887953
+test_interrupt no 'INTERRUPT.*no handler found'
887953
+
887953
+## Finish up
887953
+TEST $CLI volume stop $V0;
887953
+EXPECT 'Stopped' volinfo_field $V0 'Status';
887953
+
887953
+TEST $CLI volume delete $V0;
887953
+TEST ! $CLI volume info $V0;
887953
+
887953
+cleanup_tester $(dirname $0)/open_and_sleep;
887953
+cleanup;
887953
diff --git a/tests/features/open_and_sleep.c b/tests/features/open_and_sleep.c
887953
new file mode 100644
887953
index 0000000..da089e9
887953
--- /dev/null
887953
+++ b/tests/features/open_and_sleep.c
887953
@@ -0,0 +1,27 @@
887953
+#include <unistd.h>
887953
+#include <stdio.h>
887953
+#include <fcntl.h>
887953
+
887953
+int
887953
+main (int argc, char **argv)
887953
+{
887953
+        pid_t pid;
887953
+        int fd;
887953
+
887953
+        if (argc >= 2) {
887953
+                fd = open (argv[1], O_RDWR | O_CREAT, 0644);
887953
+                if (fd == -1) {
887953
+                        fprintf (stderr, "cannot open/create %s\n", argv[1]);
887953
+                        return 1;
887953
+                }
887953
+        }
887953
+
887953
+        pid = getpid ();
887953
+        printf ("%d\n", pid);
887953
+        fflush (stdout);
887953
+
887953
+        for (;;)
887953
+                sleep (1);
887953
+
887953
+        return 0;
887953
+}
887953
diff --git a/xlators/mount/fuse/src/fuse-bridge.c b/xlators/mount/fuse/src/fuse-bridge.c
887953
index 0d4b9db..44c39e4 100644
887953
--- a/xlators/mount/fuse/src/fuse-bridge.c
887953
+++ b/xlators/mount/fuse/src/fuse-bridge.c
887953
@@ -1779,6 +1779,21 @@ fuse_err_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
887953
 }
887953
 
887953
 static int
887953
+fuse_flush_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
887953
+                           int32_t op_ret, int32_t op_errno, dict_t *xdata)
887953
+{
887953
+        fuse_private_t *priv = this->private;
887953
+
887953
+        if (priv->flush_handle_interrupt) {
887953
+                if (fuse_interrupt_finish_fop (frame, this, _gf_false, NULL)) {
887953
+                        return 0;
887953
+                }
887953
+        }
887953
+
887953
+        return fuse_err_cbk (frame, cookie, this, op_ret, op_errno, xdata);
887953
+}
887953
+
887953
+static int
887953
 fuse_fsync_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
887953
                 int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
887953
                 struct iatt *postbuf, dict_t *xdata)
887953
@@ -2961,6 +2976,19 @@ fuse_flush_resume (fuse_state_t *state)
887953
 {
887953
         FUSE_FOP (state, fuse_err_cbk, GF_FOP_FLUSH,
887953
                   flush, state->fd, state->xdata);
887953
+        FUSE_FOP (state, fuse_flush_cbk, GF_FOP_FLUSH,
887953
+                  flush, state->fd, state->xdata);
887953
+}
887953
+
887953
+static void
887953
+fuse_flush_interrupt_handler (xlator_t *this, fuse_interrupt_record_t *fir)
887953
+{
887953
+        gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
887953
+                "FLUSH unique %" PRIu64 ": interrupt handler triggered",
887953
+                fir->fuse_in_header.unique);
887953
+
887953
+        fuse_interrupt_finish_interrupt (this, fir, INTERRUPT_HANDLED,
887953
+                                         _gf_false, NULL);
887953
 }
887953
 
887953
 static void
887953
@@ -2968,6 +2996,7 @@ fuse_flush (xlator_t *this, fuse_in_header_t *finh, void *msg,
887953
             struct iobuf *iobuf)
887953
 {
887953
         struct fuse_flush_in *ffi = msg;
887953
+        fuse_private_t *priv = NULL;
887953
 
887953
         fuse_state_t *state = NULL;
887953
         fd_t         *fd = NULL;
887953
@@ -2976,6 +3005,27 @@ fuse_flush (xlator_t *this, fuse_in_header_t *finh, void *msg,
887953
         fd = FH_TO_FD (ffi->fh);
887953
         state->fd = fd;
887953
 
887953
+        priv = this->private;
887953
+        if (priv->flush_handle_interrupt) {
887953
+                fuse_interrupt_record_t *fir = NULL;
887953
+
887953
+                fir = fuse_interrupt_record_new (finh,
887953
+                                                 fuse_flush_interrupt_handler);
887953
+                if (!fir) {
887953
+                        send_fuse_err (this, finh, ENOMEM);
887953
+
887953
+                        gf_log ("glusterfs-fuse", GF_LOG_ERROR,
887953
+                                "FLUSH unique %" PRIu64
887953
+                                ":"
887953
+                                " interrupt record allocation failed",
887953
+                                finh->unique);
887953
+                        free_fuse_state (state);
887953
+
887953
+                        return;
887953
+                }
887953
+                fuse_interrupt_record_insert (this, fir);
887953
+        }
887953
+
887953
         fuse_resolve_fd_init (state, &state->resolve, fd);
887953
 
887953
         state->lk_owner = ffi->lock_owner;
887953
@@ -6226,6 +6276,9 @@ init (xlator_t *this_xl)
887953
         GF_OPTION_INIT("event-history", priv->event_history, bool,
887953
                        cleanup_exit);
887953
 
887953
+        GF_OPTION_INIT ("flush-handle-interrupt", priv->flush_handle_interrupt, bool,
887953
+                                   cleanup_exit);
887953
+
887953
         /* user has set only background-qlen, not congestion-threshold,
887953
            use the fuse kernel driver formula to set congestion. ie, 75% */
887953
         if (dict_get (this_xl->options, "background-qlen") &&
887953
@@ -6552,5 +6605,11 @@ struct volume_options options[] = {
887953
          .description = "makes glusterfs invalidate kernel inodes after "
887953
          "reaching this limit (0 means 'unlimited')",
887953
         },
887953
+        { .key = {"flush-handle-interrupt"},
887953
+          .type = GF_OPTION_TYPE_BOOL,
887953
+          .default_value = "false",
887953
+          .description = "Handle iterrupts in FLUSH handler (for testing "
887953
+          "purposes).",
887953
+        },
887953
         { .key = {NULL} },
887953
 };
887953
diff --git a/xlators/mount/fuse/src/fuse-bridge.h b/xlators/mount/fuse/src/fuse-bridge.h
887953
index ba3e000..e18469d 100644
887953
--- a/xlators/mount/fuse/src/fuse-bridge.h
887953
+++ b/xlators/mount/fuse/src/fuse-bridge.h
887953
@@ -157,6 +157,8 @@ struct fuse_private {
887953
         /* Interrupt subscription */
887953
         struct list_head interrupt_list;
887953
         pthread_mutex_t interrupt_mutex;
887953
+
887953
+        gf_boolean_t flush_handle_interrupt;
887953
 };
887953
 typedef struct fuse_private fuse_private_t;
887953
 
887953
@@ -191,7 +193,7 @@ typedef struct fuse_interrupt_record fuse_interrupt_record_t;
887953
 typedef void (*fuse_interrupt_handler_t) (xlator_t *this,
887953
                                           fuse_interrupt_record_t *);
887953
 struct fuse_interrupt_record {
887953
-        struct fuse_in_header fuse_in_header;
887953
+        fuse_in_header_t fuse_in_header;
887953
         void *data;
887953
         gf_boolean_t hit;
887953
         fuse_interrupt_state_t interrupt_state;
887953
diff --git a/xlators/mount/fuse/utils/mount.glusterfs.in b/xlators/mount/fuse/utils/mount.glusterfs.in
887953
index 9a0404f..a3a9fbd 100755
887953
--- a/xlators/mount/fuse/utils/mount.glusterfs.in
887953
+++ b/xlators/mount/fuse/utils/mount.glusterfs.in
887953
@@ -273,6 +273,10 @@ start_glusterfs ()
887953
         cmd_line=$(echo "$cmd_line --dump-fuse=$dump_fuse");
887953
     fi
887953
 
887953
+    if [ -n "$fuse_flush_handle_interrupt" ]; then
887953
+        cmd_line=$(echo "$cmd_line --fuse-flush-handle-interrupt=$fuse_flush_handle_interrupt");
887953
+    fi
887953
+
887953
     # if trasnport type is specified, we have to append it to
887953
     # volume name, so that it fetches the right client vol file
887953
 
887953
@@ -524,6 +528,9 @@ with_options()
887953
                 [ $value = "false" ] ; then
887953
                 no_root_squash=1;
887953
             fi ;;
887953
+        "fuse-flush-handle-interrupt")
887953
+            fuse_flush_handle_interrupt=$value
887953
+            ;;
887953
         "context"|"fscontext"|"defcontext"|"rootcontext")
887953
             # standard SElinux mount options to pass to the kernel
887953
             [ -z "$fuse_mountopts" ] || fuse_mountopts="$fuse_mountopts,"
887953
-- 
887953
1.8.3.1
887953