Skip to content

Commit d03727b

Browse files
Olga Kornievskaiaamschuma-ntap
authored andcommitted
NFSv4 fix CLOSE not waiting for direct IO compeletion
Figuring out the root case for the REMOVE/CLOSE race and suggesting the solution was done by Neil Brown. Currently what happens is that direct IO calls hold a reference on the open context which is decremented as an asynchronous task in the nfs_direct_complete(). Before reference is decremented, control is returned to the application which is free to close the file. When close is being processed, it decrements its reference on the open_context but since directIO still holds one, it doesn't sent a close on the wire. It returns control to the application which is free to do other operations. For instance, it can delete a file. Direct IO is finally releasing its reference and triggering an asynchronous close. Which races with the REMOVE. On the server, REMOVE can be processed before the CLOSE, failing the REMOVE with EACCES as the file is still opened. Signed-off-by: Olga Kornievskaia <[email protected]> Suggested-by: Neil Brown <[email protected]> CC: [email protected] Signed-off-by: Anna Schumaker <[email protected]>
1 parent 8b04013 commit d03727b

File tree

2 files changed

+10
-4
lines changed

2 files changed

+10
-4
lines changed

fs/nfs/direct.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,6 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq)
267267
{
268268
struct inode *inode = dreq->inode;
269269

270-
inode_dio_end(inode);
271-
272270
if (dreq->iocb) {
273271
long res = (long) dreq->error;
274272
if (dreq->count != 0) {
@@ -280,7 +278,10 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq)
280278

281279
complete(&dreq->completion);
282280

281+
igrab(inode);
283282
nfs_direct_req_release(dreq);
283+
inode_dio_end(inode);
284+
iput(inode);
284285
}
285286

286287
static void nfs_direct_read_completion(struct nfs_pgio_header *hdr)
@@ -410,8 +411,10 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
410411
* generic layer handle the completion.
411412
*/
412413
if (requested_bytes == 0) {
413-
inode_dio_end(inode);
414+
igrab(inode);
414415
nfs_direct_req_release(dreq);
416+
inode_dio_end(inode);
417+
iput(inode);
415418
return result < 0 ? result : -EIO;
416419
}
417420

@@ -864,8 +867,10 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
864867
* generic layer handle the completion.
865868
*/
866869
if (requested_bytes == 0) {
867-
inode_dio_end(inode);
870+
igrab(inode);
868871
nfs_direct_req_release(dreq);
872+
inode_dio_end(inode);
873+
iput(inode);
869874
return result < 0 ? result : -EIO;
870875
}
871876

fs/nfs/file.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ nfs_file_release(struct inode *inode, struct file *filp)
8383
dprintk("NFS: release(%pD2)\n", filp);
8484

8585
nfs_inc_stats(inode, NFSIOS_VFSRELEASE);
86+
inode_dio_wait(inode);
8687
nfs_file_clear_open_context(filp);
8788
return 0;
8889
}

0 commit comments

Comments
 (0)