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:
parent
07c8f41576
commit
dd00220b1e
|
@ -31,6 +31,7 @@
|
|||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -168,11 +169,28 @@ int
|
|||
os_resize_anonymous_file(int fd, off_t size)
|
||||
{
|
||||
#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
|
||||
*/
|
||||
do {
|
||||
errno = posix_fallocate(fd, 0, size);
|
||||
} while (errno == EINTR);
|
||||
sigprocmask(SIG_SETMASK, &old_mask, NULL);
|
||||
if (errno == 0)
|
||||
return 0;
|
||||
else if (errno != EINVAL && errno != EOPNOTSUPP)
|
||||
|
|
Loading…
Reference in New Issue
Block a user