Commit f0551101 authored by Trond Myklebust's avatar Trond Myklebust Committed by Wang Zhaolong
Browse files

NFS: Don't report ENOSPC write errors twice

mainline inclusion
from mainline-v5.19-rc1
commit e6005436
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IACBGS

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e6005436f6cc9ed13288f936903f0151e5543485



--------------------------------

Any errors reported by the write() system call need to be cleared from
the file descriptor's error tracking. The current call to nfs_wb_all()
causes the error to be reported, but since it doesn't call
file_check_and_advance_wb_err(), we can end up reporting the same error
a second time when the application calls fsync().

Note that since Linux 4.13, the rule is that EIO may be reported for
write(), but it must be reported by a subsequent fsync(), so let's just
drop reporting it in write.

The check for nfs_ctx_key_to_expire() is just a duplicate to the one
already in nfs_write_end(), so let's drop that too.

Reported-by: default avatarChenXiaoSong <chenxiaosong2@huawei.com>
Fixes: ce368536 ("nfs: nfs_file_write() should check for writeback errors")
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
Conflicts:
    fs/nfs/file.c
[nfs_file_write() optimized and eager writes feature added]
Signed-off-by: default avatarWang Zhaolong <wangzhaolong1@huawei.com>
parent 879db184
Loading
Loading
Loading
Loading
+15 −21
Original line number Diff line number Diff line
@@ -597,18 +597,6 @@ static const struct vm_operations_struct nfs_file_vm_ops = {
	.page_mkwrite = nfs_vm_page_mkwrite,
};

static int nfs_need_check_write(struct file *filp, struct inode *inode,
				int error)
{
	struct nfs_open_context *ctx;

	ctx = nfs_file_open_context(filp);
	if (nfs_error_is_fatal_on_server(error) ||
	    nfs_ctx_key_to_expire(ctx, inode))
		return 1;
	return 0;
}

ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
{
	struct file *file = iocb->ki_filp;
@@ -636,7 +624,7 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
	if (iocb->ki_flags & IOCB_APPEND) {
		result = nfs_revalidate_file_size(inode, file);
		if (result)
			goto out;
			return result;
	}
	if (iocb->ki_pos > i_size_read(inode))
		nfs_revalidate_mapping(inode, file->f_mapping);
@@ -655,19 +643,25 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)

	written = result;
	iocb->ki_pos += written;
	nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, written);

	result = generic_write_sync(iocb, written);
	if (result < 0)
		goto out;

		return result;
out:
	/* Return error values */
	error = filemap_check_wb_err(file->f_mapping, since);
	if (nfs_need_check_write(file, inode, error)) {
		int err = nfs_wb_all(inode);
		if (err < 0)
			result = err;
	switch (error) {
	default:
		break;
	case -EDQUOT:
	case -EFBIG:
	case -ENOSPC:
		nfs_wb_all(inode);
		error = file_check_and_advance_wb_err(file);
		if (error < 0)
			result = error;
	}
	nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, written);
out:
	return result;

out_swapfile: