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

Commit af7fa165 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

NFS: Fix up the fsync code



Christoph points out that the VFS will always flush out data before calling
nfs_fsync(), so we can dispense with a full call to nfs_wb_all(), and
replace that with a simpler call to nfs_commit_inode().

Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 77041ed9
Loading
Loading
Loading
Loading
+21 −30
Original line number Original line Diff line number Diff line
@@ -201,38 +201,12 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
	return loff;
	return loff;
}
}


/*
 * Helper for nfs_file_flush() and nfs_file_fsync()
 *
 * Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to
 * disk, but it retrieves and clears ctx->error after synching, despite
 * the two being set at the same time in nfs_context_set_write_error().
 * This is because the former is used to notify the _next_ call to
 * nfs_file_write() that a write error occured, and hence cause it to
 * fall back to doing a synchronous write.
 */
static int nfs_do_fsync(struct nfs_open_context *ctx, struct inode *inode)
{
	int have_error, status;
	int ret = 0;

	have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
	status = nfs_wb_all(inode);
	have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
	if (have_error)
		ret = xchg(&ctx->error, 0);
	if (!ret)
		ret = status;
	return ret;
}

/*
/*
 * Flush all dirty pages, and check for write errors.
 * Flush all dirty pages, and check for write errors.
 */
 */
static int
static int
nfs_file_flush(struct file *file, fl_owner_t id)
nfs_file_flush(struct file *file, fl_owner_t id)
{
{
	struct nfs_open_context *ctx = nfs_file_open_context(file);
	struct dentry	*dentry = file->f_path.dentry;
	struct dentry	*dentry = file->f_path.dentry;
	struct inode	*inode = dentry->d_inode;
	struct inode	*inode = dentry->d_inode;


@@ -245,7 +219,7 @@ nfs_file_flush(struct file *file, fl_owner_t id)
		return 0;
		return 0;


	/* Flush writes to the server and return any errors */
	/* Flush writes to the server and return any errors */
	return nfs_do_fsync(ctx, inode);
	return vfs_fsync(file, 0);
}
}


static ssize_t
static ssize_t
@@ -320,6 +294,13 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
 * Flush any dirty pages for this process, and check for write errors.
 * Flush any dirty pages for this process, and check for write errors.
 * The return status from this call provides a reliable indication of
 * The return status from this call provides a reliable indication of
 * whether any write errors occurred for this process.
 * whether any write errors occurred for this process.
 *
 * Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to
 * disk, but it retrieves and clears ctx->error after synching, despite
 * the two being set at the same time in nfs_context_set_write_error().
 * This is because the former is used to notify the _next_ call to
 * nfs_file_write() that a write error occured, and hence cause it to
 * fall back to doing a synchronous write.
 */
 */
static int
static int
nfs_file_fsync(struct file *file, int datasync)
nfs_file_fsync(struct file *file, int datasync)
@@ -327,13 +308,23 @@ nfs_file_fsync(struct file *file, int datasync)
	struct dentry *dentry = file->f_path.dentry;
	struct dentry *dentry = file->f_path.dentry;
	struct nfs_open_context *ctx = nfs_file_open_context(file);
	struct nfs_open_context *ctx = nfs_file_open_context(file);
	struct inode *inode = dentry->d_inode;
	struct inode *inode = dentry->d_inode;
	int have_error, status;
	int ret = 0;



	dprintk("NFS: fsync file(%s/%s) datasync %d\n",
	dprintk("NFS: fsync file(%s/%s) datasync %d\n",
			dentry->d_parent->d_name.name, dentry->d_name.name,
			dentry->d_parent->d_name.name, dentry->d_name.name,
			datasync);
			datasync);


	nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
	nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
	return nfs_do_fsync(ctx, inode);
	have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
	status = nfs_commit_inode(inode, FLUSH_SYNC);
	have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
	if (have_error)
		ret = xchg(&ctx->error, 0);
	if (!ret)
		ret = status;
	return ret;
}
}


/*
/*
@@ -639,7 +630,7 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,


	/* Return error values for O_DSYNC and IS_SYNC() */
	/* Return error values for O_DSYNC and IS_SYNC() */
	if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) {
	if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) {
		int err = nfs_do_fsync(nfs_file_open_context(iocb->ki_filp), inode);
		int err = vfs_fsync(iocb->ki_filp, 0);
		if (err < 0)
		if (err < 0)
			result = err;
			result = err;
	}
	}
@@ -675,7 +666,7 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe,
		written = ret;
		written = ret;


	if (ret >= 0 && nfs_need_sync_write(filp, inode)) {
	if (ret >= 0 && nfs_need_sync_write(filp, inode)) {
		int err = nfs_do_fsync(nfs_file_open_context(filp), inode);
		int err = vfs_fsync(filp, 0);
		if (err < 0)
		if (err < 0)
			ret = err;
			ret = err;
	}
	}