aeab634
From: Trond Myklebust <Trond.Myklebust@netapp.com>
aeab634
aeab634
Currently, we will correctly optimise away a truncate that doesn't
aeab634
change the file size. However, in the case of open(O_TRUNC), we
aeab634
also want to optimise away the time changes.
aeab634
aeab634
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
aeab634
---
aeab634
 fs/nfs/dir.c      |   25 +++++++++++++++++++------
aeab634
 fs/nfs/inode.c    |    4 ++--
aeab634
 fs/nfs/nfs4proc.c |   10 +++++++---
aeab634
 3 files changed, 28 insertions(+), 11 deletions(-)
aeab634
aeab634
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
aeab634
index fd9a872..bb132a8 100644
aeab634
--- a/fs/nfs/dir.c
aeab634
+++ b/fs/nfs/dir.c
aeab634
@@ -1429,6 +1429,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
aeab634
 	}
aeab634
 
aeab634
 	open_flags = nd->intent.open.flags;
aeab634
+	attr.ia_valid = 0;
aeab634
 
aeab634
 	ctx = create_nfs_open_context(dentry, open_flags);
aeab634
 	res = ERR_CAST(ctx);
aeab634
@@ -1437,11 +1438,14 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
aeab634
 
aeab634
 	if (nd->flags & LOOKUP_CREATE) {
aeab634
 		attr.ia_mode = nd->intent.open.create_mode;
aeab634
-		attr.ia_valid = ATTR_MODE;
aeab634
+		attr.ia_valid |= ATTR_MODE;
aeab634
 		attr.ia_mode &= ~current_umask();
aeab634
-	} else {
aeab634
+	} else
aeab634
 		open_flags &= ~(O_EXCL | O_CREAT);
aeab634
-		attr.ia_valid = 0;
aeab634
+
aeab634
+	if (open_flags & O_TRUNC) {
aeab634
+		attr.ia_valid |= ATTR_SIZE;
aeab634
+		attr.ia_size = 0;
aeab634
 	}
aeab634
 
aeab634
 	/* Open the file on the server */
aeab634
@@ -1495,6 +1499,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
aeab634
 	struct inode *inode;
aeab634
 	struct inode *dir;
aeab634
 	struct nfs_open_context *ctx;
aeab634
+	struct iattr attr;
aeab634
 	int openflags, ret = 0;
aeab634
 
aeab634
 	if (nd->flags & LOOKUP_RCU)
aeab634
@@ -1523,19 +1528,27 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
aeab634
 	/* We cannot do exclusive creation on a positive dentry */
aeab634
 	if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
aeab634
 		goto no_open_dput;
aeab634
-	/* We can't create new files, or truncate existing ones here */
aeab634
-	openflags &= ~(O_CREAT|O_EXCL|O_TRUNC);
aeab634
+	/* We can't create new files here */
aeab634
+	openflags &= ~(O_CREAT|O_EXCL);
aeab634
 
aeab634
 	ctx = create_nfs_open_context(dentry, openflags);
aeab634
 	ret = PTR_ERR(ctx);
aeab634
 	if (IS_ERR(ctx))
aeab634
 		goto out;
aeab634
+
aeab634
+	attr.ia_valid = 0;
aeab634
+	if (openflags & O_TRUNC) {
aeab634
+		attr.ia_valid |= ATTR_SIZE;
aeab634
+		attr.ia_size = 0;
aeab634
+		nfs_wb_all(inode);
aeab634
+	}
aeab634
+
aeab634
 	/*
aeab634
 	 * Note: we're not holding inode->i_mutex and so may be racing with
aeab634
 	 * operations that change the directory. We therefore save the
aeab634
 	 * change attribute *before* we do the RPC call.
aeab634
 	 */
aeab634
-	inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, NULL);
aeab634
+	inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr);
aeab634
 	if (IS_ERR(inode)) {
aeab634
 		ret = PTR_ERR(inode);
aeab634
 		switch (ret) {
aeab634
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
aeab634
index f649fba..57d0abb 100644
aeab634
--- a/fs/nfs/inode.c
aeab634
+++ b/fs/nfs/inode.c
aeab634
@@ -401,7 +401,7 @@ out_no_inode:
aeab634
 	goto out;
aeab634
 }
aeab634
 
aeab634
-#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE)
aeab634
+#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE|ATTR_OPEN)
aeab634
 
aeab634
 int
aeab634
 nfs_setattr(struct dentry *dentry, struct iattr *attr)
aeab634
@@ -423,7 +423,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
aeab634
 
aeab634
 	/* Optimization: if the end result is no change, don't RPC */
aeab634
 	attr->ia_valid &= NFS_VALID_ATTRS;
aeab634
-	if ((attr->ia_valid & ~ATTR_FILE) == 0)
aeab634
+	if ((attr->ia_valid & ~(ATTR_FILE|ATTR_OPEN)) == 0)
aeab634
 		return 0;
aeab634
 
aeab634
 	/* Write all dirty data */
aeab634
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
aeab634
index 1515e45..c4c6b48 100644
aeab634
--- a/fs/nfs/nfs4proc.c
aeab634
+++ b/fs/nfs/nfs4proc.c
aeab634
@@ -833,7 +833,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
aeab634
 	p->o_arg.bitmask = server->attr_bitmask;
aeab634
 	p->o_arg.dir_bitmask = server->cache_consistency_bitmask;
aeab634
 	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
aeab634
-	if (flags & O_CREAT) {
aeab634
+	if (attrs != NULL && attrs->ia_valid != 0) {
aeab634
 		u32 *s;
aeab634
 
aeab634
 		p->o_arg.u.attrs = &p->attrs;
aeab634
@@ -890,7 +890,7 @@ static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode
aeab634
 {
aeab634
 	int ret = 0;
aeab634
 
aeab634
-	if (open_mode & O_EXCL)
aeab634
+	if (open_mode & (O_EXCL|O_TRUNC))
aeab634
 		goto out;
aeab634
 	switch (mode & (FMODE_READ|FMODE_WRITE)) {
aeab634
 		case FMODE_READ:
aeab634
@@ -1038,7 +1038,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
aeab634
 	struct nfs4_state *state = opendata->state;
aeab634
 	struct nfs_inode *nfsi = NFS_I(state->inode);
aeab634
 	struct nfs_delegation *delegation;
aeab634
-	int open_mode = opendata->o_arg.open_flags & O_EXCL;
aeab634
+	int open_mode = opendata->o_arg.open_flags & (O_EXCL|O_TRUNC);
aeab634
 	fmode_t fmode = opendata->o_arg.fmode;
aeab634
 	nfs4_stateid stateid;
aeab634
 	int ret = -EAGAIN;
aeab634
@@ -2439,6 +2439,10 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
aeab634
 		}
aeab634
 	}
aeab634
 
aeab634
+	/* Deal with open(O_TRUNC) */
aeab634
+	if (sattr->ia_valid & ATTR_OPEN)
aeab634
+		sattr->ia_valid &= ~(ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
aeab634
+
aeab634
 	status = nfs4_do_setattr(inode, cred, fattr, sattr, state);
aeab634
 	if (status == 0)
aeab634
 		nfs_setattr_update_inode(inode, sattr);
aeab634
-- 
aeab634
1.7.7.6
aeab634
aeab634
_______________________________________________
aeab634
kernel mailing list
aeab634
kernel@lists.fedoraproject.org
aeab634
https://admin.fedoraproject.org/mailman/listinfo/kernel