@@ -581,6 +581,52 @@ get_dirent_type(const char *path,
581
581
return result ;
582
582
}
583
583
584
+ /*
585
+ * Compute what remains to be done after a possibly partial vectored read or
586
+ * write. The part of 'source' beginning after 'transferred' bytes is copied
587
+ * to 'destination', and its length is returned. 'source' and 'destination'
588
+ * may point to the same array, for in-place adjustment. A return value of
589
+ * zero indicates completion (for callers without a cheaper way to know that).
590
+ */
591
+ int
592
+ compute_remaining_iovec (struct iovec * destination ,
593
+ const struct iovec * source ,
594
+ int iovcnt ,
595
+ size_t transferred )
596
+ {
597
+ Assert (iovcnt > 0 );
598
+
599
+ /* Skip wholly transferred iovecs. */
600
+ while (source -> iov_len <= transferred )
601
+ {
602
+ transferred -= source -> iov_len ;
603
+ source ++ ;
604
+ iovcnt -- ;
605
+
606
+ /* All iovecs transferred? */
607
+ if (iovcnt == 0 )
608
+ {
609
+ /*
610
+ * We don't expect the kernel to transfer more than we asked it
611
+ * to, or something is out of sync.
612
+ */
613
+ Assert (transferred == 0 );
614
+ return 0 ;
615
+ }
616
+ }
617
+
618
+ /* Copy the remaining iovecs to the front of the array. */
619
+ if (source != destination )
620
+ memmove (destination , source , sizeof (* source ) * iovcnt );
621
+
622
+ /* Adjust leading iovec, which may have been partially transferred. */
623
+ Assert (destination -> iov_len > transferred );
624
+ destination -> iov_base = (char * ) destination -> iov_base + transferred ;
625
+ destination -> iov_len -= transferred ;
626
+
627
+ return iovcnt ;
628
+ }
629
+
584
630
/*
585
631
* pg_pwritev_with_retry
586
632
*
@@ -601,7 +647,7 @@ pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset)
601
647
return -1 ;
602
648
}
603
649
604
- for (;;)
650
+ do
605
651
{
606
652
/* Write as much as we can. */
607
653
part = pg_pwritev (fd , iov , iovcnt , offset );
@@ -616,33 +662,14 @@ pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset)
616
662
sum += part ;
617
663
offset += part ;
618
664
619
- /* Step over iovecs that are done. */
620
- while (iovcnt > 0 && iov -> iov_len <= part )
621
- {
622
- part -= iov -> iov_len ;
623
- ++ iov ;
624
- -- iovcnt ;
625
- }
626
-
627
- /* Are they all done? */
628
- if (iovcnt == 0 )
629
- {
630
- /* We don't expect the kernel to write more than requested. */
631
- Assert (part == 0 );
632
- break ;
633
- }
634
-
635
665
/*
636
- * Move whatever's left to the front of our mutable copy and adjust
637
- * the leading iovec.
666
+ * See what is left. On the first loop we used the caller's array,
667
+ * but in later loops we'll use our local copy that we are allowed to
668
+ * mutate.
638
669
*/
639
- Assert (iovcnt > 0 );
640
- memmove (iov_copy , iov , sizeof (* iov ) * iovcnt );
641
- Assert (iov -> iov_len > part );
642
- iov_copy [0 ].iov_base = (char * ) iov_copy [0 ].iov_base + part ;
643
- iov_copy [0 ].iov_len -= part ;
670
+ iovcnt = compute_remaining_iovec (iov_copy , iov , iovcnt , part );
644
671
iov = iov_copy ;
645
- }
672
+ } while ( iovcnt > 0 );
646
673
647
674
return sum ;
648
675
}
0 commit comments