⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vfs.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
}intnfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_acl **acl){	struct inode *inode = dentry->d_inode;	int error = 0;	struct posix_acl *pacl = NULL, *dpacl = NULL;	unsigned int flags = 0;	pacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_ACCESS);	if (IS_ERR(pacl) && PTR_ERR(pacl) == -ENODATA)		pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);	if (IS_ERR(pacl)) {		error = PTR_ERR(pacl);		pacl = NULL;		goto out;	}	if (S_ISDIR(inode->i_mode)) {		dpacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_DEFAULT);		if (IS_ERR(dpacl) && PTR_ERR(dpacl) == -ENODATA)			dpacl = NULL;		else if (IS_ERR(dpacl)) {			error = PTR_ERR(dpacl);			dpacl = NULL;			goto out;		}		flags = NFS4_ACL_DIR;	}	*acl = nfs4_acl_posix_to_nfsv4(pacl, dpacl, flags);	if (IS_ERR(*acl)) {		error = PTR_ERR(*acl);		*acl = NULL;	} out:	posix_acl_release(pacl);	posix_acl_release(dpacl);	return error;}#endif /* defined(CONFIG_NFS_V4) */#ifdef CONFIG_NFSD_V3/* * Check server access rights to a file system object */struct accessmap {	u32		access;	int		how;};static struct accessmap	nfs3_regaccess[] = {    {	NFS3_ACCESS_READ,	MAY_READ			},    {	NFS3_ACCESS_EXECUTE,	MAY_EXEC			},    {	NFS3_ACCESS_MODIFY,	MAY_WRITE|MAY_TRUNC		},    {	NFS3_ACCESS_EXTEND,	MAY_WRITE			},    {	0,			0				}};static struct accessmap	nfs3_diraccess[] = {    {	NFS3_ACCESS_READ,	MAY_READ			},    {	NFS3_ACCESS_LOOKUP,	MAY_EXEC			},    {	NFS3_ACCESS_MODIFY,	MAY_EXEC|MAY_WRITE|MAY_TRUNC	},    {	NFS3_ACCESS_EXTEND,	MAY_EXEC|MAY_WRITE		},    {	NFS3_ACCESS_DELETE,	MAY_REMOVE			},    {	0,			0				}};static struct accessmap	nfs3_anyaccess[] = {	/* Some clients - Solaris 2.6 at least, make an access call	 * to the server to check for access for things like /dev/null	 * (which really, the server doesn't care about).  So	 * We provide simple access checking for them, looking	 * mainly at mode bits, and we make sure to ignore read-only	 * filesystem checks	 */    {	NFS3_ACCESS_READ,	MAY_READ			},    {	NFS3_ACCESS_EXECUTE,	MAY_EXEC			},    {	NFS3_ACCESS_MODIFY,	MAY_WRITE|MAY_LOCAL_ACCESS	},    {	NFS3_ACCESS_EXTEND,	MAY_WRITE|MAY_LOCAL_ACCESS	},    {	0,			0				}};__be32nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *supported){	struct accessmap	*map;	struct svc_export	*export;	struct dentry		*dentry;	u32			query, result = 0, sresult = 0;	__be32			error;	error = fh_verify(rqstp, fhp, 0, MAY_NOP);	if (error)		goto out;	export = fhp->fh_export;	dentry = fhp->fh_dentry;	if (S_ISREG(dentry->d_inode->i_mode))		map = nfs3_regaccess;	else if (S_ISDIR(dentry->d_inode->i_mode))		map = nfs3_diraccess;	else		map = nfs3_anyaccess;	query = *access;	for  (; map->access; map++) {		if (map->access & query) {			__be32 err2;			sresult |= map->access;			err2 = nfsd_permission(rqstp, export, dentry, map->how);			switch (err2) {			case nfs_ok:				result |= map->access;				break;							/* the following error codes just mean the access was not allowed,			 * rather than an error occurred */			case nfserr_rofs:			case nfserr_acces:			case nfserr_perm:				/* simply don't "or" in the access bit. */				break;			default:				error = err2;				goto out;			}		}	}	*access = result;	if (supported)		*supported = sresult; out:	return error;}#endif /* CONFIG_NFSD_V3 *//* * Open an existing file or directory. * The access argument indicates the type of open (read/write/lock) * N.B. After this call fhp needs an fh_put */__be32nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,			int access, struct file **filp){	struct dentry	*dentry;	struct inode	*inode;	int		flags = O_RDONLY|O_LARGEFILE;	__be32		err;	int		host_err;	/*	 * If we get here, then the client has already done an "open",	 * and (hopefully) checked permission - so allow OWNER_OVERRIDE	 * in case a chmod has now revoked permission.	 */	err = fh_verify(rqstp, fhp, type, access | MAY_OWNER_OVERRIDE);	if (err)		goto out;	dentry = fhp->fh_dentry;	inode = dentry->d_inode;	/* Disallow write access to files with the append-only bit set	 * or any access when mandatory locking enabled	 */	err = nfserr_perm;	if (IS_APPEND(inode) && (access & MAY_WRITE))		goto out;	/*	 * We must ignore files (but only files) which might have mandatory	 * locks on them because there is no way to know if the accesser has	 * the lock.	 */	if (S_ISREG((inode)->i_mode) && mandatory_lock(inode))		goto out;	if (!inode->i_fop)		goto out;	/*	 * Check to see if there are any leases on this file.	 * This may block while leases are broken.	 */	host_err = break_lease(inode, O_NONBLOCK | ((access & MAY_WRITE) ? FMODE_WRITE : 0));	if (host_err == -EWOULDBLOCK)		host_err = -ETIMEDOUT;	if (host_err) /* NOMEM or WOULDBLOCK */		goto out_nfserr;	if (access & MAY_WRITE) {		if (access & MAY_READ)			flags = O_RDWR|O_LARGEFILE;		else			flags = O_WRONLY|O_LARGEFILE;		DQUOT_INIT(inode);	}	*filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_mnt), flags);	if (IS_ERR(*filp))		host_err = PTR_ERR(*filp);out_nfserr:	err = nfserrno(host_err);out:	return err;}/* * Close a file. */voidnfsd_close(struct file *filp){	fput(filp);}/* * Sync a file * As this calls fsync (not fdatasync) there is no need for a write_inode * after it. */static inline int nfsd_dosync(struct file *filp, struct dentry *dp,			      const struct file_operations *fop){	struct inode *inode = dp->d_inode;	int (*fsync) (struct file *, struct dentry *, int);	int err;	err = filemap_fdatawrite(inode->i_mapping);	if (err == 0 && fop && (fsync = fop->fsync))		err = fsync(filp, dp, 0);	if (err == 0)		err = filemap_fdatawait(inode->i_mapping);	return err;}	static intnfsd_sync(struct file *filp){        int err;	struct inode *inode = filp->f_path.dentry->d_inode;	dprintk("nfsd: sync file %s\n", filp->f_path.dentry->d_name.name);	mutex_lock(&inode->i_mutex);	err=nfsd_dosync(filp, filp->f_path.dentry, filp->f_op);	mutex_unlock(&inode->i_mutex);	return err;}intnfsd_sync_dir(struct dentry *dp){	return nfsd_dosync(NULL, dp, dp->d_inode->i_fop);}/* * Obtain the readahead parameters for the file * specified by (dev, ino). */static inline struct raparms *nfsd_get_raparms(dev_t dev, ino_t ino){	struct raparms	*ra, **rap, **frap = NULL;	int depth = 0;	unsigned int hash;	struct raparm_hbucket *rab;	hash = jhash_2words(dev, ino, 0xfeedbeef) & RAPARM_HASH_MASK;	rab = &raparm_hash[hash];	spin_lock(&rab->pb_lock);	for (rap = &rab->pb_head; (ra = *rap); rap = &ra->p_next) {		if (ra->p_ino == ino && ra->p_dev == dev)			goto found;		depth++;		if (ra->p_count == 0)			frap = rap;	}	depth = nfsdstats.ra_size*11/10;	if (!frap) {			spin_unlock(&rab->pb_lock);		return NULL;	}	rap = frap;	ra = *frap;	ra->p_dev = dev;	ra->p_ino = ino;	ra->p_set = 0;	ra->p_hindex = hash;found:	if (rap != &rab->pb_head) {		*rap = ra->p_next;		ra->p_next   = rab->pb_head;		rab->pb_head = ra;	}	ra->p_count++;	nfsdstats.ra_depth[depth*10/nfsdstats.ra_size]++;	spin_unlock(&rab->pb_lock);	return ra;}/* * Grab and keep cached pages associated with a file in the svc_rqst * so that they can be passed to the network sendmsg/sendpage routines * directly. They will be released after the sending has completed. */static intnfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf,		  struct splice_desc *sd){	struct svc_rqst *rqstp = sd->u.data;	struct page **pp = rqstp->rq_respages + rqstp->rq_resused;	struct page *page = buf->page;	size_t size;	int ret;	ret = buf->ops->confirm(pipe, buf);	if (unlikely(ret))		return ret;	size = sd->len;	if (rqstp->rq_res.page_len == 0) {		get_page(page);		put_page(*pp);		*pp = page;		rqstp->rq_resused++;		rqstp->rq_res.page_base = buf->offset;		rqstp->rq_res.page_len = size;	} else if (page != pp[-1]) {		get_page(page);		if (*pp)			put_page(*pp);		*pp = page;		rqstp->rq_resused++;		rqstp->rq_res.page_len += size;	} else		rqstp->rq_res.page_len += size;	return size;}static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe,				    struct splice_desc *sd){	return __splice_from_pipe(pipe, sd, nfsd_splice_actor);}static inline int svc_msnfs(struct svc_fh *ffhp){#ifdef MSNFS	return (ffhp->fh_export->ex_flags & NFSEXP_MSNFS);#else	return 0;#endif}static __be32nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,              loff_t offset, struct kvec *vec, int vlen, unsigned long *count){	struct inode *inode;	struct raparms	*ra;	mm_segment_t	oldfs;	__be32		err;	int		host_err;	err = nfserr_perm;	inode = file->f_path.dentry->d_inode;	if (svc_msnfs(fhp) && !lock_may_read(inode, offset, *count))		goto out;	/* Get readahead parameters */	ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino);	if (ra && ra->p_set)		file->f_ra = ra->p_ra;	if (file->f_op->splice_read && rqstp->rq_splice_ok) {		struct splice_desc sd = {			.len		= 0,			.total_len	= *count,			.pos		= offset,			.u.data		= rqstp,		};		rqstp->rq_resused = 1;		host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor);	} else {		oldfs = get_fs();		set_fs(KERNEL_DS);		host_err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset);		set_fs(oldfs);	}	/* Write back readahead params */	if (ra) {		struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex];		spin_lock(&rab->pb_lock);		ra->p_ra = file->f_ra;		ra->p_set = 1;		ra->p_count--;		spin_unlock(&rab->pb_lock);	}	if (host_err >= 0) {		nfsdstats.io_read += host_err;		*count = host_err;		err = 0;		fsnotify_access(file->f_path.dentry);	} else 		err = nfserrno(host_err);out:	return err;}static void kill_suid(struct dentry *dentry){	struct iattr	ia;	ia.ia_valid = ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;	mutex_lock(&dentry->d_inode->i_mutex);	notify_change(dentry, &ia);	mutex_unlock(&dentry->d_inode->i_mutex);}static __be32nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,				loff_t offset, struct kvec *vec, int vlen,	   			unsigned long cnt, int *stablep){	struct svc_export	*exp;	struct dentry		*dentry;	struct inode		*inode;	mm_segment_t		oldfs;	__be32			err = 0;	int			host_err;	int			stable = *stablep;#ifdef MSNFS	err = nfserr_perm;	if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&		(!lock_may_write(file->f_path.dentry->d_inode, offset, cnt)))		goto out;#endif	dentry = file->f_path.dentry;	inode = dentry->d_inode;	exp   = fhp->fh_export;	/*	 * Request sync writes if	 *  -	the sync export option has been set, or	 *  -	the client requested O_SYNC behavior (NFSv3 feature).	 *  -   The file system doesn't support fsync().	 * When gathered writes have been configured for this volume,	 * flushing the data to disk is handled separately below.	 */	if (file->f_op->fsync == 0) {/* COMMIT3 cannot work */	       stable = 2;	       *stablep = 2; /* FILE_SYNC */	}	if (!EX_ISSYNC(exp))		stable = 0;	if (stable && !EX_WGATHER(exp))		file->f_flags |= O_SYNC;	/* Write the data. */	oldfs = get_fs(); set_fs(KERNEL_DS);	host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset);	set_fs(oldfs);	if (host_err >= 0) {		nfsdstats.io_write += cnt;		fsnotify_modify(file->f_path.dentry);	}	/* clear setuid/setgid flag after write */	if (host_err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID)))		kill_suid(dentry);	if (host_err >= 0 && stable) {		static ino_t	last_ino;		static dev_t	last_dev;		/*		 * Gathered writes: If another process is currently		 * writing to the file, there's a high chance		 * this is another nfsd (triggered by a bulk write		 * from a client's biod). Rather than syncing the		 * file with each write request, we sleep for 10 msec.		 *		 * I don't know if this roughly approximates		 * C. Juszak's idea of gathered writes, but it's a		 * nice and simple solution (IMHO), and it seems to

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -