NFS: Don't report ENOSPC write errors twice
[ Upstream commite6005436f6
] 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:ce368536dd
("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> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Родитель
0d548c0c70
Коммит
3a2d62ec41
|
@ -591,18 +591,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;
|
||||
|
@ -630,7 +618,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);
|
||||
|
@ -649,6 +637,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,
|
||||
|
@ -666,17 +655,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:
|
||||
|
|
Загрузка…
Ссылка в новой задаче