ul_copy_file: handle EAGAIN and EINTR
I did this by implementing a function called sendfile_all() similar to read_all()/write_all(). The manpage for sendfile doesn't mention EINTR, but I decided to check it anyway, just in case. Suggested-by: Karel Zak <kzak@redhat.com> Reviewed-by: Sami Kerola <kerolasa@iki.fi> Signed-off-by: Egor Chelak <egor.chelak@gmail.com>
This commit is contained in:
parent
f19a16550a
commit
212bde6cf7
|
@ -12,6 +12,10 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SENDFILE
|
||||
#include <sys/sendfile.h>
|
||||
#endif
|
||||
|
||||
#include "c.h"
|
||||
|
||||
|
@ -78,4 +82,32 @@ static inline ssize_t read_all(int fd, char *buf, size_t count)
|
|||
return c;
|
||||
}
|
||||
|
||||
static inline ssize_t sendfile_all(int out, int in, off_t *off, size_t count)
|
||||
{
|
||||
#ifdef HAVE_SENDFILE
|
||||
ssize_t ret;
|
||||
ssize_t c = 0;
|
||||
int tries = 0;
|
||||
while (count) {
|
||||
ret = sendfile(out, in, off, count);
|
||||
if (ret < 0) {
|
||||
if ((errno == EAGAIN || errno == EINTR) && (tries++ < 5)) {
|
||||
xusleep(250000);
|
||||
continue;
|
||||
}
|
||||
return c ? c : -1;
|
||||
}
|
||||
if (ret == 0)
|
||||
return c;
|
||||
tries = 0;
|
||||
count -= ret;
|
||||
c += ret;
|
||||
}
|
||||
return c;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* UTIL_LINUX_ALL_IO_H */
|
||||
|
|
|
@ -11,9 +11,6 @@
|
|||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#ifdef HAVE_SENDFILE
|
||||
#include <sys/sendfile.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
|
||||
#include "c.h"
|
||||
|
@ -275,21 +272,15 @@ int ul_copy_file(int from, int to)
|
|||
#ifdef HAVE_SENDFILE
|
||||
struct stat st;
|
||||
ssize_t nw;
|
||||
off_t left;
|
||||
|
||||
if (fstat(from, &st) == -1)
|
||||
return -1;
|
||||
if (!S_ISREG(st.st_mode))
|
||||
return copy_file_simple(from, to);
|
||||
for (left = st.st_size; left != 0; left -= nw) {
|
||||
if ((nw = sendfile(to, from, NULL, left)) < 0)
|
||||
return copy_file_simple(from, to);
|
||||
if (!nw)
|
||||
return 0;
|
||||
}
|
||||
/* For extra robustness, treat st_size as advisory and ensure that we
|
||||
* actually get EOF. */
|
||||
while ((nw = sendfile(to, from, NULL, 1024*1024)) != 0)
|
||||
if (sendfile_all(to, from, NULL, st.st_size) < 0)
|
||||
return copy_file_simple(from, to);
|
||||
/* ensure we either get an EOF or an error */
|
||||
while ((nw = sendfile_all(to, from, NULL, 16*1024*1024)) != 0)
|
||||
if (nw < 0)
|
||||
return copy_file_simple(from, to);
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue