@@ -581,6 +581,52 @@ get_dirent_type(const char *path,
581581 return result ;
582582}
583583
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+
584630/*
585631 * pg_pwritev_with_retry
586632 *
@@ -601,7 +647,7 @@ pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset)
601647 return -1 ;
602648 }
603649
604- for (;;)
650+ do
605651 {
606652 /* Write as much as we can. */
607653 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)
616662 sum += part ;
617663 offset += part ;
618664
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-
635665 /*
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.
638669 */
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 );
644671 iov = iov_copy ;
645- }
672+ } while ( iovcnt > 0 );
646673
647674 return sum ;
648675}
0 commit comments