From 15bd3a6457f59f3ba4bf72c645499132e90127cd Mon Sep 17 00:00:00 2001 From: Bernd Helmle Date: Wed, 26 Feb 2020 16:49:03 +0100 Subject: [PATCH 1/2] Formerly pg_checksums recursively dived into pg_tblspc, scanning any tablespace location found there without taking into account, that tablespace locations might be used by other PostgreSQL instances at the same time. This could likely happen for example by using pg_upgrade to upgrade clusters with tablespaces. Fix this by resolving tablespace locations explicitly by looking up their TABLESPACE_VERSION_DIRECTORY subdirectory if called on the pg_tblspc directory, and, if found, recursively diving into them directly. If we can't resolve the tablespace location link, we throw an error to indicate a probably orphaned or missing tablespace location. --- src/bin/pg_checksums/pg_checksums.c | 43 ++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/bin/pg_checksums/pg_checksums.c b/src/bin/pg_checksums/pg_checksums.c index 9bd0bf947f..1367f53bbf 100644 --- a/src/bin/pg_checksums/pg_checksums.c +++ b/src/bin/pg_checksums/pg_checksums.c @@ -385,7 +385,48 @@ scan_directory(const char *basedir, const char *subdir, bool sizeonly) #else else if (S_ISDIR(st.st_mode) || pgwin32_is_junction(fn)) #endif - dirsize += scan_directory(path, de->d_name, sizeonly); + { + /* + * If we are called with subdir pg_tblspc, we assume to + * operate on tablespace locations. We're just interested + * in TABLESPACE_VERSION_DIRECTORY only, so we're resolving + * the linked locations here explicitely and dive into them + * directly. + */ + if (strncmp("pg_tblspc", subdir, strlen("pg_tblspc")) == 0) + { + char tblspc_path[MAXPGPATH]; + struct stat tblspc_st; + + /* + * Resolve tablespace location path and check + * whether a TABLESPACE_VERSION_DIRECTORY exists. Not finding + * a valid location is an unexpected condition, since there + * shouldn't be orphaned links. Tell the user something + * is wrong. + */ + snprintf(tblspc_path, sizeof(tblspc_path), "%s/%s/%s", + path, de->d_name, TABLESPACE_VERSION_DIRECTORY); + + if (lstat(tblspc_path, &tblspc_st) < 0) + { + pg_log_error("invalid tablespace location \"%s/%s\"", + subdir, de->d_name); + exit(1); + } + + snprintf(tblspc_path, sizeof(tblspc_path), "%s/%s", + path, de->d_name); + + /* Looks like a valid tablespace location */ + dirsize += scan_directory(tblspc_path, TABLESPACE_VERSION_DIRECTORY, + sizeonly); + } + else + { + dirsize += scan_directory(path, de->d_name, sizeonly); + } + } } closedir(dir); return dirsize; -- 2.24.1