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 *
53 322 : get_controlfile(const char *DataDir, bool *crc_ok_p)
54 : {
55 : char ControlFilePath[MAXPGPATH];
56 :
57 322 : snprintf(ControlFilePath, MAXPGPATH, "%s/%s", DataDir, XLOG_CONTROL_FILE);
58 :
59 322 : 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 420 : 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;
77 389 : int retries = 0;
78 : #endif
79 :
80 : Assert(crc_ok_p);
81 :
82 420 : ControlFile = palloc_object(ControlFileData);
83 :
84 : #ifdef FRONTEND
85 389 : INIT_CRC32C(last_crc);
86 :
87 390 : retry:
88 : #endif
89 :
90 : #ifndef FRONTEND
91 31 : if ((fd = OpenTransientFile(ControlFilePath, O_RDONLY | PG_BINARY)) == -1)
92 0 : ereport(ERROR,
93 : (errcode_for_file_access(),
94 : errmsg("could not open file \"%s\" for reading: %m",
95 : ControlFilePath)));
96 : #else
97 390 : if ((fd = open(ControlFilePath, O_RDONLY | PG_BINARY, 0)) == -1)
98 1 : pg_fatal("could not open file \"%s\" for reading: %m",
99 : ControlFilePath);
100 : #endif
101 :
102 420 : r = read(fd, ControlFile, sizeof(ControlFileData));
103 420 : if (r != sizeof(ControlFileData))
104 : {
105 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
111 0 : pg_fatal("could not read file \"%s\": %m", ControlFilePath);
112 : #endif
113 : else
114 : #ifndef FRONTEND
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
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
126 31 : if (CloseTransientFile(fd) != 0)
127 0 : ereport(ERROR,
128 : (errcode_for_file_access(),
129 : errmsg("could not close file \"%s\": %m",
130 : ControlFilePath)));
131 : #else
132 389 : if (close(fd) != 0)
133 0 : pg_fatal("could not close file \"%s\": %m", ControlFilePath);
134 : #endif
135 :
136 : /* Check the CRC. */
137 420 : INIT_CRC32C(crc);
138 420 : COMP_CRC32C(crc,
139 : ControlFile,
140 : offsetof(ControlFileData, crc));
141 420 : FIN_CRC32C(crc);
142 :
143 420 : *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 : */
154 389 : 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. */
166 419 : if (ControlFile->pg_control_version % 65536 == 0 &&
167 0 : ControlFile->pg_control_version / 65536 != 0)
168 : #ifndef FRONTEND
169 0 : elog(ERROR, _("byte ordering mismatch"));
170 : #else
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 :
177 419 : 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
190 9700 : 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 */
198 9700 : ControlFile->time = (pg_time_t) time(NULL);
199 :
200 : /* Recalculate CRC of control file */
201 9700 : INIT_CRC32C(ControlFile->crc);
202 9700 : COMP_CRC32C(ControlFile->crc,
203 : ControlFile,
204 : offsetof(ControlFileData, crc));
205 9700 : 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 9700 : memset(buffer, 0, PG_CONTROL_FILE_SIZE);
213 9700 : memcpy(buffer, ControlFile, sizeof(ControlFileData));
214 :
215 9700 : 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 : */
223 9611 : if ((fd = BasicOpenFile(ControlFilePath, O_RDWR | PG_BINARY)) < 0)
224 0 : ereport(PANIC,
225 : (errcode_for_file_access(),
226 : errmsg("could not open file \"%s\": %m",
227 : ControlFilePath)));
228 : #else
229 89 : if ((fd = open(ControlFilePath, O_WRONLY | PG_BINARY,
230 : pg_file_create_mode)) == -1)
231 0 : pg_fatal("could not open file \"%s\": %m", ControlFilePath);
232 : #endif
233 :
234 9700 : errno = 0;
235 : #ifndef FRONTEND
236 9611 : pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_WRITE_UPDATE);
237 : #endif
238 9700 : 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 */
241 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
250 0 : pg_fatal("could not write file \"%s\": %m", ControlFilePath);
251 : #endif
252 : }
253 : #ifndef FRONTEND
254 9611 : pgstat_report_wait_end();
255 : #endif
256 :
257 9700 : if (do_sync)
258 : {
259 : #ifndef FRONTEND
260 9611 : pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_SYNC_UPDATE);
261 9611 : if (pg_fsync(fd) != 0)
262 0 : ereport(PANIC,
263 : (errcode_for_file_access(),
264 : errmsg("could not fsync file \"%s\": %m",
265 : ControlFilePath)));
266 9611 : pgstat_report_wait_end();
267 : #else
268 75 : if (fsync(fd) != 0)
269 0 : pg_fatal("could not fsync file \"%s\": %m", ControlFilePath);
270 : #endif
271 : }
272 :
273 9700 : if (close(fd) != 0)
274 : {
275 : #ifndef FRONTEND
276 0 : ereport(PANIC,
277 : (errcode_for_file_access(),
278 : errmsg("could not close file \"%s\": %m",
279 : ControlFilePath)));
280 : #else
281 0 : pg_fatal("could not close file \"%s\": %m", ControlFilePath);
282 : #endif
283 : }
284 9700 : }
|