vfs.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,815 行 · 第 1/3 页

C
1,815
字号
		 */		v_mtime = verifier[0]&0x7fffffff;		v_atime = verifier[1]&0x7fffffff;		v_mode  = S_IFREG			| ((verifier[0]&0x80000000) >> (32-7)) /* u+x */			| ((verifier[1]&0x80000000) >> (32-9)) /* u+r */			;	}		if (dchild->d_inode) {		err = 0;		switch (createmode) {		case NFS3_CREATE_UNCHECKED:			if (! S_ISREG(dchild->d_inode->i_mode))				err = nfserr_exist;			else if (truncp) {				/* in nfsv4, we need to treat this case a little				 * differently.  we don't want to truncate the				 * file now; this would be wrong if the OPEN				 * fails for some other reason.  furthermore,				 * if the size is nonzero, we should ignore it				 * according to spec!				 */				*truncp = (iap->ia_valid & ATTR_SIZE) && !iap->ia_size;			}			else {				iap->ia_valid &= ATTR_SIZE;				goto set_attr;			}			break;		case NFS3_CREATE_EXCLUSIVE:			if (   dchild->d_inode->i_mtime.tv_sec == v_mtime			    && dchild->d_inode->i_atime.tv_sec == v_atime			    && dchild->d_inode->i_mode  == v_mode			    && dchild->d_inode->i_size  == 0 )				break;			 /* fallthru */		case NFS3_CREATE_GUARDED:			err = nfserr_exist;		}		goto out;	}	err = vfs_create(dirp, dchild, iap->ia_mode, NULL);	if (err < 0)		goto out_nfserr;	if (EX_ISSYNC(fhp->fh_export)) {		nfsd_sync_dir(dentry);		/* setattr will sync the child (or not) */	}	/*	 * Update the filehandle to get the new inode info.	 */	err = fh_update(resfhp);	if (err)		goto out;	if (createmode == NFS3_CREATE_EXCLUSIVE) {		/* Cram the verifier into atime/mtime/mode */		iap->ia_valid = ATTR_MTIME|ATTR_ATIME			| ATTR_MTIME_SET|ATTR_ATIME_SET			| ATTR_MODE;		/* XXX someone who knows this better please fix it for nsec */ 		iap->ia_mtime.tv_sec = v_mtime;		iap->ia_atime.tv_sec = v_atime;		iap->ia_mtime.tv_nsec = 0;		iap->ia_atime.tv_nsec = 0;		iap->ia_mode  = v_mode;	}	/* Set file attributes.	 * Mode has already been set but we might need to reset it	 * for CREATE_EXCLUSIVE	 * Irix appears to send along the gid when it tries to	 * implement setgid directories via NFS. Clear out all that cruft.	 */ set_attr:	if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0) 		err = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); out:	fh_unlock(fhp);	if (dchild && !IS_ERR(dchild))		dput(dchild); 	return err;  out_nfserr:	err = nfserrno(err);	goto out;}#endif /* CONFIG_NFSD_V3 *//* * Read a symlink. On entry, *lenp must contain the maximum path length that * fits into the buffer. On return, it contains the true length. * N.B. After this call fhp needs an fh_put */intnfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp){	struct dentry	*dentry;	struct inode	*inode;	mm_segment_t	oldfs;	int		err;	err = fh_verify(rqstp, fhp, S_IFLNK, MAY_NOP);	if (err)		goto out;	dentry = fhp->fh_dentry;	inode = dentry->d_inode;	err = nfserr_inval;	if (!inode->i_op || !inode->i_op->readlink)		goto out;	touch_atime(fhp->fh_export->ex_mnt, dentry);	/* N.B. Why does this call need a get_fs()??	 * Remove the set_fs and watch the fireworks:-) --okir	 */	oldfs = get_fs(); set_fs(KERNEL_DS);	err = inode->i_op->readlink(dentry, buf, *lenp);	set_fs(oldfs);	if (err < 0)		goto out_nfserr;	*lenp = err;	err = 0;out:	return err;out_nfserr:	err = nfserrno(err);	goto out;}/* * Create a symlink and look up its inode * N.B. After this call _both_ fhp and resfhp need an fh_put */intnfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,				char *fname, int flen,				char *path,  int plen,				struct svc_fh *resfhp,				struct iattr *iap){	struct dentry	*dentry, *dnew;	int		err, cerr;	umode_t		mode;	err = nfserr_noent;	if (!flen || !plen)		goto out;	err = nfserr_exist;	if (isdotent(fname, flen))		goto out;	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);	if (err)		goto out;	fh_lock(fhp);	dentry = fhp->fh_dentry;	dnew = lookup_one_len(fname, dentry, flen);	err = PTR_ERR(dnew);	if (IS_ERR(dnew))		goto out_nfserr;	mode = S_IALLUGO;	/* Only the MODE ATTRibute is even vaguely meaningful */	if (iap && (iap->ia_valid & ATTR_MODE))		mode = iap->ia_mode & S_IALLUGO;	if (unlikely(path[plen] != 0)) {		char *path_alloced = kmalloc(plen+1, GFP_KERNEL);		if (path_alloced == NULL)			err = -ENOMEM;		else {			strncpy(path_alloced, path, plen);			path_alloced[plen] = 0;			err = vfs_symlink(dentry->d_inode, dnew, path_alloced, mode);			kfree(path_alloced);		}	} else		err = vfs_symlink(dentry->d_inode, dnew, path, mode);	if (!err) {		if (EX_ISSYNC(fhp->fh_export))			nfsd_sync_dir(dentry);	} else		err = nfserrno(err);	fh_unlock(fhp);	cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);	dput(dnew);	if (err==0) err = cerr;out:	return err;out_nfserr:	err = nfserrno(err);	goto out;}/* * Create a hardlink * N.B. After this call _both_ ffhp and tfhp need an fh_put */intnfsd_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;	int		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(ffhp);	ddir = ffhp->fh_dentry;	dirp = ddir->d_inode;	dnew = lookup_one_len(name, ddir, len);	err = PTR_ERR(dnew);	if (IS_ERR(dnew))		goto out_nfserr;	dold = tfhp->fh_dentry;	dest = dold->d_inode;	err = vfs_link(dold, dirp, dnew);	if (!err) {		if (EX_ISSYNC(ffhp->fh_export)) {			nfsd_sync_dir(ddir);			write_inode_now(dest, 1);		}	} else {		if (err == -EXDEV && rqstp->rq_vers == 2)			err = nfserr_acces;		else			err = nfserrno(err);	}	fh_unlock(ffhp);	dput(dnew);out:	return err;out_nfserr:	err = nfserrno(err);	goto out;}/* * Rename a file * N.B. After this call _both_ ffhp and tfhp need an fh_put */intnfsd_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;	int		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 (fdir->i_sb != tdir->i_sb)		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);	err = PTR_ERR(odentry);	if (IS_ERR(odentry))		goto out_nfserr;	err = -ENOENT;	if (!odentry->d_inode)		goto out_dput_old;	err = -EINVAL;	if (odentry == trap)		goto out_dput_old;	ndentry = lookup_one_len(tname, tdentry, tlen);	err = PTR_ERR(ndentry);	if (IS_ERR(ndentry))		goto out_dput_old;	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))) {			err = nfserr_perm;	} else#endif	err = vfs_rename(fdir, odentry, tdir, ndentry);	if (!err && EX_ISSYNC(tfhp->fh_export)) {		nfsd_sync_dir(tdentry);		nfsd_sync_dir(fdentry);	} out_dput_new:	dput(ndentry); out_dput_old:	dput(odentry); out_nfserr:	if (err)		err = nfserrno(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 */intnfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,				char *fname, int flen){	struct dentry	*dentry, *rdentry;	struct inode	*dirp;	int		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(fhp);	dentry = fhp->fh_dentry;	dirp = dentry->d_inode;	rdentry = lookup_one_len(fname, dentry, flen);	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)) {			err = nfserr_perm;		} else#endif		err = vfs_unlink(dirp, rdentry);	} else { /* It's RMDIR */		err = vfs_rmdir(dirp, rdentry);	}	dput(rdentry);	if (err)		goto out_nfserr;	if (EX_ISSYNC(fhp->fh_export)) 		nfsd_sync_dir(dentry);out:	return err;out_nfserr:	err = nfserrno(err);	goto out;}/* * Read entries from a directory. * The  NFSv3/4 verifier we ignore for now. */intnfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, 	     struct readdir_cd *cdp, encode_dent_fn func){	int		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 */		err = vfs_readdir(file, (filldir_t) func, cdp);	} while (err >=0 && cdp->err == nfs_ok);	if (err)		err = nfserrno(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 */intnfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat){	int err = fh_verify(rqstp, fhp, 0, MAY_NOP);	if (!err && vfs_statfs(fhp->fh_dentry->d_inode->i_sb,stat))		err = nfserr_io;	return err;}/* * Check for a user's access permissions to this inode. */intnfsd_permission(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 (EX_RDONLY(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 (!raparm_cache)		return;	dprintk("nfsd: freeing readahead buffers.\n");	kfree(raparml);	raparm_cache = raparml = NULL;}/* * Initialize readahead param cache */intnfsd_racache_init(int cache_size){	int	i;	if (raparm_cache)		return 0;	raparml = kmalloc(sizeof(struct raparms) * cache_size, GFP_KERNEL);	if (raparml != NULL) {		dprintk("nfsd: allocating %d readahead buffers.\n",			cache_size);		memset(raparml, 0, sizeof(struct raparms) * cache_size);		for (i = 0; i < cache_size - 1; i++) {			raparml[i].p_next = raparml + i + 1;		}		raparm_cache = raparml;	} else {		printk(KERN_WARNING		       "nfsd: Could not allocate memory read-ahead cache.\n");		return -ENOMEM;	}	nfsdstats.ra_size = cache_size;	return 0;}

⌨️ 快捷键说明

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