spurious sillyrename after O_DIRECT writes get ENOSPC
Subsystems (2)
Last year Christoph noticed a bug that could result in a file being unnecessarily sillyrenamed after O_DIRECT writes get ENOSPC:
http://lkml.kernel.org/r/[email protected]
It's reproduceable on upstream, over v3 or v4.
I looked into it some more, and it seems to reproduce whenever a write system call results in multiple WRITE calls, only some of which receive ENOSPC. I think that's resulting in a leak of the wb_kref on some nfs_pages (possibly the ones corresponding to the ENOSPC failures?). Those nfs_pages in turn hold references on nfs_{lock,open}_contexts. So a "rm" on the client (even after the file is closed) results in a sillyrename.
I'll keep looking at this, but the relevant code is pretty opaque to me so far. Any ideas welcomed.
--b.
Quoted 15 lines · J. Bruce Fields
Last year Christoph noticed a bug that could result in a file being unnecessarily sillyrenamed after
O_DIRECTwrites get ENOSPC:http://lkml.kernel.org/r/[email protected]It's reproduceable on upstream, over v3 or v4.
I looked into it some more, and it seems to reproduce whenever a write system call results in multiple WRITE calls, only some of which receive ENOSPC. I think that's resulting in a leak of the
wb_krefon somenfs_pages(possibly the ones corresponding to the ENOSPC failures?). Thosenfs_pagesin turn hold references on nfs_{lock,open}_contexts. So a "rm" on the client (even after the file is closed) results in a sillyrename.
Quoted 2 lines
I'll keep looking at this, but the relevant code is pretty opaque to me so far. Any ideas welcomed.
Actually it looks like a leak of dreq->io_count? That prevents commits from being sent (which I'm also seeing in network traces--the succesfull WRITEs are unstable but never get committed), which means nfs_direct_commit_complete() is never called, and the reference taken on wb_kref in the request_commit case of nfs_direct_write_completion is never put.
--b.
Quoted 19 lines · J. Bruce Fields
Quoted 15 lines · J. Bruce Fields
Last year Christoph noticed a bug that could result in a file being unnecessarily sillyrenamed after
O_DIRECTwrites get ENOSPC:http://lkml.kernel.org/r/[email protected]It's reproduceable on upstream, over v3 or v4.
I looked into it some more, and it seems to reproduce whenever a write system call results in multiple WRITE calls, only some of which receive ENOSPC. I think that's resulting in a leak of the
wb_krefon somenfs_pages(possibly the ones corresponding to the ENOSPC failures?). Thosenfs_pagesin turn hold references on nfs_{lock,open}_contexts. So a "rm" on the client (even after the file is closed) results in a sillyrename.Quoted 2 lines
I'll keep looking at this, but the relevant code is pretty opaque to me so far. Any ideas welcomed.
Quoted 6 lines
Actually it looks like a leak of
dreq->io_count? That prevents commits from being sent (which I'm also seeing in network traces--the succesfull WRITEs are unstable but never get committed), which meansnfs_direct_commit_complete()is never called, and the reference taken onwb_krefin therequest_commitcase ofnfs_direct_write_completionis never put.
This sounds to me like the problem Scott's working - he sent a patch yesterday "nfs/pnfs: fix nfs_direct_req ref leak when i/o falls back to the mds".
I think the the rule should be that once we call nfs_pgio_completion_ops->init_hdr, we have to finish with ->completion. However, there are some paths where that is not the case.
The callgraph in between nfs_pgheader_init() and nfs_initiate_pgio() in nfs_generic_pg_pgios() for this case might show where we're bailing out early.
Ben
Quoted 29 lines · Benjamin Coddington
Quoted 19 lines · J. Bruce Fields
Quoted 15 lines · J. Bruce Fields
Last year Christoph noticed a bug that could result in a file being unnecessarily sillyrenamed after
O_DIRECTwrites get ENOSPC:http://lkml.kernel.org/r/[email protected]It's reproduceable on upstream, over v3 or v4.
I looked into it some more, and it seems to reproduce whenever a write system call results in multiple WRITE calls, only some of which receive ENOSPC. I think that's resulting in a leak of the
wb_krefon somenfs_pages(possibly the ones corresponding to the ENOSPC failures?). Thosenfs_pagesin turn hold references on nfs_{lock,open}_contexts. So a "rm" on the client (even after the file is closed) results in a sillyrename.Quoted 2 lines
I'll keep looking at this, but the relevant code is pretty opaque to me so far. Any ideas welcomed.
Quoted 6 lines
Actually it looks like a leak of
dreq->io_count? That prevents commits from being sent (which I'm also seeing in network traces--the succesfull WRITEs are unstable but never get committed), which meansnfs_direct_commit_complete()is never called, and the reference taken onwb_krefin therequest_commitcase ofnfs_direct_write_completionis never put.
Quoted 7 lines
This sounds to me like the problem Scott's working - he sent a patch yesterday "nfs/pnfs: fix
nfs_direct_reqref leak when i/o falls back to the mds".I think the the rule should be that once we call
nfs_pgio_completion_ops->init_hdr, we have to finish with ->completion. However, there are some paths where that is not the case.
Yes, I wondered about that....
Unfortunately after some more tests now I was think I was wrong, the dreq_get()s and put()s are balanced and the bug is somewhere else--in the case of my particular reproducer. Argh. But yes I can easily believe there could be a leak there.
--b.
Quoted 4 lines
The callgraph in between
nfs_pgheader_init()andnfs_initiate_pgio()innfs_generic_pg_pgios()for this case might show where we're bailing out early.
Quoted 38 lines · J. Bruce Fields
Quoted 29 lines · Benjamin Coddington
Quoted 19 lines · J. Bruce Fields
Quoted 15 lines · J. Bruce Fields
Last year Christoph noticed a bug that could result in a file being unnecessarily sillyrenamed after
O_DIRECTwrites get ENOSPC:http://lkml.kernel.org/r/[email protected]It's reproduceable on upstream, over v3 or v4.
I looked into it some more, and it seems to reproduce whenever a write system call results in multiple WRITE calls, only some of which receive ENOSPC. I think that's resulting in a leak of the
wb_krefon somenfs_pages(possibly the ones corresponding to the ENOSPC failures?). Thosenfs_pagesin turn hold references on nfs_{lock,open}_contexts. So a "rm" on the client (even after the file is closed) results in a sillyrename.Quoted 2 lines
I'll keep looking at this, but the relevant code is pretty opaque to me so far. Any ideas welcomed.
Quoted 6 lines
Actually it looks like a leak of
dreq->io_count? That prevents commits from being sent (which I'm also seeing in network traces--the succesfull WRITEs are unstable but never get committed), which meansnfs_direct_commit_complete()is never called, and the reference taken onwb_krefin therequest_commitcase ofnfs_direct_write_completionis never put.Quoted 7 lines
This sounds to me like the problem Scott's working - he sent a patch yesterday "nfs/pnfs: fix
nfs_direct_reqref leak when i/o falls back to the mds".I think the the rule should be that once we call
nfs_pgio_completion_ops->init_hdr, we have to finish with ->completion. However, there are some paths where that is not the case.
Quoted 6 lines
Yes, I wondered about that....
Unfortunately after some more tests now I was think I was wrong, the dreq_get()s and put()s are balanced and the bug is somewhere else--in the case of my particular reproducer. Argh. But yes I can easily believe there could be a leak there.
So actually what happens is if you do a direct io write where some WRITEs succeed and the one fails, then this:
if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) {
dreq->flags = 0;
dreq->error = hdr->error;
}clears the NFS_ODIRECT_DO_COMMIT flag, so nfs_direct_write_complete never scheduels the commit calls. It looks like that leaves a bunch of nfs_pages on some to-be-committed list, so we end up leaking a bunch of stuff, with the most visible symptom being an unnecessarily sillyrename on close.
I can just remove that clear of dreq_flags and that fixes the problem, but I doubt that's correct.
--b.
Quoted 8 lines · J. Bruce Fields
So actually what happens is if you do a direct io write where some WRITEs succeed and the one fails, then this:
if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) { dreq->flags = 0; dreq->error = hdr->error; }
Quoted 8 lines
clears the
NFS_ODIRECT_DO_COMMITflag, sonfs_direct_write_completenever scheduels the commit calls. It looks like that leaves a bunch ofnfs_pageson some to-be-committed list, so we end up leaking a bunch of stuff, with the most visible symptom being an unnecessarily sillyrename on close.I can just remove that clear of
dreq_flagsand that fixes the problem, but I doubt that's correct.
Or, maybe it is. If *any* WRITE(s) involved in this write might need a commit or reschedule, then surely we should run nfs_direct_write_schedule_work and let it sort them out? I'm having trouble seeing why clearing that field partway through could ever be correct.
Trond, Anna, does the following look right?
--b.
PATCH 1/1 NFS: commit direct writes even if they fail partially
From: "J. Bruce Fields" <[email protected]>
If some of the WRITE calls making up an O_DIRECT write syscall fail, we neglect to commit, even if some of the WRITEs succeed.
We also depend on the commit code to free the reference count on the nfs_page taken in the "if (request_commit)" case at the end of nfs_direct_write_completion(). The problem was originally noticed because ENOSPC's encountered partway through a write would result in a closed file being sillyrenamed when it should have been unlinked.
--- fs/nfs/direct.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
fs/nfs/direct.c +1 -3
@@ -775,10 +775,8 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)spin_lock (&dreq->lock); -if (test_bit (NFS_IOHDR_ERROR , &hdr->flags)) { - dreq->flags =0 ; +if (test_bit (NFS_IOHDR_ERROR , &hdr->flags)) dreq->error = hdr->error; - }if (dreq->error ==0 ) {nfs_direct_good_bytes (dreq, hdr);if (nfs_write_need_commit (hdr)) {
Signature · 1 line
2.14.3