2011-02-17 18:02:19

by Aneesh Kumar K.V

[permalink] [raw]
Subject: [PATCH -V3] Buffered write and writeable mmap support for 9P

Hi All,

This patch series is on top of the last patchset i posted
http://thread.gmane.org/gmane.linux.kernel/1096376

Changes include
a) various fixes for 9p when caching is enabled
b) DirectIO support

-aneesh


2011-02-17 18:02:24

by Aneesh Kumar K.V

[permalink] [raw]
Subject: [PATCH 02/14] fs/9p: Add direct IO support in cached mode

Signed-off-by: Aneesh Kumar K.V <[email protected]>
---
fs/9p/vfs_file.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 114 insertions(+), 4 deletions(-)

diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index a56a33b..5de87e2 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -590,15 +590,125 @@ out_unlock:
return VM_FAULT_NOPAGE;
}

+static ssize_t
+v9fs_direct_read(struct file *filp, char __user *udata, size_t count,
+ loff_t *offsetp)
+{
+ loff_t size, offset;
+ struct inode *inode;
+ struct address_space *mapping;
+
+ offset = *offsetp;
+ mapping = filp->f_mapping;
+ inode = mapping->host;
+ if (!count)
+ return 0;
+ size = i_size_read(inode);
+ if (offset < size)
+ filemap_write_and_wait_range(mapping, offset,
+ offset + count - 1);
+
+ return v9fs_file_read(filp, udata, count, offsetp);
+}
+
+/**
+ * v9fs_cached_file_read - read from a file
+ * @filp: file pointer to read
+ * @udata: user data buffer to read data into
+ * @count: size of buffer
+ * @offset: offset at which to read data
+ *
+ */
+static ssize_t
+v9fs_cached_file_read(struct file *filp, char __user *data, size_t count,
+ loff_t *offset)
+{
+ if (filp->f_flags & O_DIRECT)
+ return v9fs_direct_read(filp, data, count, offset);
+ return do_sync_read(filp, data, count, offset);
+}
+
+static ssize_t
+v9fs_direct_write(struct file *filp, const char __user * data,
+ size_t count, loff_t *offsetp)
+{
+ loff_t offset;
+ ssize_t retval;
+ struct inode *inode;
+ struct address_space *mapping;
+
+ offset = *offsetp;
+ mapping = filp->f_mapping;
+ inode = mapping->host;
+ if (!count)
+ return 0;
+
+ mutex_lock(&inode->i_mutex);
+ retval = filemap_write_and_wait_range(mapping, offset,
+ offset + count - 1);
+ if (retval)
+ goto err_out;
+ /*
+ * After a write we want buffered reads to be sure to go to disk to get
+ * the new data. We invalidate clean cached page from the region we're
+ * about to write. We do this *before* the write so that if we fail
+ * here we fall back to buffered write
+ */
+ if (mapping->nrpages) {
+ pgoff_t pg_start = offset >> PAGE_CACHE_SHIFT;
+ pgoff_t pg_end = (offset + count - 1) >> PAGE_CACHE_SHIFT;
+
+ retval = invalidate_inode_pages2_range(mapping,
+ pg_start, pg_end);
+ /*
+ * If a page can not be invalidated, return 0 to fall back
+ * to buffered write.
+ */
+ if (retval) {
+ if (retval == -EBUSY) {
+ retval = 0;
+ goto buff_write;
+ }
+ goto err_out;
+ }
+ }
+ retval = v9fs_file_write(filp, data, count, offsetp);
+err_out:
+ mutex_unlock(&inode->i_mutex);
+ return retval;
+
+buff_write:
+ return do_sync_write(filp, data, count, offsetp);
+}
+
+/**
+ * v9fs_cached_file_write - write to a file
+ * @filp: file pointer to write
+ * @data: data buffer to write data from
+ * @count: size of buffer
+ * @offset: offset at which to write data
+ *
+ */
+static ssize_t
+v9fs_cached_file_write(struct file *filp, const char __user * data,
+ size_t count, loff_t *offset)
+{
+
+ if (filp->f_flags & O_DIRECT)
+ return v9fs_direct_write(filp, data, count, offset);
+ return do_sync_write(filp, data, count, offset);
+}
+
static const struct vm_operations_struct v9fs_file_vm_ops = {
.fault = filemap_fault,
.page_mkwrite = v9fs_vm_page_mkwrite,
};

+
const struct file_operations v9fs_cached_file_operations = {
.llseek = generic_file_llseek,
- .read = do_sync_read,
- .write = do_sync_write,
+ .read = v9fs_cached_file_read,
+ .write = v9fs_cached_file_write,
.aio_read = generic_file_aio_read,
.aio_write = generic_file_aio_write,
.open = v9fs_file_open,
@@ -610,8 +720,8 @@ const struct file_operations v9fs_cached_file_operations = {

const struct file_operations v9fs_cached_file_operations_dotl = {
.llseek = generic_file_llseek,
- .read = do_sync_read,
- .write = do_sync_write,
+ .read = v9fs_cached_file_read,
+ .write = v9fs_cached_file_write,
.aio_read = generic_file_aio_read,
.aio_write = generic_file_aio_write,
.open = v9fs_file_open,
--
1.7.1

2011-02-17 18:02:35

by Aneesh Kumar K.V

[permalink] [raw]
Subject: [PATCH 06/14] fs/9p: Update link count correctly on mkdir

We need update parent directory link count on success full
mkdir

Signed-off-by: Aneesh Kumar K.V <[email protected]>
---
fs/9p/vfs_inode.c | 3 ++-
fs/9p/vfs_inode_dotl.c | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 8a895bb..d72cabe 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -717,7 +717,8 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (IS_ERR(fid)) {
err = PTR_ERR(fid);
fid = NULL;
- }
+ } else
+ inc_nlink(dir);

if (fid)
p9_client_clunk(fid);
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index aebe532..b0fa56a 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -382,7 +382,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
}
/* Now set the ACL based on the default value */
v9fs_set_create_acl(dentry, dacl, pacl);
-
+ inc_nlink(dir);
error:
if (fid)
p9_client_clunk(fid);
--
1.7.1

2011-02-17 18:02:37

by Aneesh Kumar K.V

[permalink] [raw]
Subject: [PATCH 08/14] fs/9p: Add support for marking inode attribute invalid

With cached mode some of the file system operation result
in updating inode attributes (ctime). Add support for
marking inode attribute invalid in such cases so that
we fetch the updated inode attribute on dentry revalidation.

Signed-off-by: Aneesh Kumar K.V <[email protected]>
---
fs/9p/v9fs.h | 4 ++++
fs/9p/v9fs_vfs.h | 10 ++++++++++
fs/9p/vfs_dentry.c | 34 ++++++++++++++++++++++++++++++++++
fs/9p/vfs_inode.c | 16 ++++++++++++++++
fs/9p/vfs_inode_dotl.c | 15 +++++++++++++++
5 files changed, 79 insertions(+), 0 deletions(-)

diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index aed2a25..64acf72 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -112,6 +112,9 @@ struct v9fs_session_info {
struct p9_fid *root_fid; /* Used for file system sync */
};

+/* cache_validity flags */
+#define V9FS_INO_INVALID_ATTR 0x01
+
struct v9fs_inode {
#ifdef CONFIG_9P_FSCACHE
spinlock_t fscache_lock;
@@ -120,6 +123,7 @@ struct v9fs_inode {
#endif
struct p9_fid *writeback_fid;
struct inode vfs_inode;
+ unsigned int cache_validity;
};

static inline struct v9fs_inode *V9FS_I(const struct inode *inode)
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index db3c00e..3ac13b4 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -70,4 +70,14 @@ int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *);
int v9fs_file_fsync_dotl(struct file *filp, int datasync);
ssize_t v9fs_file_write_internal(struct inode *, struct p9_fid *, char *,
size_t, loff_t *);
+int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode);
+int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode);
+static inline void v9fs_invalidate_inode_attr(struct inode *inode)
+{
+ struct v9fs_inode *v9inode;
+ v9inode = V9FS_I(inode);
+ v9inode->cache_validity |= V9FS_INO_INVALID_ATTR;
+ return;
+}
+
#define P9_LOCK_TIMEOUT (30*HZ)
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c
index a4ae4be..b6a3b9f 100644
--- a/fs/9p/vfs_dentry.c
+++ b/fs/9p/vfs_dentry.c
@@ -100,7 +100,41 @@ static void v9fs_dentry_release(struct dentry *dentry)
}
}

+static int v9fs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
+{
+ struct p9_fid *fid;
+ struct inode *inode;
+ struct v9fs_inode *v9inode;
+
+ if (nd->flags & LOOKUP_RCU)
+ return -ECHILD;
+
+ inode = dentry->d_inode;
+ if (!inode)
+ goto out_valid;
+
+ v9inode = V9FS_I(inode);
+ if (v9inode->cache_validity & V9FS_INO_INVALID_ATTR) {
+ int retval;
+ struct v9fs_session_info *v9ses;
+ fid = v9fs_fid_lookup(dentry);
+ if (IS_ERR(fid))
+ return PTR_ERR(fid);
+
+ v9ses = v9fs_inode2v9ses(inode);
+ if (v9fs_proto_dotl(v9ses))
+ retval = v9fs_refresh_inode_dotl(fid, inode);
+ else
+ retval = v9fs_refresh_inode(fid, inode);
+ if (retval <= 0)
+ return retval;
+ }
+out_valid:
+ return 1;
+}
+
const struct dentry_operations v9fs_cached_dentry_operations = {
+ .d_revalidate = v9fs_lookup_revalidate,
.d_delete = v9fs_cached_dentry_delete,
.d_release = v9fs_dentry_release,
};
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index d72cabe..21d36c7 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -220,6 +220,7 @@ struct inode *v9fs_alloc_inode(struct super_block *sb)
spin_lock_init(&v9inode->fscache_lock);
#endif
v9inode->writeback_fid = NULL;
+ v9inode->cache_validity = 0;
return &v9inode->vfs_inode;
}

@@ -1021,6 +1022,7 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
char tag_name[14];
unsigned int i_nlink;
struct v9fs_session_info *v9ses = sb->s_fs_info;
+ struct v9fs_inode *v9inode = V9FS_I(inode);

inode->i_nlink = 1;

@@ -1080,6 +1082,7 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,

/* not real number of blocks, but 512 byte ones ... */
inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9;
+ v9inode->cache_validity &= ~V9FS_INO_INVALID_ATTR;
}

/**
@@ -1334,6 +1337,19 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
return retval;
}

+int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode)
+{
+ struct p9_wstat *st;
+ st = p9_client_stat(fid);
+ if (IS_ERR(st))
+ return PTR_ERR(st);
+
+ spin_lock(&inode->i_lock);
+ v9fs_stat2inode(st, inode, inode->i_sb);
+ spin_unlock(&inode->i_lock);
+ return 0;
+}
+
static const struct inode_operations v9fs_dir_inode_operations_dotu = {
.create = v9fs_vfs_create,
.lookup = v9fs_vfs_lookup,
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index b0fa56a..1cab2b5 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -495,6 +495,7 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
void
v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
{
+ struct v9fs_inode *v9inode = V9FS_I(inode);

if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) {
inode->i_atime.tv_sec = stat->st_atime_sec;
@@ -553,6 +554,7 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
/* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION
* because the inode structure does not have fields for them.
*/
+ v9inode->cache_validity &= ~V9FS_INO_INVALID_ATTR;
}

static int
@@ -833,6 +835,19 @@ ndset:
return NULL;
}

+int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
+{
+ struct p9_stat_dotl *st;
+ st = p9_client_getattr_dotl(fid, P9_STATS_ALL);
+ if (IS_ERR(st))
+ return PTR_ERR(st);
+
+ spin_lock(&inode->i_lock);
+ v9fs_stat2inode_dotl(st, inode);
+ spin_unlock(&inode->i_lock);
+ return 0;
+}
+
const struct inode_operations v9fs_dir_inode_operations_dotl = {
.create = v9fs_vfs_create_dotl,
.lookup = v9fs_vfs_lookup,
--
1.7.1

2011-02-17 18:02:41

by Aneesh Kumar K.V

[permalink] [raw]
Subject: [PATCH 11/14] fs/9p: Mark directory inode invalid for many directory inode operations

One successfull directory operation we would have changed directory
inode attribute. So mark them invalid

Signed-off-by: Aneesh Kumar K.V <[email protected]>
---
fs/9p/vfs_inode.c | 22 +++++++++++++++-------
fs/9p/vfs_inode_dotl.c | 23 ++++++++++++++---------
2 files changed, 29 insertions(+), 16 deletions(-)

diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index e3597eb..27045d9 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -498,8 +498,8 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
{
int retval;
- struct inode *file_inode;
struct p9_fid *v9fid;
+ struct inode *file_inode;

P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file,
rmdir);
@@ -520,6 +520,7 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
drop_nlink(dir);
} else
drop_nlink(file_inode);
+ v9fs_invalidate_inode_attr(dir);
}
return retval;
}
@@ -642,6 +643,7 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
goto error;
}

+ v9fs_invalidate_inode_attr(dir);
/* 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);
@@ -707,8 +709,8 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
int err;
u32 perm;
- struct v9fs_session_info *v9ses;
struct p9_fid *fid;
+ struct v9fs_session_info *v9ses;

P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
err = 0;
@@ -718,8 +720,10 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (IS_ERR(fid)) {
err = PTR_ERR(fid);
fid = NULL;
- } else
+ } else {
inc_nlink(dir);
+ v9fs_invalidate_inode_attr(dir);
+ }

if (fid)
p9_client_clunk(fid);
@@ -830,6 +834,7 @@ int
v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
+ int retval;
struct inode *old_inode;
struct inode *new_inode;
struct v9fs_session_info *v9ses;
@@ -837,7 +842,6 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct p9_fid *olddirfid;
struct p9_fid *newdirfid;
struct p9_wstat wstat;
- int retval;

P9_DPRINTK(P9_DEBUG_VFS, "\n");
retval = 0;
@@ -895,6 +899,8 @@ clunk_newdir:
inc_nlink(new_dir);
drop_nlink(old_dir);
}
+ v9fs_invalidate_inode_attr(old_dir);
+ v9fs_invalidate_inode_attr(new_dir);
/* successful rename */
d_move(old_dentry, new_dentry);
}
@@ -1222,8 +1228,8 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
int mode, const char *extension)
{
u32 perm;
- struct v9fs_session_info *v9ses;
struct p9_fid *fid;
+ struct v9fs_session_info *v9ses;

v9ses = v9fs_inode2v9ses(dir);
if (!v9fs_proto_dotu(v9ses)) {
@@ -1237,6 +1243,7 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
if (IS_ERR(fid))
return PTR_ERR(fid);

+ v9fs_invalidate_inode_attr(dir);
p9_client_clunk(fid);
return 0;
}
@@ -1273,8 +1280,8 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *dentry)
{
int retval;
- struct p9_fid *oldfid;
char *name;
+ struct p9_fid *oldfid;

P9_DPRINTK(P9_DEBUG_VFS,
" %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
@@ -1293,7 +1300,8 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
sprintf(name, "%d\n", oldfid->fid);
retval = v9fs_vfs_mkspecial(dir, dentry, P9_DMLINK, name);
__putname(name);
-
+ if (!retval)
+ v9fs_invalidate_inode_attr(dir);
clunk_fid:
p9_client_clunk(oldfid);
return retval;
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index 81b2b4f..167959f 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -220,6 +220,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
err);
goto error;
}
+ v9fs_invalidate_inode_attr(dir);

/* instantiate inode and assign the unopened fid to the dentry */
fid = p9_client_walk(dfid, 1, &name, 1);
@@ -383,6 +384,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
/* Now set the ACL based on the default value */
v9fs_set_create_acl(dentry, dacl, pacl);
inc_nlink(dir);
+ v9fs_invalidate_inode_attr(dir);
error:
if (fid)
p9_client_clunk(fid);
@@ -567,14 +569,14 @@ static int
v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
const char *symname)
{
- struct v9fs_session_info *v9ses;
- struct p9_fid *dfid;
- struct p9_fid *fid = NULL;
- struct inode *inode;
- struct p9_qid qid;
- char *name;
int err;
gid_t gid;
+ char *name;
+ struct p9_qid qid;
+ struct inode *inode;
+ struct p9_fid *dfid;
+ struct p9_fid *fid = NULL;
+ struct v9fs_session_info *v9ses;

name = (char *) dentry->d_name.name;
P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_symlink_dotl : %lu,%s,%s\n",
@@ -598,6 +600,7 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
goto error;
}

+ v9fs_invalidate_inode_attr(dir);
if (v9ses->cache) {
/* Now walk from the parent so we can get an unopened fid. */
fid = p9_client_walk(dfid, 1, &name, 1);
@@ -652,10 +655,10 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
struct dentry *dentry)
{
int err;
- struct p9_fid *dfid, *oldfid;
char *name;
- struct v9fs_session_info *v9ses;
struct dentry *dir_dentry;
+ struct p9_fid *dfid, *oldfid;
+ struct v9fs_session_info *v9ses;

P9_DPRINTK(P9_DEBUG_VFS, "dir ino: %lu, old_name: %s, new_name: %s\n",
dir->i_ino, old_dentry->d_name.name,
@@ -680,6 +683,7 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
return err;
}

+ v9fs_invalidate_inode_attr(dir);
if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
/* Get the latest stat info from server. */
struct p9_fid *fid;
@@ -716,12 +720,12 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode,
dev_t rdev)
{
int err;
+ gid_t gid;
char *name;
mode_t mode;
struct v9fs_session_info *v9ses;
struct p9_fid *fid = NULL, *dfid = NULL;
struct inode *inode;
- gid_t gid;
struct p9_qid qid;
struct dentry *dir_dentry;
struct posix_acl *dacl = NULL, *pacl = NULL;
@@ -758,6 +762,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode,
if (err < 0)
goto error;

+ v9fs_invalidate_inode_attr(dir);
/* instantiate inode and assign the unopened fid to the dentry */
if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
fid = p9_client_walk(dfid, 1, &name, 1);
--
1.7.1

2011-02-17 18:02:47

by Aneesh Kumar K.V

[permalink] [raw]
Subject: [PATCH 13/14] fs/9p: Workaround vfs rename rehash bug

This is similar to what ceph, ocfs2 and nfs does
http://kerneltrap.org/mailarchive/linux-fsdevel/2008/4/18/1498534

May be we should get vfs fixed

Signed-off-by: Aneesh Kumar K.V <[email protected]>
---
fs/9p/vfs_inode.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index eaa089c..52dacbb 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -895,6 +895,11 @@ clunk_newdir:
clear_nlink(new_inode);
else
drop_nlink(new_inode);
+ /*
+ * Work around vfs rename rehash bug with
+ * FS_RENAME_DOES_D_MOVE
+ */
+ v9fs_invalidate_inode_attr(new_inode);
}
if (S_ISDIR(old_inode->i_mode)) {
if (!new_inode)
--
1.7.1

2011-02-17 18:02:56

by Aneesh Kumar K.V

[permalink] [raw]
Subject: [PATCH 14/14] fs/9p: Prevent multiple inclusion of same header

Add necessary #ifndef #endif blocks to avoid mulitple inclusion of same headers

Signed-off-by: Aneesh Kumar K.V <[email protected]>
---
fs/9p/fid.h | 4 +++-
fs/9p/v9fs.h | 4 ++++
fs/9p/v9fs_vfs.h | 6 ++++--
3 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/fs/9p/fid.h b/fs/9p/fid.h
index c3bbd6a..f610510 100644
--- a/fs/9p/fid.h
+++ b/fs/9p/fid.h
@@ -19,7 +19,8 @@
* Boston, MA 02111-1301 USA
*
*/
-
+#ifndef FS_9P_FID_H
+#define FS_9P_FID_H
#include <linux/list.h>

/**
@@ -45,3 +46,4 @@ struct v9fs_dentry {
struct p9_fid *v9fs_fid_lookup(struct dentry *dentry);
struct p9_fid *v9fs_fid_clone(struct dentry *dentry);
int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid);
+#endif
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index 64acf72..92fb61b 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -20,6 +20,9 @@
* Boston, MA 02111-1301 USA
*
*/
+#ifndef FS_9P_V9FS_H
+#define FS_9P_V9FS_H
+
#include <linux/backing-dev.h>

/**
@@ -193,3 +196,4 @@ v9fs_get_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
else
return v9fs_inode_from_fid(v9ses, fid, sb);
}
+#endif
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index 3ac13b4..e719282 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -20,6 +20,8 @@
* Boston, MA 02111-1301 USA
*
*/
+#ifndef FS_9P_V9FS_VFS_H
+#define FS_9P_V9FS_VFS_H

/* plan9 semantics are that created files are implicitly opened.
* But linux semantics are that you call create, then open.
@@ -36,6 +38,7 @@
* unlink calls remove, which is an implicit clunk. So we have to track
* that kind of thing so that we don't try to clunk a dead fid.
*/
+#define P9_LOCK_TIMEOUT (30*HZ)

extern struct file_system_type v9fs_fs_type;
extern const struct address_space_operations v9fs_addr_operations;
@@ -79,5 +82,4 @@ static inline void v9fs_invalidate_inode_attr(struct inode *inode)
v9inode->cache_validity |= V9FS_INO_INVALID_ATTR;
return;
}
-
-#define P9_LOCK_TIMEOUT (30*HZ)
+#endif
--
1.7.1

2011-02-17 18:03:30

by Aneesh Kumar K.V

[permalink] [raw]
Subject: [PATCH 12/14] fs/9p: mark inode attribute invalid on rename and unlink

Both rename and unlink result in update of inode attribute.
So mark the cached copy invalid

Signed-off-by: Aneesh Kumar K.V <[email protected]>
---
fs/9p/vfs_inode.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 27045d9..eaa089c 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -520,7 +520,9 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
drop_nlink(dir);
} else
drop_nlink(file_inode);
+
v9fs_invalidate_inode_attr(dir);
+ v9fs_invalidate_inode_attr(file_inode);
}
return retval;
}
@@ -901,6 +903,7 @@ clunk_newdir:
}
v9fs_invalidate_inode_attr(old_dir);
v9fs_invalidate_inode_attr(new_dir);
+ v9fs_invalidate_inode_attr(old_inode);
/* successful rename */
d_move(old_dentry, new_dentry);
}
--
1.7.1

2011-02-17 18:03:55

by Aneesh Kumar K.V

[permalink] [raw]
Subject: [PATCH 10/14] fs/9p: Add . and .. dentry revalidation flag

We need to revalidate . and .. entries also

Signed-off-by: Aneesh Kumar K.V <[email protected]>
---
fs/9p/vfs_super.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 6e04cf3..ffc8090 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -332,5 +332,5 @@ struct file_system_type v9fs_fs_type = {
.mount = v9fs_mount,
.kill_sb = v9fs_kill_super,
.owner = THIS_MODULE,
- .fs_flags = FS_RENAME_DOES_D_MOVE,
+ .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT,
};
--
1.7.1

2011-02-17 18:02:32

by Aneesh Kumar K.V

[permalink] [raw]
Subject: [PATCH 04/14] fs/9p: Drop the directory link count correctly

On unlink we should clear the director link count

Signed-off-by: Aneesh Kumar K.V <[email protected]>
---
fs/9p/vfs_inode.c | 13 +++++++++++--
1 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index b36711b..ae4fd90 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -509,8 +509,17 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
return PTR_ERR(v9fid);

retval = p9_client_remove(v9fid);
- if (!retval)
- drop_nlink(file_inode);
+ if (!retval) {
+ /*
+ * directories on unlink should have zero
+ * link count
+ */
+ if (rmdir) {
+ clear_nlink(file_inode);
+ drop_nlink(dir);
+ } else
+ drop_nlink(file_inode);
+ }
return retval;
}

--
1.7.1

2011-02-17 18:04:18

by Aneesh Kumar K.V

[permalink] [raw]
Subject: [PATCH 09/14] fs/9p: Mark inode attr invalid on setattr

Signed-off-by: Aneesh Kumar K.V <[email protected]>
---
fs/9p/vfs_inode.c | 9 ++++++++-
fs/9p/vfs_inode_dotl.c | 8 +++++++-
2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 21d36c7..e3597eb 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -958,9 +958,10 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
{
int retval;
- struct v9fs_session_info *v9ses;
struct p9_fid *fid;
struct p9_wstat wstat;
+ struct v9fs_session_info *v9ses;
+

P9_DPRINTK(P9_DEBUG_VFS, "\n");
retval = -EPERM;
@@ -993,6 +994,12 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
retval = p9_client_wstat(fid, &wstat);
if (retval < 0)
return retval;
+ /*
+ * Changing some of the attribute can result in
+ * implicit update of other attributes. So mark
+ * all of them invalid
+ */
+ v9fs_invalidate_inode_attr(dentry->d_inode);

if ((iattr->ia_valid & ATTR_SIZE) &&
iattr->ia_size != i_size_read(dentry->d_inode)) {
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index 1cab2b5..81b2b4f 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -436,9 +436,9 @@ v9fs_vfs_getattr_dotl(struct vfsmount *mnt, struct dentry *dentry,
int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
{
int retval;
- struct v9fs_session_info *v9ses;
struct p9_fid *fid;
struct p9_iattr_dotl p9attr;
+ struct v9fs_session_info *v9ses;

P9_DPRINTK(P9_DEBUG_VFS, "\n");

@@ -465,6 +465,12 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
retval = p9_client_setattr(fid, &p9attr);
if (retval < 0)
return retval;
+ /*
+ * Changing some of the attribute can result in
+ * implicit update of other attributes. So mark
+ * all of them invalid
+ */
+ v9fs_invalidate_inode_attr(dentry->d_inode);

if ((iattr->ia_valid & ATTR_SIZE) &&
iattr->ia_size != i_size_read(dentry->d_inode)) {
--
1.7.1

2011-02-17 18:04:41

by Aneesh Kumar K.V

[permalink] [raw]
Subject: [PATCH 07/14] fs/9p: Initialize root inode number for dotl

Signed-off-by: Aneesh Kumar K.V <[email protected]>
---
fs/9p/vfs_super.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 0dc9e4b..6e04cf3 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -168,7 +168,7 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
retval = PTR_ERR(st);
goto release_sb;
}
-
+ root->d_inode->i_ino = v9fs_qid2ino(&st->qid);
v9fs_stat2inode_dotl(st, root->d_inode);
kfree(st);
} else {
--
1.7.1

2011-02-17 18:04:55

by Aneesh Kumar K.V

[permalink] [raw]
Subject: [PATCH 05/14] fs/9p: Update link count correctly during rename

Signed-off-by: Aneesh Kumar K.V <[email protected]>
---
fs/9p/vfs_inode.c | 16 +++++++++++++++-
1 files changed, 15 insertions(+), 1 deletions(-)

diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index ae4fd90..8a895bb 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -829,6 +829,7 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
struct inode *old_inode;
+ struct inode *new_inode;
struct v9fs_session_info *v9ses;
struct p9_fid *oldfid;
struct p9_fid *olddirfid;
@@ -839,6 +840,7 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
P9_DPRINTK(P9_DEBUG_VFS, "\n");
retval = 0;
old_inode = old_dentry->d_inode;
+ new_inode = new_dentry->d_inode;
v9ses = v9fs_inode2v9ses(old_inode);
oldfid = v9fs_fid_lookup(old_dentry);
if (IS_ERR(oldfid))
@@ -879,9 +881,21 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
retval = p9_client_wstat(oldfid, &wstat);

clunk_newdir:
- if (!retval)
+ if (!retval) {
+ if (new_inode) {
+ if (S_ISDIR(new_inode->i_mode))
+ clear_nlink(new_inode);
+ else
+ drop_nlink(new_inode);
+ }
+ if (S_ISDIR(old_inode->i_mode)) {
+ if (!new_inode)
+ inc_nlink(new_dir);
+ drop_nlink(old_dir);
+ }
/* successful rename */
d_move(old_dentry, new_dentry);
+ }
up_write(&v9ses->rename_sem);
p9_client_clunk(newdirfid);

--
1.7.1

2011-02-17 18:05:15

by Aneesh Kumar K.V

[permalink] [raw]
Subject: [PATCH 03/14] fs/9p: Add drop_inode 9p callback

We want to immediately drop the inode in non cached mode

Signed-off-by: Aneesh Kumar K.V <[email protected]>
---
fs/9p/vfs_super.c | 15 +++++++++++++++
1 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index cfb8e97..0dc9e4b 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -293,6 +293,20 @@ static int v9fs_sync_fs(struct super_block *sb, int wait)
return p9_client_sync_fs(v9ses->root_fid);
}

+int v9fs_drop_inode(struct inode *inode)
+{
+ struct v9fs_session_info *v9ses;
+ v9ses = v9fs_inode2v9ses(inode);
+ if (v9ses->cache)
+ return !inode->i_nlink || inode_unhashed(inode);
+ /*
+ * in case of non cached mode always drop the
+ * the inode because we want the inode attribute
+ * to always match that on the server.
+ */
+ return 1;
+}
+
static const struct super_operations v9fs_super_ops = {
.alloc_inode = v9fs_alloc_inode,
.destroy_inode = v9fs_destroy_inode,
@@ -307,6 +321,7 @@ static const struct super_operations v9fs_super_ops_dotl = {
.destroy_inode = v9fs_destroy_inode,
.sync_fs = v9fs_sync_fs,
.statfs = v9fs_statfs,
+ .drop_inode = v9fs_drop_inode,
.evict_inode = v9fs_evict_inode,
.show_options = generic_show_options,
.umount_begin = v9fs_umount_begin,
--
1.7.1

2011-02-17 18:05:37

by Aneesh Kumar K.V

[permalink] [raw]
Subject: [PATCH 01/14] fs/9p: Fix inode i_size update in file_write

Only update inode i_size when we write towards end of file.

Signed-off-by: Aneesh Kumar K.V <[email protected]>
---
fs/9p/vfs_file.c | 9 ++++++---
1 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index e9cd277..a56a33b 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -451,6 +451,7 @@ v9fs_file_write_internal(struct inode *inode, struct p9_fid *fid, char *data,
size_t count, loff_t *offset)
{
int n;
+ loff_t i_size;
size_t total = 0;
struct p9_client *clnt;
loff_t origin = *offset;
@@ -475,10 +476,12 @@ v9fs_file_write_internal(struct inode *inode, struct p9_fid *fid, char *data,
invalidate_inode_pages2_range(inode->i_mapping,
pg_start, pg_end);
*offset += total;
- i_size_write(inode, i_size_read(inode) + total);
- inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9;
+ i_size = i_size_read(inode);
+ if (*offset > i_size) {
+ inode_add_bytes(inode, *offset - i_size);
+ i_size_write(inode, *offset);
+ }
}
-
if (n < 0)
return n;

--
1.7.1