mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-21 01:06:58 +00:00
bfd: loop through read()/write() when the action is incomplete
The callers of bread() and bwrite() assume the operation reads/writes the complete length of the passed buffer. We must loop when invoking the read()/write() APIs. Fixes #1504 Signed-off-by: Nicolas Viennot <Nicolas.Viennot@twosigma.com>
This commit is contained in:
parent
24bc083653
commit
031a8d7905
3 changed files with 71 additions and 7 deletions
17
criu/bfd.c
17
criu/bfd.c
|
|
@ -145,7 +145,7 @@ static int brefill(struct bfd *f)
|
|||
memmove(b->mem, b->data, b->sz);
|
||||
b->data = b->mem;
|
||||
|
||||
ret = read(f->fd, b->mem + b->sz, BUFSIZE - b->sz);
|
||||
ret = read_all(f->fd, b->mem + b->sz, BUFSIZE - b->sz);
|
||||
if (ret < 0) {
|
||||
pr_perror("Error reading file");
|
||||
return -1;
|
||||
|
|
@ -241,7 +241,7 @@ static int bflush(struct bfd *bfd)
|
|||
if (!b->sz)
|
||||
return 0;
|
||||
|
||||
ret = write(bfd->fd, b->data, b->sz);
|
||||
ret = write_all(bfd->fd, b->data, b->sz);
|
||||
if (ret != b->sz)
|
||||
return -1;
|
||||
|
||||
|
|
@ -261,7 +261,7 @@ static int __bwrite(struct bfd *bfd, const void *buf, int size)
|
|||
}
|
||||
|
||||
if (size > BUFSIZE)
|
||||
return write(bfd->fd, buf, size);
|
||||
return write_all(bfd->fd, buf, size);
|
||||
|
||||
memcpy(b->data + b->sz, buf, size);
|
||||
b->sz += size;
|
||||
|
|
@ -271,7 +271,7 @@ static int __bwrite(struct bfd *bfd, const void *buf, int size)
|
|||
int bwrite(struct bfd *bfd, const void *buf, int size)
|
||||
{
|
||||
if (!bfd_buffered(bfd))
|
||||
return write(bfd->fd, buf, size);
|
||||
return write_all(bfd->fd, buf, size);
|
||||
|
||||
return __bwrite(bfd, buf, size);
|
||||
}
|
||||
|
|
@ -280,8 +280,13 @@ int bwritev(struct bfd *bfd, const struct iovec *iov, int cnt)
|
|||
{
|
||||
int i, written = 0;
|
||||
|
||||
if (!bfd_buffered(bfd))
|
||||
if (!bfd_buffered(bfd)) {
|
||||
/*
|
||||
* FIXME writev() should be called again if writev() writes
|
||||
* less bytes than requested.
|
||||
*/
|
||||
return writev(bfd->fd, iov, cnt);
|
||||
}
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
int ret;
|
||||
|
|
@ -304,7 +309,7 @@ int bread(struct bfd *bfd, void *buf, int size)
|
|||
int more = 1, filled = 0;
|
||||
|
||||
if (!bfd_buffered(bfd))
|
||||
return read(bfd->fd, buf, size);
|
||||
return read_all(bfd->fd, buf, size);
|
||||
|
||||
while (more > 0) {
|
||||
int chunk;
|
||||
|
|
|
|||
|
|
@ -385,4 +385,7 @@ extern int mount_detached_fs(const char *fsname);
|
|||
|
||||
extern char *get_legacy_iptables_bin(bool ipv6);
|
||||
|
||||
extern ssize_t read_all(int fd, void *buf, size_t size);
|
||||
extern ssize_t write_all(int fd, const void *buf, size_t size);
|
||||
|
||||
#endif /* __CR_UTIL_H__ */
|
||||
|
|
|
|||
58
criu/util.c
58
criu/util.c
|
|
@ -1583,4 +1583,60 @@ char *get_legacy_iptables_bin(bool ipv6)
|
|||
iptables_present[ipv6] = 1;
|
||||
|
||||
return iptables_bin[ipv6];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* read_all() behaves like read() without the possibility of partial reads.
|
||||
* Use only with blocking I/O.
|
||||
*/
|
||||
ssize_t read_all(int fd, void *buf, size_t size)
|
||||
{
|
||||
ssize_t n = 0;
|
||||
while (size > 0) {
|
||||
ssize_t ret = read(fd, buf, size);
|
||||
if (ret == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
/*
|
||||
* The caller should use standard read() for
|
||||
* non-blocking I/O.
|
||||
*/
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
errno = EINVAL;
|
||||
return ret;
|
||||
}
|
||||
if (ret == 0)
|
||||
break;
|
||||
n += ret;
|
||||
buf = (char *)buf + ret;
|
||||
size -= ret;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* write_all() behaves like write() without the possibility of partial writes.
|
||||
* Use only with blocking I/O.
|
||||
*/
|
||||
ssize_t write_all(int fd, const void *buf, size_t size)
|
||||
{
|
||||
ssize_t n = 0;
|
||||
while (size > 0) {
|
||||
ssize_t ret = write(fd, buf, size);
|
||||
if (ret == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
/*
|
||||
* The caller should use standard write() for
|
||||
* non-blocking I/O.
|
||||
*/
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
errno = EINVAL;
|
||||
return ret;
|
||||
}
|
||||
n += ret;
|
||||
buf = (char *)buf + ret;
|
||||
size -= ret;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue