fd.c: Retry after EINTR in more places
Starting with 4d330a61bb1 we can use posix_fallocate() to extend files. Unfortunately in some situation, e.g. on tmpfs filesystems, EINTR may be returned. See also 4518c798b2b. To fix, add a retry path to FileFallocate(). In contrast to 4518c798b2b the amount we extend by is limited and the extending may happen at a high frequency, so disabling signals does not appear to be the correct path here. Also add retry paths to other file operations currently lacking them (around fdatasync(), fsync(), ftruncate(), posix_fadvise(), sync_file_range(), truncate()) - they are all documented or have been observed to return EINTR. Even though most of these functions used in the back branches, it does not seem worth the risk to backpatch - outside of the new-to-16 case of posix_fallocate() I am not aware of problem reports due to the lack of retries. Reported-by: Christoph Berg <myon@debian.org> Discussion: https://postgr.es/m/ZEZDj1H61ryrmY9o@msg.df7cb.de Backpatch: -
This commit is contained in:
parent
797f980364
commit
0d369ac650
@ -415,10 +415,18 @@ pg_fsync(int fd)
|
|||||||
int
|
int
|
||||||
pg_fsync_no_writethrough(int fd)
|
pg_fsync_no_writethrough(int fd)
|
||||||
{
|
{
|
||||||
if (enableFsync)
|
int rc;
|
||||||
return fsync(fd);
|
|
||||||
else
|
if (!enableFsync)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
retry:
|
||||||
|
rc = fsync(fd);
|
||||||
|
|
||||||
|
if (rc == -1 && errno == EINTR)
|
||||||
|
goto retry;
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -448,10 +456,18 @@ pg_fsync_writethrough(int fd)
|
|||||||
int
|
int
|
||||||
pg_fdatasync(int fd)
|
pg_fdatasync(int fd)
|
||||||
{
|
{
|
||||||
if (enableFsync)
|
int rc;
|
||||||
return fdatasync(fd);
|
|
||||||
else
|
if (!enableFsync)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
retry:
|
||||||
|
rc = fdatasync(fd);
|
||||||
|
|
||||||
|
if (rc == -1 && errno == EINTR)
|
||||||
|
goto retry;
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -483,6 +499,7 @@ pg_flush_data(int fd, off_t offset, off_t nbytes)
|
|||||||
if (not_implemented_by_kernel)
|
if (not_implemented_by_kernel)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
retry:
|
||||||
/*
|
/*
|
||||||
* sync_file_range(SYNC_FILE_RANGE_WRITE), currently linux specific,
|
* sync_file_range(SYNC_FILE_RANGE_WRITE), currently linux specific,
|
||||||
* tells the OS that writeback for the specified blocks should be
|
* tells the OS that writeback for the specified blocks should be
|
||||||
@ -498,6 +515,9 @@ pg_flush_data(int fd, off_t offset, off_t nbytes)
|
|||||||
{
|
{
|
||||||
int elevel;
|
int elevel;
|
||||||
|
|
||||||
|
if (rc == EINTR)
|
||||||
|
goto retry;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For systems that don't have an implementation of
|
* For systems that don't have an implementation of
|
||||||
* sync_file_range() such as Windows WSL, generate only one
|
* sync_file_range() such as Windows WSL, generate only one
|
||||||
@ -629,32 +649,54 @@ pg_flush_data(int fd, off_t offset, off_t nbytes)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Truncate an open file to a given length.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
pg_ftruncate(int fd, off_t length)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
retry:
|
||||||
|
ret = ftruncate(fd, length);
|
||||||
|
|
||||||
|
if (ret == -1 && errno == EINTR)
|
||||||
|
goto retry;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Truncate a file to a given length by name.
|
* Truncate a file to a given length by name.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
pg_truncate(const char *path, off_t length)
|
pg_truncate(const char *path, off_t length)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
int save_errno;
|
int save_errno;
|
||||||
int ret;
|
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
|
fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
|
||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
{
|
{
|
||||||
ret = ftruncate(fd, length);
|
ret = pg_ftruncate(fd, length);
|
||||||
save_errno = errno;
|
save_errno = errno;
|
||||||
CloseTransientFile(fd);
|
CloseTransientFile(fd);
|
||||||
errno = save_errno;
|
errno = save_errno;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ret = -1;
|
ret = -1;
|
||||||
|
#else
|
||||||
|
|
||||||
|
retry:
|
||||||
|
ret = truncate(path, length);
|
||||||
|
|
||||||
|
if (ret == -1 && errno == EINTR)
|
||||||
|
goto retry;
|
||||||
|
#endif
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
#else
|
|
||||||
return truncate(path, length);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2001,11 +2043,15 @@ FilePrefetch(File file, off_t offset, off_t amount, uint32 wait_event_info)
|
|||||||
if (returnCode < 0)
|
if (returnCode < 0)
|
||||||
return returnCode;
|
return returnCode;
|
||||||
|
|
||||||
|
retry:
|
||||||
pgstat_report_wait_start(wait_event_info);
|
pgstat_report_wait_start(wait_event_info);
|
||||||
returnCode = posix_fadvise(VfdCache[file].fd, offset, amount,
|
returnCode = posix_fadvise(VfdCache[file].fd, offset, amount,
|
||||||
POSIX_FADV_WILLNEED);
|
POSIX_FADV_WILLNEED);
|
||||||
pgstat_report_wait_end();
|
pgstat_report_wait_end();
|
||||||
|
|
||||||
|
if (returnCode == EINTR)
|
||||||
|
goto retry;
|
||||||
|
|
||||||
return returnCode;
|
return returnCode;
|
||||||
#else
|
#else
|
||||||
Assert(FileIsValid(file));
|
Assert(FileIsValid(file));
|
||||||
@ -2281,12 +2327,15 @@ FileFallocate(File file, off_t offset, off_t amount, uint32 wait_event_info)
|
|||||||
if (returnCode < 0)
|
if (returnCode < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
retry:
|
||||||
pgstat_report_wait_start(wait_event_info);
|
pgstat_report_wait_start(wait_event_info);
|
||||||
returnCode = posix_fallocate(VfdCache[file].fd, offset, amount);
|
returnCode = posix_fallocate(VfdCache[file].fd, offset, amount);
|
||||||
pgstat_report_wait_end();
|
pgstat_report_wait_end();
|
||||||
|
|
||||||
if (returnCode == 0)
|
if (returnCode == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
else if (returnCode == EINTR)
|
||||||
|
goto retry;
|
||||||
|
|
||||||
/* for compatibility with %m printing etc */
|
/* for compatibility with %m printing etc */
|
||||||
errno = returnCode;
|
errno = returnCode;
|
||||||
@ -2334,7 +2383,7 @@ FileTruncate(File file, off_t offset, uint32 wait_event_info)
|
|||||||
return returnCode;
|
return returnCode;
|
||||||
|
|
||||||
pgstat_report_wait_start(wait_event_info);
|
pgstat_report_wait_start(wait_event_info);
|
||||||
returnCode = ftruncate(VfdCache[file].fd, offset);
|
returnCode = pg_ftruncate(VfdCache[file].fd, offset);
|
||||||
pgstat_report_wait_end();
|
pgstat_report_wait_end();
|
||||||
|
|
||||||
if (returnCode == 0 && VfdCache[file].fileSize > offset)
|
if (returnCode == 0 && VfdCache[file].fileSize > offset)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user