mirror of
https://github.com/postgres/postgres.git
synced 2025-08-09 17:03:00 +03:00
This patch fixes a couple of low-probability bugs that could lead to reporting an irrelevant errno value (and hence possibly a wrong SQLSTATE) concerning directory-open or file-open failures. It also fixes places where we took shortcuts in reporting such errors, either by using elog instead of ereport or by using ereport but forgetting to specify an errcode. And it eliminates a lot of just plain redundant error-handling code. In service of all this, export fd.c's formerly-static function ReadDirExtended, so that external callers can make use of the coding pattern dir = AllocateDir(path); while ((de = ReadDirExtended(dir, path, LOG)) != NULL) if they'd like to treat directory-open failures as mere LOG conditions rather than errors. Also fix FreeDir to be a no-op if we reach it with dir == NULL, as such a coding pattern would cause. Then, remove code at many call sites that was throwing an error or log message for AllocateDir failure, as ReadDir or ReadDirExtended can handle that job just fine. Aside from being a net code savings, this gets rid of a lot of not-quite-up-to-snuff reports, as mentioned above. (In some places these changes result in replacing a custom error message such as "could not open tablespace directory" with more generic wording "could not open directory", but it was agreed that the custom wording buys little as long as we report the directory name.) In some other call sites where we can't just remove code, change the error reports to be fully project-style-compliant. Also reorder code in restoreTwoPhaseData that was acquiring a lock between AllocateDir and ReadDir; in the unlikely but surely not impossible case that LWLockAcquire changes errno, AllocateDir failures would be misreported. There is no great value in opening the directory before acquiring TwoPhaseStateLock, so just do it in the other order. Also fix CheckXLogRemoved to guarantee that it preserves errno, as quite a number of call sites are implicitly assuming. (Again, it's unlikely but I think not impossible that errno could change during a SpinLockAcquire. If so, this function was broken for its own purposes as well as breaking callers.) And change a few places that were using not-per-project-style messages, such as "could not read directory" when "could not open directory" is more correct. Back-patch the exporting of ReadDirExtended, in case we have occasion to back-patch some fix that makes use of it; it's not needed right now but surely making it global is pretty harmless. Also back-patch the restoreTwoPhaseData and CheckXLogRemoved fixes. The rest of this is essentially cosmetic and need not get back-patched. Michael Paquier, with a bit of additional work by me Discussion: https://postgr.es/m/CAB7nPqRpOCxjiirHmebEFhXVTK7V5Jvw4bz82p7Oimtsm3TyZA@mail.gmail.com
133 lines
4.5 KiB
C
133 lines
4.5 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* fd.h
|
|
* Virtual file descriptor definitions.
|
|
*
|
|
*
|
|
* Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* src/include/storage/fd.h
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
/*
|
|
* calls:
|
|
*
|
|
* File {Close, Read, Write, Seek, Tell, Sync}
|
|
* {Path Name Open, Allocate, Free} File
|
|
*
|
|
* These are NOT JUST RENAMINGS OF THE UNIX ROUTINES.
|
|
* Use them for all file activity...
|
|
*
|
|
* File fd;
|
|
* fd = PathNameOpenFile("foo", O_RDONLY, 0600);
|
|
*
|
|
* AllocateFile();
|
|
* FreeFile();
|
|
*
|
|
* Use AllocateFile, not fopen, if you need a stdio file (FILE*); then
|
|
* use FreeFile, not fclose, to close it. AVOID using stdio for files
|
|
* that you intend to hold open for any length of time, since there is
|
|
* no way for them to share kernel file descriptors with other files.
|
|
*
|
|
* Likewise, use AllocateDir/FreeDir, not opendir/closedir, to allocate
|
|
* open directories (DIR*), and OpenTransientFile/CloseTransient File for an
|
|
* unbuffered file descriptor.
|
|
*/
|
|
#ifndef FD_H
|
|
#define FD_H
|
|
|
|
#include <dirent.h>
|
|
|
|
|
|
/*
|
|
* FileSeek uses the standard UNIX lseek(2) flags.
|
|
*/
|
|
|
|
typedef char *FileName;
|
|
|
|
typedef int File;
|
|
|
|
|
|
/* GUC parameter */
|
|
extern int max_files_per_process;
|
|
|
|
/*
|
|
* This is private to fd.c, but exported for save/restore_backend_variables()
|
|
*/
|
|
extern int max_safe_fds;
|
|
|
|
|
|
/*
|
|
* prototypes for functions in fd.c
|
|
*/
|
|
|
|
/* Operations on virtual Files --- equivalent to Unix kernel file ops */
|
|
extern File PathNameOpenFile(FileName fileName, int fileFlags, int fileMode);
|
|
extern File OpenTemporaryFile(bool interXact);
|
|
extern void FileClose(File file);
|
|
extern int FilePrefetch(File file, off_t offset, int amount, uint32 wait_event_info);
|
|
extern int FileRead(File file, char *buffer, int amount, uint32 wait_event_info);
|
|
extern int FileWrite(File file, char *buffer, int amount, uint32 wait_event_info);
|
|
extern int FileSync(File file, uint32 wait_event_info);
|
|
extern off_t FileSeek(File file, off_t offset, int whence);
|
|
extern int FileTruncate(File file, off_t offset, uint32 wait_event_info);
|
|
extern void FileWriteback(File file, off_t offset, off_t nbytes, uint32 wait_event_info);
|
|
extern char *FilePathName(File file);
|
|
extern int FileGetRawDesc(File file);
|
|
extern int FileGetRawFlags(File file);
|
|
extern int FileGetRawMode(File file);
|
|
|
|
/* Operations that allow use of regular stdio --- USE WITH CAUTION */
|
|
extern FILE *AllocateFile(const char *name, const char *mode);
|
|
extern int FreeFile(FILE *file);
|
|
|
|
/* Operations that allow use of pipe streams (popen/pclose) */
|
|
extern FILE *OpenPipeStream(const char *command, const char *mode);
|
|
extern int ClosePipeStream(FILE *file);
|
|
|
|
/* Operations to allow use of the <dirent.h> library routines */
|
|
extern DIR *AllocateDir(const char *dirname);
|
|
extern struct dirent *ReadDir(DIR *dir, const char *dirname);
|
|
extern struct dirent *ReadDirExtended(DIR *dir, const char *dirname,
|
|
int elevel);
|
|
extern int FreeDir(DIR *dir);
|
|
|
|
/* Operations to allow use of a plain kernel FD, with automatic cleanup */
|
|
extern int OpenTransientFile(FileName fileName, int fileFlags, int fileMode);
|
|
extern int CloseTransientFile(int fd);
|
|
|
|
/* If you've really really gotta have a plain kernel FD, use this */
|
|
extern int BasicOpenFile(FileName fileName, int fileFlags, int fileMode);
|
|
|
|
/* Miscellaneous support routines */
|
|
extern void InitFileAccess(void);
|
|
extern void set_max_safe_fds(void);
|
|
extern void closeAllVfds(void);
|
|
extern void SetTempTablespaces(Oid *tableSpaces, int numSpaces);
|
|
extern bool TempTablespacesAreSet(void);
|
|
extern Oid GetNextTempTableSpace(void);
|
|
extern void AtEOXact_Files(void);
|
|
extern void AtEOSubXact_Files(bool isCommit, SubTransactionId mySubid,
|
|
SubTransactionId parentSubid);
|
|
extern void RemovePgTempFiles(void);
|
|
|
|
extern int pg_fsync(int fd);
|
|
extern int pg_fsync_no_writethrough(int fd);
|
|
extern int pg_fsync_writethrough(int fd);
|
|
extern int pg_fdatasync(int fd);
|
|
extern void pg_flush_data(int fd, off_t offset, off_t amount);
|
|
extern void fsync_fname(const char *fname, bool isdir);
|
|
extern int durable_rename(const char *oldfile, const char *newfile, int loglevel);
|
|
extern int durable_unlink(const char *fname, int loglevel);
|
|
extern int durable_link_or_rename(const char *oldfile, const char *newfile, int loglevel);
|
|
extern void SyncDataDirectory(void);
|
|
|
|
/* Filename components for OpenTemporaryFile */
|
|
#define PG_TEMP_FILES_DIR "pgsql_tmp"
|
|
#define PG_TEMP_FILE_PREFIX "pgsql_tmp"
|
|
|
|
#endif /* FD_H */
|