[PATCH -next 1/2] nfs: nfs{,4}_file_flush should consume writeback error

From: ChenXiaoSong
Date: Sat Mar 05 2022 - 07:31:52 EST


filemap_sample_wb_err() will return 0 if nobody has seen the error yet,
then filemap_check_wb_err() will return the unchanged writeback error.

Reproducer:
nfs server | nfs client
--------------------------------|-----------------------------------------------
# No space left on server |
fallocate -l 100G /server/file1 |
| mount -t nfs $nfs_server_ip:/ /mnt
| # Expected error: No space left on device
| dd if=/dev/zero of=/mnt/file2 count=1 ibs=100K
# Release space on server |
rm /server/file1 |
| # Unexpected error: No space left on device
| dd if=/dev/zero of=/mnt/file2 count=1 ibs=100K

Fix this by using file_check_and_advance_wb_err(). If there is an error during
the writeback process, it should be returned when user space calls close() or fsync(),
flush() is called when user space calls close().

Note that fsync() will not be called after close().

Fixes: 67dd23f9e6fb ("nfs: ensure correct writeback errors are returned on close()")
Signed-off-by: ChenXiaoSong <chenxiaosong2@xxxxxxxxxx>
---
fs/nfs/file.c | 4 +---
fs/nfs/nfs4file.c | 4 +---
2 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 76d76acbc594..83d63bce9596 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -141,7 +141,6 @@ static int
nfs_file_flush(struct file *file, fl_owner_t id)
{
struct inode *inode = file_inode(file);
- errseq_t since;

dprintk("NFS: flush(%pD2)\n", file);

@@ -150,9 +149,8 @@ nfs_file_flush(struct file *file, fl_owner_t id)
return 0;

/* Flush writes to the server and return any errors */
- since = filemap_sample_wb_err(file->f_mapping);
nfs_wb_all(inode);
- return filemap_check_wb_err(file->f_mapping, since);
+ return file_check_and_advance_wb_err(file);
}

ssize_t
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index e79ae4cbc395..63a57e5b6db7 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -111,7 +111,6 @@ static int
nfs4_file_flush(struct file *file, fl_owner_t id)
{
struct inode *inode = file_inode(file);
- errseq_t since;

dprintk("NFS: flush(%pD2)\n", file);

@@ -127,9 +126,8 @@ nfs4_file_flush(struct file *file, fl_owner_t id)
return filemap_fdatawrite(file->f_mapping);

/* Flush writes to the server and return any errors */
- since = filemap_sample_wb_err(file->f_mapping);
nfs_wb_all(inode);
- return filemap_check_wb_err(file->f_mapping, since);
+ return file_check_and_advance_wb_err(file);
}

#ifdef CONFIG_NFS_V4_2
--
2.31.1