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

📄 vfs.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 3 页
字号:
#define MSNFS	/* HACK HACK *//* * linux/fs/nfsd/vfs.c * * File operations used by nfsd. Some of these have been ripped from * other parts of the kernel because they weren't in ksyms.c, others * are partial duplicates with added or changed functionality. * * Note that several functions dget() the dentry upon which they want * to act, most notably those that create directory entries. Response * dentry's are dput()'d if necessary in the release callback. * So if you notice code paths that apparently fail to dput() the * dentry, don't worry--they have been taken care of. * * Copyright (C) 1995-1999 Olaf Kirch <okir@monad.swb.de> */#include <linux/config.h>#include <linux/version.h>#include <linux/string.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/locks.h>#include <linux/fs.h>#include <linux/major.h>#include <linux/ext2_fs.h>#include <linux/proc_fs.h>#include <linux/stat.h>#include <linux/fcntl.h>#include <linux/net.h>#include <linux/unistd.h>#include <linux/slab.h>#include <linux/in.h>#define __NO_VERSION__#include <linux/module.h>#include <linux/sunrpc/svc.h>#include <linux/nfsd/nfsd.h>#ifdef CONFIG_NFSD_V3#include <linux/nfs3.h>#include <linux/nfsd/xdr3.h>#endif /* CONFIG_NFSD_V3 */#include <linux/nfsd/nfsfh.h>#include <linux/quotaops.h>#include <asm/uaccess.h>#define NFSDDBG_FACILITY		NFSDDBG_FILEOP#define NFSD_PARANOIA/* 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. */#define IS_ISMNDLK(i)	(S_ISREG((i)->i_mode) && MANDATORY_LOCK(i))/* * This is a cache of readahead params that help us choose the proper * readahead strategy. Initially, we set all readahead parameters to 0 * and let the VFS handle things. * If you increase the number of cached files very much, you'll need to * add a hash table here. */struct raparms {	struct raparms		*p_next;	unsigned int		p_count;	ino_t			p_ino;	dev_t			p_dev;	unsigned long		p_reada,				p_ramax,				p_raend,				p_ralen,				p_rawin;};static struct raparms *		raparml;static struct raparms *		raparm_cache;/* * Look up one component of a pathname. * N.B. After this call _both_ fhp and resfh need an fh_put * * If the lookup would cross a mountpoint, and the mounted filesystem * is exported to the client with NFSEXP_CROSSMNT, then the lookup is * accepted as it stands and the mounted directory is * returned. Otherwise the covered directory is returned. * NOTE: this mountpoint crossing is not supported properly by all *   clients and is explicitly disallowed for NFSv3 *      NeilBrown <neilb@cse.unsw.edu.au> */intnfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,					int len, struct svc_fh *resfh){	struct svc_export	*exp;	struct dentry		*dparent;	struct dentry		*dentry;	int			err;	dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name);	/* Obtain dentry and export. */	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_EXEC);	if (err)		goto out;	dparent = fhp->fh_dentry;	exp  = fhp->fh_export;	err = nfserr_acces;	/* Lookup the name, but don't follow links */	if (isdotent(name, len)) {		if (len==1)			dentry = dget(dparent);		else  { /* must be ".." */			/* checking mountpoint crossing is very different when stepping up */			if (dparent == exp->ex_dentry) {				if (!EX_CROSSMNT(exp))					dentry = dget(dparent); /* .. == . just like at / */				else				{					struct svc_export *exp2 = NULL;					struct dentry *dp;					struct vfsmount *mnt = mntget(exp->ex_mnt);					dentry = dget(dparent);					while(follow_up(&mnt, &dentry))						;					dp = dget(dentry->d_parent);					dput(dentry);					dentry = dp;					for ( ; exp2 == NULL && dp->d_parent != dp;					      dp=dp->d_parent)						exp2 = exp_get(exp->ex_client, dp->d_inode->i_dev, dp->d_inode->i_ino);					if (exp2==NULL) {						dput(dentry);						dentry = dget(dparent);					} else {						exp = exp2;					}					mntput(mnt);				}			} else				dentry = dget(dparent->d_parent);		}	} else {		fh_lock(fhp);		dentry = lookup_one_len(name, dparent, len);		err = PTR_ERR(dentry);		if (IS_ERR(dentry))			goto out_nfserr;		/*		 * check if we have crossed a mount point ...		 */		if (d_mountpoint(dentry)) {			struct svc_export *exp2 = NULL;			struct vfsmount *mnt = mntget(exp->ex_mnt);			struct dentry *mounts = dget(dentry);			while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts))				;			exp2 = exp_get(rqstp->rq_client,				       mounts->d_inode->i_dev,				       mounts->d_inode->i_ino);			if (exp2 && EX_CROSSMNT(exp2)) {				/* successfully crossed mount point */				exp = exp2;				dput(dentry);				dentry = mounts;			} else				dput(mounts);			mntput(mnt);		}	}	/*	 * Note: we compose the file handle now, but as the	 * dentry may be negative, it may need to be updated.	 */	err = fh_compose(resfh, exp, dentry, fhp);	if (!err && !dentry->d_inode)		err = nfserr_noent;out:	return err;out_nfserr:	err = nfserrno(err);	goto out;}/* * Set various file attributes. * N.B. After this call fhp needs an fh_put */intnfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,	     int check_guard, time_t guardtime){	struct dentry	*dentry;	struct inode	*inode;	int		accmode = MAY_SATTR;	int		ftype = 0;	int		imode;	int		err;	int		size_change = 0;	if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))		accmode |= MAY_WRITE|MAY_OWNER_OVERRIDE;	if (iap->ia_valid & ATTR_SIZE)		ftype = S_IFREG;	/* Get inode */	err = fh_verify(rqstp, fhp, ftype, accmode);	if (err || !iap->ia_valid)		goto out;	dentry = fhp->fh_dentry;	inode = dentry->d_inode;	err = inode_change_ok(inode, iap);	/* could be a "touch" (utimes) request where the user is not the owner but does	 * have write permission. In this case the user should be allowed to set	 * both times to the current time.  We could just assume any such SETATTR	 * is intended to set the times to "now", but we do a couple of simple tests	 * to increase our confidence.	 */#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)#define	MAX_TOUCH_TIME_ERROR (30*60)	if (err	    && (iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET	    && iap->ia_mtime == iap->ia_atime	    ) {	    /* looks good.  now just make sure time is in the right ballpark.	     * solaris, at least, doesn't seem to care what the time request is	     */	    time_t delta = iap->ia_atime - CURRENT_TIME;	    if (delta<0) delta = -delta;	    if (delta < MAX_TOUCH_TIME_ERROR) {		/* turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME		 * this will cause notify_change to set these times to "now"		 */		iap->ia_valid &= ~BOTH_TIME_SET;		err = inode_change_ok(inode, iap);	    }	}	    	if (err)		goto out_nfserr;	/* The size case is special. It changes the file as well as the attributes.  */	if (iap->ia_valid & ATTR_SIZE) {		if (iap->ia_size < inode->i_size) {			err = nfsd_permission(fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE);			if (err)				goto out;		}		/*		 * If we are changing the size of the file, then		 * we need to break all leases.		 */		err = get_lease(inode, FMODE_WRITE);		if (err)			goto out_nfserr;		err = get_write_access(inode);		if (err)			goto out_nfserr;		err = locks_verify_truncate(inode, NULL, iap->ia_size);		if (err) {			put_write_access(inode);			goto out_nfserr;		}		DQUOT_INIT(inode);	}	imode = inode->i_mode;	if (iap->ia_valid & ATTR_MODE) {		iap->ia_mode &= S_IALLUGO;		imode = iap->ia_mode |= (imode & ~S_IALLUGO);	}	/* Revoke setuid/setgid bit on chown/chgrp */	if ((iap->ia_valid & ATTR_UID) && (imode & S_ISUID)	 && iap->ia_uid != inode->i_uid) {		iap->ia_valid |= ATTR_MODE;		iap->ia_mode = imode &= ~S_ISUID;	}	if ((iap->ia_valid & ATTR_GID) && (imode & S_ISGID)	 && iap->ia_gid != inode->i_gid) {		iap->ia_valid |= ATTR_MODE;		iap->ia_mode = imode &= ~S_ISGID;	}	/* Change the attributes. */	iap->ia_valid |= ATTR_CTIME;	if (iap->ia_valid & ATTR_SIZE) {		fh_lock(fhp);		size_change = 1;	}	err = nfserr_notsync;	if (!check_guard || guardtime == inode->i_ctime) {		err = notify_change(dentry, iap);		err = nfserrno(err);	}	if (size_change) {		fh_unlock(fhp);		put_write_access(inode);	}	if (!err)		if (EX_ISSYNC(fhp->fh_export))			write_inode_now(inode, 1);out:	return err;out_nfserr:	err = nfserrno(err);	goto out;}#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	 */    {	NFS3_ACCESS_READ,	MAY_READ			},    {	NFS3_ACCESS_EXECUTE,	MAY_EXEC			},    {	NFS3_ACCESS_MODIFY,	MAY_WRITE			},    {	NFS3_ACCESS_EXTEND,	MAY_WRITE			},    {	0,			0				}};intnfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access){	struct accessmap	*map;	struct svc_export	*export;	struct dentry		*dentry;	u32			query, result = 0;	unsigned int		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) {			unsigned int err2;			err2 = nfsd_permission(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; 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 */intnfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,			int access, struct file *filp){	struct dentry	*dentry;	struct inode	*inode;	int		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 access to files with the append-only bit set or	 * with mandatory locking enabled	 */	err = nfserr_perm;	if (IS_APPEND(inode) || IS_ISMNDLK(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.	 */	err = get_lease(inode, (access & MAY_WRITE) ? FMODE_WRITE : 0);	if (err)		goto out_nfserr;	if ((access & MAY_WRITE) && (err = get_write_access(inode)) != 0)		goto out_nfserr;	memset(filp, 0, sizeof(*filp));	filp->f_op    = fops_get(inode->i_fop);	atomic_set(&filp->f_count, 1);	filp->f_dentry = dentry;	filp->f_vfsmnt = fhp->fh_export->ex_mnt;	if (access & MAY_WRITE) {		filp->f_flags = O_WRONLY|O_LARGEFILE;		filp->f_mode  = FMODE_WRITE;		DQUOT_INIT(inode);	} else {		filp->f_flags = O_RDONLY|O_LARGEFILE;		filp->f_mode  = FMODE_READ;	}	err = 0;	if (filp->f_op && filp->f_op->open) {		err = filp->f_op->open(inode, filp);		if (err) {			fops_put(filp->f_op);			if (access & MAY_WRITE)				put_write_access(inode);			/* I nearly added put_filp() call here, but this filp			 * is really on callers stack frame. -DaveM			 */			atomic_dec(&filp->f_count);		}	}out_nfserr:	if (err)		err = nfserrno(err);out:	return err;}/* * Close a file. */voidnfsd_close(struct file *filp){	struct dentry	*dentry = filp->f_dentry;	struct inode	*inode = dentry->d_inode;	if (filp->f_op && filp->f_op->release)		filp->f_op->release(inode, filp);	fops_put(filp->f_op);	if (filp->f_mode & FMODE_WRITE)		put_write_access(inode);}/* * Sync a file * As this calls fsync (not fdatasync) there is no need for a write_inode * after it. */voidnfsd_sync(struct file *filp){	dprintk("nfsd: sync file %s\n", filp->f_dentry->d_name.name);	down(&filp->f_dentry->d_inode->i_sem);	filp->f_op->fsync(filp, filp->f_dentry, 0);	up(&filp->f_dentry->d_inode->i_sem);}voidnfsd_sync_dir(struct dentry *dp){

⌨️ 快捷键说明

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