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

📄 vfs.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
out_nfserr:	err = nfserrno(host_err);	goto out;}/* * Create a hardlink * N.B. After this call _both_ ffhp and tfhp need an fh_put */__be32nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,				char *name, int len, struct svc_fh *tfhp){	struct dentry	*ddir, *dnew, *dold;	struct inode	*dirp, *dest;	__be32		err;	int		host_err;	err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_CREATE);	if (err)		goto out;	err = fh_verify(rqstp, tfhp, -S_IFDIR, MAY_NOP);	if (err)		goto out;	err = nfserr_perm;	if (!len)		goto out;	err = nfserr_exist;	if (isdotent(name, len))		goto out;	fh_lock_nested(ffhp, I_MUTEX_PARENT);	ddir = ffhp->fh_dentry;	dirp = ddir->d_inode;	dnew = lookup_one_len(name, ddir, len);	host_err = PTR_ERR(dnew);	if (IS_ERR(dnew))		goto out_nfserr;	dold = tfhp->fh_dentry;	dest = dold->d_inode;	host_err = vfs_link(dold, dirp, dnew);	if (!host_err) {		if (EX_ISSYNC(ffhp->fh_export)) {			err = nfserrno(nfsd_sync_dir(ddir));			write_inode_now(dest, 1);		}		err = 0;	} else {		if (host_err == -EXDEV && rqstp->rq_vers == 2)			err = nfserr_acces;		else			err = nfserrno(host_err);	}	dput(dnew);out_unlock:	fh_unlock(ffhp);out:	return err;out_nfserr:	err = nfserrno(host_err);	goto out_unlock;}/* * Rename a file * N.B. After this call _both_ ffhp and tfhp need an fh_put */__be32nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,			    struct svc_fh *tfhp, char *tname, int tlen){	struct dentry	*fdentry, *tdentry, *odentry, *ndentry, *trap;	struct inode	*fdir, *tdir;	__be32		err;	int		host_err;	err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_REMOVE);	if (err)		goto out;	err = fh_verify(rqstp, tfhp, S_IFDIR, MAY_CREATE);	if (err)		goto out;	fdentry = ffhp->fh_dentry;	fdir = fdentry->d_inode;	tdentry = tfhp->fh_dentry;	tdir = tdentry->d_inode;	err = (rqstp->rq_vers == 2) ? nfserr_acces : nfserr_xdev;	if (ffhp->fh_export != tfhp->fh_export)		goto out;	err = nfserr_perm;	if (!flen || isdotent(fname, flen) || !tlen || isdotent(tname, tlen))		goto out;	/* cannot use fh_lock as we need deadlock protective ordering	 * so do it by hand */	trap = lock_rename(tdentry, fdentry);	ffhp->fh_locked = tfhp->fh_locked = 1;	fill_pre_wcc(ffhp);	fill_pre_wcc(tfhp);	odentry = lookup_one_len(fname, fdentry, flen);	host_err = PTR_ERR(odentry);	if (IS_ERR(odentry))		goto out_nfserr;	host_err = -ENOENT;	if (!odentry->d_inode)		goto out_dput_old;	host_err = -EINVAL;	if (odentry == trap)		goto out_dput_old;	ndentry = lookup_one_len(tname, tdentry, tlen);	host_err = PTR_ERR(ndentry);	if (IS_ERR(ndentry))		goto out_dput_old;	host_err = -ENOTEMPTY;	if (ndentry == trap)		goto out_dput_new;#ifdef MSNFS	if ((ffhp->fh_export->ex_flags & NFSEXP_MSNFS) &&		((atomic_read(&odentry->d_count) > 1)		 || (atomic_read(&ndentry->d_count) > 1))) {			host_err = -EPERM;	} else#endif	host_err = vfs_rename(fdir, odentry, tdir, ndentry);	if (!host_err && EX_ISSYNC(tfhp->fh_export)) {		host_err = nfsd_sync_dir(tdentry);		if (!host_err)			host_err = nfsd_sync_dir(fdentry);	} out_dput_new:	dput(ndentry); out_dput_old:	dput(odentry); out_nfserr:	err = nfserrno(host_err);	/* we cannot reply on fh_unlock on the two filehandles,	 * as that would do the wrong thing if the two directories	 * were the same, so again we do it by hand	 */	fill_post_wcc(ffhp);	fill_post_wcc(tfhp);	unlock_rename(tdentry, fdentry);	ffhp->fh_locked = tfhp->fh_locked = 0;out:	return err;}/* * Unlink a file or directory * N.B. After this call fhp needs an fh_put */__be32nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,				char *fname, int flen){	struct dentry	*dentry, *rdentry;	struct inode	*dirp;	__be32		err;	int		host_err;	err = nfserr_acces;	if (!flen || isdotent(fname, flen))		goto out;	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_REMOVE);	if (err)		goto out;	fh_lock_nested(fhp, I_MUTEX_PARENT);	dentry = fhp->fh_dentry;	dirp = dentry->d_inode;	rdentry = lookup_one_len(fname, dentry, flen);	host_err = PTR_ERR(rdentry);	if (IS_ERR(rdentry))		goto out_nfserr;	if (!rdentry->d_inode) {		dput(rdentry);		err = nfserr_noent;		goto out;	}	if (!type)		type = rdentry->d_inode->i_mode & S_IFMT;	if (type != S_IFDIR) { /* It's UNLINK */#ifdef MSNFS		if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&			(atomic_read(&rdentry->d_count) > 1)) {			host_err = -EPERM;		} else#endif		host_err = vfs_unlink(dirp, rdentry);	} else { /* It's RMDIR */		host_err = vfs_rmdir(dirp, rdentry);	}	dput(rdentry);	if (host_err)		goto out_nfserr;	if (EX_ISSYNC(fhp->fh_export))		host_err = nfsd_sync_dir(dentry);out_nfserr:	err = nfserrno(host_err);out:	return err;}/* * Read entries from a directory. * The  NFSv3/4 verifier we ignore for now. */__be32nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, 	     struct readdir_cd *cdp, filldir_t func){	__be32		err;	int 		host_err;	struct file	*file;	loff_t		offset = *offsetp;	err = nfsd_open(rqstp, fhp, S_IFDIR, MAY_READ, &file);	if (err)		goto out;	offset = vfs_llseek(file, offset, 0);	if (offset < 0) {		err = nfserrno((int)offset);		goto out_close;	}	/*	 * Read the directory entries. This silly loop is necessary because	 * readdir() is not guaranteed to fill up the entire buffer, but	 * may choose to do less.	 */	do {		cdp->err = nfserr_eof; /* will be cleared on successful read */		host_err = vfs_readdir(file, func, cdp);	} while (host_err >=0 && cdp->err == nfs_ok);	if (host_err)		err = nfserrno(host_err);	else		err = cdp->err;	*offsetp = vfs_llseek(file, 0, 1);	if (err == nfserr_eof || err == nfserr_toosmall)		err = nfs_ok; /* can still be found in ->err */out_close:	nfsd_close(file);out:	return err;}/* * Get file system stats * N.B. After this call fhp needs an fh_put */__be32nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat){	__be32 err = fh_verify(rqstp, fhp, 0, MAY_NOP);	if (!err && vfs_statfs(fhp->fh_dentry,stat))		err = nfserr_io;	return err;}static int exp_rdonly(struct svc_rqst *rqstp, struct svc_export *exp){	return nfsexp_flags(rqstp, exp) & NFSEXP_READONLY;}/* * Check for a user's access permissions to this inode. */__be32nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,					struct dentry *dentry, int acc){	struct inode	*inode = dentry->d_inode;	int		err;	if (acc == MAY_NOP)		return 0;#if 0	dprintk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n",		acc,		(acc & MAY_READ)?	" read"  : "",		(acc & MAY_WRITE)?	" write" : "",		(acc & MAY_EXEC)?	" exec"  : "",		(acc & MAY_SATTR)?	" sattr" : "",		(acc & MAY_TRUNC)?	" trunc" : "",		(acc & MAY_LOCK)?	" lock"  : "",		(acc & MAY_OWNER_OVERRIDE)? " owneroverride" : "",		inode->i_mode,		IS_IMMUTABLE(inode)?	" immut" : "",		IS_APPEND(inode)?	" append" : "",		IS_RDONLY(inode)?	" ro" : "");	dprintk("      owner %d/%d user %d/%d\n",		inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);#endif	/* Normally we reject any write/sattr etc access on a read-only file	 * system.  But if it is IRIX doing check on write-access for a 	 * device special file, we ignore rofs.	 */	if (!(acc & MAY_LOCAL_ACCESS))		if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) {			if (exp_rdonly(rqstp, exp) || IS_RDONLY(inode))				return nfserr_rofs;			if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode))				return nfserr_perm;		}	if ((acc & MAY_TRUNC) && IS_APPEND(inode))		return nfserr_perm;	if (acc & MAY_LOCK) {		/* If we cannot rely on authentication in NLM requests,		 * just allow locks, otherwise require read permission, or		 * ownership		 */		if (exp->ex_flags & NFSEXP_NOAUTHNLM)			return 0;		else			acc = MAY_READ | MAY_OWNER_OVERRIDE;	}	/*	 * The file owner always gets access permission for accesses that	 * would normally be checked at open time. This is to make	 * file access work even when the client has done a fchmod(fd, 0).	 *	 * However, `cp foo bar' should fail nevertheless when bar is	 * readonly. A sensible way to do this might be to reject all	 * attempts to truncate a read-only file, because a creat() call	 * always implies file truncation.	 * ... but this isn't really fair.  A process may reasonably call	 * ftruncate on an open file descriptor on a file with perm 000.	 * We must trust the client to do permission checking - using "ACCESS"	 * with NFSv3.	 */	if ((acc & MAY_OWNER_OVERRIDE) &&	    inode->i_uid == current->fsuid)		return 0;	err = permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC), NULL);	/* Allow read access to binaries even when mode 111 */	if (err == -EACCES && S_ISREG(inode->i_mode) &&	    acc == (MAY_READ | MAY_OWNER_OVERRIDE))		err = permission(inode, MAY_EXEC, NULL);	return err? nfserrno(err) : 0;}voidnfsd_racache_shutdown(void){	if (!raparml)		return;	dprintk("nfsd: freeing readahead buffers.\n");	kfree(raparml);	raparml = NULL;}/* * Initialize readahead param cache */intnfsd_racache_init(int cache_size){	int	i;	int	j = 0;	int	nperbucket;	if (raparml)		return 0;	if (cache_size < 2*RAPARM_HASH_SIZE)		cache_size = 2*RAPARM_HASH_SIZE;	raparml = kcalloc(cache_size, sizeof(struct raparms), GFP_KERNEL);	if (!raparml) {		printk(KERN_WARNING			"nfsd: Could not allocate memory read-ahead cache.\n");		return -ENOMEM;	}	dprintk("nfsd: allocating %d readahead buffers.\n", cache_size);	for (i = 0 ; i < RAPARM_HASH_SIZE ; i++) {		raparm_hash[i].pb_head = NULL;		spin_lock_init(&raparm_hash[i].pb_lock);	}	nperbucket = DIV_ROUND_UP(cache_size, RAPARM_HASH_SIZE);	for (i = 0; i < cache_size - 1; i++) {		if (i % nperbucket == 0)			raparm_hash[j++].pb_head = raparml + i;		if (i % nperbucket < nperbucket-1)			raparml[i].p_next = raparml + i + 1;	}	nfsdstats.ra_size = cache_size;	return 0;}#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)struct posix_acl *nfsd_get_posix_acl(struct svc_fh *fhp, int type){	struct inode *inode = fhp->fh_dentry->d_inode;	char *name;	void *value = NULL;	ssize_t size;	struct posix_acl *acl;	if (!IS_POSIXACL(inode))		return ERR_PTR(-EOPNOTSUPP);	switch (type) {	case ACL_TYPE_ACCESS:		name = POSIX_ACL_XATTR_ACCESS;		break;	case ACL_TYPE_DEFAULT:		name = POSIX_ACL_XATTR_DEFAULT;		break;	default:		return ERR_PTR(-EOPNOTSUPP);	}	size = nfsd_getxattr(fhp->fh_dentry, name, &value);	if (size < 0)		return ERR_PTR(size);	acl = posix_acl_from_xattr(value, size);	kfree(value);	return acl;}intnfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl){	struct inode *inode = fhp->fh_dentry->d_inode;	char *name;	void *value = NULL;	size_t size;	int error;	if (!IS_POSIXACL(inode) || !inode->i_op ||	    !inode->i_op->setxattr || !inode->i_op->removexattr)		return -EOPNOTSUPP;	switch(type) {		case ACL_TYPE_ACCESS:			name = POSIX_ACL_XATTR_ACCESS;			break;		case ACL_TYPE_DEFAULT:			name = POSIX_ACL_XATTR_DEFAULT;			break;		default:			return -EOPNOTSUPP;	}	if (acl && acl->a_count) {		size = posix_acl_xattr_size(acl->a_count);		value = kmalloc(size, GFP_KERNEL);		if (!value)			return -ENOMEM;		error = posix_acl_to_xattr(acl, value, size);		if (error < 0)			goto getout;		size = error;	} else		size = 0;	if (size)		error = vfs_setxattr(fhp->fh_dentry, name, value, size, 0);	else {		if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)			error = 0;		else {			error = vfs_removexattr(fhp->fh_dentry, name);			if (error == -ENODATA)				error = 0;		}	}getout:	kfree(value);	return error;}#endif  /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */

⌨️ 快捷键说明

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