diff options
| author | Csaba Henk <csaba@redhat.com> | 2018-10-22 00:59:05 +0200 | 
|---|---|---|
| committer | Amar Tumballi <amarts@redhat.com> | 2018-12-14 18:11:01 +0000 | 
| commit | eb77d69be528580ca6e4c109762b862114beca87 (patch) | |
| tree | 7e6fd97cac707f2ef2a435deb55602459598f7ea | |
| parent | d49b41e817d592c1904b6f01716df6546dad3ebe (diff) | |
fuse: SETLKW interrupt
Use the (f)getxattr based clearlocks interface to
interrupt a pending lock request.
updates: #465
Change-Id: I4e91a4d8791fc688fed400a02de4c53487e61be2
Signed-off-by: Csaba Henk <csaba@redhat.com>
| -rw-r--r-- | tests/features/flock_interrupt.t | 33 | ||||
| -rw-r--r-- | xlators/mount/fuse/src/fuse-bridge.c | 130 | 
2 files changed, 163 insertions, 0 deletions
diff --git a/tests/features/flock_interrupt.t b/tests/features/flock_interrupt.t new file mode 100644 index 00000000000..8603b656c24 --- /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 5bc070658e2..633398a3108 100644 --- a/xlators/mount/fuse/src/fuse-bridge.c +++ b/xlators/mount/fuse/src/fuse-bridge.c @@ -4557,6 +4557,17 @@ 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; @@ -4603,9 +4614,128 @@ 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);  | 
