2392 lines · 54.5 KB · C
RawDownload
/*  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.