diff options
| author | Jiri Kosina <jkosina@suse.cz> | 2011-09-15 15:08:05 +0200 | 
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.cz> | 2011-09-15 15:08:18 +0200 | 
| commit | e060c38434b2caa78efe7cedaff4191040b65a15 (patch) | |
| tree | 407361230bf6733f63d8e788e4b5e6566ee04818 /fs/9p/vfs_inode.c | |
| parent | 10e4ac572eeffe5317019bd7330b6058a400dfc2 (diff) | |
| parent | cc39c6a9bbdebfcf1a7dee64d83bf302bc38d941 (diff) | |
| download | olio-linux-3.10-e060c38434b2caa78efe7cedaff4191040b65a15.tar.xz olio-linux-3.10-e060c38434b2caa78efe7cedaff4191040b65a15.zip  | |
Merge branch 'master' into for-next
Fast-forward merge with Linus to be able to merge patches
based on more recent version of the tree.
Diffstat (limited to 'fs/9p/vfs_inode.c')
| -rw-r--r-- | fs/9p/vfs_inode.c | 139 | 
1 files changed, 87 insertions, 52 deletions
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 8bb5507e822..e3c03db3c78 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -95,15 +95,18 @@ static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode)  /**   * p9mode2unixmode- convert plan9 mode bits to unix mode bits   * @v9ses: v9fs session information - * @mode: mode to convert + * @stat: p9_wstat from which mode need to be derived + * @rdev: major number, minor number in case of device files.   *   */ - -static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) +static int p9mode2unixmode(struct v9fs_session_info *v9ses, +			   struct p9_wstat *stat, dev_t *rdev)  {  	int res; +	int mode = stat->mode; -	res = mode & 0777; +	res = mode & S_IALLUGO; +	*rdev = 0;  	if ((mode & P9_DMDIR) == P9_DMDIR)  		res |= S_IFDIR; @@ -116,9 +119,26 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)  		 && (v9ses->nodev == 0))  		res |= S_IFIFO;  	else if ((mode & P9_DMDEVICE) && (v9fs_proto_dotu(v9ses)) -		 && (v9ses->nodev == 0)) -		res |= S_IFBLK; -	else +		 && (v9ses->nodev == 0)) { +		char type = 0, ext[32]; +		int major = -1, minor = -1; + +		strncpy(ext, stat->extension, sizeof(ext)); +		sscanf(ext, "%c %u %u", &type, &major, &minor); +		switch (type) { +		case 'c': +			res |= S_IFCHR; +			break; +		case 'b': +			res |= S_IFBLK; +			break; +		default: +			P9_DPRINTK(P9_DEBUG_ERROR, +				"Unknown special type %c %s\n", type, +				stat->extension); +		}; +		*rdev = MKDEV(major, minor); +	} else  		res |= S_IFREG;  	if (v9fs_proto_dotu(v9ses)) { @@ -131,7 +151,6 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)  		if ((mode & P9_DMSETVTX) == P9_DMSETVTX)  			res |= S_ISVTX;  	} -  	return res;  } @@ -242,13 +261,13 @@ void v9fs_destroy_inode(struct inode *inode)  }  int v9fs_init_inode(struct v9fs_session_info *v9ses, -		    struct inode *inode, int mode) +		    struct inode *inode, int mode, dev_t rdev)  {  	int err = 0;  	inode_init_owner(inode, NULL, mode);  	inode->i_blocks = 0; -	inode->i_rdev = 0; +	inode->i_rdev = rdev;  	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;  	inode->i_mapping->a_ops = &v9fs_addr_operations; @@ -335,7 +354,7 @@ error:   *   */ -struct inode *v9fs_get_inode(struct super_block *sb, int mode) +struct inode *v9fs_get_inode(struct super_block *sb, int mode, dev_t rdev)  {  	int err;  	struct inode *inode; @@ -348,7 +367,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)  		P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n");  		return ERR_PTR(-ENOMEM);  	} -	err = v9fs_init_inode(v9ses, inode, mode); +	err = v9fs_init_inode(v9ses, inode, mode, rdev);  	if (err) {  		iput(inode);  		return ERR_PTR(err); @@ -435,11 +454,12 @@ void v9fs_evict_inode(struct inode *inode)  static int v9fs_test_inode(struct inode *inode, void *data)  {  	int umode; +	dev_t rdev;  	struct v9fs_inode *v9inode = V9FS_I(inode);  	struct p9_wstat *st = (struct p9_wstat *)data;  	struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); -	umode = p9mode2unixmode(v9ses, st->mode); +	umode = p9mode2unixmode(v9ses, st, &rdev);  	/* don't match inode of different type */  	if ((inode->i_mode & S_IFMT) != (umode & S_IFMT))  		return 0; @@ -473,6 +493,7 @@ static struct inode *v9fs_qid_iget(struct super_block *sb,  				   struct p9_wstat *st,  				   int new)  { +	dev_t rdev;  	int retval, umode;  	unsigned long i_ino;  	struct inode *inode; @@ -496,8 +517,8 @@ static struct inode *v9fs_qid_iget(struct super_block *sb,  	 * later.  	 */  	inode->i_ino = i_ino; -	umode = p9mode2unixmode(v9ses, st->mode); -	retval = v9fs_init_inode(v9ses, inode, umode); +	umode = p9mode2unixmode(v9ses, st, &rdev); +	retval = v9fs_init_inode(v9ses, inode, umode, rdev);  	if (retval)  		goto error; @@ -532,6 +553,19 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,  }  /** + * v9fs_at_to_dotl_flags- convert Linux specific AT flags to + * plan 9 AT flag. + * @flags: flags to convert + */ +static int v9fs_at_to_dotl_flags(int flags) +{ +	int rflags = 0; +	if (flags & AT_REMOVEDIR) +		rflags |= P9_DOTL_AT_REMOVEDIR; +	return rflags; +} + +/**   * v9fs_remove - helper function to remove files and directories   * @dir: directory inode that is being deleted   * @dentry:  dentry that is being deleted @@ -558,7 +592,8 @@ static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags)  		return retval;  	}  	if (v9fs_proto_dotl(v9ses)) -		retval = p9_client_unlinkat(dfid, dentry->d_name.name, flags); +		retval = p9_client_unlinkat(dfid, dentry->d_name.name, +					    v9fs_at_to_dotl_flags(flags));  	if (retval == -EOPNOTSUPP) {  		/* Try the one based on path */  		v9fid = v9fs_fid_clone(dentry); @@ -645,13 +680,11 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,  		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);  	return ofid; -  error:  	if (ofid)  		p9_client_clunk(ofid); @@ -792,6 +825,7 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)  struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,  				      struct nameidata *nameidata)  { +	struct dentry *res;  	struct super_block *sb;  	struct v9fs_session_info *v9ses;  	struct p9_fid *dfid, *fid; @@ -823,22 +857,35 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,  		return ERR_PTR(result);  	} - -	inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); +	/* +	 * Make sure we don't use a wrong inode due to parallel +	 * unlink. For cached mode create calls request for new +	 * inode. But with cache disabled, lookup should do this. +	 */ +	if (v9ses->cache) +		inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); +	else +		inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);  	if (IS_ERR(inode)) {  		result = PTR_ERR(inode);  		inode = NULL;  		goto error;  	} -  	result = v9fs_fid_add(dentry, fid);  	if (result < 0)  		goto error_iput; -  inst_out: -	d_add(dentry, inode); -	return NULL; - +	/* +	 * If we had a rename on the server and a parallel lookup +	 * for the new name, then make sure we instantiate with +	 * the new name. ie look up for a/b, while on server somebody +	 * moved b under k and client parallely did a lookup for +	 * k/b. +	 */ +	res = d_materialise_unique(dentry, inode); +	if (!IS_ERR(res)) +		return res; +	result = PTR_ERR(res);  error_iput:  	iput(inode);  error: @@ -1002,7 +1049,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,  		return PTR_ERR(st);  	v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb); -		generic_fillattr(dentry->d_inode, stat); +	generic_fillattr(dentry->d_inode, stat);  	p9stat_free(st);  	kfree(st); @@ -1086,6 +1133,7 @@ void  v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,  	struct super_block *sb)  { +	mode_t mode;  	char ext[32];  	char tag_name[14];  	unsigned int i_nlink; @@ -1121,31 +1169,9 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,  				inode->i_nlink = i_nlink;  		}  	} -	inode->i_mode = p9mode2unixmode(v9ses, stat->mode); -	if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { -		char type = 0; -		int major = -1; -		int minor = -1; - -		strncpy(ext, stat->extension, sizeof(ext)); -		sscanf(ext, "%c %u %u", &type, &major, &minor); -		switch (type) { -		case 'c': -			inode->i_mode &= ~S_IFBLK; -			inode->i_mode |= S_IFCHR; -			break; -		case 'b': -			break; -		default: -			P9_DPRINTK(P9_DEBUG_ERROR, -				"Unknown special type %c %s\n", type, -				stat->extension); -		}; -		inode->i_rdev = MKDEV(major, minor); -		init_special_inode(inode, inode->i_mode, inode->i_rdev); -	} else -		inode->i_rdev = 0; - +	mode = stat->mode & S_IALLUGO; +	mode |= inode->i_mode & ~S_IALLUGO; +	inode->i_mode = mode;  	i_size_write(inode, stat->length);  	/* not real number of blocks, but 512 byte ones ... */ @@ -1411,6 +1437,8 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)  int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode)  { +	int umode; +	dev_t rdev;  	loff_t i_size;  	struct p9_wstat *st;  	struct v9fs_session_info *v9ses; @@ -1419,6 +1447,12 @@ int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode)  	st = p9_client_stat(fid);  	if (IS_ERR(st))  		return PTR_ERR(st); +	/* +	 * Don't update inode if the file type is different +	 */ +	umode = p9mode2unixmode(v9ses, st, &rdev); +	if ((inode->i_mode & S_IFMT) != (umode & S_IFMT)) +		goto out;  	spin_lock(&inode->i_lock);  	/* @@ -1430,6 +1464,7 @@ int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode)  	if (v9ses->cache)  		inode->i_size = i_size;  	spin_unlock(&inode->i_lock); +out:  	p9stat_free(st);  	kfree(st);  	return 0;  |