|
|
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 |
|