Skip to content

Commit c675610

Browse files
committed
bfd: fix partial write handling in bwritev()
When bfd is unbuffered, bwritev() used writev() directly, which can return partial writes and leave checkpoint images incomplete. This patch adds bfd_writev_all() helper that retries writev() until all iovecs are written or an error occurs. This matches the pattern used by write_all() for single writes. Changes: - Add bfd_writev_all() helper to retry writev() until completion - Return 0 early when cnt == 0 to avoid zero-size edge cases - Treat a zero-byte writev() result as EIO to avoid infinite loops - Cast away const on the iov parameter for bfd_writev_all() Signed-off-by: Ahmed Elaidy <elaidya225@gmail.com>
1 parent 33dca79 commit c675610

File tree

1 file changed

+47
-5
lines changed

1 file changed

+47
-5
lines changed

criu/bfd.c

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -275,16 +275,58 @@ int bwrite(struct bfd *bfd, const void *buf, int size)
275275
return __bwrite(bfd, buf, size);
276276
}
277277

278+
/*
279+
* bfd_writev_all() behaves like writev() without the possibility of
280+
* partial writes. Use only with blocking I/O.
281+
*/
282+
static ssize_t bfd_writev_all(int fd, struct iovec *iov, int cnt)
283+
{
284+
ssize_t n = 0;
285+
286+
while (cnt > 0) {
287+
ssize_t ret = writev(fd, iov, cnt);
288+
if (ret == -1)
289+
return ret;
290+
291+
if (!ret) {
292+
errno = EIO;
293+
return -1;
294+
}
295+
296+
n += ret;
297+
298+
while (cnt > 0 && ret >= iov->iov_len) {
299+
ret -= iov->iov_len;
300+
iov++;
301+
cnt--;
302+
}
303+
304+
if (cnt > 0 && ret > 0) {
305+
iov->iov_base = (char *)iov->iov_base + ret;
306+
iov->iov_len -= ret;
307+
}
308+
}
309+
310+
return n;
311+
}
312+
278313
int bwritev(struct bfd *bfd, const struct iovec *iov, int cnt)
279314
{
280315
int i, written = 0;
281316

282317
if (!bfd_buffered(bfd)) {
283-
/*
284-
* FIXME writev() should be called again if writev() writes
285-
* less bytes than requested.
286-
*/
287-
return writev(bfd->fd, iov, cnt);
318+
ssize_t ret;
319+
320+
if (cnt <= 0) {
321+
if (cnt < 0) {
322+
errno = EINVAL;
323+
return -1;
324+
}
325+
return 0;
326+
}
327+
328+
ret = bfd_writev_all(bfd->fd, (struct iovec *)iov, cnt);
329+
return ret;
288330
}
289331

290332
for (i = 0; i < cnt; i++) {

0 commit comments

Comments
 (0)