Skip to content

Commit 67f4b5d

Browse files
author
Trond Myklebust
committed
NFS: Fix another fsync() issue after a server reboot
Currently, when the writeback code detects a server reboot, it redirties any pages that were not committed to disk, and it sets the flag NFS_CONTEXT_RESEND_WRITES in the nfs_open_context of the file descriptor that dirtied the file. While this allows the file descriptor in question to redrive its own writes, it violates the fsync() requirement that we should be synchronising all writes to disk. While the problem is infrequent, we do see corner cases where an untimely server reboot causes the fsync() call to abandon its attempt to sync data to disk and causing data corruption issues due to missed error conditions or similar. In order to tighted up the client's ability to deal with this situation without introducing livelocks, add a counter that records the number of times pages are redirtied due to a server reboot-like condition, and use that in fsync() to redrive the sync to disk. Fixes: 2197e9b ("NFS: Fix up fsync() when the server rebooted") Cc: [email protected] Signed-off-by: Trond Myklebust <[email protected]>
1 parent 2067231 commit 67f4b5d

File tree

4 files changed

+12
-11
lines changed

4 files changed

+12
-11
lines changed

fs/nfs/file.c

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,10 @@ nfs_file_fsync_commit(struct file *file, int datasync)
221221
int
222222
nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
223223
{
224-
struct nfs_open_context *ctx = nfs_file_open_context(file);
225224
struct inode *inode = file_inode(file);
225+
struct nfs_inode *nfsi = NFS_I(inode);
226+
long save_nredirtied = atomic_long_read(&nfsi->redirtied_pages);
227+
long nredirtied;
226228
int ret;
227229

228230
trace_nfs_fsync_enter(inode);
@@ -237,15 +239,10 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
237239
ret = pnfs_sync_inode(inode, !!datasync);
238240
if (ret != 0)
239241
break;
240-
if (!test_and_clear_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags))
242+
nredirtied = atomic_long_read(&nfsi->redirtied_pages);
243+
if (nredirtied == save_nredirtied)
241244
break;
242-
/*
243-
* If nfs_file_fsync_commit detected a server reboot, then
244-
* resend all dirty pages that might have been covered by
245-
* the NFS_CONTEXT_RESEND_WRITES flag
246-
*/
247-
start = 0;
248-
end = LLONG_MAX;
245+
save_nredirtied = nredirtied;
249246
}
250247

251248
trace_nfs_fsync_exit(inode, ret);

fs/nfs/inode.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ nfs_ilookup(struct super_block *sb, struct nfs_fattr *fattr, struct nfs_fh *fh)
426426
static void nfs_inode_init_regular(struct nfs_inode *nfsi)
427427
{
428428
atomic_long_set(&nfsi->nrequests, 0);
429+
atomic_long_set(&nfsi->redirtied_pages, 0);
429430
INIT_LIST_HEAD(&nfsi->commit_info.list);
430431
atomic_long_set(&nfsi->commit_info.ncommit, 0);
431432
atomic_set(&nfsi->commit_info.rpcs_out, 0);

fs/nfs/write.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,10 +1420,12 @@ static void nfs_initiate_write(struct nfs_pgio_header *hdr,
14201420
*/
14211421
static void nfs_redirty_request(struct nfs_page *req)
14221422
{
1423+
struct nfs_inode *nfsi = NFS_I(page_file_mapping(req->wb_page)->host);
1424+
14231425
/* Bump the transmission count */
14241426
req->wb_nio++;
14251427
nfs_mark_request_dirty(req);
1426-
set_bit(NFS_CONTEXT_RESEND_WRITES, &nfs_req_openctx(req)->flags);
1428+
atomic_long_inc(&nfsi->redirtied_pages);
14271429
nfs_end_page_writeback(req);
14281430
nfs_release_request(req);
14291431
}
@@ -1904,7 +1906,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
19041906
/* We have a mismatch. Write the page again */
19051907
dprintk_cont(" mismatch\n");
19061908
nfs_mark_request_dirty(req);
1907-
set_bit(NFS_CONTEXT_RESEND_WRITES, &nfs_req_openctx(req)->flags);
1909+
atomic_long_inc(&NFS_I(data->inode)->redirtied_pages);
19081910
next:
19091911
nfs_unlock_and_release_request(req);
19101912
/* Latency breaker */

include/linux/nfs_fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ struct nfs_inode {
182182
/* Regular file */
183183
struct {
184184
atomic_long_t nrequests;
185+
atomic_long_t redirtied_pages;
185186
struct nfs_mds_commit_info commit_info;
186187
struct mutex commit_mutex;
187188
};

0 commit comments

Comments
 (0)