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

📄 vfs.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		 * work:-)		 */		if (EX_WGATHER(exp)) {			if (atomic_read(&inode->i_writecount) > 1			    || (last_ino == inode->i_ino && last_dev == inode->i_sb->s_dev)) {				dprintk("nfsd: write defer %d\n", task_pid_nr(current));				msleep(10);				dprintk("nfsd: write resume %d\n", task_pid_nr(current));			}			if (inode->i_state & I_DIRTY) {				dprintk("nfsd: write sync %d\n", task_pid_nr(current));				host_err=nfsd_sync(file);			}#if 0			wake_up(&inode->i_wait);#endif		}		last_ino = inode->i_ino;		last_dev = inode->i_sb->s_dev;	}	dprintk("nfsd: write complete host_err=%d\n", host_err);	if (host_err >= 0)		err = 0;	else 		err = nfserrno(host_err);out:	return err;}/* * Read data from a file. count must contain the requested read count * on entry. On return, *count contains the number of bytes actually read. * N.B. After this call fhp needs an fh_put */__be32nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,		loff_t offset, struct kvec *vec, int vlen,		unsigned long *count){	__be32		err;	if (file) {		err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,				MAY_READ|MAY_OWNER_OVERRIDE);		if (err)			goto out;		err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);	} else {		err = nfsd_open(rqstp, fhp, S_IFREG, MAY_READ, &file);		if (err)			goto out;		err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);		nfsd_close(file);	}out:	return err;}/* * Write data to a file. * The stable flag requests synchronous writes. * N.B. After this call fhp needs an fh_put */__be32nfsd_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){	__be32			err = 0;	if (file) {		err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,				MAY_WRITE|MAY_OWNER_OVERRIDE);		if (err)			goto out;		err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen, cnt,				stablep);	} else {		err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file);		if (err)			goto out;		if (cnt)			err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen,					     cnt, stablep);		nfsd_close(file);	}out:	return err;}#ifdef CONFIG_NFSD_V3/* * Commit all pending writes to stable storage. * Strictly speaking, we could sync just the indicated file region here, * but there's currently no way we can ask the VFS to do so. * * Unfortunately we cannot lock the file to make sure we return full WCC * data to the client, as locking happens lower down in the filesystem. */__be32nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,               loff_t offset, unsigned long count){	struct file	*file;	__be32		err;	if ((u64)count > ~(u64)offset)		return nfserr_inval;	if ((err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file)) != 0)		return err;	if (EX_ISSYNC(fhp->fh_export)) {		if (file->f_op && file->f_op->fsync) {			err = nfserrno(nfsd_sync(file));		} else {			err = nfserr_notsupp;		}	}	nfsd_close(file);	return err;}#endif /* CONFIG_NFSD_V3 *//* * Create a file (regular, directory, device, fifo); UNIX sockets  * not yet implemented. * If the response fh has been verified, the parent directory should * already be locked. Note that the parent directory is left locked. * * N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp */__be32nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,		char *fname, int flen, struct iattr *iap,		int type, dev_t rdev, struct svc_fh *resfhp){	struct dentry	*dentry, *dchild = NULL;	struct inode	*dirp;	__be32		err;	int		host_err;	err = nfserr_perm;	if (!flen)		goto out;	err = nfserr_exist;	if (isdotent(fname, flen))		goto out;	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);	if (err)		goto out;	dentry = fhp->fh_dentry;	dirp = dentry->d_inode;	err = nfserr_notdir;	if(!dirp->i_op || !dirp->i_op->lookup)		goto out;	/*	 * Check whether the response file handle has been verified yet.	 * If it has, the parent directory should already be locked.	 */	if (!resfhp->fh_dentry) {		/* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */		fh_lock_nested(fhp, I_MUTEX_PARENT);		dchild = lookup_one_len(fname, dentry, flen);		host_err = PTR_ERR(dchild);		if (IS_ERR(dchild))			goto out_nfserr;		err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);		if (err)			goto out;	} else {		/* called from nfsd_proc_create */		dchild = dget(resfhp->fh_dentry);		if (!fhp->fh_locked) {			/* not actually possible */			printk(KERN_ERR				"nfsd_create: parent %s/%s not locked!\n",				dentry->d_parent->d_name.name,				dentry->d_name.name);			err = nfserr_io;			goto out;		}	}	/*	 * Make sure the child dentry is still negative ...	 */	err = nfserr_exist;	if (dchild->d_inode) {		dprintk("nfsd_create: dentry %s/%s not negative!\n",			dentry->d_name.name, dchild->d_name.name);		goto out; 	}	if (!(iap->ia_valid & ATTR_MODE))		iap->ia_mode = 0;	iap->ia_mode = (iap->ia_mode & S_IALLUGO) | type;	/*	 * Get the dir op function pointer.	 */	err = 0;	switch (type) {	case S_IFREG:		host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);		break;	case S_IFDIR:		host_err = vfs_mkdir(dirp, dchild, iap->ia_mode);		break;	case S_IFCHR:	case S_IFBLK:	case S_IFIFO:	case S_IFSOCK:		host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);		break;	default:	        printk("nfsd: bad file type %o in nfsd_create\n", type);		host_err = -EINVAL;	}	if (host_err < 0)		goto out_nfserr;	if (EX_ISSYNC(fhp->fh_export)) {		err = nfserrno(nfsd_sync_dir(dentry));		write_inode_now(dchild->d_inode, 1);	}	/* Set file attributes. Mode has already been set and	 * setting uid/gid works only for root. Irix appears to	 * send along the gid when it tries to implement setgid	 * directories via NFS.	 */	if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) {		__be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);		if (err2)			err = err2;	}	/*	 * Update the file handle to get the new inode info.	 */	if (!err)		err = fh_update(resfhp);out:	if (dchild && !IS_ERR(dchild))		dput(dchild);	return err;out_nfserr:	err = nfserrno(host_err);	goto out;}#ifdef CONFIG_NFSD_V3/* * NFSv3 version of nfsd_create */__be32nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,		char *fname, int flen, struct iattr *iap,		struct svc_fh *resfhp, int createmode, u32 *verifier,	        int *truncp, int *created){	struct dentry	*dentry, *dchild = NULL;	struct inode	*dirp;	__be32		err;	int		host_err;	__u32		v_mtime=0, v_atime=0;	err = nfserr_perm;	if (!flen)		goto out;	err = nfserr_exist;	if (isdotent(fname, flen))		goto out;	if (!(iap->ia_valid & ATTR_MODE))		iap->ia_mode = 0;	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);	if (err)		goto out;	dentry = fhp->fh_dentry;	dirp = dentry->d_inode;	/* Get all the sanity checks out of the way before	 * we lock the parent. */	err = nfserr_notdir;	if(!dirp->i_op || !dirp->i_op->lookup)		goto out;	fh_lock_nested(fhp, I_MUTEX_PARENT);	/*	 * Compose the response file handle.	 */	dchild = lookup_one_len(fname, dentry, flen);	host_err = PTR_ERR(dchild);	if (IS_ERR(dchild))		goto out_nfserr;	err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);	if (err)		goto out;	if (createmode == NFS3_CREATE_EXCLUSIVE) {		/* solaris7 gets confused (bugid 4218508) if these have		 * the high bit set, so just clear the high bits. If this is		 * ever changed to use different attrs for storing the		 * verifier, then do_open_lookup() will also need to be fixed		 * accordingly.		 */		v_mtime = verifier[0]&0x7fffffff;		v_atime = verifier[1]&0x7fffffff;	}		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_size  == 0 )				break;			 /* fallthru */		case NFS3_CREATE_GUARDED:			err = nfserr_exist;		}		goto out;	}	host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);	if (host_err < 0)		goto out_nfserr;	if (created)		*created = 1;	if (EX_ISSYNC(fhp->fh_export)) {		err = nfserrno(nfsd_sync_dir(dentry));		/* setattr will sync the child (or not) */	}	if (createmode == NFS3_CREATE_EXCLUSIVE) {		/* Cram the verifier into atime/mtime */		iap->ia_valid = ATTR_MTIME|ATTR_ATIME			| ATTR_MTIME_SET|ATTR_ATIME_SET;		/* 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;	}	/* Set file attributes.	 * 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|ATTR_MODE)) != 0) { 		__be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);		if (err2)			err = err2;	}	/*	 * Update the filehandle to get the new inode info.	 */	if (!err)		err = fh_update(resfhp); out:	fh_unlock(fhp);	if (dchild && !IS_ERR(dchild))		dput(dchild); 	return err;  out_nfserr:	err = nfserrno(host_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 */__be32nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp){	struct dentry	*dentry;	struct inode	*inode;	mm_segment_t	oldfs;	__be32		err;	int		host_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);	host_err = inode->i_op->readlink(dentry, buf, *lenp);	set_fs(oldfs);	if (host_err < 0)		goto out_nfserr;	*lenp = host_err;	err = 0;out:	return err;out_nfserr:	err = nfserrno(host_err);	goto out;}/* * Create a symlink and look up its inode * N.B. After this call _both_ fhp and resfhp need an fh_put */__be32nfsd_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;	__be32		err, cerr;	int		host_err;	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);	host_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)			host_err = -ENOMEM;		else {			strncpy(path_alloced, path, plen);			path_alloced[plen] = 0;			host_err = vfs_symlink(dentry->d_inode, dnew, path_alloced, mode);			kfree(path_alloced);		}	} else		host_err = vfs_symlink(dentry->d_inode, dnew, path, mode);	if (!host_err) {		if (EX_ISSYNC(fhp->fh_export))			host_err = nfsd_sync_dir(dentry);	}	err = nfserrno(host_err);	fh_unlock(fhp);	cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);	dput(dnew);	if (err==0) err = cerr;out:	return err;

⌨️ 快捷键说明

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