]> git.proxmox.com Git - ceph.git/blob - ceph/src/pmdk/src/libpmempool/check_backup.c
import ceph 16.2.7
[ceph.git] / ceph / src / pmdk / src / libpmempool / check_backup.c
1 // SPDX-License-Identifier: BSD-3-Clause
2 /* Copyright 2016-2018, Intel Corporation */
3
4 /*
5 * check_backup.c -- pre-check backup
6 */
7
8 #include <stddef.h>
9 #include <stdint.h>
10 #include <unistd.h>
11
12 #include "out.h"
13 #include "file.h"
14 #include "os.h"
15 #include "libpmempool.h"
16 #include "pmempool.h"
17 #include "pool.h"
18 #include "check_util.h"
19
20 enum question {
21 Q_OVERWRITE_EXISTING_FILE,
22 Q_OVERWRITE_EXISTING_PARTS
23 };
24
25 /*
26 * location_release -- (internal) release poolset structure
27 */
28 static void
29 location_release(location *loc)
30 {
31 if (loc->set) {
32 util_poolset_free(loc->set);
33 loc->set = NULL;
34 }
35 }
36
37 /*
38 * backup_nonpoolset_requirements -- (internal) check backup requirements
39 */
40 static int
41 backup_nonpoolset_requirements(PMEMpoolcheck *ppc, location *loc)
42 {
43 LOG(3, "backup_path %s", ppc->backup_path);
44
45 int exists = util_file_exists(ppc->backup_path);
46 if (exists < 0) {
47 return CHECK_ERR(ppc,
48 "unable to access the backup destination: %s",
49 ppc->backup_path);
50 }
51
52 if (!exists) {
53 errno = 0;
54 return 0;
55 }
56
57 if ((size_t)util_file_get_size(ppc->backup_path) !=
58 ppc->pool->set_file->size) {
59 ppc->result = CHECK_RESULT_ERROR;
60 return CHECK_ERR(ppc,
61 "destination of the backup does not match the size of the source pool file: %s",
62 ppc->backup_path);
63 }
64
65 if (CHECK_WITHOUT_FIXING(ppc)) {
66 location_release(loc);
67 loc->step = CHECK_STEP_COMPLETE;
68 return 0;
69 }
70
71 CHECK_ASK(ppc, Q_OVERWRITE_EXISTING_FILE,
72 "destination of the backup already exists.|Do you want to overwrite it?");
73
74 return check_questions_sequence_validate(ppc);
75 }
76
77 /*
78 * backup_nonpoolset_overwrite -- (internal) overwrite pool
79 */
80 static int
81 backup_nonpoolset_overwrite(PMEMpoolcheck *ppc, location *loc,
82 uint32_t question, void *context)
83 {
84 LOG(3, NULL);
85
86 ASSERTne(loc, NULL);
87
88 switch (question) {
89 case Q_OVERWRITE_EXISTING_FILE:
90 if (pool_copy(ppc->pool, ppc->backup_path, 1 /* overwrite */)) {
91 location_release(loc);
92 ppc->result = CHECK_RESULT_ERROR;
93 return CHECK_ERR(ppc, "cannot perform backup");
94 }
95
96 location_release(loc);
97 loc->step = CHECK_STEP_COMPLETE;
98 return 0;
99 default:
100 ERR("not implemented question id: %u", question);
101 }
102
103 return 0;
104 }
105
106 /*
107 * backup_nonpoolset_create -- (internal) create backup
108 */
109 static int
110 backup_nonpoolset_create(PMEMpoolcheck *ppc, location *loc)
111 {
112 CHECK_INFO(ppc, "creating backup file: %s", ppc->backup_path);
113
114 if (pool_copy(ppc->pool, ppc->backup_path, 0)) {
115 location_release(loc);
116 ppc->result = CHECK_RESULT_ERROR;
117 return CHECK_ERR(ppc, "cannot perform backup");
118 }
119
120 location_release(loc);
121 loc->step = CHECK_STEP_COMPLETE;
122 return 0;
123 }
124
125 /*
126 * backup_poolset_requirements -- (internal) check backup requirements
127 */
128 static int
129 backup_poolset_requirements(PMEMpoolcheck *ppc, location *loc)
130 {
131 LOG(3, "backup_path %s", ppc->backup_path);
132
133 if (ppc->pool->set_file->poolset->nreplicas > 1) {
134 CHECK_INFO(ppc,
135 "backup of a poolset with multiple replicas is not supported");
136 goto err;
137 }
138
139 if (pool_set_parse(&loc->set, ppc->backup_path)) {
140 CHECK_INFO_ERRNO(ppc, "invalid poolset backup file: %s",
141 ppc->backup_path);
142 goto err;
143 }
144
145 if (loc->set->nreplicas > 1) {
146 CHECK_INFO(ppc,
147 "backup to a poolset with multiple replicas is not supported");
148 goto err_poolset;
149 }
150
151 ASSERTeq(loc->set->nreplicas, 1);
152 struct pool_replica *srep = ppc->pool->set_file->poolset->replica[0];
153 struct pool_replica *drep = loc->set->replica[0];
154 if (srep->nparts != drep->nparts) {
155 CHECK_INFO(ppc,
156 "number of part files in the backup poolset must match number of part files in the source poolset");
157 goto err_poolset;
158 }
159
160 int overwrite_required = 0;
161 for (unsigned p = 0; p < srep->nparts; p++) {
162 int exists = util_file_exists(drep->part[p].path);
163 if (exists < 0) {
164 CHECK_INFO(ppc,
165 "unable to access the part of the destination poolset: %s",
166 ppc->backup_path);
167 goto err_poolset;
168 }
169
170 if (srep->part[p].filesize != drep->part[p].filesize) {
171 CHECK_INFO(ppc,
172 "size of the part %u of the backup poolset does not match source poolset",
173 p);
174 goto err_poolset;
175 }
176
177 if (!exists) {
178 errno = 0;
179 continue;
180 }
181
182 overwrite_required = true;
183
184 if ((size_t)util_file_get_size(drep->part[p].path) !=
185 srep->part[p].filesize) {
186 CHECK_INFO(ppc,
187 "destination of the backup part does not match size of the source part file: %s",
188 drep->part[p].path);
189 goto err_poolset;
190 }
191 }
192
193 if (CHECK_WITHOUT_FIXING(ppc)) {
194 location_release(loc);
195 loc->step = CHECK_STEP_COMPLETE;
196 return 0;
197 }
198
199 if (overwrite_required) {
200 CHECK_ASK(ppc, Q_OVERWRITE_EXISTING_PARTS,
201 "part files of the destination poolset of the backup already exist.|"
202 "Do you want to overwrite them?");
203 }
204
205 return check_questions_sequence_validate(ppc);
206
207 err_poolset:
208 location_release(loc);
209 err:
210 ppc->result = CHECK_RESULT_ERROR;
211 return CHECK_ERR(ppc, "unable to backup poolset");
212 }
213
214 /*
215 * backup_poolset -- (internal) backup the poolset
216 */
217 static int
218 backup_poolset(PMEMpoolcheck *ppc, location *loc, int overwrite)
219 {
220 struct pool_replica *srep = ppc->pool->set_file->poolset->replica[0];
221 struct pool_replica *drep = loc->set->replica[0];
222 for (unsigned p = 0; p < srep->nparts; p++) {
223 if (overwrite == 0) {
224 CHECK_INFO(ppc, "creating backup file: %s",
225 drep->part[p].path);
226 }
227 if (pool_set_part_copy(&drep->part[p], &srep->part[p],
228 overwrite)) {
229 location_release(loc);
230 ppc->result = CHECK_RESULT_ERROR;
231 CHECK_INFO(ppc, "unable to create backup file");
232 return CHECK_ERR(ppc, "unable to backup poolset");
233 }
234 }
235
236 return 0;
237 }
238
239 /*
240 * backup_poolset_overwrite -- (internal) backup poolset with overwrite
241 */
242 static int
243 backup_poolset_overwrite(PMEMpoolcheck *ppc, location *loc,
244 uint32_t question, void *context)
245 {
246 LOG(3, NULL);
247
248 ASSERTne(loc, NULL);
249
250 switch (question) {
251 case Q_OVERWRITE_EXISTING_PARTS:
252 if (backup_poolset(ppc, loc, 1 /* overwrite */)) {
253 location_release(loc);
254 ppc->result = CHECK_RESULT_ERROR;
255 return CHECK_ERR(ppc, "cannot perform backup");
256 }
257
258 location_release(loc);
259 loc->step = CHECK_STEP_COMPLETE;
260 return 0;
261 default:
262 ERR("not implemented question id: %u", question);
263 }
264
265 return 0;
266 }
267
268 /*
269 * backup_poolset_create -- (internal) backup poolset
270 */
271 static int
272 backup_poolset_create(PMEMpoolcheck *ppc, location *loc)
273 {
274 if (backup_poolset(ppc, loc, 0)) {
275 location_release(loc);
276 ppc->result = CHECK_RESULT_ERROR;
277 return CHECK_ERR(ppc, "cannot perform backup");
278 }
279
280 location_release(loc);
281 loc->step = CHECK_STEP_COMPLETE;
282 return 0;
283 }
284
285 struct step {
286 int (*check)(PMEMpoolcheck *, location *);
287 int (*fix)(PMEMpoolcheck *, location *, uint32_t, void *);
288 int poolset;
289 };
290
291 static const struct step steps[] = {
292 {
293 .check = backup_nonpoolset_requirements,
294 .poolset = false,
295 },
296 {
297 .fix = backup_nonpoolset_overwrite,
298 .poolset = false,
299 },
300 {
301 .check = backup_nonpoolset_create,
302 .poolset = false
303 },
304 {
305 .check = backup_poolset_requirements,
306 .poolset = true,
307 },
308 {
309 .fix = backup_poolset_overwrite,
310 .poolset = true,
311 },
312 {
313 .check = backup_poolset_create,
314 .poolset = true
315 },
316 {
317 .check = NULL,
318 .fix = NULL,
319 },
320 };
321
322 /*
323 * step_exe -- (internal) perform single step according to its parameters
324 */
325 static int
326 step_exe(PMEMpoolcheck *ppc, location *loc)
327 {
328 ASSERT(loc->step < ARRAY_SIZE(steps));
329
330 const struct step *step = &steps[loc->step++];
331
332 if (step->poolset == 0 && ppc->pool->params.is_poolset == 1)
333 return 0;
334
335 if (!step->fix)
336 return step->check(ppc, loc);
337
338 if (!check_has_answer(ppc->data))
339 return 0;
340
341 if (check_answer_loop(ppc, loc, NULL, 1, step->fix))
342 return -1;
343
344 ppc->result = CHECK_RESULT_CONSISTENT;
345
346 return 0;
347 }
348
349 /*
350 * check_backup -- perform backup if requested and needed
351 */
352 void
353 check_backup(PMEMpoolcheck *ppc)
354 {
355 LOG(3, "backup_path %s", ppc->backup_path);
356
357 if (ppc->backup_path == NULL)
358 return;
359
360 location *loc = check_get_step_data(ppc->data);
361
362 /* do all checks */
363 while (CHECK_NOT_COMPLETE(loc, steps)) {
364 if (step_exe(ppc, loc))
365 break;
366 }
367 }