cursor/os-compatibility: handle EINTR gracefully

If os_resize_anonymous_file() called from os_create_anonymous_file()
fails with EINTR (Interrupted system call), then the buffer allocation
fails.

To avoid that, retry posix_fallocate() on EINTR.

However, in the presence of an alarm, the interrupt may trigger
repeatedly and prevent a large posix_fallocate() to ever complete
successfully, so we need to first block SIGALRM to prevent this.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
This commit is contained in:
Olivier Fourdan 2022-05-30 09:14:04 +02:00 committed by Simon Ser
parent 07c8f41576
commit dd00220b1e

View File

@ -31,6 +31,7 @@
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <signal.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -168,11 +169,28 @@ int
os_resize_anonymous_file(int fd, off_t size) os_resize_anonymous_file(int fd, off_t size)
{ {
#ifdef HAVE_POSIX_FALLOCATE #ifdef HAVE_POSIX_FALLOCATE
sigset_t mask;
sigset_t old_mask;
/* /*
* Filesystems that do support fallocate will return EINVAL or * posix_fallocate() might be interrupted, so we need to check
* for EINTR and retry in that case.
* However, in the presence of an alarm, the interrupt may trigger
* repeatedly and prevent a large posix_fallocate() to ever complete
* successfully, so we need to first block SIGALRM to prevent
* this.
*/
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
sigprocmask(SIG_BLOCK, &mask, &old_mask);
/*
* Filesystems that do not support fallocate will return EINVAL or
* EOPNOTSUPP. In this case we need to fall back to ftruncate * EOPNOTSUPP. In this case we need to fall back to ftruncate
*/ */
errno = posix_fallocate(fd, 0, size); do {
errno = posix_fallocate(fd, 0, size);
} while (errno == EINTR);
sigprocmask(SIG_SETMASK, &old_mask, NULL);
if (errno == 0) if (errno == 0)
return 0; return 0;
else if (errno != EINVAL && errno != EOPNOTSUPP) else if (errno != EINVAL && errno != EOPNOTSUPP)