/* FUSE: Filesystem in Userspace Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu> This program can be distributed under the terms of the GNU GPL. See the file COPYING.*/ #include "fuse_i.h" #include <linux/init.h>#include <linux/module.h>#include <linux/poll.h>#include <linux/uio.h>#include <linux/miscdevice.h>#include <linux/pagemap.h>#include <linux/file.h>#include <linux/slab.h>#include <linux/pipe_fs_i.h>#include <linux/swap.h>#include <linux/splice.h> MODULE_ALIAS_MISCDEV(FUSE_MINOR);MODULE_ALIAS("devname:fuse"); static struct kmem_cache *fuse_req_cachep; static struct fuse_conn *fuse_get_conn(struct file *file){ /* * Lockless access is OK, because file->private data is set * once during mount and is valid until the file is released. */ return file->private_data;} static void fuse_request_init(struct fuse_req *req, struct page **pages, struct fuse_page_desc *page_descs, unsigned npages){ memset(req, 0, sizeof(*req)); memset(pages, 0, sizeof(*pages) * npages); memset(page_descs, 0, sizeof(*page_descs) * npages); INIT_LIST_HEAD(&req->list); INIT_LIST_HEAD(&req->intr_entry); init_waitqueue_head(&req->waitq); atomic_set(&req->count, 1); req->pages = pages; req->page_descs = page_descs; req->max_pages = npages;} static struct fuse_req *__fuse_request_alloc(unsigned npages, gfp_t flags){ struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, flags); if (req) { struct page **pages; struct fuse_page_desc *page_descs; if (npages <= FUSE_REQ_INLINE_PAGES) { pages = req->inline_pages; page_descs = req->inline_page_descs; } else { pages = kmalloc(sizeof(struct page *) * npages, flags); page_descs = kmalloc(sizeof(struct fuse_page_desc) * npages, flags); } if (!pages || !page_descs) { kfree(pages); kfree(page_descs); kmem_cache_free(fuse_req_cachep, req); return NULL; } fuse_request_init(req, pages, page_descs, npages); } return req;} struct fuse_req *fuse_request_alloc(unsigned npages){ return __fuse_request_alloc(npages, GFP_KERNEL);}EXPORT_SYMBOL_GPL(fuse_request_alloc); struct fuse_req *fuse_request_alloc_nofs(unsigned npages){ return __fuse_request_alloc(npages, GFP_NOFS);} void fuse_request_free(struct fuse_req *req){ if (req->pages != req->inline_pages) { kfree(req->pages); kfree(req->page_descs); } kmem_cache_free(fuse_req_cachep, req);} static void block_sigs(sigset_t *oldset){ sigset_t mask; siginitsetinv(&mask, sigmask(SIGKILL)); sigprocmask(SIG_BLOCK, &mask, oldset);} static void restore_sigs(sigset_t *oldset){ sigprocmask(SIG_SETMASK, oldset, NULL);} static void __fuse_get_request(struct fuse_req *req){ atomic_inc(&req->count);} /* Must be called with > 1 refcount */static void __fuse_put_request(struct fuse_req *req){ BUG_ON(atomic_read(&req->count) < 2); atomic_dec(&req->count);} static void fuse_req_init_context(struct fuse_req *req){ req->in.h.uid = from_kuid_munged(&init_user_ns, current_fsuid()); req->in.h.gid = from_kgid_munged(&init_user_ns, current_fsgid()); req->in.h.pid = current->pid;} struct fuse_req *fuse_get_req(struct fuse_conn *fc, unsigned npages){ struct fuse_req *req; sigset_t oldset; int intr; int err; atomic_inc(&fc->num_waiting); block_sigs(&oldset); intr = wait_event_interruptible(fc->blocked_waitq, !fc->blocked); restore_sigs(&oldset); err = -EINTR; if (intr) goto out; err = -ENOTCONN; if (!fc->connected) goto out; req = fuse_request_alloc(npages); err = -ENOMEM; if (!req) goto out; fuse_req_init_context(req); req->waiting = 1; return req; out: atomic_dec(&fc->num_waiting); return ERR_PTR(err);}EXPORT_SYMBOL_GPL(fuse_get_req); /* * Return request in fuse_file->reserved_req. However that may * currently be in use. If that is the case, wait for it to become * available. */static struct fuse_req *get_reserved_req(struct fuse_conn *fc, struct file *file){ struct fuse_req *req = NULL; struct fuse_file *ff = file->private_data; do { wait_event(fc->reserved_req_waitq, ff->reserved_req); spin_lock(&fc->lock); if (ff->reserved_req) { req = ff->reserved_req; ff->reserved_req = NULL; req->stolen_file = get_file(file); } spin_unlock(&fc->lock); } while (!req); return req;} /* * Put stolen request back into fuse_file->reserved_req */static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req){ struct file *file = req->stolen_file; struct fuse_file *ff = file->private_data; spin_lock(&fc->lock); fuse_request_init(req, req->pages, req->page_descs, req->max_pages); BUG_ON(ff->reserved_req); ff->reserved_req = req; wake_up_all(&fc->reserved_req_waitq); spin_unlock(&fc->lock); fput(file);} /* * Gets a requests for a file operation, always succeeds * * This is used for sending the FLUSH request, which must get to * userspace, due to POSIX locks which may need to be unlocked. * * If allocation fails due to OOM, use the reserved request in * fuse_file. * * This is very unlikely to deadlock accidentally, since the * filesystem should not have it's own file open. If deadlock is * intentional, it can still be broken by "aborting" the filesystem. */struct fuse_req *fuse_get_req_nofail_nopages(struct fuse_conn *fc, struct file *file){ struct fuse_req *req; atomic_inc(&fc->num_waiting); wait_event(fc->blocked_waitq, !fc->blocked); req = fuse_request_alloc(0); if (!req) req = get_reserved_req(fc, file); fuse_req_init_context(req); req->waiting = 1; return req;} void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req){ if (atomic_dec_and_test(&req->count)) { if (req->waiting) atomic_dec(&fc->num_waiting); if (req->stolen_file) put_reserved_req(fc, req); else fuse_request_free(req); }}EXPORT_SYMBOL_GPL(fuse_put_request); static unsigned len_args(unsigned numargs, struct fuse_arg *args){ unsigned nbytes = 0; unsigned i; for (i = 0; i < numargs; i++) nbytes += args[i].size; return nbytes;} static u64 fuse_get_unique(struct fuse_conn *fc){ fc->reqctr++; /* zero is special */ if (fc->reqctr == 0) fc->reqctr = 1; return fc->reqctr;} static void queue_request(struct fuse_conn *fc, struct fuse_req *req){ req->in.h.len = sizeof(struct fuse_in_header) + len_args(req->in.numargs, (struct fuse_arg *) req->in.args); list_add_tail(&req->list, &fc->pending); req->state = FUSE_REQ_PENDING; if (!req->waiting) { req->waiting = 1; atomic_inc(&fc->num_waiting); } wake_up(&fc->waitq); kill_fasync(&fc->fasync, SIGIO, POLL_IN);} void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, u64 nodeid, u64 nlookup){ forget->forget_one.nodeid = nodeid; forget->forget_one.nlookup = nlookup; spin_lock(&fc->lock); if (fc->connected) { fc->forget_list_tail->next = forget; fc->forget_list_tail = forget; wake_up(&fc->waitq); kill_fasync(&fc->fasync, SIGIO, POLL_IN); } else { kfree(forget); } spin_unlock(&fc->lock);} static void flush_bg_queue(struct fuse_conn *fc){ while (fc->active_background < fc->max_background && !list_empty(&fc->bg_queue)) { struct fuse_req *req; req = list_entry(fc->bg_queue.next, struct fuse_req, list); list_del(&req->list); fc->active_background++; req->in.h.unique = fuse_get_unique(fc); queue_request(fc, req); }} /* * This function is called when a request is finished. Either a reply * has arrived or it was aborted (and not yet sent) or some error * occurred during communication with userspace, or the device file * was closed. The requester thread is woken up (if still waiting), * the 'end' callback is called if given, else the reference to the * request is released * * Called with fc->lock, unlocks it */static void request_end(struct fuse_conn *fc, struct fuse_req *req)__releases(fc->lock){ void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; req->end = NULL; list_del(&req->list); list_del(&req->intr_entry); req->state = FUSE_REQ_FINISHED; if (req->background) { if (fc->num_background == fc->max_background) { fc->blocked = 0; wake_up_all(&fc->blocked_waitq); } if (fc->num_background == fc->congestion_threshold && fc->connected && fc->bdi_initialized) { clear_bdi_congested(&fc->bdi, BLK_RW_SYNC); clear_bdi_congested(&fc->bdi, BLK_RW_ASYNC); } fc->num_background--; fc->active_background--; flush_bg_queue(fc); } spin_unlock(&fc->lock); wake_up(&req->waitq); if (end) end(fc, req); fuse_put_request(fc, req);} static void wait_answer_interruptible(struct fuse_conn *fc, struct fuse_req *req)__releases(fc->lock)__acquires(fc->lock){ if (signal_pending(current)) return; spin_unlock(&fc->lock); wait_event_interruptible(req->waitq, req->state == FUSE_REQ_FINISHED); spin_lock(&fc->lock);} static void queue_interrupt(struct fuse_conn *fc, struct fuse_req *req){ list_add_tail(&req->intr_entry, &fc->interrupts); wake_up(&fc->waitq); kill_fasync(&fc->fasync, SIGIO, POLL_IN);} static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)__releases(fc->lock)__acquires(fc->lock){ if (!fc->no_interrupt) { /* Any signal may interrupt this */ wait_answer_interruptible(fc, req); if (req->aborted) goto aborted; if (req->state == FUSE_REQ_FINISHED) return; req->interrupted = 1; if (req->state == FUSE_REQ_SENT) queue_interrupt(fc, req); } if (!req->force) { sigset_t oldset; /* Only fatal signals may interrupt this */ block_sigs(&oldset); wait_answer_interruptible(fc, req); restore_sigs(&oldset); if (req->aborted) goto aborted; if (req->state == FUSE_REQ_FINISHED) return; /* Request is not yet in userspace, bail out */ if (req->state == FUSE_REQ_PENDING) { list_del(&req->list); __fuse_put_request(req); req->out.h.error = -EINTR; return; } } /* * Either request is already in userspace, or it was forced. * Wait it out. */ spin_unlock(&fc->lock); wait_event(req->waitq, req->state == FUSE_REQ_FINISHED); spin_lock(&fc->lock); if (!req->aborted) return; aborted: BUG_ON(req->state != FUSE_REQ_FINISHED); if (req->locked) { /* This is uninterruptible sleep, because data is being copied to/from the buffers of req. During locked state, there mustn't be any filesystem operation (e.g. page fault), since that could lead to deadlock */ spin_unlock(&fc->lock); wait_event(req->waitq, !req->locked); spin_lock(&fc->lock); }} static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req){ spin_lock(&fc->lock); if (!fc->connected) req->out.h.error = -ENOTCONN; else if (fc->conn_error) req->out.h.error = -ECONNREFUSED; else { req->in.h.unique = fuse_get_unique(fc); queue_request(fc, req); /* acquire extra reference, since request is still needed after request_end() */ __fuse_get_request(req); request_wait_answer(fc, req); } spin_unlock(&fc->lock);} void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req){ req->isreply = 1; __fuse_request_send(fc, req);}EXPORT_SYMBOL_GPL(fuse_request_send); static void fuse_request_send_nowait_locked(struct fuse_conn *fc, struct fuse_req *req){ req->background = 1; fc->num_background++; if (fc->num_background == fc->max_background) fc->blocked = 1; if (fc->num_background == fc->congestion_threshold && fc->bdi_initialized) { set_bdi_congested(&fc->bdi, BLK_RW_SYNC); set_bdi_congested(&fc->bdi, BLK_RW_ASYNC); } list_add_tail(&req->list, &fc->bg_queue); flush_bg_queue(fc);} static void fuse_request_send_nowait(struct fuse_conn *fc, struct fuse_req *req){ spin_lock(&fc->lock); if (fc->connected) { fuse_request_send_nowait_locked(fc, req); spin_unlock(&fc->lock); } else { req->out.h.error = -ENOTCONN; request_end(fc, req); }} void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req){ req->isreply = 1; fuse_request_send_nowait(fc, req);Lines 1–500 of 2159. Load more
/* FUSE: Filesystem in Userspace Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu> This program can be distributed under the terms of the GNU GPL. See the file COPYING. */ #include "fuse_i.h" #include <linux/init.h> #include <linux/module.h> #include <linux/poll.h> #include <linux/uio.h> #include <linux/miscdevice.h> #include <linux/pagemap.h> #include <linux/file.h> #include <linux/slab.h> #include <linux/pipe_fs_i.h> #include <linux/swap.h> #include <linux/splice.h> MODULE_ALIAS_MISCDEV(FUSE_MINOR); MODULE_ALIAS("devname:fuse"); static struct kmem_cache *fuse_req_cachep; static struct fuse_conn *fuse_get_conn(struct file *file) { /* * Lockless access is OK, because file->private data is set * once during mount and is valid until the file is released. */ return file->private_data; } static void fuse_request_init(struct fuse_req *req, struct page **pages, struct fuse_page_desc *page_descs, unsigned npages) { memset(req, 0, sizeof(*req)); memset(pages, 0, sizeof(*pages) * npages); memset(page_descs, 0, sizeof(*page_descs) * npages); INIT_LIST_HEAD(&req->list); INIT_LIST_HEAD(&req->intr_entry); init_waitqueue_head(&req->waitq); atomic_set(&req->count, 1); req->pages = pages; req->page_descs = page_descs; req->max_pages = npages; } static struct fuse_req *__fuse_request_alloc(unsigned npages, gfp_t flags) { struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, flags); if (req) { struct page **pages; struct fuse_page_desc *page_descs; if (npages <= FUSE_REQ_INLINE_PAGES) { pages = req->inline_pages; page_descs = req->inline_page_descs; } else { pages = kmalloc(sizeof(struct page *) * npages, flags); page_descs = kmalloc(sizeof(struct fuse_page_desc) * npages, flags); } if (!pages || !page_descs) { kfree(pages); kfree(page_descs); kmem_cache_free(fuse_req_cachep, req); return NULL; } fuse_request_init(req, pages, page_descs, npages); } return req; } struct fuse_req *fuse_request_alloc(unsigned npages) { return __fuse_request_alloc(npages, GFP_KERNEL); } EXPORT_SYMBOL_GPL(fuse_request_alloc); struct fuse_req *fuse_request_alloc_nofs(unsigned npages) { return __fuse_request_alloc(npages, GFP_NOFS); } void fuse_request_free(struct fuse_req *req) { if (req->pages != req->inline_pages) { kfree(req->pages); kfree(req->page_descs); } kmem_cache_free(fuse_req_cachep, req); } static void block_sigs(sigset_t *oldset) { sigset_t mask; siginitsetinv(&mask, sigmask(SIGKILL)); sigprocmask(SIG_BLOCK, &mask, oldset); } static void restore_sigs(sigset_t *oldset) { sigprocmask(SIG_SETMASK, oldset, NULL); } static void __fuse_get_request(struct fuse_req *req) { atomic_inc(&req->count); } /* Must be called with > 1 refcount */ static void __fuse_put_request(struct fuse_req *req) { BUG_ON(atomic_read(&req->count) < 2); atomic_dec(&req->count); } static void fuse_req_init_context(struct fuse_req *req) { req->in.h.uid = from_kuid_munged(&init_user_ns, current_fsuid()); req->in.h.gid = from_kgid_munged(&init_user_ns, current_fsgid()); req->in.h.pid = current->pid; } struct fuse_req *fuse_get_req(struct fuse_conn *fc, unsigned npages) { struct fuse_req *req; sigset_t oldset; int intr; int err; atomic_inc(&fc->num_waiting); block_sigs(&oldset); intr = wait_event_interruptible(fc->blocked_waitq, !fc->blocked); restore_sigs(&oldset); err = -EINTR; if (intr) goto out; err = -ENOTCONN; if (!fc->connected) goto out; req = fuse_request_alloc(npages); err = -ENOMEM; if (!req) goto out; fuse_req_init_context(req); req->waiting = 1; return req; out: atomic_dec(&fc->num_waiting); return ERR_PTR(err); } EXPORT_SYMBOL_GPL(fuse_get_req); /* * Return request in fuse_file->reserved_req. However that may * currently be in use. If that is the case, wait for it to become * available. */ static struct fuse_req *get_reserved_req(struct fuse_conn *fc, struct file *file) { struct fuse_req *req = NULL; struct fuse_file *ff = file->private_data; do { wait_event(fc->reserved_req_waitq, ff->reserved_req); spin_lock(&fc->lock); if (ff->reserved_req) { req = ff->reserved_req; ff->reserved_req = NULL; req->stolen_file = get_file(file); } spin_unlock(&fc->lock); } while (!req); return req; } /* * Put stolen request back into fuse_file->reserved_req */ static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req) { struct file *file = req->stolen_file; struct fuse_file *ff = file->private_data; spin_lock(&fc->lock); fuse_request_init(req, req->pages, req->page_descs, req->max_pages); BUG_ON(ff->reserved_req); ff->reserved_req = req; wake_up_all(&fc->reserved_req_waitq); spin_unlock(&fc->lock); fput(file); } /* * Gets a requests for a file operation, always succeeds * * This is used for sending the FLUSH request, which must get to * userspace, due to POSIX locks which may need to be unlocked. * * If allocation fails due to OOM, use the reserved request in * fuse_file. * * This is very unlikely to deadlock accidentally, since the * filesystem should not have it's own file open. If deadlock is * intentional, it can still be broken by "aborting" the filesystem. */ struct fuse_req *fuse_get_req_nofail_nopages(struct fuse_conn *fc, struct file *file) { struct fuse_req *req; atomic_inc(&fc->num_waiting); wait_event(fc->blocked_waitq, !fc->blocked); req = fuse_request_alloc(0); if (!req) req = get_reserved_req(fc, file); fuse_req_init_context(req); req->waiting = 1; return req; } void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) { if (atomic_dec_and_test(&req->count)) { if (req->waiting) atomic_dec(&fc->num_waiting); if (req->stolen_file) put_reserved_req(fc, req); else fuse_request_free(req); } } EXPORT_SYMBOL_GPL(fuse_put_request); static unsigned len_args(unsigned numargs, struct fuse_arg *args) { unsigned nbytes = 0; unsigned i; for (i = 0; i < numargs; i++) nbytes += args[i].size; return nbytes; } static u64 fuse_get_unique(struct fuse_conn *fc) { fc->reqctr++; /* zero is special */ if (fc->reqctr == 0) fc->reqctr = 1; return fc->reqctr; } static void queue_request(struct fuse_conn *fc, struct fuse_req *req) { req->in.h.len = sizeof(struct fuse_in_header) + len_args(req->in.numargs, (struct fuse_arg *) req->in.args); list_add_tail(&req->list, &fc->pending); req->state = FUSE_REQ_PENDING; if (!req->waiting) { req->waiting = 1; atomic_inc(&fc->num_waiting); } wake_up(&fc->waitq); kill_fasync(&fc->fasync, SIGIO, POLL_IN); } void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, u64 nodeid, u64 nlookup) { forget->forget_one.nodeid = nodeid; forget->forget_one.nlookup = nlookup; spin_lock(&fc->lock); if (fc->connected) { fc->forget_list_tail->next = forget; fc->forget_list_tail = forget; wake_up(&fc->waitq); kill_fasync(&fc->fasync, SIGIO, POLL_IN); } else { kfree(forget); } spin_unlock(&fc->lock); } static void flush_bg_queue(struct fuse_conn *fc) { while (fc->active_background < fc->max_background && !list_empty(&fc->bg_queue)) { struct fuse_req *req; req = list_entry(fc->bg_queue.next, struct fuse_req, list); list_del(&req->list); fc->active_background++; req->in.h.unique = fuse_get_unique(fc); queue_request(fc, req); } } /* * This function is called when a request is finished. Either a reply * has arrived or it was aborted (and not yet sent) or some error * occurred during communication with userspace, or the device file * was closed. The requester thread is woken up (if still waiting), * the 'end' callback is called if given, else the reference to the * request is released * * Called with fc->lock, unlocks it */ static void request_end(struct fuse_conn *fc, struct fuse_req *req) __releases(fc->lock) { void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; req->end = NULL; list_del(&req->list); list_del(&req->intr_entry); req->state = FUSE_REQ_FINISHED; if (req->background) { if (fc->num_background == fc->max_background) { fc->blocked = 0; wake_up_all(&fc->blocked_waitq); } if (fc->num_background == fc->congestion_threshold && fc->connected && fc->bdi_initialized) { clear_bdi_congested(&fc->bdi, BLK_RW_SYNC); clear_bdi_congested(&fc->bdi, BLK_RW_ASYNC); } fc->num_background--; fc->active_background--; flush_bg_queue(fc); } spin_unlock(&fc->lock); wake_up(&req->waitq); if (end) end(fc, req); fuse_put_request(fc, req); } static void wait_answer_interruptible(struct fuse_conn *fc, struct fuse_req *req) __releases(fc->lock) __acquires(fc->lock) { if (signal_pending(current)) return; spin_unlock(&fc->lock); wait_event_interruptible(req->waitq, req->state == FUSE_REQ_FINISHED); spin_lock(&fc->lock); } static void queue_interrupt(struct fuse_conn *fc, struct fuse_req *req) { list_add_tail(&req->intr_entry, &fc->interrupts); wake_up(&fc->waitq); kill_fasync(&fc->fasync, SIGIO, POLL_IN); } static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) __releases(fc->lock) __acquires(fc->lock) { if (!fc->no_interrupt) { /* Any signal may interrupt this */ wait_answer_interruptible(fc, req); if (req->aborted) goto aborted; if (req->state == FUSE_REQ_FINISHED) return; req->interrupted = 1; if (req->state == FUSE_REQ_SENT) queue_interrupt(fc, req); } if (!req->force) { sigset_t oldset; /* Only fatal signals may interrupt this */ block_sigs(&oldset); wait_answer_interruptible(fc, req); restore_sigs(&oldset); if (req->aborted) goto aborted; if (req->state == FUSE_REQ_FINISHED) return; /* Request is not yet in userspace, bail out */ if (req->state == FUSE_REQ_PENDING) { list_del(&req->list); __fuse_put_request(req); req->out.h.error = -EINTR; return; } } /* * Either request is already in userspace, or it was forced. * Wait it out. */ spin_unlock(&fc->lock); wait_event(req->waitq, req->state == FUSE_REQ_FINISHED); spin_lock(&fc->lock); if (!req->aborted) return; aborted: BUG_ON(req->state != FUSE_REQ_FINISHED); if (req->locked) { /* This is uninterruptible sleep, because data is being copied to/from the buffers of req. During locked state, there mustn't be any filesystem operation (e.g. page fault), since that could lead to deadlock */ spin_unlock(&fc->lock); wait_event(req->waitq, !req->locked); spin_lock(&fc->lock); } } static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) { spin_lock(&fc->lock); if (!fc->connected) req->out.h.error = -ENOTCONN; else if (fc->conn_error) req->out.h.error = -ECONNREFUSED; else { req->in.h.unique = fuse_get_unique(fc); queue_request(fc, req); /* acquire extra reference, since request is still needed after request_end() */ __fuse_get_request(req); request_wait_answer(fc, req); } spin_unlock(&fc->lock); } void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) { req->isreply = 1; __fuse_request_send(fc, req); } EXPORT_SYMBOL_GPL(fuse_request_send); static void fuse_request_send_nowait_locked(struct fuse_conn *fc, struct fuse_req *req) { req->background = 1; fc->num_background++; if (fc->num_background == fc->max_background) fc->blocked = 1; if (fc->num_background == fc->congestion_threshold && fc->bdi_initialized) { set_bdi_congested(&fc->bdi, BLK_RW_SYNC); set_bdi_congested(&fc->bdi, BLK_RW_ASYNC); } list_add_tail(&req->list, &fc->bg_queue); flush_bg_queue(fc); } static void fuse_request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) { spin_lock(&fc->lock); if (fc->connected) { fuse_request_send_nowait_locked(fc, req); spin_unlock(&fc->lock); } else { req->out.h.error = -ENOTCONN; request_end(fc, req); } } void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req) { req->isreply = 1; fuse_request_send_nowait(fc, req);