From 5a7e0a8cf50cf905403f5a498e86d1f97cfcf51b Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 8 Mar 2011 16:39:46 +0530 Subject: fs/9p: Fix race in initializing writeback fid When two process open the same file we can end up with both of them allocating the writeback_fid. Add a new mutex which can be used for synchronizing v9fs_inode member values. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Venkateswararao Jujjuri Signed-off-by: Eric Van Hensbergen --- fs/9p/vfs_inode.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'fs/9p/vfs_inode.c') diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 8a2c232f708a..c6cef2495f00 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -221,6 +221,7 @@ struct inode *v9fs_alloc_inode(struct super_block *sb) #endif v9inode->writeback_fid = NULL; v9inode->cache_validity = 0; + mutex_init(&v9inode->v_mutex); return &v9inode->vfs_inode; } @@ -650,6 +651,7 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, /* if we are opening a file, assign the open fid to the file */ if (nd && nd->flags & LOOKUP_OPEN) { v9inode = V9FS_I(dentry->d_inode); + mutex_lock(&v9inode->v_mutex); if (v9ses->cache && !v9inode->writeback_fid) { /* * clone a fid and add it to writeback_fid @@ -661,10 +663,12 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, inode_fid = v9fs_writeback_fid(dentry); if (IS_ERR(inode_fid)) { err = PTR_ERR(inode_fid); + mutex_unlock(&v9inode->v_mutex); goto error; } v9inode->writeback_fid = (void *) inode_fid; } + mutex_unlock(&v9inode->v_mutex); filp = lookup_instantiate_filp(nd, dentry, generic_file_open); if (IS_ERR(filp)) { err = PTR_ERR(filp); -- cgit v1.2.3 From 059c138bc79320bd7d6fba91bad4d50eeec9c31f Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 8 Mar 2011 16:39:48 +0530 Subject: fs/9p: Use truncate_setsize instead of vmtruncate convert vmtruncate usage to truncate_setsize. We also writeback all dirty pages before doing 9p operations and on success call truncate_setsize. This ensure that we continue sanely on failed truncate on the server. The disadvantage is that we are now going to write back the content that get thrown away later as a part of truncate. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Venkateswararao Jujjuri Signed-off-by: Eric Van Hensbergen --- fs/9p/vfs_inode.c | 16 ++++++++++------ fs/9p/vfs_inode_dotl.c | 12 +++++------- 2 files changed, 15 insertions(+), 13 deletions(-) (limited to 'fs/9p/vfs_inode.c') diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index c6cef2495f00..0afbbb450faf 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -971,6 +971,10 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) struct p9_wstat wstat; P9_DPRINTK(P9_DEBUG_VFS, "\n"); + retval = inode_change_ok(dentry->d_inode, iattr); + if (retval) + return retval; + retval = -EPERM; v9ses = v9fs_inode2v9ses(dentry->d_inode); fid = v9fs_fid_lookup(dentry); @@ -997,12 +1001,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) if (iattr->ia_valid & ATTR_GID) wstat.n_gid = iattr->ia_gid; } - if ((iattr->ia_valid & ATTR_SIZE) && - iattr->ia_size != i_size_read(dentry->d_inode)) { - retval = vmtruncate(dentry->d_inode, iattr->ia_size); - if (retval) - return retval; - } + /* Write all dirty data */ if (S_ISREG(dentry->d_inode->i_mode)) filemap_write_and_wait(dentry->d_inode->i_mapping); @@ -1010,6 +1009,11 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) retval = p9_client_wstat(fid, &wstat); if (retval < 0) return retval; + + if ((iattr->ia_valid & ATTR_SIZE) && + iattr->ia_size != i_size_read(dentry->d_inode)) + truncate_setsize(dentry->d_inode, iattr->ia_size); + v9fs_invalidate_inode_attr(dentry->d_inode); setattr_copy(dentry->d_inode, iattr); diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 327c578c7ba6..0a0ac30d51d6 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -456,12 +456,6 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) if (IS_ERR(fid)) return PTR_ERR(fid); - if ((iattr->ia_valid & ATTR_SIZE) && - iattr->ia_size != i_size_read(dentry->d_inode)) { - retval = vmtruncate(dentry->d_inode, iattr->ia_size); - if (retval) - return retval; - } /* Write all dirty data */ if (S_ISREG(dentry->d_inode->i_mode)) filemap_write_and_wait(dentry->d_inode->i_mapping); @@ -469,8 +463,12 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) retval = p9_client_setattr(fid, &p9attr); if (retval < 0) return retval; - v9fs_invalidate_inode_attr(dentry->d_inode); + if ((iattr->ia_valid & ATTR_SIZE) && + iattr->ia_size != i_size_read(dentry->d_inode)) + truncate_setsize(dentry->d_inode, iattr->ia_size); + + v9fs_invalidate_inode_attr(dentry->d_inode); setattr_copy(dentry->d_inode, iattr); mark_inode_dirty(dentry->d_inode); if (iattr->ia_valid & ATTR_MODE) { -- cgit v1.2.3 From 7add697a3d271aa7080513f92dab190c75174b7e Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 8 Mar 2011 16:39:49 +0530 Subject: fs/9p: Attach writeback_fid on first open with WR flag We don't need writeback fid if we are only doing O_RDONLY open Signed-off-by: Aneesh Kumar K.V Signed-off-by: Venkateswararao Jujjuri Signed-off-by: Eric Van Hensbergen --- fs/9p/vfs_file.c | 3 ++- fs/9p/vfs_inode.c | 3 ++- fs/9p/vfs_inode_dotl.c | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'fs/9p/vfs_inode.c') diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 3337d58d0fc5..6997eb62fbba 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -91,7 +91,8 @@ int v9fs_file_open(struct inode *inode, struct file *file) file->private_data = fid; mutex_lock(&v9inode->v_mutex); - if (v9ses->cache && !v9inode->writeback_fid) { + if (v9ses->cache && !v9inode->writeback_fid && + ((file->f_flags & O_ACCMODE) != O_RDONLY)) { /* * clone a fid and add it to writeback_fid * we do it during open time instead of diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 0afbbb450faf..774a20af01ea 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -652,7 +652,8 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, if (nd && nd->flags & LOOKUP_OPEN) { v9inode = V9FS_I(dentry->d_inode); mutex_lock(&v9inode->v_mutex); - if (v9ses->cache && !v9inode->writeback_fid) { + if (v9ses->cache && !v9inode->writeback_fid && + ((flags & O_ACCMODE) != O_RDONLY)) { /* * clone a fid and add it to writeback_fid * we do it during open time instead of diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 0a0ac30d51d6..8b616dc3567a 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -246,7 +246,8 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, v9inode = V9FS_I(inode); mutex_lock(&v9inode->v_mutex); - if (v9ses->cache && !v9inode->writeback_fid) { + if (v9ses->cache && !v9inode->writeback_fid && + ((flags & O_ACCMODE) != O_RDONLY)) { /* * clone a fid and add it to writeback_fid * we do it during open time instead of -- cgit v1.2.3 From 42869c8adae72366fc6c4f3924ce3d6c3735c4a3 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 8 Mar 2011 16:39:50 +0530 Subject: fs/9p: Add v9fs_dentry2v9ses Add the new static inline and use the same Signed-off-by: Aneesh Kumar K.V Signed-off-by: Venkateswararao Jujjuri Signed-off-by: Eric Van Hensbergen --- fs/9p/acl.c | 4 ++-- fs/9p/fid.c | 6 +++--- fs/9p/v9fs.h | 5 +++++ fs/9p/vfs_inode.c | 6 +++--- fs/9p/vfs_inode_dotl.c | 4 ++-- fs/9p/vfs_super.c | 2 +- 6 files changed, 16 insertions(+), 11 deletions(-) (limited to 'fs/9p/vfs_inode.c') diff --git a/fs/9p/acl.c b/fs/9p/acl.c index 515455296378..33aa116732c8 100644 --- a/fs/9p/acl.c +++ b/fs/9p/acl.c @@ -262,7 +262,7 @@ static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name, if (strcmp(name, "") != 0) return -EINVAL; - v9ses = v9fs_inode2v9ses(dentry->d_inode); + v9ses = v9fs_dentry2v9ses(dentry); /* * We allow set/get/list of acl when access=client is not specified */ @@ -312,7 +312,7 @@ static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name, if (strcmp(name, "") != 0) return -EINVAL; - v9ses = v9fs_inode2v9ses(dentry->d_inode); + v9ses = v9fs_dentry2v9ses(dentry); /* * set the attribute on the remote. Without even looking at the * xattr value. We leave it to the server to validate diff --git a/fs/9p/fid.c b/fs/9p/fid.c index 99a1a7b08634..0ee594569dcc 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -134,7 +134,7 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry, struct v9fs_session_info *v9ses; struct p9_fid *fid, *old_fid = NULL; - v9ses = v9fs_inode2v9ses(dentry->d_inode); + v9ses = v9fs_dentry2v9ses(dentry); access = v9ses->flags & V9FS_ACCESS_MASK; fid = v9fs_fid_find(dentry, uid, any); if (fid) @@ -237,7 +237,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry) int any, access; struct v9fs_session_info *v9ses; - v9ses = v9fs_inode2v9ses(dentry->d_inode); + v9ses = v9fs_dentry2v9ses(dentry); access = v9ses->flags & V9FS_ACCESS_MASK; switch (access) { case V9FS_ACCESS_SINGLE: @@ -290,7 +290,7 @@ struct p9_fid *v9fs_writeback_fid(struct dentry *dentry) struct p9_fid *fid; struct v9fs_session_info *v9ses; - v9ses = v9fs_inode2v9ses(dentry->d_inode); + v9ses = v9fs_dentry2v9ses(dentry); fid = v9fs_fid_clone_with_uid(dentry, 0); if (IS_ERR(fid)) goto error_out; diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h index 89657e865162..9665c2b840e6 100644 --- a/fs/9p/v9fs.h +++ b/fs/9p/v9fs.h @@ -174,6 +174,11 @@ static inline struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode) return (inode->i_sb->s_fs_info); } +static inline struct v9fs_session_info *v9fs_dentry2v9ses(struct dentry *dentry) +{ + return dentry->d_sb->s_fs_info; +} + static inline int v9fs_proto_dotu(struct v9fs_session_info *v9ses) { return v9ses->flags & V9FS_PROTO_2000U; diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 774a20af01ea..7f6c67703195 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -936,7 +936,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry); err = -EPERM; - v9ses = v9fs_inode2v9ses(dentry->d_inode); + v9ses = v9fs_dentry2v9ses(dentry); if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) { generic_fillattr(dentry->d_inode, stat); return 0; @@ -977,7 +977,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) return retval; retval = -EPERM; - v9ses = v9fs_inode2v9ses(dentry->d_inode); + v9ses = v9fs_dentry2v9ses(dentry); fid = v9fs_fid_lookup(dentry); if(IS_ERR(fid)) return PTR_ERR(fid); @@ -1139,7 +1139,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name); retval = -EPERM; - v9ses = v9fs_inode2v9ses(dentry->d_inode); + v9ses = v9fs_dentry2v9ses(dentry); fid = v9fs_fid_lookup(dentry); if (IS_ERR(fid)) return PTR_ERR(fid); diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 8b616dc3567a..ffbb113d5f33 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -395,7 +395,7 @@ v9fs_vfs_getattr_dotl(struct vfsmount *mnt, struct dentry *dentry, P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry); err = -EPERM; - v9ses = v9fs_inode2v9ses(dentry->d_inode); + v9ses = v9fs_dentry2v9ses(dentry); if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) { generic_fillattr(dentry->d_inode, stat); return 0; @@ -452,7 +452,7 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) p9attr.mtime_nsec = iattr->ia_mtime.tv_nsec; retval = -EPERM; - v9ses = v9fs_inode2v9ses(dentry->d_inode); + v9ses = v9fs_dentry2v9ses(dentry); fid = v9fs_fid_lookup(dentry); if (IS_ERR(fid)) return PTR_ERR(fid); diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 09fd08d1606f..f3eed3383e4f 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -262,7 +262,7 @@ static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf) goto done; } - v9ses = v9fs_inode2v9ses(dentry->d_inode); + v9ses = v9fs_dentry2v9ses(dentry); if (v9fs_proto_dotl(v9ses)) { res = p9_client_statfs(fid, &rs); if (res == 0) { -- cgit v1.2.3