From 825d6d3395e88a616e4c953984d77eeacbad4310 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Wed, 1 Jul 2015 16:25:58 +0200 Subject: [PATCH] fuse: req use bitops Finer grained locking will mean there's no single lock to protect modification of bitfileds in fuse_req. So move to using bitops. Can use the non-atomic variants for those which happen while the request definitely has only one reference. Signed-off-by: Miklos Szeredi Reviewed-by: Ashish Samant --- fs/fuse/dev.c | 71 ++++++++++++++++++++++++------------------------ fs/fuse/file.c | 17 ++++++------ fs/fuse/fuse_i.h | 49 ++++++++++++++++----------------- fs/fuse/inode.c | 6 ++-- 4 files changed, 71 insertions(+), 72 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 3b979abb7b54..dcfef5475ada 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -181,8 +181,10 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages, } fuse_req_init_context(req); - req->waiting = 1; - req->background = for_background; + __set_bit(FR_WAITING, &req->flags); + if (for_background) + __set_bit(FR_BACKGROUND, &req->flags); + return req; out: @@ -272,15 +274,15 @@ struct fuse_req *fuse_get_req_nofail_nopages(struct fuse_conn *fc, req = get_reserved_req(fc, file); fuse_req_init_context(req); - req->waiting = 1; - req->background = 0; + __set_bit(FR_WAITING, &req->flags); + __clear_bit(FR_BACKGROUND, &req->flags); return req; } void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) { if (atomic_dec_and_test(&req->count)) { - if (unlikely(req->background)) { + if (test_bit(FR_BACKGROUND, &req->flags)) { /* * We get here in the unlikely case that a background * request was allocated but not sent @@ -291,9 +293,9 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) spin_unlock(&fc->lock); } - if (req->waiting) { + if (test_bit(FR_WAITING, &req->flags)) { + __clear_bit(FR_WAITING, &req->flags); atomic_dec(&fc->num_waiting); - req->waiting = 0; } if (req->stolen_file) @@ -385,9 +387,8 @@ __releases(fc->lock) list_del_init(&req->list); list_del_init(&req->intr_entry); req->state = FUSE_REQ_FINISHED; - if (req->background) { - req->background = 0; - + if (test_bit(FR_BACKGROUND, &req->flags)) { + clear_bit(FR_BACKGROUND, &req->flags); if (fc->num_background == fc->max_background) fc->blocked = 0; @@ -442,12 +443,12 @@ __acquires(fc->lock) if (req->state == FUSE_REQ_FINISHED) return; - req->interrupted = 1; + set_bit(FR_INTERRUPTED, &req->flags); if (req->state == FUSE_REQ_SENT) queue_interrupt(fc, req); } - if (!req->force) { + if (!test_bit(FR_FORCE, &req->flags)) { sigset_t oldset; /* Only fatal signals may interrupt this */ @@ -478,7 +479,7 @@ __acquires(fc->lock) static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) { - BUG_ON(req->background); + BUG_ON(test_bit(FR_BACKGROUND, &req->flags)); spin_lock(&fc->lock); if (!fc->connected) req->out.h.error = -ENOTCONN; @@ -496,9 +497,9 @@ static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) { - req->isreply = 1; - if (!req->waiting) { - req->waiting = 1; + __set_bit(FR_ISREPLY, &req->flags); + if (!test_bit(FR_WAITING, &req->flags)) { + __set_bit(FR_WAITING, &req->flags); atomic_inc(&fc->num_waiting); } __fuse_request_send(fc, req); @@ -578,12 +579,12 @@ ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args) void fuse_request_send_background_locked(struct fuse_conn *fc, struct fuse_req *req) { - BUG_ON(!req->background); - if (!req->waiting) { - req->waiting = 1; + BUG_ON(!test_bit(FR_BACKGROUND, &req->flags)); + if (!test_bit(FR_WAITING, &req->flags)) { + __set_bit(FR_WAITING, &req->flags); atomic_inc(&fc->num_waiting); } - req->isreply = 1; + __set_bit(FR_ISREPLY, &req->flags); fc->num_background++; if (fc->num_background == fc->max_background) fc->blocked = 1; @@ -617,7 +618,7 @@ static int fuse_request_send_notify_reply(struct fuse_conn *fc, { int err = -ENODEV; - req->isreply = 0; + __clear_bit(FR_ISREPLY, &req->flags); req->in.h.unique = unique; spin_lock(&fc->lock); if (fc->connected) { @@ -644,7 +645,7 @@ void fuse_force_forget(struct file *file, u64 nodeid) req->in.numargs = 1; req->in.args[0].size = sizeof(inarg); req->in.args[0].value = &inarg; - req->isreply = 0; + __clear_bit(FR_ISREPLY, &req->flags); __fuse_request_send(fc, req); /* ignore errors */ fuse_put_request(fc, req); @@ -660,10 +661,10 @@ static int lock_request(struct fuse_conn *fc, struct fuse_req *req) int err = 0; if (req) { spin_lock(&fc->lock); - if (req->aborted) + if (test_bit(FR_ABORTED, &req->flags)) err = -ENOENT; else - req->locked = 1; + set_bit(FR_LOCKED, &req->flags); spin_unlock(&fc->lock); } return err; @@ -678,10 +679,10 @@ static int unlock_request(struct fuse_conn *fc, struct fuse_req *req) int err = 0; if (req) { spin_lock(&fc->lock); - if (req->aborted) + if (test_bit(FR_ABORTED, &req->flags)) err = -ENOENT; else - req->locked = 0; + clear_bit(FR_LOCKED, &req->flags); spin_unlock(&fc->lock); } return err; @@ -902,7 +903,7 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep) err = 0; spin_lock(&cs->fc->lock); - if (cs->req->aborted) + if (test_bit(FR_ABORTED, &cs->req->flags)) err = -ENOENT; else *pagep = newpage; @@ -1309,7 +1310,7 @@ static ssize_t fuse_dev_do_read(struct fuse_conn *fc, struct file *file, (struct fuse_arg *) in->args, 0); fuse_copy_finish(cs); spin_lock(&fc->lock); - req->locked = 0; + clear_bit(FR_LOCKED, &req->flags); if (!fc->connected) { request_end(fc, req); return -ENODEV; @@ -1319,12 +1320,12 @@ static ssize_t fuse_dev_do_read(struct fuse_conn *fc, struct file *file, request_end(fc, req); return err; } - if (!req->isreply) + if (!test_bit(FR_ISREPLY, &req->flags)) { request_end(fc, req); - else { + } else { req->state = FUSE_REQ_SENT; list_move_tail(&req->list, &fc->processing); - if (req->interrupted) + if (test_bit(FR_INTERRUPTED, &req->flags)) queue_interrupt(fc, req); spin_unlock(&fc->lock); } @@ -1921,7 +1922,7 @@ static ssize_t fuse_dev_do_write(struct fuse_conn *fc, req->state = FUSE_REQ_WRITING; list_move(&req->list, &fc->io); req->out.h = oh; - req->locked = 1; + set_bit(FR_LOCKED, &req->flags); cs->req = req; if (!req->out.page_replace) cs->move_pages = 0; @@ -1931,7 +1932,7 @@ static ssize_t fuse_dev_do_write(struct fuse_conn *fc, fuse_copy_finish(cs); spin_lock(&fc->lock); - req->locked = 0; + clear_bit(FR_LOCKED, &req->flags); if (!fc->connected) err = -ENOENT; else if (err) @@ -2097,8 +2098,8 @@ __acquires(fc->lock) list_for_each_entry_safe(req, next, &fc->io, list) { req->out.h.error = -ECONNABORTED; - req->aborted = 1; - if (!req->locked) + set_bit(FR_ABORTED, &req->flags); + if (!test_bit(FR_LOCKED, &req->flags)) list_move(&req->list, &to_end); } while (!list_empty(&to_end)) { diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 5ef05b5c4cff..bf272263c1a2 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -96,17 +96,17 @@ static void fuse_file_put(struct fuse_file *ff, bool sync) * Drop the release request when client does not * implement 'open' */ - req->background = 0; + __clear_bit(FR_BACKGROUND, &req->flags); iput(req->misc.release.inode); fuse_put_request(ff->fc, req); } else if (sync) { - req->background = 0; + __clear_bit(FR_BACKGROUND, &req->flags); fuse_request_send(ff->fc, req); iput(req->misc.release.inode); fuse_put_request(ff->fc, req); } else { req->end = fuse_release_end; - req->background = 1; + __set_bit(FR_BACKGROUND, &req->flags); fuse_request_send_background(ff->fc, req); } kfree(ff); @@ -299,8 +299,8 @@ void fuse_sync_release(struct fuse_file *ff, int flags) { WARN_ON(atomic_read(&ff->count) > 1); fuse_prepare_release(ff, flags, FUSE_RELEASE); - ff->reserved_req->force = 1; - ff->reserved_req->background = 0; + __set_bit(FR_FORCE, &ff->reserved_req->flags); + __clear_bit(FR_BACKGROUND, &ff->reserved_req->flags); fuse_request_send(ff->fc, ff->reserved_req); fuse_put_request(ff->fc, ff->reserved_req); kfree(ff); @@ -426,7 +426,7 @@ static int fuse_flush(struct file *file, fl_owner_t id) req->in.numargs = 1; req->in.args[0].size = sizeof(inarg); req->in.args[0].value = &inarg; - req->force = 1; + __set_bit(FR_FORCE, &req->flags); fuse_request_send(fc, req); err = req->out.h.error; fuse_put_request(fc, req); @@ -1611,7 +1611,8 @@ static int fuse_writepage_locked(struct page *page) if (!req) goto err; - req->background = 1; /* writeback always goes to bg_queue */ + /* writeback always goes to bg_queue */ + __set_bit(FR_BACKGROUND, &req->flags); tmp_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); if (!tmp_page) goto err_free; @@ -1830,7 +1831,7 @@ static int fuse_writepages_fill(struct page *page, req->misc.write.in.write_flags |= FUSE_WRITE_CACHE; req->misc.write.next = NULL; req->in.argpages = 1; - req->background = 1; + __set_bit(FR_BACKGROUND, &req->flags); req->num_pages = 0; req->end = fuse_writepage_end; req->inode = inode; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 7354dc142a50..4503e995c7b2 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -266,6 +266,27 @@ struct fuse_io_priv { struct completion *done; }; +/** + * Request flags + * + * FR_ISREPLY: set if the request has reply + * FR_FORCE: force sending of the request even if interrupted + * FR_BACKGROUND: request is sent in the background + * FR_WAITING: request is counted as "waiting" + * FR_ABORTED: the request was aborted + * FR_INTERRUPTED: the request has been interrupted + * FR_LOCKED: data is being copied to/from the request + */ +enum fuse_req_flag { + FR_ISREPLY, + FR_FORCE, + FR_BACKGROUND, + FR_WAITING, + FR_ABORTED, + FR_INTERRUPTED, + FR_LOCKED, +}; + /** * A request to the client */ @@ -283,32 +304,8 @@ struct fuse_req { /** Unique ID for the interrupt request */ u64 intr_unique; - /* - * The following bitfields are either set once before the - * request is queued or setting/clearing them is protected by - * fuse_conn->lock - */ - - /** True if the request has reply */ - unsigned isreply:1; - - /** Force sending of the request even if interrupted */ - unsigned force:1; - - /** The request was aborted */ - unsigned aborted:1; - - /** Request is sent in the background */ - unsigned background:1; - - /** The request has been interrupted */ - unsigned interrupted:1; - - /** Data is being copied to/from the request */ - unsigned locked:1; - - /** Request is counted as "waiting" */ - unsigned waiting:1; + /* Request flags, updated with test/set/clear_bit() */ + unsigned long flags; /** State of the request */ enum fuse_req_state state; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index cec8abbe2c8c..f7c9b7225ec5 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -362,8 +362,8 @@ static void fuse_send_destroy(struct fuse_conn *fc) if (req && fc->conn_init) { fc->destroy_req = NULL; req->in.h.opcode = FUSE_DESTROY; - req->force = 1; - req->background = 0; + __set_bit(FR_FORCE, &req->flags); + __clear_bit(FR_BACKGROUND, &req->flags); fuse_request_send(fc, req); fuse_put_request(fc, req); } @@ -1060,7 +1060,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) init_req = fuse_request_alloc(0); if (!init_req) goto err_put_root; - init_req->background = 1; + __set_bit(FR_BACKGROUND, &init_req->flags); if (is_bdev) { fc->destroy_req = fuse_request_alloc(0); -- GitLab