Skip to content

Commit 428a260

Browse files
committed
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
1 parent 05d8449 commit 428a260

File tree

2 files changed

+54
-2
lines changed

2 files changed

+54
-2
lines changed

src/bin/pg_checksums/pg_checksums.c

+46-1
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,52 @@ scan_directory(const char *basedir, const char *subdir, bool sizeonly)
385385
#else
386386
else if (S_ISDIR(st.st_mode) || pgwin32_is_junction(fn))
387387
#endif
388-
dirsize += scan_directory(path, de->d_name, sizeonly);
388+
{
389+
/*
390+
* If going through the entries of pg_tblspc, we assume to operate
391+
* on tablespace locations where only TABLESPACE_VERSION_DIRECTORY
392+
* is valid, resolving the linked locations and dive into them
393+
* directly.
394+
*/
395+
if (strncmp("pg_tblspc", subdir, strlen("pg_tblspc")) == 0)
396+
{
397+
char tblspc_path[MAXPGPATH];
398+
struct stat tblspc_st;
399+
400+
/*
401+
* Resolve tablespace location path and check whether
402+
* TABLESPACE_VERSION_DIRECTORY exists. Not finding a valid
403+
* location is unexpected, since there should be no orphaned
404+
* links and no links pointing to something else than a
405+
* directory.
406+
*/
407+
snprintf(tblspc_path, sizeof(tblspc_path), "%s/%s/%s",
408+
path, de->d_name, TABLESPACE_VERSION_DIRECTORY);
409+
410+
if (lstat(tblspc_path, &tblspc_st) < 0)
411+
{
412+
pg_log_error("could not stat file \"%s\": %m",
413+
tblspc_path);
414+
exit(1);
415+
}
416+
417+
/*
418+
* Move backwards once as the scan needs to happen for the
419+
* contents of TABLESPACE_VERSION_DIRECTORY.
420+
*/
421+
snprintf(tblspc_path, sizeof(tblspc_path), "%s/%s",
422+
path, de->d_name);
423+
424+
/* Looks like a valid tablespace location */
425+
dirsize += scan_directory(tblspc_path,
426+
TABLESPACE_VERSION_DIRECTORY,
427+
sizeonly);
428+
}
429+
else
430+
{
431+
dirsize += scan_directory(path, de->d_name, sizeonly);
432+
}
433+
}
389434
}
390435
closedir(dir);
391436
return dirsize;

src/bin/pg_checksums/t/002_actions.pl

+8-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use warnings;
66
use PostgresNode;
77
use TestLib;
8-
use Test::More tests => 62;
8+
use Test::More tests => 63;
99

1010

1111
# Utility routine to create and check a table with corrupted checksums
@@ -217,6 +217,13 @@ sub fail_corrupt
217217
# Stop instance for the follow-up checks.
218218
$node->stop;
219219

220+
# Create a fake tablespace location that should not be scanned
221+
# when verifying checksums.
222+
mkdir "$tablespace_dir/PG_99_999999991/";
223+
append_to_file "$tablespace_dir/PG_99_999999991/foo", "123";
224+
command_ok([ 'pg_checksums', '--check', '-D', $pgdata ],
225+
"succeeds with foreign tablespace");
226+
220227
# Authorized relation files filled with corrupted data cause the
221228
# checksum checks to fail. Make sure to use file names different
222229
# than the previous ones.

0 commit comments

Comments
 (0)