Skip to content

Commit 0d369ac

Browse files
committed
fd.c: Retry after EINTR in more places
Starting with 4d330a6 we can use posix_fallocate() to extend files. Unfortunately in some situation, e.g. on tmpfs filesystems, EINTR may be returned. See also 4518c79. To fix, add a retry path to FileFallocate(). In contrast to 4518c79 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: -
1 parent 797f980 commit 0d369ac

File tree

1 file changed

+61
-12
lines changed
  • src/backend/storage/file

1 file changed

+61
-12
lines changed

src/backend/storage/file/fd.c

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -415,10 +415,18 @@ pg_fsync(int fd)
415415
int
416416
pg_fsync_no_writethrough(int fd)
417417
{
418-
if (enableFsync)
419-
return fsync(fd);
420-
else
418+
int rc;
419+
420+
if (!enableFsync)
421421
return 0;
422+
423+
retry:
424+
rc = fsync(fd);
425+
426+
if (rc == -1 && errno == EINTR)
427+
goto retry;
428+
429+
return rc;
422430
}
423431

424432
/*
@@ -448,10 +456,18 @@ pg_fsync_writethrough(int fd)
448456
int
449457
pg_fdatasync(int fd)
450458
{
451-
if (enableFsync)
452-
return fdatasync(fd);
453-
else
459+
int rc;
460+
461+
if (!enableFsync)
454462
return 0;
463+
464+
retry:
465+
rc = fdatasync(fd);
466+
467+
if (rc == -1 && errno == EINTR)
468+
goto retry;
469+
470+
return rc;
455471
}
456472

457473
/*
@@ -483,6 +499,7 @@ pg_flush_data(int fd, off_t offset, off_t nbytes)
483499
if (not_implemented_by_kernel)
484500
return;
485501

502+
retry:
486503
/*
487504
* sync_file_range(SYNC_FILE_RANGE_WRITE), currently linux specific,
488505
* 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)
498515
{
499516
int elevel;
500517

518+
if (rc == EINTR)
519+
goto retry;
520+
501521
/*
502522
* For systems that don't have an implementation of
503523
* 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)
629649
#endif
630650
}
631651

652+
/*
653+
* Truncate an open file to a given length.
654+
*/
655+
static int
656+
pg_ftruncate(int fd, off_t length)
657+
{
658+
int ret;
659+
660+
retry:
661+
ret = ftruncate(fd, length);
662+
663+
if (ret == -1 && errno == EINTR)
664+
goto retry;
665+
666+
return ret;
667+
}
668+
632669
/*
633670
* Truncate a file to a given length by name.
634671
*/
635672
int
636673
pg_truncate(const char *path, off_t length)
637674
{
675+
int ret;
638676
#ifdef WIN32
639677
int save_errno;
640-
int ret;
641678
int fd;
642679

643680
fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
644681
if (fd >= 0)
645682
{
646-
ret = ftruncate(fd, length);
683+
ret = pg_ftruncate(fd, length);
647684
save_errno = errno;
648685
CloseTransientFile(fd);
649686
errno = save_errno;
650687
}
651688
else
652689
ret = -1;
653-
654-
return ret;
655690
#else
656-
return truncate(path, length);
691+
692+
retry:
693+
ret = truncate(path, length);
694+
695+
if (ret == -1 && errno == EINTR)
696+
goto retry;
657697
#endif
698+
699+
return ret;
658700
}
659701

660702
/*
@@ -2001,11 +2043,15 @@ FilePrefetch(File file, off_t offset, off_t amount, uint32 wait_event_info)
20012043
if (returnCode < 0)
20022044
return returnCode;
20032045

2046+
retry:
20042047
pgstat_report_wait_start(wait_event_info);
20052048
returnCode = posix_fadvise(VfdCache[file].fd, offset, amount,
20062049
POSIX_FADV_WILLNEED);
20072050
pgstat_report_wait_end();
20082051

2052+
if (returnCode == EINTR)
2053+
goto retry;
2054+
20092055
return returnCode;
20102056
#else
20112057
Assert(FileIsValid(file));
@@ -2281,12 +2327,15 @@ FileFallocate(File file, off_t offset, off_t amount, uint32 wait_event_info)
22812327
if (returnCode < 0)
22822328
return -1;
22832329

2330+
retry:
22842331
pgstat_report_wait_start(wait_event_info);
22852332
returnCode = posix_fallocate(VfdCache[file].fd, offset, amount);
22862333
pgstat_report_wait_end();
22872334

22882335
if (returnCode == 0)
22892336
return 0;
2337+
else if (returnCode == EINTR)
2338+
goto retry;
22902339

22912340
/* for compatibility with %m printing etc */
22922341
errno = returnCode;
@@ -2334,7 +2383,7 @@ FileTruncate(File file, off_t offset, uint32 wait_event_info)
23342383
return returnCode;
23352384

23362385
pgstat_report_wait_start(wait_event_info);
2337-
returnCode = ftruncate(VfdCache[file].fd, offset);
2386+
returnCode = pg_ftruncate(VfdCache[file].fd, offset);
23382387
pgstat_report_wait_end();
23392388

23402389
if (returnCode == 0 && VfdCache[file].fileSize > offset)

0 commit comments

Comments
 (0)