aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Paquier <michael@paquier.xyz>2020-02-27 15:31:27 +0900
committerMichael Paquier <michael@paquier.xyz>2020-02-27 15:31:27 +0900
commit428a2609ef64b69d709418a50e192ff11a2643f1 (patch)
tree6c6c218647be0df3bc2d06dea42ae2cb710ca0a0
parent05d8449e73694585b59f8b03aaa087f04cc4679a (diff)
downloadpostgresql-428a2609ef64b69d709418a50e192ff11a2643f1.tar.gz
postgresql-428a2609ef64b69d709418a50e192ff11a2643f1.zip
Skip foreign tablespaces when running pg_checksums/pg_verify_checksums
Attempting to use pg_checksums (pg_verify_checksums in 11) on a data folder which includes tablespace paths used across multiple major versions would cause pg_checksums to scan all directories present in pg_tblspc, and not only marked with TABLESPACE_VERSION_DIRECTORY. This could lead to failures when for example running sanity checks on an upgraded instance with --check. Even worse, it was possible to rewrite on-disk pages with --enable for a cluster potentially online. This commit makes pg_checksums skip any directories not named TABLESPACE_VERSION_DIRECTORY, similarly to what is done for base backups. Reported-by: Michael Banck Author: Michael Banck, Bernd Helmle Discussion: https://postgr.es/m/62031974fd8e941dd8351fbc8c7eff60d59c5338.camel@credativ.de backpatch-through: 11
-rw-r--r--src/bin/pg_checksums/pg_checksums.c47
-rw-r--r--src/bin/pg_checksums/t/002_actions.pl9
2 files changed, 54 insertions, 2 deletions
diff --git a/src/bin/pg_checksums/pg_checksums.c b/src/bin/pg_checksums/pg_checksums.c
index 9bd0bf947f7..eb179500960 100644
--- a/src/bin/pg_checksums/pg_checksums.c
+++ b/src/bin/pg_checksums/pg_checksums.c
@@ -385,7 +385,52 @@ 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 going through the entries of pg_tblspc, we assume to operate
+ * on tablespace locations where only TABLESPACE_VERSION_DIRECTORY
+ * is valid, resolving the linked locations 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
+ * TABLESPACE_VERSION_DIRECTORY exists. Not finding a valid
+ * location is unexpected, since there should be no orphaned
+ * links and no links pointing to something else than a
+ * directory.
+ */
+ 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("could not stat file \"%s\": %m",
+ tblspc_path);
+ exit(1);
+ }
+
+ /*
+ * Move backwards once as the scan needs to happen for the
+ * contents of TABLESPACE_VERSION_DIRECTORY.
+ */
+ 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;
diff --git a/src/bin/pg_checksums/t/002_actions.pl b/src/bin/pg_checksums/t/002_actions.pl
index 83a730ea947..4e4934532a3 100644
--- a/src/bin/pg_checksums/t/002_actions.pl
+++ b/src/bin/pg_checksums/t/002_actions.pl
@@ -5,7 +5,7 @@ use strict;
use warnings;
use PostgresNode;
use TestLib;
-use Test::More tests => 62;
+use Test::More tests => 63;
# Utility routine to create and check a table with corrupted checksums
@@ -217,6 +217,13 @@ sub fail_corrupt
# Stop instance for the follow-up checks.
$node->stop;
+# Create a fake tablespace location that should not be scanned
+# when verifying checksums.
+mkdir "$tablespace_dir/PG_99_999999991/";
+append_to_file "$tablespace_dir/PG_99_999999991/foo", "123";
+command_ok([ 'pg_checksums', '--check', '-D', $pgdata ],
+ "succeeds with foreign tablespace");
+
# Authorized relation files filled with corrupted data cause the
# checksum checks to fail. Make sure to use file names different
# than the previous ones.