Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 536e43d1 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

NFS: Optimise away unnecessary setattrs for open(O_TRUNC);



Currently, we will correctly optimise away a truncate that doesn't
change the file size. However, in the case of open(O_TRUNC), we
also want to optimise away the time changes.

Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 48c22eb2
Loading
Loading
Loading
Loading
+19 −6
Original line number Diff line number Diff line
@@ -1429,6 +1429,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
	}

	open_flags = nd->intent.open.flags;
	attr.ia_valid = 0;

	ctx = create_nfs_open_context(dentry, open_flags);
	res = ERR_CAST(ctx);
@@ -1437,11 +1438,14 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry

	if (nd->flags & LOOKUP_CREATE) {
		attr.ia_mode = nd->intent.open.create_mode;
		attr.ia_valid = ATTR_MODE;
		attr.ia_valid |= ATTR_MODE;
		attr.ia_mode &= ~current_umask();
	} else {
	} else
		open_flags &= ~(O_EXCL | O_CREAT);
		attr.ia_valid = 0;

	if (open_flags & O_TRUNC) {
		attr.ia_valid |= ATTR_SIZE;
		attr.ia_size = 0;
	}

	/* Open the file on the server */
@@ -1495,6 +1499,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
	struct inode *inode;
	struct inode *dir;
	struct nfs_open_context *ctx;
	struct iattr attr;
	int openflags, ret = 0;

	if (nd->flags & LOOKUP_RCU)
@@ -1523,19 +1528,27 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
	/* We cannot do exclusive creation on a positive dentry */
	if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
		goto no_open_dput;
	/* We can't create new files, or truncate existing ones here */
	openflags &= ~(O_CREAT|O_EXCL|O_TRUNC);
	/* We can't create new files here */
	openflags &= ~(O_CREAT|O_EXCL);

	ctx = create_nfs_open_context(dentry, openflags);
	ret = PTR_ERR(ctx);
	if (IS_ERR(ctx))
		goto out;

	attr.ia_valid = 0;
	if (openflags & O_TRUNC) {
		attr.ia_valid |= ATTR_SIZE;
		attr.ia_size = 0;
		nfs_wb_all(inode);
	}

	/*
	 * Note: we're not holding inode->i_mutex and so may be racing with
	 * operations that change the directory. We therefore save the
	 * change attribute *before* we do the RPC call.
	 */
	inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, NULL);
	inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr);
	if (IS_ERR(inode)) {
		ret = PTR_ERR(inode);
		switch (ret) {
+2 −2
Original line number Diff line number Diff line
@@ -402,7 +402,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
	goto out;
}

#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE)
#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)

int
nfs_setattr(struct dentry *dentry, struct iattr *attr)
@@ -424,7 +424,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)

	/* Optimization: if the end result is no change, don't RPC */
	attr->ia_valid &= NFS_VALID_ATTRS;
	if ((attr->ia_valid & ~ATTR_FILE) == 0)
	if ((attr->ia_valid & ~(ATTR_FILE|ATTR_OPEN)) == 0)
		return 0;

	/* Write all dirty data */
+7 −3
Original line number Diff line number Diff line
@@ -828,7 +828,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
	p->o_arg.bitmask = server->attr_bitmask;
	p->o_arg.dir_bitmask = server->cache_consistency_bitmask;
	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
	if (flags & O_CREAT) {
	if (attrs != NULL && attrs->ia_valid != 0) {
		u32 *s;

		p->o_arg.u.attrs = &p->attrs;
@@ -885,7 +885,7 @@ static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode
{
	int ret = 0;

	if (open_mode & O_EXCL)
	if (open_mode & (O_EXCL|O_TRUNC))
		goto out;
	switch (mode & (FMODE_READ|FMODE_WRITE)) {
		case FMODE_READ:
@@ -1033,7 +1033,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
	struct nfs4_state *state = opendata->state;
	struct nfs_inode *nfsi = NFS_I(state->inode);
	struct nfs_delegation *delegation;
	int open_mode = opendata->o_arg.open_flags & O_EXCL;
	int open_mode = opendata->o_arg.open_flags & (O_EXCL|O_TRUNC);
	fmode_t fmode = opendata->o_arg.fmode;
	nfs4_stateid stateid;
	int ret = -EAGAIN;
@@ -2431,6 +2431,10 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
		}
	}

	/* Deal with open(O_TRUNC) */
	if (sattr->ia_valid & ATTR_OPEN)
		sattr->ia_valid &= ~(ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);

	status = nfs4_do_setattr(inode, cred, fattr, sattr, state);
	if (status == 0)
		nfs_setattr_update_inode(inode, sattr);