2264 lines · 50.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/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/aio.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);} 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;} 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 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)) {		sigset_t oldset;		int intr; 		block_sigs(&oldset);		intr = wait_event_interruptible_exclusive(fc->blocked_waitq,				!fuse_block_alloc(fc, for_background));		restore_sigs(&oldset);		err = -EINTR;		if (intr)			goto out;	}	/* Matches smp_wmb() in fuse_set_initialized() */	smp_rmb(); 	err = -ENOTCONN;	if (!fc->connected)		goto out; 	req = fuse_request_alloc(npages);	err = -ENOMEM;	if (!req) {		if (for_background)			wake_up(&fc->blocked_waitq);		goto out;	} 	fuse_req_init_context(req);	req->waiting = 1;	req->background = for_background;	return req;  out:	atomic_dec(&fc->num_waiting);	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_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->initialized);	/* Matches smp_wmb() in fuse_set_initialized() */	smp_rmb();	req = fuse_request_alloc(0);	if (!req)		req = get_reserved_req(fc, file); 	fuse_req_init_context(req);	req->waiting = 1;	req->background = 0;	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)) {			/*			 * We get here in the unlikely case that a background			 * request was allocated but not sent			 */			spin_lock(&fc->lock);			if (!fc->blocked)				wake_up(&fc->blocked_waitq);			spin_unlock(&fc->lock);		} 		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) {		req->background = 0; 		if (fc->num_background == fc->max_background)			fc->blocked = 0; 		/* Wake up next waiter, if any */		if (!fc->blocked && waitqueue_active(&fc->blocked_waitq))			wake_up(&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){	BUG_ON(req->background);

Lines 1–500 of 2264.