Skip to content

Commit 94521bf

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. 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 33dca79 commit 94521bf

File tree

2 files changed

+37
-7
lines changed

2 files changed

+37
-7
lines changed

criu/bfd.c

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

278-
int bwritev(struct bfd *bfd, const struct iovec *iov, int cnt)
278+
int bwritev(struct bfd *bfd, struct iovec *iov, int cnt)
279279
{
280280
int i, written = 0;
281281

282282
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);
283+
size_t off = 0;
284+
285+
while (cnt) {
286+
int ret;
287+
288+
/*
289+
* Temporarily modify the first iovec to skip already-written
290+
* bytes from previous partial writes, then restore it before
291+
* the next iteration.
292+
*/
293+
iov[0].iov_base += off;
294+
iov[0].iov_len -= off;
295+
ret = writev(bfd->fd, iov, cnt);
296+
iov[0].iov_base -= off;
297+
iov[0].iov_len += off;
298+
if (ret < 0) {
299+
pr_perror("writev");
300+
return ret;
301+
}
302+
303+
written += ret;
304+
ret += off;
305+
while (ret) {
306+
if (iov[0].iov_len > ret) {
307+
off = ret;
308+
break;
309+
}
310+
ret -= iov[0].iov_len;
311+
iov++;
312+
cnt--;
313+
off = 0;
314+
}
315+
316+
}
317+
return written;
288318
}
289319

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

criu/include/bfd.h

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

0 commit comments

Comments
 (0)