@@ -42,7 +42,7 @@ struct nfs_local_kiocb {
4242 /* Begin mostly DIO-specific members */
4343 size_t end_len ;
4444 short int end_iter_index ;
45- short int n_iters ;
45+ atomic_t n_iters ;
4646 bool iter_is_dio_aligned [NFSLOCAL_MAX_IOS ];
4747 loff_t offset [NFSLOCAL_MAX_IOS ] ____cacheline_aligned ;
4848 struct iov_iter iters [NFSLOCAL_MAX_IOS ];
@@ -407,6 +407,7 @@ nfs_local_iters_setup_dio(struct nfs_local_kiocb *iocb, int rw,
407407 iters [n_iters ].count = local_dio -> start_len ;
408408 iocb -> offset [n_iters ] = iocb -> hdr -> args .offset ;
409409 iocb -> iter_is_dio_aligned [n_iters ] = false;
410+ atomic_inc (& iocb -> n_iters );
410411 ++ n_iters ;
411412 }
412413
@@ -425,6 +426,7 @@ nfs_local_iters_setup_dio(struct nfs_local_kiocb *iocb, int rw,
425426 /* Save index and length of end */
426427 iocb -> end_iter_index = n_iters ;
427428 iocb -> end_len = local_dio -> end_len ;
429+ atomic_inc (& iocb -> n_iters );
428430 ++ n_iters ;
429431 }
430432
@@ -448,7 +450,6 @@ nfs_local_iters_setup_dio(struct nfs_local_kiocb *iocb, int rw,
448450 }
449451 ++ n_iters ;
450452
451- iocb -> n_iters = n_iters ;
452453 return n_iters ;
453454}
454455
@@ -474,6 +475,12 @@ nfs_local_iters_init(struct nfs_local_kiocb *iocb, int rw)
474475 }
475476 len = hdr -> args .count - total ;
476477
478+ /*
479+ * For each iocb, iocb->n_iter is always at least 1 and we always
480+ * end io after first nfs_local_pgio_done call unless misaligned DIO.
481+ */
482+ atomic_set (& iocb -> n_iters , 1 );
483+
477484 if (test_bit (NFS_IOHDR_ODIRECT , & hdr -> flags )) {
478485 struct nfs_local_dio local_dio ;
479486
@@ -486,7 +493,6 @@ nfs_local_iters_init(struct nfs_local_kiocb *iocb, int rw)
486493 iocb -> offset [0 ] = hdr -> args .offset ;
487494 iov_iter_bvec (& iocb -> iters [0 ], rw , iocb -> bvec , v , len );
488495 iocb -> iter_is_dio_aligned [0 ] = false;
489- iocb -> n_iters = 1 ;
490496}
491497
492498static void
@@ -506,9 +512,11 @@ nfs_local_pgio_init(struct nfs_pgio_header *hdr,
506512 hdr -> task .tk_start = ktime_get ();
507513}
508514
509- static void
510- nfs_local_pgio_done (struct nfs_pgio_header * hdr , long status )
515+ static bool
516+ nfs_local_pgio_done (struct nfs_local_kiocb * iocb , long status , bool force )
511517{
518+ struct nfs_pgio_header * hdr = iocb -> hdr ;
519+
512520 /* Must handle partial completions */
513521 if (status >= 0 ) {
514522 hdr -> res .count += status ;
@@ -519,6 +527,12 @@ nfs_local_pgio_done(struct nfs_pgio_header *hdr, long status)
519527 hdr -> res .op_status = nfs_localio_errno_to_nfs4_stat (status );
520528 hdr -> task .tk_status = status ;
521529 }
530+
531+ if (force )
532+ return true;
533+
534+ BUG_ON (atomic_read (& iocb -> n_iters ) <= 0 );
535+ return atomic_dec_and_test (& iocb -> n_iters );
522536}
523537
524538static void
@@ -549,11 +563,11 @@ static inline void nfs_local_pgio_aio_complete(struct nfs_local_kiocb *iocb)
549563 queue_work (nfsiod_workqueue , & iocb -> work );
550564}
551565
552- static void
553- nfs_local_read_done (struct nfs_local_kiocb * iocb , long status )
566+ static void nfs_local_read_done (struct nfs_local_kiocb * iocb )
554567{
555568 struct nfs_pgio_header * hdr = iocb -> hdr ;
556569 struct file * filp = iocb -> kiocb .ki_filp ;
570+ long status = hdr -> task .tk_status ;
557571
558572 if ((iocb -> kiocb .ki_flags & IOCB_DIRECT ) && status == - EINVAL ) {
559573 /* Underlying FS will return -EINVAL if misaligned DIO is attempted. */
@@ -574,21 +588,29 @@ nfs_local_read_done(struct nfs_local_kiocb *iocb, long status)
574588 status > 0 ? status : 0 , hdr -> res .eof );
575589}
576590
591+ static inline void nfs_local_read_iocb_done (struct nfs_local_kiocb * iocb )
592+ {
593+ nfs_local_read_done (iocb );
594+ nfs_local_pgio_release (iocb );
595+ }
596+
577597static void nfs_local_read_aio_complete_work (struct work_struct * work )
578598{
579599 struct nfs_local_kiocb * iocb =
580600 container_of (work , struct nfs_local_kiocb , work );
581601
582- nfs_local_pgio_release (iocb );
602+ nfs_local_read_iocb_done (iocb );
583603}
584604
585605static void nfs_local_read_aio_complete (struct kiocb * kiocb , long ret )
586606{
587607 struct nfs_local_kiocb * iocb =
588608 container_of (kiocb , struct nfs_local_kiocb , kiocb );
589609
590- nfs_local_pgio_done (iocb -> hdr , ret );
591- nfs_local_read_done (iocb , ret );
610+ /* AIO completion of DIO read should always be last to complete */
611+ if (unlikely (!nfs_local_pgio_done (iocb , ret , false)))
612+ return ;
613+
592614 nfs_local_pgio_aio_complete (iocb ); /* Calls nfs_local_read_aio_complete_work */
593615}
594616
@@ -599,10 +621,13 @@ static void nfs_local_call_read(struct work_struct *work)
599621 struct file * filp = iocb -> kiocb .ki_filp ;
600622 const struct cred * save_cred ;
601623 ssize_t status ;
624+ int n_iters ;
602625
603626 save_cred = override_creds (filp -> f_cred );
604627
605- for (int i = 0 ; i < iocb -> n_iters ; i ++ ) {
628+ n_iters = atomic_read (& iocb -> n_iters );
629+ for (int i = 0 ; i < n_iters ; i ++ ) {
630+ /* DIO-aligned middle is always issued last with AIO completion */
606631 if (iocb -> iter_is_dio_aligned [i ]) {
607632 iocb -> kiocb .ki_flags |= IOCB_DIRECT ;
608633 iocb -> kiocb .ki_complete = nfs_local_read_aio_complete ;
@@ -612,18 +637,14 @@ static void nfs_local_call_read(struct work_struct *work)
612637 iocb -> kiocb .ki_pos = iocb -> offset [i ];
613638 status = filp -> f_op -> read_iter (& iocb -> kiocb , & iocb -> iters [i ]);
614639 if (status != - EIOCBQUEUED ) {
615- nfs_local_pgio_done (iocb -> hdr , status );
616- if (iocb -> hdr -> task . tk_status )
640+ if ( nfs_local_pgio_done (iocb , status , false)) {
641+ nfs_local_read_iocb_done (iocb );
617642 break ;
643+ }
618644 }
619645 }
620646
621647 revert_creds (save_cred );
622-
623- if (status != - EIOCBQUEUED ) {
624- nfs_local_read_done (iocb , status );
625- nfs_local_pgio_release (iocb );
626- }
627648}
628649
629650static int
@@ -738,11 +759,10 @@ static void nfs_local_vfs_getattr(struct nfs_local_kiocb *iocb)
738759 fattr -> du .nfs3 .used = stat .blocks << 9 ;
739760}
740761
741- static void
742- nfs_local_write_done (struct nfs_local_kiocb * iocb , long status )
762+ static void nfs_local_write_done (struct nfs_local_kiocb * iocb )
743763{
744764 struct nfs_pgio_header * hdr = iocb -> hdr ;
745- struct inode * inode = hdr -> inode ;
765+ long status = hdr -> task . tk_status ;
746766
747767 dprintk ("%s: wrote %ld bytes.\n" , __func__ , status > 0 ? status : 0 );
748768
@@ -761,28 +781,36 @@ nfs_local_write_done(struct nfs_local_kiocb *iocb, long status)
761781 nfs_set_pgio_error (hdr , - ENOSPC , hdr -> args .offset );
762782 status = - ENOSPC ;
763783 /* record -ENOSPC in terms of nfs_local_pgio_done */
764- nfs_local_pgio_done (hdr , status );
784+ ( void ) nfs_local_pgio_done (iocb , status , true );
765785 }
766786 if (hdr -> task .tk_status < 0 )
767- nfs_reset_boot_verifier (inode );
787+ nfs_reset_boot_verifier (hdr -> inode );
788+ }
789+
790+ static inline void nfs_local_write_iocb_done (struct nfs_local_kiocb * iocb )
791+ {
792+ nfs_local_write_done (iocb );
793+ nfs_local_vfs_getattr (iocb );
794+ nfs_local_pgio_release (iocb );
768795}
769796
770797static void nfs_local_write_aio_complete_work (struct work_struct * work )
771798{
772799 struct nfs_local_kiocb * iocb =
773800 container_of (work , struct nfs_local_kiocb , work );
774801
775- nfs_local_vfs_getattr (iocb );
776- nfs_local_pgio_release (iocb );
802+ nfs_local_write_iocb_done (iocb );
777803}
778804
779805static void nfs_local_write_aio_complete (struct kiocb * kiocb , long ret )
780806{
781807 struct nfs_local_kiocb * iocb =
782808 container_of (kiocb , struct nfs_local_kiocb , kiocb );
783809
784- nfs_local_pgio_done (iocb -> hdr , ret );
785- nfs_local_write_done (iocb , ret );
810+ /* AIO completion of DIO write should always be last to complete */
811+ if (unlikely (!nfs_local_pgio_done (iocb , ret , false)))
812+ return ;
813+
786814 nfs_local_pgio_aio_complete (iocb ); /* Calls nfs_local_write_aio_complete_work */
787815}
788816
@@ -793,13 +821,17 @@ static void nfs_local_call_write(struct work_struct *work)
793821 struct file * filp = iocb -> kiocb .ki_filp ;
794822 unsigned long old_flags = current -> flags ;
795823 const struct cred * save_cred ;
824+ bool force_done = false;
796825 ssize_t status ;
826+ int n_iters ;
797827
798828 current -> flags |= PF_LOCAL_THROTTLE | PF_MEMALLOC_NOIO ;
799829 save_cred = override_creds (filp -> f_cred );
800830
801831 file_start_write (filp );
802- for (int i = 0 ; i < iocb -> n_iters ; i ++ ) {
832+ n_iters = atomic_read (& iocb -> n_iters );
833+ for (int i = 0 ; i < n_iters ; i ++ ) {
834+ /* DIO-aligned middle is always issued last with AIO completion */
803835 if (iocb -> iter_is_dio_aligned [i ]) {
804836 iocb -> kiocb .ki_flags |= IOCB_DIRECT ;
805837 iocb -> kiocb .ki_complete = nfs_local_write_aio_complete ;
@@ -812,35 +844,27 @@ static void nfs_local_call_write(struct work_struct *work)
812844 if (unlikely (status >= 0 && status < iocb -> iters [i ].count )) {
813845 /* partial write */
814846 if (i == iocb -> end_iter_index ) {
815- /* Must not account partial end, otherwise, due
816- * to end being issued before middle: the partial
847+ /* Must not account DIO partial end, otherwise ( due
848+ * to end being issued before middle) : the partial
817849 * write accounting in nfs_local_write_done()
818850 * would incorrectly advance hdr->args.offset
819851 */
820852 status = 0 ;
821853 } else {
822- /* Partial write at start or buffered middle,
823- * exit early.
824- */
825- nfs_local_pgio_done (iocb -> hdr , status );
826- break ;
854+ /* Partial write at start or middle, force done */
855+ force_done = true;
827856 }
828857 }
829- nfs_local_pgio_done (iocb -> hdr , status );
830- if (iocb -> hdr -> task . tk_status )
858+ if ( nfs_local_pgio_done (iocb , status , force_done )) {
859+ nfs_local_write_iocb_done (iocb );
831860 break ;
861+ }
832862 }
833863 }
834864 file_end_write (filp );
835865
836866 revert_creds (save_cred );
837867 current -> flags = old_flags ;
838-
839- if (status != - EIOCBQUEUED ) {
840- nfs_local_write_done (iocb , status );
841- nfs_local_vfs_getattr (iocb );
842- nfs_local_pgio_release (iocb );
843- }
844868}
845869
846870static int
0 commit comments