Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * controldata_utils.c
4 : : * Common code for control data file output.
5 : : *
6 : : *
7 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
8 : : * Portions Copyright (c) 1994, Regents of the University of California
9 : : *
10 : : *
11 : : * IDENTIFICATION
12 : : * src/common/controldata_utils.c
13 : : *
14 : : *-------------------------------------------------------------------------
15 : : */
16 : :
17 : : #ifndef FRONTEND
18 : : #include "postgres.h"
19 : : #else
20 : : #include "postgres_fe.h"
21 : : #endif
22 : :
23 : : #include <unistd.h>
24 : : #include <sys/stat.h>
25 : : #include <fcntl.h>
26 : : #include <time.h>
27 : :
28 : : #include "access/xlog_internal.h"
29 : : #include "catalog/pg_control.h"
30 : : #include "common/controldata_utils.h"
31 : : #ifdef FRONTEND
32 : : #include "common/file_perm.h"
33 : : #include "common/logging.h"
34 : : #endif
35 : : #include "port/pg_crc32c.h"
36 : :
37 : : #ifndef FRONTEND
38 : : #include "pgstat.h"
39 : : #include "storage/fd.h"
40 : : #include "utils/wait_event.h"
41 : : #endif
42 : :
43 : : /*
44 : : * get_controlfile()
45 : : *
46 : : * Get controlfile values. The result is returned as a palloc'd copy of the
47 : : * control file data.
48 : : *
49 : : * crc_ok_p can be used by the caller to see whether the CRC of the control
50 : : * file data is correct.
51 : : */
52 : : ControlFileData *
2540 peter@eisentraut.org 53 :CBC 301 : get_controlfile(const char *DataDir, bool *crc_ok_p)
54 : : {
55 : : char ControlFilePath[MAXPGPATH];
56 : :
342 fujii@postgresql.org 57 : 301 : snprintf(ControlFilePath, MAXPGPATH, "%s/%s", DataDir, XLOG_CONTROL_FILE);
58 : :
732 rhaas@postgresql.org 59 : 301 : return get_controlfile_by_exact_path(ControlFilePath, crc_ok_p);
60 : : }
61 : :
62 : : /*
63 : : * get_controlfile_by_exact_path()
64 : : *
65 : : * As above, but the caller specifies the path to the control file itself,
66 : : * rather than the path to the data directory.
67 : : */
68 : : ControlFileData *
69 : 401 : get_controlfile_by_exact_path(const char *ControlFilePath, bool *crc_ok_p)
70 : : {
71 : : ControlFileData *ControlFile;
72 : : int fd;
73 : : pg_crc32c crc;
74 : : int r;
75 : : #ifdef FRONTEND
76 : : pg_crc32c last_crc;
881 tmunro@postgresql.or 77 : 370 : int retries = 0;
78 : : #endif
79 : :
1234 peter@eisentraut.org 80 [ - + ]: 401 : Assert(crc_ok_p);
81 : :
1280 82 : 401 : ControlFile = palloc_object(ControlFileData);
83 : :
84 : : #ifdef FRONTEND
881 tmunro@postgresql.or 85 : 370 : INIT_CRC32C(last_crc);
86 : :
87 : 371 : retry:
88 : : #endif
89 : :
90 : : #ifndef FRONTEND
2572 mail@joeconway.com 91 [ - + ]: 31 : if ((fd = OpenTransientFile(ControlFilePath, O_RDONLY | PG_BINARY)) == -1)
3660 mail@joeconway.com 92 [ # # ]:UBC 0 : ereport(ERROR,
93 : : (errcode_for_file_access(),
94 : : errmsg("could not open file \"%s\" for reading: %m",
95 : : ControlFilePath)));
96 : : #else
2572 mail@joeconway.com 97 [ + + ]:CBC 371 : if ((fd = open(ControlFilePath, O_RDONLY | PG_BINARY, 0)) == -1)
1437 tgl@sss.pgh.pa.us 98 : 1 : pg_fatal("could not open file \"%s\" for reading: %m",
99 : : ControlFilePath);
100 : : #endif
101 : :
2858 magnus@hagander.net 102 : 401 : r = read(fd, ControlFile, sizeof(ControlFileData));
103 [ - + ]: 401 : if (r != sizeof(ControlFileData))
104 : : {
2858 magnus@hagander.net 105 [ # # ]:UBC 0 : if (r < 0)
106 : : #ifndef FRONTEND
107 [ # # ]: 0 : ereport(ERROR,
108 : : (errcode_for_file_access(),
109 : : errmsg("could not read file \"%s\": %m", ControlFilePath)));
110 : : #else
1437 tgl@sss.pgh.pa.us 111 : 0 : pg_fatal("could not read file \"%s\": %m", ControlFilePath);
112 : : #endif
113 : : else
114 : : #ifndef FRONTEND
2858 magnus@hagander.net 115 [ # # ]: 0 : ereport(ERROR,
116 : : (errcode(ERRCODE_DATA_CORRUPTED),
117 : : errmsg("could not read file \"%s\": read %d of %zu",
118 : : ControlFilePath, r, sizeof(ControlFileData))));
119 : : #else
1437 tgl@sss.pgh.pa.us 120 : 0 : pg_fatal("could not read file \"%s\": read %d of %zu",
121 : : ControlFilePath, r, sizeof(ControlFileData));
122 : : #endif
123 : : }
124 : :
125 : : #ifndef FRONTEND
2444 peter@eisentraut.org 126 [ - + ]:CBC 31 : if (CloseTransientFile(fd) != 0)
2563 michael@paquier.xyz 127 [ # # ]:UBC 0 : ereport(ERROR,
128 : : (errcode_for_file_access(),
129 : : errmsg("could not close file \"%s\": %m",
130 : : ControlFilePath)));
131 : : #else
2444 peter@eisentraut.org 132 [ - + ]:CBC 370 : if (close(fd) != 0)
1437 tgl@sss.pgh.pa.us 133 :UBC 0 : pg_fatal("could not close file \"%s\": %m", ControlFilePath);
134 : : #endif
135 : :
136 : : /* Check the CRC. */
3662 mail@joeconway.com 137 :CBC 401 : INIT_CRC32C(crc);
138 : 401 : COMP_CRC32C(crc,
139 : : ControlFile,
140 : : offsetof(ControlFileData, crc));
141 : 401 : FIN_CRC32C(crc);
142 : :
3455 peter_e@gmx.net 143 : 401 : *crc_ok_p = EQ_CRC32C(crc, ControlFile->crc);
144 : :
145 : : #ifdef FRONTEND
146 : :
147 : : /*
148 : : * If the server was writing at the same time, it is possible that we read
149 : : * partially updated contents on some systems. If the CRC doesn't match,
150 : : * retry a limited number of times until we compute the same bad CRC twice
151 : : * in a row with a short sleep in between. Then the failure is unlikely
152 : : * to be due to a concurrent write.
153 : : */
881 tmunro@postgresql.or 154 [ + + + + ]: 370 : if (!*crc_ok_p &&
155 [ - + + - ]: 2 : (retries == 0 || !EQ_CRC32C(crc, last_crc)) &&
156 : : retries < 10)
157 : : {
158 : 1 : retries++;
159 : 1 : last_crc = crc;
160 : 1 : pg_usleep(10000);
161 : 1 : goto retry;
162 : : }
163 : : #endif
164 : :
165 : : /* Make sure the control file is valid byte order. */
3662 mail@joeconway.com 166 [ - + ]: 400 : if (ControlFile->pg_control_version % 65536 == 0 &&
3662 mail@joeconway.com 167 [ # # ]:LBC (1) : ControlFile->pg_control_version / 65536 != 0)
168 : : #ifndef FRONTEND
3662 mail@joeconway.com 169 [ # # ]:UBC 0 : elog(ERROR, _("byte ordering mismatch"));
170 : : #else
2540 peter@eisentraut.org 171 : 0 : pg_log_warning("possible byte ordering mismatch\n"
172 : : "The byte ordering used to store the pg_control file might not match the one\n"
173 : : "used by this program. In that case the results below would be incorrect, and\n"
174 : : "the PostgreSQL installation would be incompatible with this data directory.");
175 : : #endif
176 : :
3662 mail@joeconway.com 177 :CBC 400 : return ControlFile;
178 : : }
179 : :
180 : : /*
181 : : * update_controlfile()
182 : : *
183 : : * Update controlfile values with the contents given by caller. The
184 : : * contents to write are included in "ControlFile". "do_sync" can be
185 : : * optionally used to flush the updated control file. Note that it is up
186 : : * to the caller to properly lock ControlFileLock when calling this
187 : : * routine in the backend.
188 : : */
189 : : void
2540 peter@eisentraut.org 190 : 9782 : update_controlfile(const char *DataDir,
191 : : ControlFileData *ControlFile, bool do_sync)
192 : : {
193 : : int fd;
194 : : char buffer[PG_CONTROL_FILE_SIZE];
195 : : char ControlFilePath[MAXPGPATH];
196 : :
197 : : /* Update timestamp */
1567 michael@paquier.xyz 198 : 9782 : ControlFile->time = (pg_time_t) time(NULL);
199 : :
200 : : /* Recalculate CRC of control file */
2560 201 : 9782 : INIT_CRC32C(ControlFile->crc);
202 : 9782 : COMP_CRC32C(ControlFile->crc,
203 : : ControlFile,
204 : : offsetof(ControlFileData, crc));
205 : 9782 : FIN_CRC32C(ControlFile->crc);
206 : :
207 : : /*
208 : : * Write out PG_CONTROL_FILE_SIZE bytes into pg_control by zero-padding
209 : : * the excess over sizeof(ControlFileData), to avoid premature EOF related
210 : : * errors when reading it.
211 : : */
212 : 9782 : memset(buffer, 0, PG_CONTROL_FILE_SIZE);
213 : 9782 : memcpy(buffer, ControlFile, sizeof(ControlFileData));
214 : :
215 : 9782 : snprintf(ControlFilePath, sizeof(ControlFilePath), "%s/%s", DataDir, XLOG_CONTROL_FILE);
216 : :
217 : : #ifndef FRONTEND
218 : :
219 : : /*
220 : : * All errors issue a PANIC, so no need to use OpenTransientFile() and to
221 : : * worry about file descriptor leaks.
222 : : */
2554 223 [ - + ]: 9693 : if ((fd = BasicOpenFile(ControlFilePath, O_RDWR | PG_BINARY)) < 0)
2560 michael@paquier.xyz 224 [ # # ]:UBC 0 : ereport(PANIC,
225 : : (errcode_for_file_access(),
226 : : errmsg("could not open file \"%s\": %m",
227 : : ControlFilePath)));
228 : : #else
2560 michael@paquier.xyz 229 [ - + ]:CBC 89 : if ((fd = open(ControlFilePath, O_WRONLY | PG_BINARY,
230 : : pg_file_create_mode)) == -1)
1437 tgl@sss.pgh.pa.us 231 :UBC 0 : pg_fatal("could not open file \"%s\": %m", ControlFilePath);
232 : : #endif
233 : :
2560 michael@paquier.xyz 234 :CBC 9782 : errno = 0;
235 : : #ifndef FRONTEND
2554 236 : 9693 : pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_WRITE_UPDATE);
237 : : #endif
2560 238 [ - + ]: 9782 : if (write(fd, buffer, PG_CONTROL_FILE_SIZE) != PG_CONTROL_FILE_SIZE)
239 : : {
240 : : /* if write didn't set errno, assume problem is no disk space */
2560 michael@paquier.xyz 241 [ # # ]:UBC 0 : if (errno == 0)
242 : 0 : errno = ENOSPC;
243 : :
244 : : #ifndef FRONTEND
245 [ # # ]: 0 : ereport(PANIC,
246 : : (errcode_for_file_access(),
247 : : errmsg("could not write file \"%s\": %m",
248 : : ControlFilePath)));
249 : : #else
1437 tgl@sss.pgh.pa.us 250 : 0 : pg_fatal("could not write file \"%s\": %m", ControlFilePath);
251 : : #endif
252 : : }
253 : : #ifndef FRONTEND
2554 michael@paquier.xyz 254 :CBC 9693 : pgstat_report_wait_end();
255 : : #endif
256 : :
257 [ + + ]: 9782 : if (do_sync)
258 : : {
259 : : #ifndef FRONTEND
260 : 9693 : pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_SYNC_UPDATE);
261 [ - + ]: 9693 : if (pg_fsync(fd) != 0)
2554 michael@paquier.xyz 262 [ # # ]:UBC 0 : ereport(PANIC,
263 : : (errcode_for_file_access(),
264 : : errmsg("could not fsync file \"%s\": %m",
265 : : ControlFilePath)));
2554 michael@paquier.xyz 266 :CBC 9693 : pgstat_report_wait_end();
267 : : #else
268 [ - + ]: 75 : if (fsync(fd) != 0)
1437 tgl@sss.pgh.pa.us 269 :UBC 0 : pg_fatal("could not fsync file \"%s\": %m", ControlFilePath);
270 : : #endif
271 : : }
272 : :
2444 peter@eisentraut.org 273 [ - + ]:CBC 9782 : if (close(fd) != 0)
274 : : {
275 : : #ifndef FRONTEND
2560 michael@paquier.xyz 276 [ # # ]:UBC 0 : ereport(PANIC,
277 : : (errcode_for_file_access(),
278 : : errmsg("could not close file \"%s\": %m",
279 : : ControlFilePath)));
280 : : #else
1437 tgl@sss.pgh.pa.us 281 : 0 : pg_fatal("could not close file \"%s\": %m", ControlFilePath);
282 : : #endif
283 : : }
2560 michael@paquier.xyz 284 :CBC 9782 : }
|