2502 lines · 56.2 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> #define CREATE_TRACE_POINTS#include "fuse_trace.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 void end_requests(struct list_head *head); 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_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;} 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);} 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_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(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); static unsigned int fuse_req_hash(u64 unique){	return hash_long(unique & ~FUSE_INT_REQ_BIT, FUSE_PQ_HASH_BITS);} /* * 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);} static 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);	}} static 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 void fuse_dev_queue_req(struct fuse_iqueue *fiq, struct fuse_req *req){	spin_lock(&fiq->lock);	if (fiq->connected) {		if (req->in.h.opcode != FUSE_NOTIFY_REPLY)			req->in.h.unique = fuse_get_unique_locked(fiq);		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);	trace_fuse_request_send(req);	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);	} else {		/* Wake up waiter sleeping in request_wait_answer() */		wake_up(&req->waitq);	} 	if (test_bit(FR_ASYNC, &req->flags))		req->args->end(fm, req->args, req->out.h.error);put_request:	fuse_put_request(req);}EXPORT_SYMBOL_GPL(fuse_request_end); static int queue_interrupt(struct fuse_req *req){	struct fuse_iqueue *fiq = &req->fm->fc->iq; 	/* Check for we've sent request to interrupt this req */	if (unlikely(!test_bit(FR_INTERRUPTED, &req->flags)))		return -EINVAL; 	fiq->ops->send_interrupt(fiq, req); 	return 0;} static void request_wait_answer(struct fuse_req *req){	struct fuse_conn *fc = req->fm->fc;	struct fuse_iqueue *fiq = &fc->iq;	int err; 	if (!fc->no_interrupt) {		/* Any signal may interrupt this */		err = wait_event_interruptible(req->waitq,					test_bit(FR_FINISHED, &req->flags));		if (!err)			return; 		set_bit(FR_INTERRUPTED, &req->flags);		/* matches barrier in fuse_dev_do_read() */		smp_mb__after_atomic();		if (test_bit(FR_SENT, &req->flags))			queue_interrupt(req);	} 	if (!test_bit(FR_FORCE, &req->flags)) {		/* Only fatal signals may interrupt this */		err = wait_event_killable(req->waitq,					test_bit(FR_FINISHED, &req->flags));		if (!err)			return; 		spin_lock(&fiq->lock);		/* Request is not yet in userspace, bail out */		if (test_bit(FR_PENDING, &req->flags)) {			list_del(&req->list);			spin_unlock(&fiq->lock);			__fuse_put_request(req);			req->out.h.error = -EINTR;			return;		}		spin_unlock(&fiq->lock);	} 	/*	 * Either request is already in userspace, or it was forced.	 * Wait it out.	 */	wait_event(req->waitq, test_bit(FR_FINISHED, &req->flags));} static void __fuse_request_send(struct fuse_req *req){	struct fuse_iqueue *fiq = &req->fm->fc->iq; 	BUG_ON(test_bit(FR_BACKGROUND, &req->flags)); 	/* acquire extra reference, since request is still needed after	   fuse_request_end() */	__fuse_get_request(req);	fuse_send_one(fiq, req); 	request_wait_answer(req);	/* Pairs with smp_wmb() in fuse_request_end() */	smp_rmb();} static void fuse_adjust_compat(struct fuse_conn *fc, struct fuse_args *args){	if (fc->minor < 4 && args->opcode == FUSE_STATFS)		args->out_args[0].size = FUSE_COMPAT_STATFS_SIZE; 	if (fc->minor < 9) {		switch (args->opcode) {		case FUSE_LOOKUP:		case FUSE_CREATE:		case FUSE_MKNOD:		case FUSE_MKDIR:		case FUSE_SYMLINK:		case FUSE_LINK:			args->out_args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE;			break;		case FUSE_GETATTR:		case FUSE_SETATTR:			args->out_args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE;

Lines 1–500 of 2502.