diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2015-07-01 16:26:06 +0200 |
---|---|---|
committer | Miklos Szeredi <mszeredi@suse.cz> | 2015-07-01 16:26:06 +0200 |
commit | 365ae710df91edc97d24817e3271e01bffaaee32 (patch) | |
tree | 3e535e7168b57fc310119e29947d2281ed60f484 /fs/fuse | |
parent | 77cd9d488b32d19be852ad4d310ef13701557d61 (diff) | |
download | linux-365ae710df91edc97d24817e3271e01bffaaee32.tar.gz linux-365ae710df91edc97d24817e3271e01bffaaee32.tar.bz2 linux-365ae710df91edc97d24817e3271e01bffaaee32.zip |
fuse: request_end(): do once
When the connection is aborted it is possible that request_end() will be
called twice. Use atomic test and set to do the actual ending only once.
test_and_set_bit() also provides the necessary barrier semantics so no
explicit smp_wmb() is necessary.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Reviewed-by: Ashish Samant <ashish.samant@oracle.com>
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/dev.c | 8 |
1 files changed, 6 insertions, 2 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 7f37e55edc0e..cd242fc6a92b 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -384,14 +384,18 @@ __releases(fc->lock) { struct fuse_iqueue *fiq = &fc->iq; void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; + + if (test_and_set_bit(FR_FINISHED, &req->flags)) { + spin_unlock(&fc->lock); + return; + } + req->end = NULL; spin_lock(&fiq->waitq.lock); list_del_init(&req->intr_entry); spin_unlock(&fiq->waitq.lock); WARN_ON(test_bit(FR_PENDING, &req->flags)); WARN_ON(test_bit(FR_SENT, &req->flags)); - smp_wmb(); - set_bit(FR_FINISHED, &req->flags); if (test_bit(FR_BACKGROUND, &req->flags)) { clear_bit(FR_BACKGROUND, &req->flags); if (fc->num_background == fc->max_background) |