From 5f2e017ce7875de1906eb319339f11c4ef321208 Mon Sep 17 00:00:00 2001 From: Csaba Henk Date: Mon, 22 Oct 2018 00:59:05 +0200 Subject: [PATCH 529/529] fuse: SETLKW interrupt Use the (f)getxattr based clearlocks interface to interrupt a pending lock request. Upstream: https://review.gluster.org/21472 > updates: #465 > Change-Id: I4e91a4d8791fc688fed400a02de4c53487e61be2 > Signed-off-by: Csaba Henk Change-Id: Ib436f1524cda6ade24c6970caee3dbd7d5f452d4 BUG: 1595246 Signed-off-by: Csaba Henk Reviewed-on: https://code.engineering.redhat.com/gerrit/162552 Tested-by: RHGS Build Bot Reviewed-by: Amar Tumballi Suryanarayan Reviewed-by: Sunil Kumar Heggodu Gopala Acharya --- tests/features/flock_interrupt.t | 33 +++++++++ xlators/mount/fuse/src/fuse-bridge.c | 132 +++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 tests/features/flock_interrupt.t diff --git a/tests/features/flock_interrupt.t b/tests/features/flock_interrupt.t new file mode 100644 index 0000000..8603b65 --- /dev/null +++ b/tests/features/flock_interrupt.t @@ -0,0 +1,33 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +## Start and create a volume +TEST glusterd; +TEST pidof glusterd; + +TEST $CLI volume create $V0 $H0:$B0/${V0}0; + +## Verify volume is is created +EXPECT "$V0" volinfo_field $V0 'Volume Name'; +EXPECT 'Created' volinfo_field $V0 'Status'; + +## Start volume and verify +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +TEST touch $M0/testfile; + +function flock_interrupt { + flock $MO/testfile sleep 3 & flock -w 1 $M0/testfile true; + echo ok; +} + +EXPECT_WITHIN 2 ok flock_interrupt; + +## Finish up +cleanup; diff --git a/xlators/mount/fuse/src/fuse-bridge.c b/xlators/mount/fuse/src/fuse-bridge.c index 44c39e4..deaf533 100644 --- a/xlators/mount/fuse/src/fuse-bridge.c +++ b/xlators/mount/fuse/src/fuse-bridge.c @@ -4346,6 +4346,18 @@ fuse_setlk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, { uint32_t op = 0; fuse_state_t *state = NULL; + int ret = 0; + + ret = fuse_interrupt_finish_fop (frame, this, _gf_false, + (void **)&state); + if (state) { + GF_FREE (state->name); + dict_unref (state->xdata); + GF_FREE (state); + } + if (ret) { + return 0; + } state = frame->root->state; op = state->finh->opcode; @@ -4392,10 +4404,130 @@ fuse_setlk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, return 0; } +static int +fuse_setlk_interrupt_handler_cbk (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, dict_t *dict, + dict_t *xdata) +{ + fuse_interrupt_state_t intstat = INTERRUPT_NONE; + fuse_interrupt_record_t *fir; + fuse_state_t *state = NULL; + int ret = 0; + + ret = dict_get_bin (xdata, "fuse-interrupt-record", (void **)&fir); + if (ret < 0) { + gf_log ("glusterfs-fuse", GF_LOG_ERROR, + "interrupt record not found"); + + goto out; + } + + intstat = op_ret >= 0 ? INTERRUPT_HANDLED : INTERRUPT_SQUELCHED; + + fuse_interrupt_finish_interrupt (this, fir, intstat, _gf_false, + (void **)&state); + if (state) { + GF_FREE (state->name); + dict_unref (state->xdata); + GF_FREE (state); + } + +out: + STACK_DESTROY (frame->root); + + return 0; +} + +static void +fuse_setlk_interrupt_handler (xlator_t *this, fuse_interrupt_record_t *fir) +{ + fuse_state_t *state = NULL; + call_frame_t *frame = NULL; + char *xattr_name = NULL; + int ret = 0; + + gf_log ("glusterfs-fuse", GF_LOG_DEBUG, + "SETLK%s unique %" PRIu64 ": interrupt handler triggered", + fir->fuse_in_header.opcode == FUSE_SETLK ? "" : "W", + fir->fuse_in_header.unique); + + state = fir->data; + + ret = gf_asprintf ( + &xattr_name, GF_XATTR_CLRLK_CMD ".tposix.kblocked.%hd,%jd-%jd", + state->lk_lock.l_whence, state->lk_lock.l_start, + state->lk_lock.l_len); + if (ret == -1) { + xattr_name = NULL; + goto err; + } + + frame = get_call_frame_for_req (state); + if (!frame) { + goto err; + } + frame->root->state = state; + frame->root->op = GF_FOP_GETXATTR; + frame->op = GF_FOP_GETXATTR; + state->name = xattr_name; + + STACK_WIND (frame, fuse_setlk_interrupt_handler_cbk, state->active_subvol, + state->active_subvol->fops->fgetxattr, state->fd, xattr_name, + state->xdata); + + return; + +err: + GF_FREE (xattr_name); + fuse_interrupt_finish_interrupt (this, fir, INTERRUPT_SQUELCHED, + _gf_false, (void **)&state); + if (state) { + dict_unref (state->xdata); + GF_FREE (state); + } +} void fuse_setlk_resume (fuse_state_t *state) { + fuse_interrupt_record_t *fir = NULL; + fuse_state_t *state_clone = NULL; + + fir = fuse_interrupt_record_new (state->finh, fuse_setlk_interrupt_handler); + state_clone = gf_memdup (state, sizeof (*state)); + if (state_clone) { + /* + * Calling this allocator with fir casted to (char *) seems like + * an abuse of this API, but in fact the API is stupid to assume + * a (char *) argument (in the funcion it's casted to (void *) + * anyway). + */ + state_clone->xdata = dict_for_key_value ( + "fuse-interrupt-record", (char *)fir, sizeof (*fir), _gf_true); + } + if (!fir || !state_clone || !state_clone->xdata) { + if (fir) { + GF_FREE (fir); + } + if (state_clone) { + GF_FREE (state_clone); + } + send_fuse_err (state->this, state->finh, ENOMEM); + + gf_log ("glusterfs-fuse", GF_LOG_ERROR, + "SETLK%s unique %"PRIu64":" + " interrupt record allocation failed", + state->finh->opcode == FUSE_SETLK ? "" : "W", + state->finh->unique); + free_fuse_state (state); + + return; + } + state_clone->name = NULL; + fir->data = state_clone; + fuse_interrupt_record_insert (state->this, fir); + gf_log ("glusterfs-fuse", GF_LOG_TRACE, "%"PRIu64": SETLK%s %p", state->finh->unique, state->finh->opcode == FUSE_SETLK ? "" : "W", state->fd); -- 1.8.3.1