diff options
Diffstat (limited to 'fs/9p/vfs_inode_dotl.c')
| -rw-r--r-- | fs/9p/vfs_inode_dotl.c | 86 | 
1 files changed, 73 insertions, 13 deletions
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index b6c8ed20519..aded79fcd5c 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -153,7 +153,8 @@ static struct inode *v9fs_qid_iget_dotl(struct super_block *sb,  	 * later.  	 */  	inode->i_ino = i_ino; -	retval = v9fs_init_inode(v9ses, inode, st->st_mode); +	retval = v9fs_init_inode(v9ses, inode, +				 st->st_mode, new_decode_dev(st->st_rdev));  	if (retval)  		goto error; @@ -190,6 +191,58 @@ v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid,  	return inode;  } +struct dotl_openflag_map { +	int open_flag; +	int dotl_flag; +}; + +static int v9fs_mapped_dotl_flags(int flags) +{ +	int i; +	int rflags = 0; +	struct dotl_openflag_map dotl_oflag_map[] = { +		{ O_CREAT,	P9_DOTL_CREATE }, +		{ O_EXCL,	P9_DOTL_EXCL }, +		{ O_NOCTTY,	P9_DOTL_NOCTTY }, +		{ O_TRUNC,	P9_DOTL_TRUNC }, +		{ O_APPEND,	P9_DOTL_APPEND }, +		{ O_NONBLOCK,	P9_DOTL_NONBLOCK }, +		{ O_DSYNC,	P9_DOTL_DSYNC }, +		{ FASYNC,	P9_DOTL_FASYNC }, +		{ O_DIRECT,	P9_DOTL_DIRECT }, +		{ O_LARGEFILE,	P9_DOTL_LARGEFILE }, +		{ O_DIRECTORY,	P9_DOTL_DIRECTORY }, +		{ O_NOFOLLOW,	P9_DOTL_NOFOLLOW }, +		{ O_NOATIME,	P9_DOTL_NOATIME }, +		{ O_CLOEXEC,	P9_DOTL_CLOEXEC }, +		{ O_SYNC,	P9_DOTL_SYNC}, +	}; +	for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) { +		if (flags & dotl_oflag_map[i].open_flag) +			rflags |= dotl_oflag_map[i].dotl_flag; +	} +	return rflags; +} + +/** + * v9fs_open_to_dotl_flags- convert Linux specific open flags to + * plan 9 open flag. + * @flags: flags to convert + */ +int v9fs_open_to_dotl_flags(int flags) +{ +	int rflags = 0; + +	/* +	 * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY +	 * and P9_DOTL_NOACCESS +	 */ +	rflags |= flags & O_ACCMODE; +	rflags |= v9fs_mapped_dotl_flags(flags); + +	return rflags; +} +  /**   * v9fs_vfs_create_dotl - VFS hook to create files for 9P2000.L protocol.   * @dir: directory inode that is being created @@ -258,7 +311,8 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,  			   "Failed to get acl values in creat %d\n", err);  		goto error;  	} -	err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid); +	err = p9_client_create_dotl(ofid, name, v9fs_open_to_dotl_flags(flags), +				    mode, gid, &qid);  	if (err < 0) {  		P9_DPRINTK(P9_DEBUG_VFS,  				"p9_client_open_dotl failed in creat %d\n", @@ -281,10 +335,10 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,  		P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);  		goto error;  	} -	d_instantiate(dentry, inode);  	err = v9fs_fid_add(dentry, fid);  	if (err < 0)  		goto error; +	d_instantiate(dentry, inode);  	/* Now set the ACL based on the default value */  	v9fs_set_create_acl(dentry, &dacl, &pacl); @@ -403,10 +457,10 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,  				err);  			goto error;  		} -		d_instantiate(dentry, inode);  		err = v9fs_fid_add(dentry, fid);  		if (err < 0)  			goto error; +		d_instantiate(dentry, inode);  		fid = NULL;  	} else {  		/* @@ -414,7 +468,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,  		 * inode with stat. We need to get an inode  		 * so that we can set the acl with dentry  		 */ -		inode = v9fs_get_inode(dir->i_sb, mode); +		inode = v9fs_get_inode(dir->i_sb, mode, 0);  		if (IS_ERR(inode)) {  			err = PTR_ERR(inode);  			goto error; @@ -540,6 +594,7 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)  void  v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)  { +	mode_t mode;  	struct v9fs_inode *v9inode = V9FS_I(inode);  	if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) { @@ -552,11 +607,10 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)  		inode->i_uid = stat->st_uid;  		inode->i_gid = stat->st_gid;  		inode->i_nlink = stat->st_nlink; -		inode->i_mode = stat->st_mode; -		inode->i_rdev = new_decode_dev(stat->st_rdev); -		if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) -			init_special_inode(inode, inode->i_mode, inode->i_rdev); +		mode = stat->st_mode & S_IALLUGO; +		mode |= inode->i_mode & ~S_IALLUGO; +		inode->i_mode = mode;  		i_size_write(inode, stat->st_size);  		inode->i_blocks = stat->st_blocks; @@ -657,14 +711,14 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,  					err);  			goto error;  		} -		d_instantiate(dentry, inode);  		err = v9fs_fid_add(dentry, fid);  		if (err < 0)  			goto error; +		d_instantiate(dentry, inode);  		fid = NULL;  	} else {  		/* Not in cached mode. No need to populate inode with stat */ -		inode = v9fs_get_inode(dir->i_sb, S_IFLNK); +		inode = v9fs_get_inode(dir->i_sb, S_IFLNK, 0);  		if (IS_ERR(inode)) {  			err = PTR_ERR(inode);  			goto error; @@ -810,17 +864,17 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode,  				err);  			goto error;  		} -		d_instantiate(dentry, inode);  		err = v9fs_fid_add(dentry, fid);  		if (err < 0)  			goto error; +		d_instantiate(dentry, inode);  		fid = NULL;  	} else {  		/*  		 * Not in cached mode. No need to populate inode with stat.  		 * socket syscall returns a fd, so we need instantiate  		 */ -		inode = v9fs_get_inode(dir->i_sb, mode); +		inode = v9fs_get_inode(dir->i_sb, mode, rdev);  		if (IS_ERR(inode)) {  			err = PTR_ERR(inode);  			goto error; @@ -886,6 +940,11 @@ int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)  	st = p9_client_getattr_dotl(fid, P9_STATS_ALL);  	if (IS_ERR(st))  		return PTR_ERR(st); +	/* +	 * Don't update inode if the file type is different +	 */ +	if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT)) +		goto out;  	spin_lock(&inode->i_lock);  	/* @@ -897,6 +956,7 @@ int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)  	if (v9ses->cache)  		inode->i_size = i_size;  	spin_unlock(&inode->i_lock); +out:  	kfree(st);  	return 0;  }  |