Skip to content

Commit f943d4f

Browse files
3ideyavagin
authored andcommitted
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. Fix this by retrying writev() until all iovecs are written or an error occurs. Temporarily modify the first iovec's base and length to track progress on partial writes, then restore it before the next iteration. Changes the function signature to accept non-const iovec, as we need to modify it to track progress (same pattern as write_all() with buffers). Signed-off-by: Ahmed Elaidy <elaidya225@gmail.com>
1 parent 78a7120 commit f943d4f

File tree

2 files changed

+42
-7
lines changed

2 files changed

+42
-7
lines changed

criu/bfd.c

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -321,16 +321,51 @@ int bwrite(struct bfd *bfd, const void *buf, int size)
321321
return __bwrite(bfd, buf, size);
322322
}
323323

324-
int bwritev(struct bfd *bfd, const struct iovec *iov, int cnt)
324+
int bwritev(struct bfd *bfd, struct iovec *iov, int cnt)
325325
{
326326
int i, written = 0;
327327

328328
if (!bfd_buffered(bfd)) {
329-
/*
330-
* FIXME writev() should be called again if writev() writes
331-
* less bytes than requested.
332-
*/
333-
return writev(bfd->fd, iov, cnt);
329+
size_t off = 0;
330+
331+
while (cnt) {
332+
ssize_t ret;
333+
334+
/*
335+
* Temporarily modify the first iovec to skip already-written
336+
* bytes from previous partial writes, then restore it before
337+
* the next iteration.
338+
*/
339+
iov[0].iov_base += off;
340+
iov[0].iov_len -= off;
341+
ret = writev(bfd->fd, iov, cnt);
342+
iov[0].iov_base -= off;
343+
iov[0].iov_len += off;
344+
if (ret < 0) {
345+
pr_perror("writev failed for fd %d", bfd->fd);
346+
return ret;
347+
}
348+
if (ret == 0) {
349+
errno = EIO;
350+
pr_perror("writev made no progress (fd %d)", bfd->fd);
351+
return -1;
352+
}
353+
354+
written += ret;
355+
ret += off;
356+
while (ret) {
357+
if (iov[0].iov_len > ret) {
358+
off = ret;
359+
break;
360+
}
361+
ret -= iov[0].iov_len;
362+
iov++;
363+
cnt--;
364+
off = 0;
365+
}
366+
367+
}
368+
return written;
334369
}
335370

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

criu/include/bfd.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ char *breadline(struct bfd *f);
3535
char *breadchr(struct bfd *f, char c);
3636
int bwrite(struct bfd *f, const void *buf, int sz);
3737
struct iovec;
38-
int bwritev(struct bfd *f, const struct iovec *iov, int cnt);
38+
int bwritev(struct bfd *f, struct iovec *iov, int cnt);
3939
int bread(struct bfd *f, void *buf, int sz);
4040
int bfd_flush_images(void);
4141
#endif

0 commit comments

Comments
 (0)