Skip to content

Commit

Permalink
NFS: Don't report ENOSPC write errors twice
Browse files Browse the repository at this point in the history
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: ChenXiaoSong <chenxiaosong2@huawei.com>
Fixes: ce36853 ("nfs: nfs_file_write() should check for writeback errors")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
  • Loading branch information
Trond Myklebust authored and Anna Schumaker committed May 17, 2022
1 parent 9641d9b commit e600543
Showing 1 changed file with 14 additions and 20 deletions.
34 changes: 14 additions & 20 deletions fs/nfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -598,18 +598,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;
Expand Down Expand Up @@ -637,7 +625,7 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
if (iocb->ki_flags & IOCB_APPEND || iocb->ki_pos > i_size_read(inode)) {
result = nfs_revalidate_file_size(inode, file);
if (result)
goto out;
return result;
}

nfs_clear_invalid_mapping(file->f_mapping);
Expand All @@ -656,6 +644,7 @@ 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);

if (mntflags & NFS_MOUNT_WRITE_EAGER) {
result = filemap_fdatawrite_range(file->f_mapping,
Expand All @@ -673,17 +662,22 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
}
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:
Expand Down

0 comments on commit e600543

Please sign in to comment.