/* 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/sched/signal.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>#include <linux/sched.h> MODULE_ALIAS_MISCDEV(FUSE_MINOR);MODULE_ALIAS("devname:fuse"); /* Ordinary requests have even IDs, while interrupts IDs are odd */#define FUSE_INT_REQ_BIT (1ULL << 0)#define FUSE_REQ_ID_STEP (1ULL << 1) static struct kmem_cache *fuse_req_cachep; static struct fuse_dev *fuse_get_dev(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 READ_ONCE(file->private_data);} static void fuse_request_init(struct fuse_req *req, struct page **pages, struct fuse_page_desc *page_descs, unsigned npages){ INIT_LIST_HEAD(&req->list); INIT_LIST_HEAD(&req->intr_entry); init_waitqueue_head(&req->waitq); refcount_set(&req->count, 1); req->pages = pages; req->page_descs = page_descs; req->max_pages = npages; __set_bit(FR_PENDING, &req->flags);} static struct page **fuse_req_pages_alloc(unsigned int npages, gfp_t flags, struct fuse_page_desc **desc){ struct page **pages; pages = kzalloc(npages * (sizeof(struct page *) + sizeof(struct fuse_page_desc)), flags); *desc = (void *) pages + npages * sizeof(struct page *); return pages;} static struct fuse_req *__fuse_request_alloc(unsigned npages, gfp_t flags){ struct fuse_req *req = kmem_cache_zalloc(fuse_req_cachep, flags); if (req) { struct page **pages = NULL; struct fuse_page_desc *page_descs = NULL; WARN_ON(npages > FUSE_MAX_MAX_PAGES); if (npages > FUSE_REQ_INLINE_PAGES) { pages = fuse_req_pages_alloc(npages, flags, &page_descs); if (!pages) { kmem_cache_free(fuse_req_cachep, req); return NULL; } } else if (npages) { pages = req->inline_pages; page_descs = req->inline_page_descs; } 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);} static void fuse_req_pages_free(struct fuse_req *req){ if (req->pages != req->inline_pages) kfree(req->pages);} bool fuse_req_realloc_pages(struct fuse_conn *fc, struct fuse_req *req, gfp_t flags){ struct page **pages; struct fuse_page_desc *page_descs; unsigned int npages = min_t(unsigned int, max_t(unsigned int, req->max_pages * 2, FUSE_DEFAULT_MAX_PAGES_PER_REQ), fc->max_pages); WARN_ON(npages <= req->max_pages); pages = fuse_req_pages_alloc(npages, flags, &page_descs); if (!pages) return false; memcpy(pages, req->pages, sizeof(struct page *) * req->max_pages); memcpy(page_descs, req->page_descs, sizeof(struct fuse_page_desc) * req->max_pages); fuse_req_pages_free(req); req->pages = pages; req->page_descs = page_descs; req->max_pages = npages; return true;} void fuse_request_free(struct fuse_req *req){ fuse_req_pages_free(req); kmem_cache_free(fuse_req_cachep, req);} void __fuse_get_request(struct fuse_req *req){ refcount_inc(&req->count);} /* Must be called with > 1 refcount */static void __fuse_put_request(struct fuse_req *req){ refcount_dec(&req->count);} void fuse_set_initialized(struct fuse_conn *fc){ /* Make sure stores before this are seen on another CPU */ smp_wmb(); fc->initialized = 1;} static bool fuse_block_alloc(struct fuse_conn *fc, bool for_background){ return !fc->initialized || (for_background && fc->blocked);} static void fuse_drop_waiting(struct fuse_conn *fc){ /* * lockess check of fc->connected is okay, because atomic_dec_and_test() * provides a memory barrier mached with the one in fuse_wait_aborted() * to ensure no wake-up is missed. */ if (atomic_dec_and_test(&fc->num_waiting) && !READ_ONCE(fc->connected)) { /* wake up aborters */ wake_up_all(&fc->blocked_waitq); }} static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages, bool for_background){ struct fuse_req *req; int err; atomic_inc(&fc->num_waiting); if (fuse_block_alloc(fc, for_background)) { err = -EINTR; if (wait_event_killable_exclusive(fc->blocked_waitq, !fuse_block_alloc(fc, for_background))) goto out; } /* Matches smp_wmb() in fuse_set_initialized() */ smp_rmb(); err = -ENOTCONN; if (!fc->connected) goto out; err = -ECONNREFUSED; if (fc->conn_error) goto out; req = fuse_request_alloc(npages); err = -ENOMEM; if (!req) { if (for_background) wake_up(&fc->blocked_waitq); goto out; } req->in.h.uid = from_kuid(fc->user_ns, current_fsuid()); req->in.h.gid = from_kgid(fc->user_ns, current_fsgid()); req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns); __set_bit(FR_WAITING, &req->flags); if (for_background) __set_bit(FR_BACKGROUND, &req->flags); if (unlikely(req->in.h.uid == ((uid_t)-1) || req->in.h.gid == ((gid_t)-1))) { fuse_put_request(fc, req); return ERR_PTR(-EOVERFLOW); } return req; out: fuse_drop_waiting(fc); return ERR_PTR(err);} struct fuse_req *fuse_get_req(struct fuse_conn *fc, unsigned npages){ return __fuse_get_req(fc, npages, false);}EXPORT_SYMBOL_GPL(fuse_get_req); struct fuse_req *fuse_get_req_for_background(struct fuse_conn *fc, unsigned npages){ return __fuse_get_req(fc, npages, true);}EXPORT_SYMBOL_GPL(fuse_get_req_for_background); /* * 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_inode *fi = get_fuse_inode(file_inode(file)); struct fuse_file *ff = file->private_data; do { wait_event(fc->reserved_req_waitq, ff->reserved_req); spin_lock(&fi->lock); if (ff->reserved_req) { req = ff->reserved_req; ff->reserved_req = NULL; req->stolen_file = get_file(file); } spin_unlock(&fi->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_inode *fi = get_fuse_inode(file_inode(file)); struct fuse_file *ff = file->private_data; WARN_ON(req->max_pages); spin_lock(&fi->lock); memset(req, 0, sizeof(*req)); fuse_request_init(req, NULL, NULL, 0); BUG_ON(ff->reserved_req); ff->reserved_req = req; wake_up_all(&fc->reserved_req_waitq); spin_unlock(&fi->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->initialized); /* Matches smp_wmb() in fuse_set_initialized() */ smp_rmb(); req = fuse_request_alloc(0); if (!req) req = get_reserved_req(fc, file); req->in.h.uid = from_kuid_munged(fc->user_ns, current_fsuid()); req->in.h.gid = from_kgid_munged(fc->user_ns, current_fsgid()); req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns); __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 (refcount_dec_and_test(&req->count)) { if (test_bit(FR_BACKGROUND, &req->flags)) { /* * We get here in the unlikely case that a background * request was allocated but not sent */ spin_lock(&fc->bg_lock); if (!fc->blocked) wake_up(&fc->blocked_waitq); spin_unlock(&fc->bg_lock); } if (test_bit(FR_WAITING, &req->flags)) { __clear_bit(FR_WAITING, &req->flags); fuse_drop_waiting(fc); } 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_iqueue *fiq){ fiq->reqctr += FUSE_REQ_ID_STEP; return fiq->reqctr;} static unsigned int fuse_req_hash(u64 unique){ return hash_long(unique & ~FUSE_INT_REQ_BIT, FUSE_PQ_HASH_BITS);} static void queue_request(struct fuse_iqueue *fiq, 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, &fiq->pending); wake_up_locked(&fiq->waitq); kill_fasync(&fiq->fasync, SIGIO, POLL_IN);} void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, u64 nodeid, u64 nlookup){ struct fuse_iqueue *fiq = &fc->iq; forget->forget_one.nodeid = nodeid; forget->forget_one.nlookup = nlookup; spin_lock(&fiq->waitq.lock); if (fiq->connected) { fiq->forget_list_tail->next = forget; fiq->forget_list_tail = forget; wake_up_locked(&fiq->waitq); kill_fasync(&fiq->fasync, SIGIO, POLL_IN); } else { kfree(forget); } spin_unlock(&fiq->waitq.lock);} static void flush_bg_queue(struct fuse_conn *fc){ struct fuse_iqueue *fiq = &fc->iq; while (fc->active_background < fc->max_background && !list_empty(&fc->bg_queue)) { struct fuse_req *req; req = list_first_entry(&fc->bg_queue, struct fuse_req, list); list_del(&req->list); fc->active_background++; spin_lock(&fiq->waitq.lock); req->in.h.unique = fuse_get_unique(fiq); queue_request(fiq, req); spin_unlock(&fiq->waitq.lock); }} /* * 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 */static void request_end(struct fuse_conn *fc, struct fuse_req *req){ struct fuse_iqueue *fiq = &fc->iq; if (test_and_set_bit(FR_FINISHED, &req->flags)) goto put_request; /* * test_and_set_bit() implies smp_mb() between bit * changing and below intr_entry check. Pairs with * smp_mb() from queue_interrupt(). */ if (!list_empty(&req->intr_entry)) { 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)); if (test_bit(FR_BACKGROUND, &req->flags)) { spin_lock(&fc->bg_lock); clear_bit(FR_BACKGROUND, &req->flags); if (fc->num_background == fc->max_background) { fc->blocked = 0; wake_up(&fc->blocked_waitq); } else if (!fc->blocked) { /* * Wake up next waiter, if any. It's okay to use * waitqueue_active(), as we've already synced up * fc->blocked with waiters with the wake_up() call * above. */ if (waitqueue_active(&fc->blocked_waitq)) wake_up(&fc->blocked_waitq); } if (fc->num_background == fc->congestion_threshold && fc->sb) { clear_bdi_congested(fc->sb->s_bdi, BLK_RW_SYNC); clear_bdi_congested(fc->sb->s_bdi, BLK_RW_ASYNC); } fc->num_background--; fc->active_background--; flush_bg_queue(fc); spin_unlock(&fc->bg_lock); } else { /* Wake up waiter sleeping in request_wait_answer() */ wake_up(&req->waitq); } if (req->end) req->end(fc, req);put_request: fuse_put_request(fc, req);} static int queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req){ spin_lock(&fiq->waitq.lock); /* Check for we've sent request to interrupt this req */ if (unlikely(!test_bit(FR_INTERRUPTED, &req->flags))) { spin_unlock(&fiq->waitq.lock); return -EINVAL; } if (list_empty(&req->intr_entry)) { list_add_tail(&req->intr_entry, &fiq->interrupts); /* * Pairs with smp_mb() implied by test_and_set_bit() * from request_end(). */ smp_mb(); if (test_bit(FR_FINISHED, &req->flags)) {Lines 1–500 of 2392. 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/sched/signal.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> #include <linux/sched.h> MODULE_ALIAS_MISCDEV(FUSE_MINOR); MODULE_ALIAS("devname:fuse"); /* Ordinary requests have even IDs, while interrupts IDs are odd */ #define FUSE_INT_REQ_BIT (1ULL << 0) #define FUSE_REQ_ID_STEP (1ULL << 1) static struct kmem_cache *fuse_req_cachep; static struct fuse_dev *fuse_get_dev(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 READ_ONCE(file->private_data); } static void fuse_request_init(struct fuse_req *req, struct page **pages, struct fuse_page_desc *page_descs, unsigned npages) { INIT_LIST_HEAD(&req->list); INIT_LIST_HEAD(&req->intr_entry); init_waitqueue_head(&req->waitq); refcount_set(&req->count, 1); req->pages = pages; req->page_descs = page_descs; req->max_pages = npages; __set_bit(FR_PENDING, &req->flags); } static struct page **fuse_req_pages_alloc(unsigned int npages, gfp_t flags, struct fuse_page_desc **desc) { struct page **pages; pages = kzalloc(npages * (sizeof(struct page *) + sizeof(struct fuse_page_desc)), flags); *desc = (void *) pages + npages * sizeof(struct page *); return pages; } static struct fuse_req *__fuse_request_alloc(unsigned npages, gfp_t flags) { struct fuse_req *req = kmem_cache_zalloc(fuse_req_cachep, flags); if (req) { struct page **pages = NULL; struct fuse_page_desc *page_descs = NULL; WARN_ON(npages > FUSE_MAX_MAX_PAGES); if (npages > FUSE_REQ_INLINE_PAGES) { pages = fuse_req_pages_alloc(npages, flags, &page_descs); if (!pages) { kmem_cache_free(fuse_req_cachep, req); return NULL; } } else if (npages) { pages = req->inline_pages; page_descs = req->inline_page_descs; } 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); } static void fuse_req_pages_free(struct fuse_req *req) { if (req->pages != req->inline_pages) kfree(req->pages); } bool fuse_req_realloc_pages(struct fuse_conn *fc, struct fuse_req *req, gfp_t flags) { struct page **pages; struct fuse_page_desc *page_descs; unsigned int npages = min_t(unsigned int, max_t(unsigned int, req->max_pages * 2, FUSE_DEFAULT_MAX_PAGES_PER_REQ), fc->max_pages); WARN_ON(npages <= req->max_pages); pages = fuse_req_pages_alloc(npages, flags, &page_descs); if (!pages) return false; memcpy(pages, req->pages, sizeof(struct page *) * req->max_pages); memcpy(page_descs, req->page_descs, sizeof(struct fuse_page_desc) * req->max_pages); fuse_req_pages_free(req); req->pages = pages; req->page_descs = page_descs; req->max_pages = npages; return true; } void fuse_request_free(struct fuse_req *req) { fuse_req_pages_free(req); kmem_cache_free(fuse_req_cachep, req); } void __fuse_get_request(struct fuse_req *req) { refcount_inc(&req->count); } /* Must be called with > 1 refcount */ static void __fuse_put_request(struct fuse_req *req) { refcount_dec(&req->count); } void fuse_set_initialized(struct fuse_conn *fc) { /* Make sure stores before this are seen on another CPU */ smp_wmb(); fc->initialized = 1; } static bool fuse_block_alloc(struct fuse_conn *fc, bool for_background) { return !fc->initialized || (for_background && fc->blocked); } static void fuse_drop_waiting(struct fuse_conn *fc) { /* * lockess check of fc->connected is okay, because atomic_dec_and_test() * provides a memory barrier mached with the one in fuse_wait_aborted() * to ensure no wake-up is missed. */ if (atomic_dec_and_test(&fc->num_waiting) && !READ_ONCE(fc->connected)) { /* wake up aborters */ wake_up_all(&fc->blocked_waitq); } } static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages, bool for_background) { struct fuse_req *req; int err; atomic_inc(&fc->num_waiting); if (fuse_block_alloc(fc, for_background)) { err = -EINTR; if (wait_event_killable_exclusive(fc->blocked_waitq, !fuse_block_alloc(fc, for_background))) goto out; } /* Matches smp_wmb() in fuse_set_initialized() */ smp_rmb(); err = -ENOTCONN; if (!fc->connected) goto out; err = -ECONNREFUSED; if (fc->conn_error) goto out; req = fuse_request_alloc(npages); err = -ENOMEM; if (!req) { if (for_background) wake_up(&fc->blocked_waitq); goto out; } req->in.h.uid = from_kuid(fc->user_ns, current_fsuid()); req->in.h.gid = from_kgid(fc->user_ns, current_fsgid()); req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns); __set_bit(FR_WAITING, &req->flags); if (for_background) __set_bit(FR_BACKGROUND, &req->flags); if (unlikely(req->in.h.uid == ((uid_t)-1) || req->in.h.gid == ((gid_t)-1))) { fuse_put_request(fc, req); return ERR_PTR(-EOVERFLOW); } return req; out: fuse_drop_waiting(fc); return ERR_PTR(err); } struct fuse_req *fuse_get_req(struct fuse_conn *fc, unsigned npages) { return __fuse_get_req(fc, npages, false); } EXPORT_SYMBOL_GPL(fuse_get_req); struct fuse_req *fuse_get_req_for_background(struct fuse_conn *fc, unsigned npages) { return __fuse_get_req(fc, npages, true); } EXPORT_SYMBOL_GPL(fuse_get_req_for_background); /* * 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_inode *fi = get_fuse_inode(file_inode(file)); struct fuse_file *ff = file->private_data; do { wait_event(fc->reserved_req_waitq, ff->reserved_req); spin_lock(&fi->lock); if (ff->reserved_req) { req = ff->reserved_req; ff->reserved_req = NULL; req->stolen_file = get_file(file); } spin_unlock(&fi->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_inode *fi = get_fuse_inode(file_inode(file)); struct fuse_file *ff = file->private_data; WARN_ON(req->max_pages); spin_lock(&fi->lock); memset(req, 0, sizeof(*req)); fuse_request_init(req, NULL, NULL, 0); BUG_ON(ff->reserved_req); ff->reserved_req = req; wake_up_all(&fc->reserved_req_waitq); spin_unlock(&fi->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->initialized); /* Matches smp_wmb() in fuse_set_initialized() */ smp_rmb(); req = fuse_request_alloc(0); if (!req) req = get_reserved_req(fc, file); req->in.h.uid = from_kuid_munged(fc->user_ns, current_fsuid()); req->in.h.gid = from_kgid_munged(fc->user_ns, current_fsgid()); req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns); __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 (refcount_dec_and_test(&req->count)) { if (test_bit(FR_BACKGROUND, &req->flags)) { /* * We get here in the unlikely case that a background * request was allocated but not sent */ spin_lock(&fc->bg_lock); if (!fc->blocked) wake_up(&fc->blocked_waitq); spin_unlock(&fc->bg_lock); } if (test_bit(FR_WAITING, &req->flags)) { __clear_bit(FR_WAITING, &req->flags); fuse_drop_waiting(fc); } 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_iqueue *fiq) { fiq->reqctr += FUSE_REQ_ID_STEP; return fiq->reqctr; } static unsigned int fuse_req_hash(u64 unique) { return hash_long(unique & ~FUSE_INT_REQ_BIT, FUSE_PQ_HASH_BITS); } static void queue_request(struct fuse_iqueue *fiq, 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, &fiq->pending); wake_up_locked(&fiq->waitq); kill_fasync(&fiq->fasync, SIGIO, POLL_IN); } void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, u64 nodeid, u64 nlookup) { struct fuse_iqueue *fiq = &fc->iq; forget->forget_one.nodeid = nodeid; forget->forget_one.nlookup = nlookup; spin_lock(&fiq->waitq.lock); if (fiq->connected) { fiq->forget_list_tail->next = forget; fiq->forget_list_tail = forget; wake_up_locked(&fiq->waitq); kill_fasync(&fiq->fasync, SIGIO, POLL_IN); } else { kfree(forget); } spin_unlock(&fiq->waitq.lock); } static void flush_bg_queue(struct fuse_conn *fc) { struct fuse_iqueue *fiq = &fc->iq; while (fc->active_background < fc->max_background && !list_empty(&fc->bg_queue)) { struct fuse_req *req; req = list_first_entry(&fc->bg_queue, struct fuse_req, list); list_del(&req->list); fc->active_background++; spin_lock(&fiq->waitq.lock); req->in.h.unique = fuse_get_unique(fiq); queue_request(fiq, req); spin_unlock(&fiq->waitq.lock); } } /* * 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 */ static void request_end(struct fuse_conn *fc, struct fuse_req *req) { struct fuse_iqueue *fiq = &fc->iq; if (test_and_set_bit(FR_FINISHED, &req->flags)) goto put_request; /* * test_and_set_bit() implies smp_mb() between bit * changing and below intr_entry check. Pairs with * smp_mb() from queue_interrupt(). */ if (!list_empty(&req->intr_entry)) { 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)); if (test_bit(FR_BACKGROUND, &req->flags)) { spin_lock(&fc->bg_lock); clear_bit(FR_BACKGROUND, &req->flags); if (fc->num_background == fc->max_background) { fc->blocked = 0; wake_up(&fc->blocked_waitq); } else if (!fc->blocked) { /* * Wake up next waiter, if any. It's okay to use * waitqueue_active(), as we've already synced up * fc->blocked with waiters with the wake_up() call * above. */ if (waitqueue_active(&fc->blocked_waitq)) wake_up(&fc->blocked_waitq); } if (fc->num_background == fc->congestion_threshold && fc->sb) { clear_bdi_congested(fc->sb->s_bdi, BLK_RW_SYNC); clear_bdi_congested(fc->sb->s_bdi, BLK_RW_ASYNC); } fc->num_background--; fc->active_background--; flush_bg_queue(fc); spin_unlock(&fc->bg_lock); } else { /* Wake up waiter sleeping in request_wait_answer() */ wake_up(&req->waitq); } if (req->end) req->end(fc, req); put_request: fuse_put_request(fc, req); } static int queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req) { spin_lock(&fiq->waitq.lock); /* Check for we've sent request to interrupt this req */ if (unlikely(!test_bit(FR_INTERRUPTED, &req->flags))) { spin_unlock(&fiq->waitq.lock); return -EINVAL; } if (list_empty(&req->intr_entry)) { list_add_tail(&req->intr_entry, &fiq->interrupts); /* * Pairs with smp_mb() implied by test_and_set_bit() * from request_end(). */ smp_mb(); if (test_bit(FR_FINISHED, &req->flags)) {