aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlga Kornievskaia2020-06-24 12:54:08 -0500
committerSasha Levin2020-06-30 22:17:18 -0500
commite66a37c80e8ca9457d5dbd71e7d34091b894cfa1 (patch)
treef23fe8dd68fb293760ca550688a0bad3d9b635ab
parente6efe9b152c5188cd2fcd817b7edf73c5dcccc20 (diff)
downloadkernel-e66a37c80e8ca9457d5dbd71e7d34091b894cfa1.tar.gz
kernel-e66a37c80e8ca9457d5dbd71e7d34091b894cfa1.tar.xz
kernel-e66a37c80e8ca9457d5dbd71e7d34091b894cfa1.zip
NFSv4 fix CLOSE not waiting for direct IO compeletion
commit d03727b248d0dae6199569a8d7b629a681154633 upstream. 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 <kolga@netapp.com> Suggested-by: Neil Brown <neilb@suse.com> CC: stable@vger.kernel.org Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--fs/nfs/direct.c13
-rw-r--r--fs/nfs/file.c1
2 files changed, 10 insertions, 4 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index e5da9d7fb69e..1e883df26d4a 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -396,8 +396,6 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq)
396{ 396{
397 struct inode *inode = dreq->inode; 397 struct inode *inode = dreq->inode;
398 398
399 inode_dio_end(inode);
400
401 if (dreq->iocb) { 399 if (dreq->iocb) {
402 long res = (long) dreq->error; 400 long res = (long) dreq->error;
403 if (dreq->count != 0) { 401 if (dreq->count != 0) {
@@ -409,7 +407,10 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq)
409 407
410 complete(&dreq->completion); 408 complete(&dreq->completion);
411 409
410 igrab(inode);
412 nfs_direct_req_release(dreq); 411 nfs_direct_req_release(dreq);
412 inode_dio_end(inode);
413 iput(inode);
413} 414}
414 415
415static void nfs_direct_read_completion(struct nfs_pgio_header *hdr) 416static void nfs_direct_read_completion(struct nfs_pgio_header *hdr)
@@ -539,8 +540,10 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
539 * generic layer handle the completion. 540 * generic layer handle the completion.
540 */ 541 */
541 if (requested_bytes == 0) { 542 if (requested_bytes == 0) {
542 inode_dio_end(inode); 543 igrab(inode);
543 nfs_direct_req_release(dreq); 544 nfs_direct_req_release(dreq);
545 inode_dio_end(inode);
546 iput(inode);
544 return result < 0 ? result : -EIO; 547 return result < 0 ? result : -EIO;
545 } 548 }
546 549
@@ -957,8 +960,10 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
957 * generic layer handle the completion. 960 * generic layer handle the completion.
958 */ 961 */
959 if (requested_bytes == 0) { 962 if (requested_bytes == 0) {
960 inode_dio_end(inode); 963 igrab(inode);
961 nfs_direct_req_release(dreq); 964 nfs_direct_req_release(dreq);
965 inode_dio_end(inode);
966 iput(inode);
962 return result < 0 ? result : -EIO; 967 return result < 0 ? result : -EIO;
963 } 968 }
964 969
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 29553fdba8af..b2257fa209ac 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -82,6 +82,7 @@ nfs_file_release(struct inode *inode, struct file *filp)
82 dprintk("NFS: release(%pD2)\n", filp); 82 dprintk("NFS: release(%pD2)\n", filp);
83 83
84 nfs_inc_stats(inode, NFSIOS_VFSRELEASE); 84 nfs_inc_stats(inode, NFSIOS_VFSRELEASE);
85 inode_dio_wait(inode);
85 nfs_file_clear_open_context(filp); 86 nfs_file_clear_open_context(filp);
86 return 0; 87 return 0;
87} 88}