2193 lines · 52.7 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/*  FUSE: Filesystem in Userspace  Copyright (C) 2001-2008  Miklos Szeredi <miklos@szeredi.hu>*/ #include "dev.h"#include "fuse_i.h" #include <linux/dax.h>#include <linux/pagemap.h>#include <linux/slab.h>#include <linux/file.h>#include <linux/seq_file.h>#include <linux/init.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/fs_context.h>#include <linux/fs_parser.h>#include <linux/statfs.h>#include <linux/random.h>#include <linux/sched.h>#include <linux/exportfs.h>#include <linux/posix_acl.h>#include <linux/pid_namespace.h>#include <uapi/linux/magic.h> MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");MODULE_DESCRIPTION("Filesystem in Userspace");MODULE_LICENSE("GPL"); static struct kmem_cache *fuse_inode_cachep;struct list_head fuse_conn_list;DEFINE_MUTEX(fuse_mutex); static int set_global_limit(const char *val, const struct kernel_param *kp); unsigned int fuse_max_pages_limit = 256;/* default is no timeout */ unsigned int max_user_bgreq;module_param_call(max_user_bgreq, set_global_limit, param_get_uint,		  &max_user_bgreq, 0644);__MODULE_PARM_TYPE(max_user_bgreq, "uint");MODULE_PARM_DESC(max_user_bgreq, "Global limit for the maximum number of backgrounded requests an " "unprivileged user can set"); unsigned int max_user_congthresh;module_param_call(max_user_congthresh, set_global_limit, param_get_uint,		  &max_user_congthresh, 0644);__MODULE_PARM_TYPE(max_user_congthresh, "uint");MODULE_PARM_DESC(max_user_congthresh, "Global limit for the maximum congestion threshold an " "unprivileged user can set"); #define FUSE_DEFAULT_BLKSIZE 512 /** Congestion starts at 75% of maximum */#define FUSE_DEFAULT_CONGESTION_THRESHOLD (FUSE_DEFAULT_MAX_BACKGROUND * 3 / 4) #ifdef CONFIG_BLOCKstatic struct file_system_type fuseblk_fs_type;#endif static struct fuse_submount_lookup *fuse_alloc_submount_lookup(void){	struct fuse_submount_lookup *sl; 	sl = kzalloc_obj(struct fuse_submount_lookup, GFP_KERNEL_ACCOUNT);	if (!sl)		return NULL;	sl->forget = fuse_alloc_forget();	if (!sl->forget)		goto out_free; 	return sl; out_free:	kfree(sl);	return NULL;} static struct inode *fuse_alloc_inode(struct super_block *sb){	struct fuse_inode *fi; 	fi = alloc_inode_sb(sb, fuse_inode_cachep, GFP_KERNEL);	if (!fi)		return NULL; 	/* Initialize private data (i.e. everything except fi->inode) */	BUILD_BUG_ON(offsetof(struct fuse_inode, inode) != 0);	memset((void *) fi + sizeof(fi->inode), 0, sizeof(*fi) - sizeof(fi->inode)); 	fi->inval_mask = ~0;	mutex_init(&fi->mutex);	spin_lock_init(&fi->lock);	fi->forget = fuse_alloc_forget();	if (!fi->forget)		goto out_free; 	if (IS_ENABLED(CONFIG_FUSE_DAX) && !fuse_dax_inode_alloc(sb, fi))		goto out_free_forget; 	if (IS_ENABLED(CONFIG_FUSE_PASSTHROUGH))		fuse_inode_backing_set(fi, NULL); 	return &fi->inode; out_free_forget:	kfree(fi->forget);out_free:	kmem_cache_free(fuse_inode_cachep, fi);	return NULL;} static void fuse_free_inode(struct inode *inode){	struct fuse_inode *fi = get_fuse_inode(inode); 	mutex_destroy(&fi->mutex);	kfree(fi->forget);#ifdef CONFIG_FUSE_DAX	kfree(fi->dax);#endif	if (IS_ENABLED(CONFIG_FUSE_PASSTHROUGH))		fuse_backing_put(fuse_inode_backing(fi)); 	kmem_cache_free(fuse_inode_cachep, fi);} static void fuse_cleanup_submount_lookup(struct fuse_conn *fc,					 struct fuse_submount_lookup *sl){	if (!refcount_dec_and_test(&sl->count))		return; 	fuse_chan_queue_forget(fc->chan, sl->forget, sl->nodeid, 1);	sl->forget = NULL;	kfree(sl);} static void fuse_evict_inode(struct inode *inode){	struct fuse_inode *fi = get_fuse_inode(inode); 	/* Will write inode on close/munmap and in all other dirtiers */	WARN_ON(inode_state_read_once(inode) & I_DIRTY_INODE); 	if (FUSE_IS_DAX(inode))		dax_break_layout_final(inode); 	truncate_inode_pages_final(&inode->i_data);	clear_inode(inode);	if (inode->i_sb->s_flags & SB_ACTIVE) {		struct fuse_conn *fc = get_fuse_conn(inode); 		if (FUSE_IS_DAX(inode))			fuse_dax_inode_cleanup(inode);		if (fi->nlookup) {			fuse_chan_queue_forget(fc->chan, fi->forget, fi->nodeid,					       fi->nlookup);			fi->forget = NULL;		} 		if (fi->submount_lookup) {			fuse_cleanup_submount_lookup(fc, fi->submount_lookup);			fi->submount_lookup = NULL;		}		/*		 * Evict of non-deleted inode may race with outstanding		 * LOOKUP/READDIRPLUS requests and result in inconsistency when		 * the request finishes.  Deal with that here by bumping a		 * counter that can be compared to the starting value.		 */		if (inode->i_nlink > 0)			atomic64_inc(&fc->evict_ctr);	}	if (S_ISREG(inode->i_mode) && !fuse_is_bad(inode)) {		WARN_ON(fi->iocachectr != 0);		WARN_ON(!list_empty(&fi->write_files));		WARN_ON(!list_empty(&fi->queued_writes));	}} static int fuse_reconfigure(struct fs_context *fsc){	struct super_block *sb = fsc->root->d_sb; 	sync_filesystem(sb);	if (fsc->sb_flags & SB_MANDLOCK)		return -EINVAL; 	return 0;} /* * ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down * so that it will fit. */static ino_t fuse_squash_ino(u64 ino64){	ino_t ino = (ino_t) ino64;	if (sizeof(ino_t) < sizeof(u64))		ino ^= ino64 >> (sizeof(u64) - sizeof(ino_t)) * 8;	return ino;} void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,				   struct fuse_statx *sx,				   u64 attr_valid, u32 cache_mask,				   u64 evict_ctr){	struct fuse_conn *fc = get_fuse_conn(inode);	struct fuse_inode *fi = get_fuse_inode(inode); 	lockdep_assert_held(&fi->lock); 	/*	 * Clear basic stats from invalid mask.	 *	 * Don't do this if this is coming from a fuse_iget() call and there	 * might have been a racing evict which would've invalidated the result	 * if the attr_version would've been preserved.	 *	 * !evict_ctr -> this is create	 * fi->attr_version != 0 -> this is not a new inode	 * evict_ctr == fuse_get_evict_ctr() -> no evicts while during request	 */	if (!evict_ctr || fi->attr_version || evict_ctr == fuse_get_evict_ctr(fc))		set_mask_bits(&fi->inval_mask, STATX_BASIC_STATS, 0); 	fi->attr_version = atomic64_inc_return(&fc->attr_version);	fi->i_time = attr_valid; 	inode->i_ino     = fuse_squash_ino(attr->ino);	inode->i_mode    = (inode->i_mode & S_IFMT) | (attr->mode & 07777);	set_nlink(inode, attr->nlink);	inode->i_uid     = make_kuid(fc->user_ns, attr->uid);	inode->i_gid     = make_kgid(fc->user_ns, attr->gid);	inode->i_blocks  = attr->blocks; 	/* Sanitize nsecs */	attr->atimensec = min_t(u32, attr->atimensec, NSEC_PER_SEC - 1);	attr->mtimensec = min_t(u32, attr->mtimensec, NSEC_PER_SEC - 1);	attr->ctimensec = min_t(u32, attr->ctimensec, NSEC_PER_SEC - 1); 	inode_set_atime(inode, attr->atime, attr->atimensec);	/* mtime from server may be stale due to local buffered write */	if (!(cache_mask & STATX_MTIME)) {		inode_set_mtime(inode, attr->mtime, attr->mtimensec);	}	if (!(cache_mask & STATX_CTIME)) {		inode_set_ctime(inode, attr->ctime, attr->ctimensec);	}	if (sx) {		/* Sanitize nsecs */		sx->btime.tv_nsec =			min_t(u32, sx->btime.tv_nsec, NSEC_PER_SEC - 1); 		/*		 * Btime has been queried, cache is valid (whether or not btime		 * is available or not) so clear STATX_BTIME from inval_mask.		 *		 * Availability of the btime attribute is indicated in		 * FUSE_I_BTIME		 */		set_mask_bits(&fi->inval_mask, STATX_BTIME, 0);		if (sx->mask & STATX_BTIME) {			set_bit(FUSE_I_BTIME, &fi->state);			fi->i_btime.tv_sec = sx->btime.tv_sec;			fi->i_btime.tv_nsec = sx->btime.tv_nsec;		}	} 	if (attr->blksize)		fi->cached_i_blkbits = ilog2(attr->blksize);	else		fi->cached_i_blkbits = inode->i_sb->s_blocksize_bits; 	/*	 * Don't set the sticky bit in i_mode, unless we want the VFS	 * to check permissions.  This prevents failures due to the	 * check in may_delete().	 */	fi->orig_i_mode = inode->i_mode;	if (!fc->default_permissions)		inode->i_mode &= ~S_ISVTX; 	fi->orig_ino = attr->ino; 	/*	 * We are refreshing inode data and it is possible that another	 * client set suid/sgid or security.capability xattr. So clear	 * S_NOSEC. Ideally, we could have cleared it only if suid/sgid	 * was set or if security.capability xattr was set. But we don't	 * know if security.capability has been set or not. So clear it	 * anyway. Its less efficient but should be safe.	 */	inode->i_flags &= ~S_NOSEC;} u32 fuse_get_cache_mask(struct inode *inode){	struct fuse_conn *fc = get_fuse_conn(inode); 	if (!fc->writeback_cache || !S_ISREG(inode->i_mode))		return 0; 	return STATX_MTIME | STATX_CTIME | STATX_SIZE;} static void fuse_change_attributes_i(struct inode *inode, struct fuse_attr *attr,				     struct fuse_statx *sx, u64 attr_valid,				     u64 attr_version, u64 evict_ctr){	struct fuse_conn *fc = get_fuse_conn(inode);	struct fuse_inode *fi = get_fuse_inode(inode);	u32 cache_mask;	loff_t oldsize;	struct timespec64 old_mtime; 	spin_lock(&fi->lock);	/*	 * In case of writeback_cache enabled, writes update mtime, ctime and	 * may update i_size.  In these cases trust the cached value in the	 * inode.	 */	cache_mask = fuse_get_cache_mask(inode);	if (cache_mask & STATX_SIZE)		attr->size = i_size_read(inode); 	if (cache_mask & STATX_MTIME) {		attr->mtime = inode_get_mtime_sec(inode);		attr->mtimensec = inode_get_mtime_nsec(inode);	}	if (cache_mask & STATX_CTIME) {		attr->ctime = inode_get_ctime_sec(inode);		attr->ctimensec = inode_get_ctime_nsec(inode);	} 	if ((attr_version != 0 && fi->attr_version > attr_version) ||	    test_bit(FUSE_I_SIZE_UNSTABLE, &fi->state)) {		spin_unlock(&fi->lock);		return;	} 	old_mtime = inode_get_mtime(inode);	fuse_change_attributes_common(inode, attr, sx, attr_valid, cache_mask,				      evict_ctr); 	oldsize = inode->i_size;	/*	 * In case of writeback_cache enabled, the cached writes beyond EOF	 * extend local i_size without keeping userspace server in sync. So,	 * attr->size coming from server can be stale. We cannot trust it.	 */	if (!(cache_mask & STATX_SIZE))		i_size_write(inode, attr->size);	spin_unlock(&fi->lock); 	if (!cache_mask && S_ISREG(inode->i_mode)) {		bool inval = false; 		if (oldsize != attr->size) {			truncate_pagecache(inode, attr->size);			if (!fc->explicit_inval_data)				inval = true;		} else if (fc->auto_inval_data) {			struct timespec64 new_mtime = {				.tv_sec = attr->mtime,				.tv_nsec = attr->mtimensec,			}; 			/*			 * Auto inval mode also checks and invalidates if mtime			 * has changed.			 */			if (!timespec64_equal(&old_mtime, &new_mtime))				inval = true;		} 		if (inval)			invalidate_inode_pages2(inode->i_mapping);	} 	if (IS_ENABLED(CONFIG_FUSE_DAX))		fuse_dax_dontcache(inode, attr->flags);} void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,			    struct fuse_statx *sx, u64 attr_valid,			    u64 attr_version){	fuse_change_attributes_i(inode, attr, sx, attr_valid, attr_version, 0);} static void fuse_init_submount_lookup(struct fuse_submount_lookup *sl,				      u64 nodeid){	sl->nodeid = nodeid;	refcount_set(&sl->count, 1);} static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr,			    struct fuse_conn *fc){	inode->i_mode = attr->mode & S_IFMT;	inode->i_size = attr->size;	inode_set_mtime(inode, attr->mtime, attr->mtimensec);	inode_set_ctime(inode, attr->ctime, attr->ctimensec);	if (S_ISREG(inode->i_mode)) {		fuse_init_common(inode);		fuse_init_file_inode(inode, attr->flags);	} else if (S_ISDIR(inode->i_mode))		fuse_init_dir(inode);	else if (S_ISLNK(inode->i_mode))		fuse_init_symlink(inode);	else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||		 S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {		fuse_init_common(inode);		init_special_inode(inode, inode->i_mode,				   new_decode_dev(attr->rdev));	} else		BUG();	/*	 * Ensure that we don't cache acls for daemons without FUSE_POSIX_ACL	 * so they see the exact same behavior as before.	 */	if (!fc->posix_acl)		inode->i_acl = inode->i_default_acl = ACL_DONT_CACHE;} static int fuse_inode_eq(struct inode *inode, void *_nodeidp){	u64 nodeid = *(u64 *) _nodeidp;	if (get_node_id(inode) == nodeid)		return 1;	else		return 0;} static int fuse_inode_set(struct inode *inode, void *_nodeidp){	u64 nodeid = *(u64 *) _nodeidp;	get_fuse_inode(inode)->nodeid = nodeid;	return 0;} struct inode *fuse_iget(struct super_block *sb, u64 nodeid,			int generation, struct fuse_attr *attr,			u64 attr_valid, u64 attr_version,			u64 evict_ctr){	struct inode *inode;	struct fuse_inode *fi;	struct fuse_conn *fc = get_fuse_conn_super(sb);	bool is_new_inode = false; 	/*	 * Auto mount points get their node id from the submount root, which is	 * not a unique identifier within this filesystem.	 *	 * To avoid conflicts, do not place submount points into the inode hash	 * table.	 */	if (fc->auto_submounts && (attr->flags & FUSE_ATTR_SUBMOUNT) &&	    S_ISDIR(attr->mode)) {		struct fuse_inode *fi; 		inode = new_inode(sb);		if (!inode)			return NULL; 		fuse_init_inode(inode, attr, fc);		fi = get_fuse_inode(inode);		fi->nodeid = nodeid;		fi->submount_lookup = fuse_alloc_submount_lookup();		if (!fi->submount_lookup) {			iput(inode);			return NULL;		}		/* Sets nlookup = 1 on fi->submount_lookup->nlookup */		fuse_init_submount_lookup(fi->submount_lookup, nodeid);		inode->i_flags |= S_AUTOMOUNT;		goto done;	} retry:	inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);	if (!inode)		return NULL; 	is_new_inode = inode_state_read_once(inode) & I_NEW;	if (is_new_inode) {		inode->i_flags |= S_NOATIME;		if (!fc->writeback_cache || !S_ISREG(attr->mode))			inode->i_flags |= S_NOCMTIME;		inode->i_generation = generation;

Lines 1–500 of 2193.