/* 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 "dev_uring_i.h"#include "fuse_i.h"#include "fuse_dev_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>#include <linux/seq_file.h> #include "fuse_trace.h" MODULE_ALIAS_MISCDEV(FUSE_MINOR);MODULE_ALIAS("devname:fuse"); static struct kmem_cache *fuse_req_cachep; const unsigned long fuse_timeout_timer_freq = secs_to_jiffies(FUSE_TIMEOUT_TIMER_FREQ); bool fuse_request_expired(struct fuse_conn *fc, struct list_head *list){ struct fuse_req *req; req = list_first_entry_or_null(list, struct fuse_req, list); if (!req) return false; return time_is_before_jiffies(req->create_time + fc->timeout.req_timeout);} static bool fuse_fpq_processing_expired(struct fuse_conn *fc, struct list_head *processing){ int i; for (i = 0; i < FUSE_PQ_HASH_SIZE; i++) if (fuse_request_expired(fc, &processing[i])) return true; return false;} /* * Check if any requests aren't being completed by the time the request timeout * elapses. To do so, we: * - check the fiq pending list * - check the bg queue * - check the fpq io and processing lists * * To make this fast, we only check against the head request on each list since * these are generally queued in order of creation time (eg newer requests get * queued to the tail). We might miss a few edge cases (eg requests transitioning * between lists, re-sent requests at the head of the pending list having a * later creation time than other requests on that list, etc.) but that is fine * since if the request never gets fulfilled, it will eventually be caught. */void fuse_check_timeout(struct work_struct *work){ struct delayed_work *dwork = to_delayed_work(work); struct fuse_conn *fc = container_of(dwork, struct fuse_conn, timeout.work); struct fuse_iqueue *fiq = &fc->iq; struct fuse_dev *fud; struct fuse_pqueue *fpq; bool expired = false; if (!atomic_read(&fc->num_waiting)) goto out; spin_lock(&fiq->lock); expired = fuse_request_expired(fc, &fiq->pending); spin_unlock(&fiq->lock); if (expired) goto abort_conn; spin_lock(&fc->bg_lock); expired = fuse_request_expired(fc, &fc->bg_queue); spin_unlock(&fc->bg_lock); if (expired) goto abort_conn; spin_lock(&fc->lock); if (!fc->connected) { spin_unlock(&fc->lock); return; } list_for_each_entry(fud, &fc->devices, entry) { fpq = &fud->pq; spin_lock(&fpq->lock); if (fuse_request_expired(fc, &fpq->io) || fuse_fpq_processing_expired(fc, fpq->processing)) { spin_unlock(&fpq->lock); spin_unlock(&fc->lock); goto abort_conn; } spin_unlock(&fpq->lock); } spin_unlock(&fc->lock); if (fuse_uring_request_expired(fc)) goto abort_conn; out: queue_delayed_work(system_percpu_wq, &fc->timeout.work, fuse_timeout_timer_freq); return; abort_conn: fuse_abort_conn(fc);} static void fuse_request_init(struct fuse_mount *fm, struct fuse_req *req){ INIT_LIST_HEAD(&req->list); INIT_LIST_HEAD(&req->intr_entry); init_waitqueue_head(&req->waitq); refcount_set(&req->count, 1); __set_bit(FR_PENDING, &req->flags); req->fm = fm; req->create_time = jiffies;} static struct fuse_req *fuse_request_alloc(struct fuse_mount *fm, gfp_t flags){ struct fuse_req *req = kmem_cache_zalloc(fuse_req_cachep, flags); if (req) fuse_request_init(fm, req); return req;} static void fuse_request_free(struct fuse_req *req){ kmem_cache_free(fuse_req_cachep, req);} static 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) || (fc->io_uring && fc->connected && !fuse_uring_ready(fc));} 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 matched 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 void fuse_put_request(struct fuse_req *req); static struct fuse_req *fuse_get_req(struct mnt_idmap *idmap, struct fuse_mount *fm, bool for_background){ struct fuse_conn *fc = fm->fc; struct fuse_req *req; bool no_idmap = !fm->sb || (fm->sb->s_iflags & SB_I_NOIDMAP); kuid_t fsuid; kgid_t fsgid; int err; atomic_inc(&fc->num_waiting); if (fuse_block_alloc(fc, for_background)) { err = -EINTR; if (wait_event_state_exclusive(fc->blocked_waitq, !fuse_block_alloc(fc, for_background), (TASK_KILLABLE | TASK_FREEZABLE))) 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(fm, GFP_KERNEL); err = -ENOMEM; if (!req) { if (for_background) wake_up(&fc->blocked_waitq); goto out; } 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); /* * Keep the old behavior when idmappings support was not * declared by a FUSE server. * * For those FUSE servers who support idmapped mounts, * we send UID/GID only along with "inode creation" * fuse requests, otherwise idmap == &invalid_mnt_idmap and * req->in.h.{u,g}id will be equal to FUSE_INVALID_UIDGID. */ fsuid = no_idmap ? current_fsuid() : mapped_fsuid(idmap, fc->user_ns); fsgid = no_idmap ? current_fsgid() : mapped_fsgid(idmap, fc->user_ns); req->in.h.uid = from_kuid(fc->user_ns, fsuid); req->in.h.gid = from_kgid(fc->user_ns, fsgid); if (no_idmap && unlikely(req->in.h.uid == ((uid_t)-1) || req->in.h.gid == ((gid_t)-1))) { fuse_put_request(req); return ERR_PTR(-EOVERFLOW); } return req; out: fuse_drop_waiting(fc); return ERR_PTR(err);} static void fuse_put_request(struct fuse_req *req){ struct fuse_conn *fc = req->fm->fc; 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); } fuse_request_free(req); }} unsigned int fuse_len_args(unsigned int numargs, struct fuse_arg *args){ unsigned nbytes = 0; unsigned i; for (i = 0; i < numargs; i++) nbytes += args[i].size; return nbytes;}EXPORT_SYMBOL_GPL(fuse_len_args); static u64 fuse_get_unique_locked(struct fuse_iqueue *fiq){ fiq->reqctr += FUSE_REQ_ID_STEP; return fiq->reqctr;} u64 fuse_get_unique(struct fuse_iqueue *fiq){ u64 ret; spin_lock(&fiq->lock); ret = fuse_get_unique_locked(fiq); spin_unlock(&fiq->lock); return ret;}EXPORT_SYMBOL_GPL(fuse_get_unique); unsigned int fuse_req_hash(u64 unique){ return hash_long(unique & ~FUSE_INT_REQ_BIT, FUSE_PQ_HASH_BITS);}EXPORT_SYMBOL_GPL(fuse_req_hash); /* * A new request is available, wake fiq->waitq */static void fuse_dev_wake_and_unlock(struct fuse_iqueue *fiq)__releases(fiq->lock){ wake_up(&fiq->waitq); kill_fasync(&fiq->fasync, SIGIO, POLL_IN); spin_unlock(&fiq->lock);} void fuse_dev_queue_forget(struct fuse_iqueue *fiq, struct fuse_forget_link *forget){ spin_lock(&fiq->lock); if (fiq->connected) { fiq->forget_list_tail->next = forget; fiq->forget_list_tail = forget; fuse_dev_wake_and_unlock(fiq); } else { kfree(forget); spin_unlock(&fiq->lock); }} void fuse_dev_queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req){ spin_lock(&fiq->lock); 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 fuse_request_end(). */ smp_mb(); if (test_bit(FR_FINISHED, &req->flags)) { list_del_init(&req->intr_entry); spin_unlock(&fiq->lock); } else { fuse_dev_wake_and_unlock(fiq); } } else { spin_unlock(&fiq->lock); }} static inline void fuse_request_assign_unique_locked(struct fuse_iqueue *fiq, struct fuse_req *req){ if (req->in.h.opcode != FUSE_NOTIFY_REPLY) req->in.h.unique = fuse_get_unique_locked(fiq); /* tracepoint captures in.h.unique and in.h.len */ trace_fuse_request_send(req);} inline void fuse_request_assign_unique(struct fuse_iqueue *fiq, struct fuse_req *req){ if (req->in.h.opcode != FUSE_NOTIFY_REPLY) req->in.h.unique = fuse_get_unique(fiq); /* tracepoint captures in.h.unique and in.h.len */ trace_fuse_request_send(req);}EXPORT_SYMBOL_GPL(fuse_request_assign_unique); static void fuse_dev_queue_req(struct fuse_iqueue *fiq, struct fuse_req *req){ spin_lock(&fiq->lock); if (fiq->connected) { fuse_request_assign_unique_locked(fiq, req); list_add_tail(&req->list, &fiq->pending); fuse_dev_wake_and_unlock(fiq); } else { spin_unlock(&fiq->lock); req->out.h.error = -ENOTCONN; clear_bit(FR_PENDING, &req->flags); fuse_request_end(req); }} const struct fuse_iqueue_ops fuse_dev_fiq_ops = { .send_forget = fuse_dev_queue_forget, .send_interrupt = fuse_dev_queue_interrupt, .send_req = fuse_dev_queue_req,};EXPORT_SYMBOL_GPL(fuse_dev_fiq_ops); static void fuse_send_one(struct fuse_iqueue *fiq, struct fuse_req *req){ req->in.h.len = sizeof(struct fuse_in_header) + fuse_len_args(req->args->in_numargs, (struct fuse_arg *) req->args->in_args); fiq->ops->send_req(fiq, req);} 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; fiq->ops->send_forget(fiq, forget);} 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++; fuse_send_one(fiq, 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 */void fuse_request_end(struct fuse_req *req){ struct fuse_mount *fm = req->fm; struct fuse_conn *fc = fm->fc; struct fuse_iqueue *fiq = &fc->iq; if (test_and_set_bit(FR_FINISHED, &req->flags)) goto put_request; trace_fuse_request_end(req); /* * test_and_set_bit() implies smp_mb() between bit * changing and below FR_INTERRUPTED check. Pairs with * smp_mb() from queue_interrupt(). */ if (test_bit(FR_INTERRUPTED, &req->flags)) { spin_lock(&fiq->lock); list_del_init(&req->intr_entry); spin_unlock(&fiq->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); } fc->num_background--; fc->active_background--; flush_bg_queue(fc); spin_unlock(&fc->bg_lock);Lines 1–500 of 2756. 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 "dev_uring_i.h" #include "fuse_i.h" #include "fuse_dev_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> #include <linux/seq_file.h> #include "fuse_trace.h" MODULE_ALIAS_MISCDEV(FUSE_MINOR); MODULE_ALIAS("devname:fuse"); static struct kmem_cache *fuse_req_cachep; const unsigned long fuse_timeout_timer_freq = secs_to_jiffies(FUSE_TIMEOUT_TIMER_FREQ); bool fuse_request_expired(struct fuse_conn *fc, struct list_head *list) { struct fuse_req *req; req = list_first_entry_or_null(list, struct fuse_req, list); if (!req) return false; return time_is_before_jiffies(req->create_time + fc->timeout.req_timeout); } static bool fuse_fpq_processing_expired(struct fuse_conn *fc, struct list_head *processing) { int i; for (i = 0; i < FUSE_PQ_HASH_SIZE; i++) if (fuse_request_expired(fc, &processing[i])) return true; return false; } /* * Check if any requests aren't being completed by the time the request timeout * elapses. To do so, we: * - check the fiq pending list * - check the bg queue * - check the fpq io and processing lists * * To make this fast, we only check against the head request on each list since * these are generally queued in order of creation time (eg newer requests get * queued to the tail). We might miss a few edge cases (eg requests transitioning * between lists, re-sent requests at the head of the pending list having a * later creation time than other requests on that list, etc.) but that is fine * since if the request never gets fulfilled, it will eventually be caught. */ void fuse_check_timeout(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); struct fuse_conn *fc = container_of(dwork, struct fuse_conn, timeout.work); struct fuse_iqueue *fiq = &fc->iq; struct fuse_dev *fud; struct fuse_pqueue *fpq; bool expired = false; if (!atomic_read(&fc->num_waiting)) goto out; spin_lock(&fiq->lock); expired = fuse_request_expired(fc, &fiq->pending); spin_unlock(&fiq->lock); if (expired) goto abort_conn; spin_lock(&fc->bg_lock); expired = fuse_request_expired(fc, &fc->bg_queue); spin_unlock(&fc->bg_lock); if (expired) goto abort_conn; spin_lock(&fc->lock); if (!fc->connected) { spin_unlock(&fc->lock); return; } list_for_each_entry(fud, &fc->devices, entry) { fpq = &fud->pq; spin_lock(&fpq->lock); if (fuse_request_expired(fc, &fpq->io) || fuse_fpq_processing_expired(fc, fpq->processing)) { spin_unlock(&fpq->lock); spin_unlock(&fc->lock); goto abort_conn; } spin_unlock(&fpq->lock); } spin_unlock(&fc->lock); if (fuse_uring_request_expired(fc)) goto abort_conn; out: queue_delayed_work(system_percpu_wq, &fc->timeout.work, fuse_timeout_timer_freq); return; abort_conn: fuse_abort_conn(fc); } static void fuse_request_init(struct fuse_mount *fm, struct fuse_req *req) { INIT_LIST_HEAD(&req->list); INIT_LIST_HEAD(&req->intr_entry); init_waitqueue_head(&req->waitq); refcount_set(&req->count, 1); __set_bit(FR_PENDING, &req->flags); req->fm = fm; req->create_time = jiffies; } static struct fuse_req *fuse_request_alloc(struct fuse_mount *fm, gfp_t flags) { struct fuse_req *req = kmem_cache_zalloc(fuse_req_cachep, flags); if (req) fuse_request_init(fm, req); return req; } static void fuse_request_free(struct fuse_req *req) { kmem_cache_free(fuse_req_cachep, req); } static 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) || (fc->io_uring && fc->connected && !fuse_uring_ready(fc)); } 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 matched 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 void fuse_put_request(struct fuse_req *req); static struct fuse_req *fuse_get_req(struct mnt_idmap *idmap, struct fuse_mount *fm, bool for_background) { struct fuse_conn *fc = fm->fc; struct fuse_req *req; bool no_idmap = !fm->sb || (fm->sb->s_iflags & SB_I_NOIDMAP); kuid_t fsuid; kgid_t fsgid; int err; atomic_inc(&fc->num_waiting); if (fuse_block_alloc(fc, for_background)) { err = -EINTR; if (wait_event_state_exclusive(fc->blocked_waitq, !fuse_block_alloc(fc, for_background), (TASK_KILLABLE | TASK_FREEZABLE))) 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(fm, GFP_KERNEL); err = -ENOMEM; if (!req) { if (for_background) wake_up(&fc->blocked_waitq); goto out; } 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); /* * Keep the old behavior when idmappings support was not * declared by a FUSE server. * * For those FUSE servers who support idmapped mounts, * we send UID/GID only along with "inode creation" * fuse requests, otherwise idmap == &invalid_mnt_idmap and * req->in.h.{u,g}id will be equal to FUSE_INVALID_UIDGID. */ fsuid = no_idmap ? current_fsuid() : mapped_fsuid(idmap, fc->user_ns); fsgid = no_idmap ? current_fsgid() : mapped_fsgid(idmap, fc->user_ns); req->in.h.uid = from_kuid(fc->user_ns, fsuid); req->in.h.gid = from_kgid(fc->user_ns, fsgid); if (no_idmap && unlikely(req->in.h.uid == ((uid_t)-1) || req->in.h.gid == ((gid_t)-1))) { fuse_put_request(req); return ERR_PTR(-EOVERFLOW); } return req; out: fuse_drop_waiting(fc); return ERR_PTR(err); } static void fuse_put_request(struct fuse_req *req) { struct fuse_conn *fc = req->fm->fc; 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); } fuse_request_free(req); } } unsigned int fuse_len_args(unsigned int numargs, struct fuse_arg *args) { unsigned nbytes = 0; unsigned i; for (i = 0; i < numargs; i++) nbytes += args[i].size; return nbytes; } EXPORT_SYMBOL_GPL(fuse_len_args); static u64 fuse_get_unique_locked(struct fuse_iqueue *fiq) { fiq->reqctr += FUSE_REQ_ID_STEP; return fiq->reqctr; } u64 fuse_get_unique(struct fuse_iqueue *fiq) { u64 ret; spin_lock(&fiq->lock); ret = fuse_get_unique_locked(fiq); spin_unlock(&fiq->lock); return ret; } EXPORT_SYMBOL_GPL(fuse_get_unique); unsigned int fuse_req_hash(u64 unique) { return hash_long(unique & ~FUSE_INT_REQ_BIT, FUSE_PQ_HASH_BITS); } EXPORT_SYMBOL_GPL(fuse_req_hash); /* * A new request is available, wake fiq->waitq */ static void fuse_dev_wake_and_unlock(struct fuse_iqueue *fiq) __releases(fiq->lock) { wake_up(&fiq->waitq); kill_fasync(&fiq->fasync, SIGIO, POLL_IN); spin_unlock(&fiq->lock); } void fuse_dev_queue_forget(struct fuse_iqueue *fiq, struct fuse_forget_link *forget) { spin_lock(&fiq->lock); if (fiq->connected) { fiq->forget_list_tail->next = forget; fiq->forget_list_tail = forget; fuse_dev_wake_and_unlock(fiq); } else { kfree(forget); spin_unlock(&fiq->lock); } } void fuse_dev_queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req) { spin_lock(&fiq->lock); 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 fuse_request_end(). */ smp_mb(); if (test_bit(FR_FINISHED, &req->flags)) { list_del_init(&req->intr_entry); spin_unlock(&fiq->lock); } else { fuse_dev_wake_and_unlock(fiq); } } else { spin_unlock(&fiq->lock); } } static inline void fuse_request_assign_unique_locked(struct fuse_iqueue *fiq, struct fuse_req *req) { if (req->in.h.opcode != FUSE_NOTIFY_REPLY) req->in.h.unique = fuse_get_unique_locked(fiq); /* tracepoint captures in.h.unique and in.h.len */ trace_fuse_request_send(req); } inline void fuse_request_assign_unique(struct fuse_iqueue *fiq, struct fuse_req *req) { if (req->in.h.opcode != FUSE_NOTIFY_REPLY) req->in.h.unique = fuse_get_unique(fiq); /* tracepoint captures in.h.unique and in.h.len */ trace_fuse_request_send(req); } EXPORT_SYMBOL_GPL(fuse_request_assign_unique); static void fuse_dev_queue_req(struct fuse_iqueue *fiq, struct fuse_req *req) { spin_lock(&fiq->lock); if (fiq->connected) { fuse_request_assign_unique_locked(fiq, req); list_add_tail(&req->list, &fiq->pending); fuse_dev_wake_and_unlock(fiq); } else { spin_unlock(&fiq->lock); req->out.h.error = -ENOTCONN; clear_bit(FR_PENDING, &req->flags); fuse_request_end(req); } } const struct fuse_iqueue_ops fuse_dev_fiq_ops = { .send_forget = fuse_dev_queue_forget, .send_interrupt = fuse_dev_queue_interrupt, .send_req = fuse_dev_queue_req, }; EXPORT_SYMBOL_GPL(fuse_dev_fiq_ops); static void fuse_send_one(struct fuse_iqueue *fiq, struct fuse_req *req) { req->in.h.len = sizeof(struct fuse_in_header) + fuse_len_args(req->args->in_numargs, (struct fuse_arg *) req->args->in_args); fiq->ops->send_req(fiq, req); } 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; fiq->ops->send_forget(fiq, forget); } 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++; fuse_send_one(fiq, 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 */ void fuse_request_end(struct fuse_req *req) { struct fuse_mount *fm = req->fm; struct fuse_conn *fc = fm->fc; struct fuse_iqueue *fiq = &fc->iq; if (test_and_set_bit(FR_FINISHED, &req->flags)) goto put_request; trace_fuse_request_end(req); /* * test_and_set_bit() implies smp_mb() between bit * changing and below FR_INTERRUPTED check. Pairs with * smp_mb() from queue_interrupt(). */ if (test_bit(FR_INTERRUPTED, &req->flags)) { spin_lock(&fiq->lock); list_del_init(&req->intr_entry); spin_unlock(&fiq->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); } fc->num_background--; fc->active_background--; flush_bg_queue(fc); spin_unlock(&fc->bg_lock);