Skip to content

Commit 7a57a67

Browse files
committed
Replace opendir/closedir calls throughout the backend with AllocateDir
and FreeDir routines modeled on the existing AllocateFile/FreeFile. Like the latter, these routines will avoid failing on EMFILE/ENFILE conditions whenever possible, and will prevent leakage of directory descriptors if an elog() occurs while one is open. Also, reduce PANIC to ERROR in MoveOfflineLogs() --- this is not critical code and there is no reason to force a DB restart on failure. All per recent trouble report from Olivier Hubaut.
1 parent 4f57131 commit 7a57a67

File tree

6 files changed

+138
-41
lines changed

6 files changed

+138
-41
lines changed

contrib/dbsize/dbsize.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
#include "postgres.h"
22

33
#include <sys/types.h>
4-
#include <dirent.h>
54
#include <sys/stat.h>
65
#include <unistd.h>
7-
#include <errno.h>
86

97
#include "access/heapam.h"
108
#include "catalog/catalog.h"
119
#include "catalog/namespace.h"
1210
#include "commands/dbcommands.h"
1311
#include "fmgr.h"
12+
#include "storage/fd.h"
1413
#include "utils/builtins.h"
1514

1615

@@ -58,7 +57,7 @@ database_size(PG_FUNCTION_ARGS)
5857

5958
dbpath = GetDatabasePath(dbid);
6059

61-
dirdesc = opendir(dbpath);
60+
dirdesc = AllocateDir(dbpath);
6261
if (!dirdesc)
6362
ereport(ERROR,
6463
(errcode_for_file_access(),
@@ -93,7 +92,7 @@ database_size(PG_FUNCTION_ARGS)
9392
pfree(fullname);
9493
}
9594

96-
closedir(dirdesc);
95+
FreeDir(dirdesc);
9796

9897
PG_RETURN_INT64(totalsize);
9998
}

src/backend/access/transam/slru.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,13 @@
66
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
9-
* $PostgreSQL: pgsql/src/backend/access/transam/slru.c,v 1.12 2004/02/17 03:45:17 momjian Exp $
9+
* $PostgreSQL: pgsql/src/backend/access/transam/slru.c,v 1.13 2004/02/23 23:03:10 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
1313
#include "postgres.h"
1414

1515
#include <fcntl.h>
16-
#include <dirent.h>
17-
#include <errno.h>
1816
#include <sys/stat.h>
1917
#include <unistd.h>
2018

@@ -888,7 +886,7 @@ SlruScanDirectory(SlruCtl ctl, int cutoffPage, bool doDeletions)
888886
int segpage;
889887
char path[MAXPGPATH];
890888

891-
cldir = opendir(ctl->Dir);
889+
cldir = AllocateDir(ctl->Dir);
892890
if (cldir == NULL)
893891
ereport(ERROR,
894892
(errcode_for_file_access(),
@@ -927,7 +925,7 @@ SlruScanDirectory(SlruCtl ctl, int cutoffPage, bool doDeletions)
927925
ereport(ERROR,
928926
(errcode_for_file_access(),
929927
errmsg("could not read directory \"%s\": %m", ctl->Dir)));
930-
closedir(cldir);
928+
FreeDir(cldir);
931929

932930
return found;
933931
}

src/backend/access/transam/xlog.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.136 2004/02/17 03:45:17 momjian Exp $
10+
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.137 2004/02/23 23:03:10 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -17,10 +17,8 @@
1717
#include <fcntl.h>
1818
#include <signal.h>
1919
#include <unistd.h>
20-
#include <errno.h>
2120
#include <sys/stat.h>
2221
#include <sys/time.h>
23-
#include <dirent.h>
2422

2523
#include "access/clog.h"
2624
#include "access/transam.h"
@@ -1753,9 +1751,9 @@ MoveOfflineLogs(uint32 log, uint32 seg, XLogRecPtr endptr)
17531751

17541752
XLByteToPrevSeg(endptr, endlogId, endlogSeg);
17551753

1756-
xldir = opendir(XLogDir);
1754+
xldir = AllocateDir(XLogDir);
17571755
if (xldir == NULL)
1758-
ereport(PANIC,
1756+
ereport(ERROR,
17591757
(errcode_for_file_access(),
17601758
errmsg("could not open transaction log directory \"%s\": %m",
17611759
XLogDir)));
@@ -1812,11 +1810,11 @@ MoveOfflineLogs(uint32 log, uint32 seg, XLogRecPtr endptr)
18121810
errno = 0;
18131811
#endif
18141812
if (errno)
1815-
ereport(PANIC,
1813+
ereport(ERROR,
18161814
(errcode_for_file_access(),
18171815
errmsg("could not read transaction log directory \"%s\": %m",
18181816
XLogDir)));
1819-
closedir(xldir);
1817+
FreeDir(xldir);
18201818
}
18211819

18221820
/*

src/backend/storage/file/fd.c

Lines changed: 109 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/src/backend/storage/file/fd.c,v 1.107 2004/02/23 20:45:59 tgl Exp $
10+
* $PostgreSQL: pgsql/src/backend/storage/file/fd.c,v 1.108 2004/02/23 23:03:10 tgl Exp $
1111
*
1212
* NOTES:
1313
*
@@ -43,8 +43,6 @@
4343
#include <sys/file.h>
4444
#include <sys/param.h>
4545
#include <sys/stat.h>
46-
#include <dirent.h>
47-
#include <errno.h>
4846
#include <unistd.h>
4947
#include <fcntl.h>
5048

@@ -87,11 +85,11 @@ int max_files_per_process = 1000;
8785

8886
/*
8987
* Maximum number of file descriptors to open for either VFD entries or
90-
* AllocateFile files. This is initialized to a conservative value, and
91-
* remains that way indefinitely in bootstrap or standalone-backend cases.
92-
* In normal postmaster operation, the postmaster calls set_max_safe_fds()
93-
* late in initialization to update the value, and that value is then
94-
* inherited by forked subprocesses.
88+
* AllocateFile/AllocateDir operations. This is initialized to a conservative
89+
* value, and remains that way indefinitely in bootstrap or standalone-backend
90+
* cases. In normal postmaster operation, the postmaster calls
91+
* set_max_safe_fds() late in initialization to update the value, and that
92+
* value is then inherited by forked subprocesses.
9593
*
9694
* Note: the value of max_files_per_process is taken into account while
9795
* setting this variable, and so need not be tested separately.
@@ -159,6 +157,17 @@ static int nfile = 0;
159157
static int numAllocatedFiles = 0;
160158
static FILE *allocatedFiles[MAX_ALLOCATED_FILES];
161159

160+
/*
161+
* List of <dirent.h> DIRs opened with AllocateDir.
162+
*
163+
* Since we don't have heavy use of AllocateDir, it seems OK to put a pretty
164+
* small maximum limit on the number of simultaneously allocated dirs.
165+
*/
166+
#define MAX_ALLOCATED_DIRS 10
167+
168+
static int numAllocatedDirs = 0;
169+
static DIR *allocatedDirs[MAX_ALLOCATED_DIRS];
170+
162171
/*
163172
* Number of temporary files opened during the current session;
164173
* this is used in generation of tempfile names.
@@ -489,7 +498,7 @@ LruInsert(File file)
489498

490499
if (FileIsNotOpen(file))
491500
{
492-
while (nfile + numAllocatedFiles >= max_safe_fds)
501+
while (nfile + numAllocatedFiles + numAllocatedDirs >= max_safe_fds)
493502
{
494503
if (!ReleaseLruFile())
495504
break;
@@ -748,7 +757,7 @@ fileNameOpenFile(FileName fileName,
748757
file = AllocateVfd();
749758
vfdP = &VfdCache[file];
750759

751-
while (nfile + numAllocatedFiles >= max_safe_fds)
760+
while (nfile + numAllocatedFiles + numAllocatedDirs >= max_safe_fds)
752761
{
753762
if (!ReleaseLruFile())
754763
break;
@@ -1099,8 +1108,8 @@ AllocateFile(char *name, char *mode)
10991108
* looping.
11001109
*/
11011110
if (numAllocatedFiles >= MAX_ALLOCATED_FILES ||
1102-
numAllocatedFiles >= max_safe_fds - 1)
1103-
elog(ERROR, "too many private FDs demanded");
1111+
numAllocatedFiles + numAllocatedDirs >= max_safe_fds - 1)
1112+
elog(ERROR, "too many private files demanded");
11041113

11051114
TryAgain:
11061115
if ((file = fopen(name, mode)) != NULL)
@@ -1155,6 +1164,86 @@ FreeFile(FILE *file)
11551164
return fclose(file);
11561165
}
11571166

1167+
1168+
/*
1169+
* Routines that want to use <dirent.h> (ie, DIR*) should use AllocateDir
1170+
* rather than plain opendir(). This lets fd.c deal with freeing FDs if
1171+
* necessary to open the directory, and with closing it after an elog.
1172+
* When done, call FreeDir rather than closedir.
1173+
*
1174+
* Ideally this should be the *only* direct call of opendir() in the backend.
1175+
*/
1176+
DIR *
1177+
AllocateDir(const char *dirname)
1178+
{
1179+
DIR *dir;
1180+
1181+
DO_DB(elog(LOG, "AllocateDir: Allocated %d", numAllocatedDirs));
1182+
1183+
/*
1184+
* The test against MAX_ALLOCATED_DIRS prevents us from overflowing
1185+
* allocatedDirs[]; the test against max_safe_fds prevents AllocateDir
1186+
* from hogging every one of the available FDs, which'd lead to infinite
1187+
* looping.
1188+
*/
1189+
if (numAllocatedDirs >= MAX_ALLOCATED_DIRS ||
1190+
numAllocatedDirs + numAllocatedFiles >= max_safe_fds - 1)
1191+
elog(ERROR, "too many private dirs demanded");
1192+
1193+
TryAgain:
1194+
if ((dir = opendir(dirname)) != NULL)
1195+
{
1196+
allocatedDirs[numAllocatedDirs] = dir;
1197+
numAllocatedDirs++;
1198+
return dir;
1199+
}
1200+
1201+
if (errno == EMFILE || errno == ENFILE)
1202+
{
1203+
int save_errno = errno;
1204+
1205+
ereport(LOG,
1206+
(errcode(ERRCODE_INSUFFICIENT_RESOURCES),
1207+
errmsg("out of file descriptors: %m; release and retry")));
1208+
errno = 0;
1209+
if (ReleaseLruFile())
1210+
goto TryAgain;
1211+
errno = save_errno;
1212+
}
1213+
1214+
return NULL;
1215+
}
1216+
1217+
/*
1218+
* Close a directory opened with AllocateDir.
1219+
*
1220+
* Note we do not check closedir's return value --- it is up to the caller
1221+
* to handle close errors.
1222+
*/
1223+
int
1224+
FreeDir(DIR *dir)
1225+
{
1226+
int i;
1227+
1228+
DO_DB(elog(LOG, "FreeDir: Allocated %d", numAllocatedDirs));
1229+
1230+
/* Remove dir from list of allocated dirs, if it's present */
1231+
for (i = numAllocatedDirs; --i >= 0;)
1232+
{
1233+
if (allocatedDirs[i] == dir)
1234+
{
1235+
numAllocatedDirs--;
1236+
allocatedDirs[i] = allocatedDirs[numAllocatedDirs];
1237+
break;
1238+
}
1239+
}
1240+
if (i < 0)
1241+
elog(WARNING, "dir passed to FreeDir was not obtained from AllocateDir");
1242+
1243+
return closedir(dir);
1244+
}
1245+
1246+
11581247
/*
11591248
* closeAllVfds
11601249
*
@@ -1211,7 +1300,7 @@ AtProcExit_Files(int code, Datum arg)
12111300
* exiting. If that's the case, we should remove all temporary files; if
12121301
* that's not the case, we are being called for transaction commit/abort
12131302
* and should only remove transaction-local temp files. In either case,
1214-
* also clean up "allocated" stdio files.
1303+
* also clean up "allocated" stdio files and dirs.
12151304
*/
12161305
static void
12171306
CleanupTempFiles(bool isProcExit)
@@ -1240,6 +1329,9 @@ CleanupTempFiles(bool isProcExit)
12401329

12411330
while (numAllocatedFiles > 0)
12421331
FreeFile(allocatedFiles[0]);
1332+
1333+
while (numAllocatedDirs > 0)
1334+
FreeDir(allocatedDirs[0]);
12431335
}
12441336

12451337

@@ -1271,7 +1363,7 @@ RemovePgTempFiles(void)
12711363
* files.
12721364
*/
12731365
snprintf(db_path, sizeof(db_path), "%s/base", DataDir);
1274-
if ((db_dir = opendir(db_path)) != NULL)
1366+
if ((db_dir = AllocateDir(db_path)) != NULL)
12751367
{
12761368
while ((db_de = readdir(db_dir)) != NULL)
12771369
{
@@ -1287,7 +1379,7 @@ RemovePgTempFiles(void)
12871379
"%s/%s/%s",
12881380
db_path, db_de->d_name,
12891381
PG_TEMP_FILES_DIR);
1290-
if ((temp_dir = opendir(temp_path)) != NULL)
1382+
if ((temp_dir = AllocateDir(temp_path)) != NULL)
12911383
{
12921384
while ((temp_de = readdir(temp_dir)) != NULL)
12931385
{
@@ -1310,9 +1402,9 @@ RemovePgTempFiles(void)
13101402
"unexpected file found in temporary-files directory: \"%s\"",
13111403
rm_path);
13121404
}
1313-
closedir(temp_dir);
1405+
FreeDir(temp_dir);
13141406
}
13151407
}
1316-
closedir(db_dir);
1408+
FreeDir(db_dir);
13171409
}
13181410
}

src/include/storage/fd.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/storage/fd.h,v 1.43 2004/02/23 20:45:59 tgl Exp $
10+
* $PostgreSQL: pgsql/src/include/storage/fd.h,v 1.44 2004/02/23 23:03:10 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -31,10 +31,16 @@
3131
* use FreeFile, not fclose, to close it. AVOID using stdio for files
3232
* that you intend to hold open for any length of time, since there is
3333
* no way for them to share kernel file descriptors with other files.
34+
*
35+
* Likewise, use AllocateDir/FreeDir, not opendir/closedir, to allocate
36+
* open directories (DIR*).
3437
*/
3538
#ifndef FD_H
3639
#define FD_H
3740

41+
#include <dirent.h>
42+
43+
3844
/*
3945
* FileSeek uses the standard UNIX lseek(2) flags.
4046
*/
@@ -65,7 +71,11 @@ extern int FileTruncate(File file, long offset);
6571

6672
/* Operations that allow use of regular stdio --- USE WITH CAUTION */
6773
extern FILE *AllocateFile(char *name, char *mode);
68-
extern int FreeFile(FILE *);
74+
extern int FreeFile(FILE *file);
75+
76+
/* Operations to allow use of the <dirent.h> library routines */
77+
extern DIR *AllocateDir(const char *dirname);
78+
extern int FreeDir(DIR *dir);
6979

7080
/* If you've really really gotta have a plain kernel FD, use this */
7181
extern int BasicOpenFile(FileName fileName, int fileFlags, int fileMode);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy