Line data Source code
1 : /*
2 : * Copyright (C) 2011 Andrea Mazzoleni
3 : *
4 : * This program is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This program is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : #include "portable.h"
19 :
20 : #include "support.h"
21 : #include "util.h"
22 : #include "elem.h"
23 : #include "import.h"
24 : #include "search.h"
25 : #include "state.h"
26 : #include "parity.h"
27 : #include "handle.h"
28 : #include "raid/raid.h"
29 : #include "raid/combo.h"
30 :
31 : /****************************************************************************/
32 : /* check */
33 :
34 776326 : static const char* es(int err)
35 : {
36 776326 : if (is_hw(err))
37 0 : return "error_io";
38 : else
39 776326 : return "error";
40 : }
41 :
42 : /**
43 : * A block that failed the hash check, or that was deleted.
44 : */
45 : struct failed_struct {
46 : /**
47 : * If we know for sure that the block is garbage or missing
48 : * and it needs to be recovered and rewritten to the disk.
49 : */
50 : int is_bad;
51 :
52 : /**
53 : * If what we have recovered may be not updated data,
54 : * an old version, or just garbage.
55 : *
56 : * Essentially, it means that we are not sure what we have recovered
57 : * is really correct. It's just our best guess.
58 : *
59 : * These "recovered" blocks are also written to the disk if the block is marked as ::is_bad.
60 : * But these files are marked also as FILE_IS_DAMAGED, and then renamed to .unrecoverable.
61 : *
62 : * Note that this could happen only for CHG blocks.
63 : */
64 : int is_outofdate;
65 :
66 : unsigned index; /**< Index of the failed block. */
67 : struct snapraid_block* block; /**< The failed block */
68 : struct snapraid_disk* disk; /**< The failed disk. */
69 : struct snapraid_file* file; /**< The failed file. 0 for DELETED block. */
70 : block_off_t file_pos; /**< Offset inside the file */
71 : struct snapraid_handle* handle; /**< The handle containing the failed block, or 0 for a DELETED block */
72 : };
73 :
74 : /**
75 : * Check if a block hash matches the specified buffer.
76 : * Return ==0 if equal
77 : */
78 507506 : static int blockcmp(struct snapraid_state* state, int rehash, struct snapraid_block* block, unsigned pos_size, unsigned char* buffer, unsigned char* buffer_zero)
79 : {
80 : unsigned char hash[HASH_MAX];
81 :
82 : /* now compute the hash of the valid part */
83 507506 : if (rehash) {
84 0 : memhash(state->prevhash, state->prevhashseed, hash, buffer, pos_size);
85 : } else {
86 507506 : memhash(state->hash, state->hashseed, hash, buffer, pos_size);
87 : }
88 :
89 : /* compare the hash */
90 507506 : if (memcmp(hash, block->hash, BLOCK_HASH_SIZE) != 0) {
91 14487 : return -1;
92 : }
93 :
94 : /* compare to the end of the block */
95 493019 : if (pos_size < state->block_size) {
96 203358 : if (memcmp(buffer + pos_size, buffer_zero + pos_size, state->block_size - pos_size) != 0) {
97 33 : return -1;
98 : }
99 : }
100 :
101 492986 : return 0;
102 : }
103 :
104 : /**
105 : * Check if the hash of all the failed blocks we are expecting to recover are now matching.
106 : */
107 223158 : static int is_hash_matching(struct snapraid_state* state, int rehash, unsigned diskmax, struct failed_struct* failed, unsigned* failed_map, unsigned failed_count, void** buffer, void* buffer_zero)
108 : {
109 : unsigned j;
110 : int hash_checked;
111 :
112 223158 : hash_checked = 0; /* keep track if we check at least one block */
113 :
114 : /* check if the recovered blocks are OK */
115 720707 : for (j = 0; j < failed_count; ++j) {
116 : /* if we are expected to recover this block */
117 512069 : if (!failed[failed_map[j]].is_outofdate
118 : /* if the block has a hash to check */
119 507506 : && block_has_updated_hash(failed[failed_map[j]].block)
120 : ) {
121 : /* if a hash doesn't match, fail the check */
122 507506 : unsigned pos_size = file_block_size(failed[failed_map[j]].file, failed[failed_map[j]].file_pos, state->block_size);
123 507506 : if (blockcmp(state, rehash, failed[failed_map[j]].block, pos_size, buffer[failed[failed_map[j]].index], buffer_zero) != 0) {
124 14520 : log_tag("repair_hash_error:%u: Hash mismatch\n", failed_map[j]);
125 14520 : return 0;
126 : }
127 :
128 492986 : hash_checked = 1;
129 : }
130 : }
131 :
132 : /* if nothing checked, we reject it */
133 : /* note that we are excluding this case at upper level */
134 : /* but checking again doesn't hurt */
135 208638 : if (!hash_checked) {
136 : /* LCOV_EXCL_START */
137 : return 0;
138 : /* LCOV_EXCL_STOP */
139 : }
140 :
141 : /* if we checked something, and no block failed the check */
142 : /* recompute all the redundancy information */
143 208638 : raid_gen(diskmax, state->level, state->block_size, buffer);
144 208638 : return 1;
145 : }
146 :
147 : /**
148 : * Check if specified parity is now matching with a recomputed one.
149 : */
150 8 : static int is_parity_matching(struct snapraid_state* state, unsigned diskmax, unsigned i, void** buffer, void** buffer_recov)
151 : {
152 : /* recompute parity, note that we don't need parity over i */
153 8 : raid_gen(diskmax, i + 1, state->block_size, buffer);
154 :
155 : /* if the recovered parity block matches */
156 8 : if (memcmp(buffer[diskmax + i], buffer_recov[i], state->block_size) == 0) {
157 : /* recompute all the redundancy information */
158 8 : raid_gen(diskmax, state->level, state->block_size, buffer);
159 8 : return 1;
160 : }
161 :
162 0 : return 0;
163 : }
164 :
165 : /**
166 : * Repair errors.
167 : * Return <0 if failure for missing strategy, >0 if data is wrong and we cannot rebuild correctly, 0 on success.
168 : * If success, the parity is computed in the buffer variable.
169 : */
170 265489 : static int repair_step(struct snapraid_state* state, int rehash, unsigned pos, unsigned diskmax, struct failed_struct* failed, unsigned* failed_map, unsigned failed_count, void** buffer, void** buffer_recov, void* buffer_zero)
171 : {
172 : unsigned i, n;
173 : int error;
174 : int has_hash;
175 : int id[LEV_MAX];
176 : int ip[LEV_MAX];
177 :
178 : /* no fix required, already checked at higher level, but just to be sure */
179 265489 : if (failed_count == 0) {
180 : /* LCOV_EXCL_START */
181 : /* recompute only the parity */
182 : raid_gen(diskmax, state->level, state->block_size, buffer);
183 : return 0;
184 : /* LCOV_EXCL_STOP */
185 : }
186 :
187 265489 : n = state->level;
188 265489 : error = 0;
189 :
190 : /* setup vector of failed disk indexes */
191 942555 : for (i = 0; i < failed_count; ++i)
192 677066 : id[i] = failed[failed_map[i]].index;
193 :
194 : /* check if there is at least a failed block that can be checked for correctness using the hash */
195 : /* if there isn't, we have to sacrifice a parity block to check that the result is correct */
196 265489 : has_hash = 0;
197 942555 : for (i = 0; i < failed_count; ++i) {
198 : /* if we are expected to recover this block */
199 677066 : if (!failed[failed_map[i]].is_outofdate
200 : /* if the block has a hash to check */
201 667940 : && block_has_updated_hash(failed[failed_map[i]].block)
202 : )
203 667932 : has_hash = 1;
204 : }
205 :
206 : /* if we don't have a hash, but we have an extra parity */
207 : /* (strictly-less failures than number of parities) */
208 265489 : if (!has_hash && failed_count < n) {
209 : /* number of parity to use, one more to check the recovering */
210 8 : unsigned r = failed_count + 1;
211 :
212 : /* all combinations (r of n) parities */
213 8 : combination_first(r, n, ip);
214 : do {
215 : /* if a parity is missing, do nothing */
216 24 : for (i = 0; i < r; ++i) {
217 16 : if (buffer_recov[ip[i]] == 0)
218 0 : break;
219 : }
220 8 : if (i != r)
221 0 : continue;
222 :
223 : /* copy the parities to use, one less because the last is used for checking */
224 16 : for (i = 0; i < r - 1; ++i)
225 8 : memcpy(buffer[diskmax + ip[i]], buffer_recov[ip[i]], state->block_size);
226 :
227 : /* recover using one less parity, the ip[r-1] one */
228 8 : raid_data(r - 1, id, ip, diskmax, state->block_size, buffer);
229 :
230 : /* use the remaining ip[r-1] parity to check the result */
231 8 : if (is_parity_matching(state, diskmax, ip[r - 1], buffer, buffer_recov))
232 8 : return 0;
233 :
234 : /* log */
235 0 : log_tag("recover_parity_error:%u:", pos);
236 0 : for (i = 0; i < r; ++i) {
237 0 : if (i != 0)
238 0 : log_tag(",");
239 0 : log_tag("%s", lev_config_name(ip[i]));
240 : }
241 0 : log_tag(": Parity mismatch\n");
242 0 : ++error;
243 0 : } while (combination_next(r, n, ip));
244 : }
245 :
246 : /* if we have a hash, and enough parities */
247 : /* (less-or-equal failures than number of parities) */
248 265481 : if (has_hash && failed_count <= n) {
249 : /* number of parities to use equal to the number of failures */
250 218041 : unsigned r = failed_count;
251 :
252 : /* all combinations (r of n) parities */
253 218041 : combination_first(r, n, ip);
254 : do {
255 : /* if a parity is missing, do nothing */
256 739980 : for (i = 0; i < r; ++i) {
257 516822 : if (buffer_recov[ip[i]] == 0)
258 4753 : break;
259 : }
260 227911 : if (i != r)
261 4753 : continue;
262 :
263 : /* copy the parities to use */
264 735227 : for (i = 0; i < r; ++i)
265 512069 : memcpy(buffer[diskmax + ip[i]], buffer_recov[ip[i]], state->block_size);
266 :
267 : /* recover */
268 223158 : raid_data(r, id, ip, diskmax, state->block_size, buffer);
269 :
270 : /* use the hash to check the result */
271 223158 : if (is_hash_matching(state, rehash, diskmax, failed, failed_map, failed_count, buffer, buffer_zero))
272 208638 : return 0;
273 :
274 : /* log */
275 14520 : log_tag("recover_hash_error:%u:", pos);
276 29040 : for (i = 0; i < r; ++i) {
277 14520 : if (i != 0)
278 0 : log_tag("/");
279 14520 : log_tag("%s", lev_config_name(ip[i]));
280 : }
281 14520 : log_tag(": Hash mismatch\n");
282 14520 : ++error;
283 38546 : } while (combination_next(r, n, ip));
284 : }
285 :
286 : /* return the number of failed attempts, or -1 if no strategy */
287 56843 : if (error)
288 9403 : return error;
289 :
290 47440 : log_tag("recover_strategy_error:%u: No strategy to recover from %u failures with %u parity %s hash\n",
291 : pos, failed_count, n, has_hash ? "with" : "without");
292 47440 : return -1;
293 : }
294 :
295 902909 : static int repair(struct snapraid_state* state, int rehash, unsigned pos, unsigned diskmax, struct failed_struct* failed, unsigned* failed_map, unsigned failed_count, void** buffer, void** buffer_recov, void* buffer_zero)
296 : {
297 : int ret;
298 : int error;
299 : unsigned j;
300 : int n;
301 : int something_to_recover;
302 : int something_unsynced;
303 : char esc_buffer[ESC_MAX];
304 :
305 902909 : error = 0;
306 :
307 : /* if nothing failed, just recompute the parity */
308 902909 : if (failed_count == 0) {
309 602459 : raid_gen(diskmax, state->level, state->block_size, buffer);
310 602459 : return 0;
311 : }
312 :
313 : /* logs the status */
314 1066020 : for (j = 0; j < failed_count; ++j) {
315 : const char* desc;
316 : const char* hash;
317 : const char* data;
318 765570 : struct snapraid_block* block = failed[j].block;
319 765570 : unsigned block_state = block_state_get(block);
320 :
321 765570 : switch (block_state) {
322 18618 : case BLOCK_STATE_DELETED : desc = "delete"; break;
323 13787 : case BLOCK_STATE_CHG : desc = "change"; break;
324 60632 : case BLOCK_STATE_REP : desc = "replace"; break;
325 672533 : case BLOCK_STATE_BLK : desc = "block"; break;
326 : /* LCOV_EXCL_START */
327 : default : desc = "unknown"; break;
328 : /* LCOV_EXCL_STOP */
329 : }
330 :
331 765570 : if (hash_is_invalid(block->hash)) {
332 13779 : hash = "lost";
333 751791 : } else if (hash_is_zero(block->hash)) {
334 8 : hash = "zero";
335 : } else {
336 751783 : hash = "known";
337 : }
338 :
339 765570 : if (failed[j].is_bad)
340 681025 : data = "bad";
341 : else
342 84545 : data = "good";
343 :
344 765570 : if (failed[j].file) {
345 746952 : struct snapraid_disk* disk = failed[j].disk;
346 746952 : struct snapraid_file* file = failed[j].file;
347 746952 : block_off_t file_pos = failed[j].file_pos;
348 :
349 746952 : log_tag("repair_entry:%u:%s:%s:%s:%s:%s:%u:\n", j, desc, hash, data, disk->name, esc_tag(file->sub, esc_buffer), file_pos);
350 : } else {
351 18618 : log_tag("repair_entry:%u:%s:%s:%s:\n", j, desc, hash, data);
352 : }
353 : }
354 :
355 : /* Here we have to try two different strategies to recover, because in case the 'sync' */
356 : /* process is aborted, we don't know if the parity data is really updated just like after 'sync', */
357 : /* or if it still represents the state before the 'sync'. */
358 :
359 : /* Note that if the 'sync' ends normally, we don't have any DELETED, REP and CHG blocks */
360 : /* and the two strategies are identical */
361 :
362 : /* As first, we assume that the parity IS updated for the current state */
363 : /* and that we are going to recover the state after the last 'sync'. */
364 : /* In this case, parity contains info from BLK, REP and CHG blocks, */
365 : /* but not for DELETED. */
366 : /* We need to put in the recovering process only the bad blocks, because all the */
367 : /* others already contains the correct data read from disk, and the parity is correctly computed for them. */
368 : /* We are interested to recover BLK, REP and CHG blocks if they are marked as bad, */
369 : /* but we are not interested in DELETED ones. */
370 :
371 300450 : n = 0;
372 300450 : something_to_recover = 0; /* keep track if there is at least one block to fix */
373 1066020 : for (j = 0; j < failed_count; ++j) {
374 765570 : if (failed[j].is_bad) {
375 681025 : unsigned block_state = block_state_get(failed[j].block);
376 :
377 681025 : assert(block_state != BLOCK_STATE_DELETED); /* we cannot have bad DELETED blocks */
378 :
379 : /* if we have the hash for it */
380 681025 : if ((block_state == BLOCK_STATE_BLK || block_state == BLOCK_STATE_REP)
381 : /* try to fetch the block using the known hash */
382 681017 : && (state_import_fetch(state, rehash, failed[j].block, buffer[failed[j].index]) == 0
383 676484 : || state_search_fetch(state, rehash, failed[j].file, failed[j].file_pos, failed[j].block, buffer[failed[j].index]) == 0)
384 : ) {
385 : /* we already have corrected it! */
386 22211 : log_tag("repair_hash_import:%u: Fixed by import\n", j);
387 : } else {
388 : /* otherwise try to recover it */
389 658814 : failed_map[n] = j;
390 658814 : ++n;
391 :
392 : /* we have something to try to recover */
393 658814 : something_to_recover = 1;
394 : }
395 : }
396 : }
397 :
398 : /* if nothing to fix */
399 300450 : if (!something_to_recover) {
400 44087 : log_tag("recover_sync:%u:%u: Skipped for already recovered\n", pos, n);
401 :
402 : /* recompute only the parity */
403 44087 : raid_gen(diskmax, state->level, state->block_size, buffer);
404 44087 : return 0;
405 : }
406 :
407 256363 : ret = repair_step(state, rehash, pos, diskmax, failed, failed_map, n, buffer, buffer_recov, buffer_zero);
408 256363 : if (ret == 0) {
409 : /* reprocess the CHG blocks, for which we don't have a hash to check */
410 : /* if they were BAD we have to use some heuristics to ensure that we have recovered */
411 : /* the state after the sync. If unsure, we assume the worst case */
412 :
413 718639 : for (j = 0; j < failed_count; ++j) {
414 : /* we take care only of BAD blocks we have to write back */
415 514556 : if (failed[j].is_bad) {
416 501353 : unsigned block_state = block_state_get(failed[j].block);
417 :
418 : /* BLK and REP blocks are always OK, because at this point */
419 : /* we have already checked their hash */
420 501353 : if (block_state != BLOCK_STATE_CHG) {
421 501345 : assert(block_state == BLOCK_STATE_BLK || block_state == BLOCK_STATE_REP);
422 501345 : continue;
423 : }
424 :
425 : /* for CHG blocks we have to 'guess' if they are correct or not */
426 :
427 : /* if the hash is invalid we cannot check the result */
428 : /* this could happen if we have lost this information */
429 : /* after an aborted sync */
430 8 : if (hash_is_invalid(failed[j].block->hash)) {
431 : /* it may contain garbage */
432 0 : failed[j].is_outofdate = 1;
433 :
434 0 : log_tag("repair:hash_unknown:%u: Unknown hash\n", j);
435 8 : } else if (hash_is_zero(failed[j].block->hash)) {
436 : /* if the block is not filled with 0, we are sure to have */
437 : /* restored it to the state after the 'sync' */
438 : /* instead, if the block is filled with 0, it could be either that the */
439 : /* block after the sync is really filled by 0, or that */
440 : /* we restored the block before the 'sync'. */
441 8 : if (memcmp(buffer[failed[j].index], buffer_zero, state->block_size) == 0) {
442 : /* it may contain garbage */
443 8 : failed[j].is_outofdate = 1;
444 :
445 8 : log_tag("repair_hash_unknown:%u: Maybe old zero\n", j);
446 : }
447 : } else {
448 : /* if the hash is different than the previous one, we are sure to have */
449 : /* restored it to the state after the 'sync' */
450 : /* instead, if the hash matches, it could be either that the */
451 : /* block after the sync has this hash, or that */
452 : /* we restored the block before the 'sync'. */
453 0 : unsigned pos_size = file_block_size(failed[j].file, failed[j].file_pos, state->block_size);
454 0 : if (blockcmp(state, rehash, failed[j].block, pos_size, buffer[failed[j].index], buffer_zero) == 0) {
455 : /* it may contain garbage */
456 0 : failed[j].is_outofdate = 1;
457 :
458 0 : log_tag("repair_hash_unknown:%u: Maybe old data\n", j);
459 : }
460 : }
461 : }
462 : }
463 :
464 204083 : return 0;
465 : }
466 52280 : if (ret > 0)
467 9403 : error += ret;
468 :
469 52280 : if (ret < 0)
470 42877 : log_tag("recover_sync:%u:%u: Failed with no attempts\n", pos, n);
471 : else
472 9403 : log_tag("recover_sync:%u:%u: Failed with %d attempts\n", pos, n, ret);
473 :
474 : /* Now assume that the parity IS NOT updated at the current state, */
475 : /* but still represent the state before the last 'sync' process. */
476 : /* In this case, parity contains info from BLK, REP (old version), CHG (old version) and DELETED blocks, */
477 : /* but not for REP (new version) and CHG (new version). */
478 : /* We are interested to recover BLK ones marked as bad, */
479 : /* but we are not interested to recover CHG (new version) and REP (new version) blocks, */
480 : /* even if marked as bad, because we don't have parity for them and it's just impossible, */
481 : /* and we are not interested to recover DELETED ones. */
482 52280 : n = 0;
483 52280 : something_to_recover = 0; /* keep track if there is at least one block to fix */
484 52280 : something_unsynced = 0; /* keep track if we have some unsynced info to process */
485 231789 : for (j = 0; j < failed_count; ++j) {
486 179509 : unsigned block_state = block_state_get(failed[j].block);
487 :
488 179509 : if (block_state == BLOCK_STATE_DELETED
489 170383 : || block_state == BLOCK_STATE_CHG
490 170383 : || block_state == BLOCK_STATE_REP
491 : ) {
492 : /* If the block is CHG, REP or DELETED, we don't have the original content of block, */
493 : /* and we must try to recover it. */
494 : /* This applies to CHG and REP blocks even if they are not marked bad, */
495 : /* because the parity is computed with old content, and not with the new one. */
496 : /* Note that this recovering is done just to make it possible to recover any other BLK one, */
497 : /* we are not really interested in DELETED, CHG (old version) and REP (old version). */
498 9126 : something_unsynced = 1;
499 :
500 9126 : if (block_state == BLOCK_STATE_CHG
501 0 : && hash_is_zero(failed[j].block->hash)
502 : ) {
503 : /* If the block was a ZERO block, restore it to the original 0 as before the 'sync' */
504 : /* We do this to just allow recovering of other BLK ones */
505 :
506 0 : memset(buffer[failed[j].index], 0, state->block_size);
507 : /* note that from now the buffer is definitely lost */
508 : /* we can do this only because it's the last retry of recovering */
509 :
510 : /* try to fetch the old block using the old hash for CHG and DELETED blocks */
511 9126 : } else if ((block_state == BLOCK_STATE_CHG || block_state == BLOCK_STATE_DELETED)
512 9126 : && hash_is_unique(failed[j].block->hash)
513 9126 : && state_import_fetch(state, rehash, failed[j].block, buffer[failed[j].index]) == 0) {
514 :
515 : /* note that from now the buffer is definitely lost */
516 : /* we can do this only because it's the last retry of recovering */
517 : } else {
518 : /* otherwise try to recover it */
519 9126 : failed_map[n] = j;
520 9126 : ++n;
521 :
522 : /* note that we don't set something_to_recover, because we are */
523 : /* not really interested to recover *only* old blocks. */
524 : }
525 :
526 : /* avoid using the hash of this block to verify the recovering */
527 : /* this applies to REP blocks because we are going to recover the old state */
528 : /* and the REP hash represents the new one */
529 : /* it also applies to CHG and DELETE blocks because we want to have */
530 : /* a successful recovering only if a BLK one is matching */
531 9126 : failed[j].is_outofdate = 1;
532 170383 : } else if (failed[j].is_bad) {
533 : /* If the block is bad we don't know its content, and we try to recover it */
534 : /* At this point, we can have only BLK ones */
535 :
536 170383 : assert(block_state == BLOCK_STATE_BLK);
537 :
538 : /* we have something we are interested to recover */
539 170383 : something_to_recover = 1;
540 :
541 : /* we try to recover it */
542 170383 : failed_map[n] = j;
543 170383 : ++n;
544 : }
545 : }
546 :
547 : /* if nothing to fix, we just don't try */
548 : /* if nothing unsynced we also don't retry, because it's the same try as before */
549 52280 : if (something_to_recover && something_unsynced) {
550 9126 : ret = repair_step(state, rehash, pos, diskmax, failed, failed_map, n, buffer, buffer_recov, buffer_zero);
551 9126 : if (ret == 0) {
552 : /* reprocess the REP and CHG blocks, for which we have recovered an old state */
553 : /* that we don't want to save into disk */
554 : /* we have already marked them, but we redo it for logging */
555 :
556 13689 : for (j = 0; j < failed_count; ++j) {
557 : /* we take care only of BAD blocks we have to write back */
558 9126 : if (failed[j].is_bad) {
559 4563 : unsigned block_state = block_state_get(failed[j].block);
560 :
561 4563 : if (block_state == BLOCK_STATE_CHG
562 4563 : || block_state == BLOCK_STATE_REP
563 : ) {
564 : /* mark that we have restored an old state */
565 : /* and we don't want to write it to the disk */
566 0 : failed[j].is_outofdate = 1;
567 :
568 0 : log_tag("repair_hash_unknown:%u: Surely old data\n", j);
569 : }
570 : }
571 : }
572 :
573 4563 : return 0;
574 : }
575 4563 : if (ret > 0)
576 0 : error += ret;
577 :
578 4563 : if (ret < 0)
579 4563 : log_tag("recover_unsync:%u:%u: Failed with no attempts\n", pos, n);
580 : else
581 0 : log_tag("recover_unsync:%u:%u: Failed with %d attempts\n", pos, n, ret);
582 : } else {
583 43154 : log_tag("recover_unsync:%u:%u: Skipped for%s%s\n", pos, n,
584 : !something_to_recover ? " nothing to recover" : "",
585 : !something_unsynced ? " nothing unsynced" : ""
586 : );
587 : }
588 :
589 : /* return the number of failed attempts, or -1 if no strategy */
590 47717 : if (error)
591 4840 : return error;
592 : else
593 42877 : return -1;
594 : }
595 :
596 : /**
597 : * Post process all the files at the specified block index ::i.
598 : * For each file, if we are at the last block, close it,
599 : * adjust the timestamp, and print the result.
600 : *
601 : * This works only if the whole file is processed, including its last block.
602 : * This doesn't always happen, like with an explicit end block.
603 : *
604 : * In such case, the check/fix command won't report any information of the
605 : * files partially checked.
606 : */
607 942424 : static int file_post(struct snapraid_state* state, int fix, unsigned i, struct snapraid_handle* handle, unsigned diskmax)
608 : {
609 : unsigned j;
610 : int ret;
611 : char esc_buffer[ESC_MAX];
612 : char esc_buffer_alt[ESC_MAX];
613 :
614 : /* for all the files print the final status, and do the final time fix */
615 : /* we also ensure to close files after processing the last block */
616 6596968 : for (j = 0; j < diskmax; ++j) {
617 : struct snapraid_block* block;
618 : struct snapraid_disk* disk;
619 : struct snapraid_file* collide_file;
620 : struct snapraid_file* file;
621 : block_off_t file_pos;
622 : uint64_t inode;
623 :
624 5654544 : disk = handle[j].disk;
625 5654544 : if (!disk) {
626 : /* if no disk, nothing to do */
627 3464108 : continue;
628 : }
629 :
630 5640483 : block = fs_par2block_find(disk, i);
631 5640483 : if (!block_has_file(block)) {
632 : /* if no file, nothing to do */
633 239509 : continue;
634 : }
635 :
636 5400974 : file = fs_par2file_get(disk, i, &file_pos);
637 :
638 : /* if it isn't the last block in the file */
639 5400974 : if (!file_block_is_last(file, file_pos)) {
640 : /* nothing to do */
641 3210538 : continue;
642 : }
643 :
644 : /* if the file is excluded, we have nothing to adjust as the file is never written */
645 2190436 : if (file_flag_has(file, FILE_IS_EXCLUDED)
646 2116591 : || (state->opt.syncedonly && file_flag_has(file, FILE_IS_UNSYNCED))) {
647 : /* nothing to do, but close the file */
648 73845 : goto close_and_continue;
649 : }
650 :
651 : /* finish the fix process if it's the last block of the files */
652 2116591 : if (fix) {
653 : /* mark that we finished with this file */
654 : /* to identify later any NOT finished ones */
655 780709 : file_flag_set(file, FILE_IS_FINISHED);
656 :
657 : /* if the file is damaged, meaning that a fix failed */
658 780709 : if (file_flag_has(file, FILE_IS_DAMAGED)) {
659 : /* rename it to .unrecoverable */
660 : char path[PATH_MAX];
661 : char path_to[PATH_MAX];
662 :
663 63033 : pathprint(path, sizeof(path), "%s%s", disk->dir, file->sub);
664 63033 : pathprint(path_to, sizeof(path_to), "%s%s.unrecoverable", disk->dir, file->sub);
665 :
666 : /* ensure to close the file before renaming */
667 63033 : if (handle[j].file == file) {
668 63033 : ret = handle_close(&handle[j]);
669 63033 : if (ret != 0) {
670 : /* LCOV_EXCL_START */
671 : log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
672 : log_fatal_errno(errno, disk->name);
673 : return -1;
674 : /* LCOV_EXCL_STOP */
675 : }
676 : }
677 :
678 63033 : ret = rename(path, path_to);
679 63033 : if (ret != 0) {
680 : /* LCOV_EXCL_START */
681 : log_fatal(errno, "Error renaming '%s%s'. %s.\n", disk->dir, file->sub, strerror(errno));
682 : log_tag("%s:%u:%s:%s: Rename error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
683 : log_fatal_errno(errno, disk->name);
684 : return -1;
685 : /* LCOV_EXCL_STOP */
686 : }
687 :
688 63033 : log_tag("status:unrecoverable:%s:%s\n", disk->name, esc_tag(file->sub, esc_buffer));
689 63033 : msg_info("unrecoverable %s\n", fmt_term(disk, file->sub, esc_buffer));
690 :
691 : /* and do not set the time if damaged */
692 63033 : goto close_and_continue;
693 : }
694 :
695 : /* if the file is not fixed, meaning that it is untouched */
696 717676 : if (!file_flag_has(file, FILE_IS_FIXED)) {
697 : /* nothing to do, but close the file */
698 588680 : goto close_and_continue;
699 : }
700 :
701 : /* if the file is closed or different than the one expected, reopen it */
702 : /* a different open file could happen when filtering for bad blocks */
703 128996 : if (handle[j].file != file) {
704 : /* keep a pointer at the file we are going to close for error reporting */
705 0 : struct snapraid_file* report = handle[j].file;
706 0 : ret = handle_close(&handle[j]);
707 0 : if (ret != 0) {
708 : /* LCOV_EXCL_START */
709 : log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno));
710 : log_fatal_errno(errno, disk->name);
711 : return -1;
712 : /* LCOV_EXCL_STOP */
713 : }
714 :
715 : /* reopen it as readonly, as to set the mtime readonly access it's enough */
716 : /* we know that the file exists because it has the FILE_IS_FIXED tag */
717 0 : ret = handle_open(&handle[j], file, state->file_mode, log_error, log_error); /* output a message for missing files */
718 0 : if (ret != 0) {
719 : /* LCOV_EXCL_START */
720 : log_tag("%s:%u:%s:%s: Open error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
721 : log_fatal_errno(errno, disk->name);
722 : return -1;
723 : /* LCOV_EXCL_STOP */
724 : }
725 : }
726 :
727 128996 : log_tag("status:recovered:%s:%s\n", disk->name, esc_tag(file->sub, esc_buffer));
728 128996 : msg_info("recovered %s\n", fmt_term(disk, file->sub, esc_buffer));
729 :
730 128996 : inode = handle[j].st.st_ino;
731 :
732 : /* search for the corresponding inode */
733 128996 : collide_file = tommy_hashdyn_search(&disk->inodeset, file_inode_compare_to_arg, &inode, file_inode_hash(inode));
734 :
735 : /* if the inode is already in the database and it refers to a different file name, */
736 : /* we can fix the file time ONLY if the time and size allow to differentiate */
737 : /* between the two files */
738 :
739 : /* for example, suppose we delete a bunch of files with all the same size and time, */
740 : /* when recreating them the inodes may be reused in a different order, */
741 : /* and at the next sync some files may have matching inode/size/time even if different name */
742 : /* not allowing sync to detect that the file is changed and not renamed */
743 128996 : if (!collide_file /* if not in the database, there is no collision */
744 43321 : || strcmp(collide_file->sub, file->sub) == 0 /* if the name is the same, it's the right collision */
745 38111 : || collide_file->size != file->size /* if the size is different, the collision is identified */
746 12 : || collide_file->mtime_sec != file->mtime_sec /* if the mtime is different, the collision is identified */
747 5 : || collide_file->mtime_nsec != file->mtime_nsec /* same for mtime_nsec */
748 : ) {
749 : /* set the original modification time */
750 128995 : ret = handle_utime(&handle[j]);
751 128995 : if (ret == -1) {
752 : /* LCOV_EXCL_START */
753 : log_tag("%s:%u:%s:%s: Time error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
754 : log_fatal_errno(errno, disk->name);
755 :
756 : /* mark the file as damaged */
757 : file_flag_set(file, FILE_IS_DAMAGED);
758 : return -1;
759 : /* LCOV_EXCL_STOP */
760 : }
761 : } else {
762 1 : log_tag("collision:%s:%s:%s: Not setting modification time to avoid inode collision\n", disk->name, esc_tag(file->sub, esc_buffer), esc_tag(collide_file->sub, esc_buffer_alt));
763 : }
764 : } else {
765 : /* we are not fixing, but only checking */
766 : /* print just the final status */
767 1335882 : if (file_flag_has(file, FILE_IS_DAMAGED)) {
768 9544 : log_tag("status:unrecoverable:%s:%s\n", disk->name, esc_tag(file->sub, esc_buffer));
769 9544 : msg_info("unrecoverable %s\n", fmt_term(disk, file->sub, esc_buffer));
770 1326338 : } else if (file_flag_has(file, FILE_IS_FIXED)) {
771 84193 : log_tag("status:recoverable:%s:%s\n", disk->name, esc_tag(file->sub, esc_buffer));
772 84193 : msg_info("recoverable %s\n", fmt_term(disk, file->sub, esc_buffer));
773 : } else {
774 : /* we don't use msg_verbose() because it also goes into the log */
775 1242145 : if (msg_level >= MSG_VERBOSE) {
776 20289 : log_tag("status:correct:%s:%s\n", disk->name, esc_tag(file->sub, esc_buffer));
777 20289 : msg_info("correct %s\n", fmt_term(disk, file->sub, esc_buffer));
778 : }
779 : }
780 : }
781 :
782 1221856 : close_and_continue:
783 : /* if the opened file is the correct one, close it */
784 : /* in case of excluded and fragmented files it's possible */
785 : /* that the opened file is not the current one */
786 2190436 : if (handle[j].file == file) {
787 : /* ensure to close the file just after finishing with it */
788 : /* to avoid keeping it open without any possible use */
789 2040739 : ret = handle_close(&handle[j]);
790 2040739 : if (ret != 0) {
791 : /* LCOV_EXCL_START */
792 : log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
793 : log_fatal_errno(errno, disk->name);
794 : return -1;
795 : /* LCOV_EXCL_STOP */
796 : }
797 : }
798 : }
799 :
800 942424 : return 0;
801 : }
802 :
803 : /**
804 : * Check if we have to process the specified block index ::i.
805 : */
806 966399 : static int block_is_enabled(struct snapraid_state* state, block_off_t i, struct snapraid_handle* handle, unsigned diskmax)
807 : {
808 : unsigned j;
809 : unsigned l;
810 :
811 : /* filter for bad blocks */
812 966399 : if (state->opt.badblockonly) {
813 : snapraid_info info;
814 :
815 : /* get block specific info */
816 0 : info = info_get(&state->infoarr, i);
817 :
818 : /*
819 : * Filter specifically only for bad blocks
820 : */
821 0 : return info_get_bad(info);
822 : }
823 :
824 : /* filter for the parity */
825 966399 : if (state->opt.badfileonly) {
826 : snapraid_info info;
827 :
828 : /* get block specific info */
829 9374 : info = info_get(&state->infoarr, i);
830 :
831 : /*
832 : * If the block is bad, it has to be processed
833 : *
834 : * This is not necessary in normal cases because if a block is bad,
835 : * it necessary needs to have a file related to it, and files with
836 : * bad blocks are fully included.
837 : *
838 : * But some files may be excluded by additional filter options,
839 : * so it's not always true, and this ensures to always check all
840 : * the bad blocks.
841 : */
842 9374 : if (info_get_bad(info))
843 1772 : return 1;
844 : } else {
845 : /* if a parity is not excluded, include all blocks, even unused ones */
846 1106711 : for (l = 0; l < state->level; ++l) {
847 1064781 : if (!state->parity[l].is_excluded_by_filter) {
848 915095 : return 1;
849 : }
850 : }
851 : }
852 :
853 : /* filter for the files */
854 239893 : for (j = 0; j < diskmax; ++j) {
855 : struct snapraid_block* block;
856 :
857 : /* if no disk, nothing to check */
858 215918 : if (!handle[j].disk)
859 0 : continue;
860 :
861 215918 : block = fs_par2block_find(handle[j].disk, i);
862 :
863 : /* try to recover all files, even the ones without hash */
864 : /* because in some cases we can recover also them */
865 215918 : if (block_has_file(block)) {
866 210100 : struct snapraid_file* file = fs_par2file_get(handle[j].disk, i, 0);
867 210100 : if (!file_flag_has(file, FILE_IS_EXCLUDED)) { /* only if the file is not filtered out */
868 25557 : return 1;
869 : }
870 : }
871 : }
872 :
873 23975 : return 0;
874 : }
875 :
876 122 : static int state_check_process(struct snapraid_state* state, int fix, struct snapraid_parity_handle** parity, block_off_t blockstart, block_off_t blockmax)
877 : {
878 : struct snapraid_handle* handle;
879 : unsigned diskmax;
880 : block_off_t i;
881 : unsigned j;
882 : void* buffer_alloc;
883 : void** buffer;
884 : unsigned buffermax;
885 : int ret;
886 : data_off_t countsize;
887 : block_off_t countpos;
888 : block_off_t countmax;
889 : unsigned soft_error;
890 : unsigned io_error;
891 : unsigned silent_error;
892 : unsigned unrecoverable_error;
893 : unsigned recovered_error;
894 : struct failed_struct* failed;
895 : unsigned* failed_map;
896 : unsigned l;
897 : char esc_buffer[ESC_MAX];
898 : char esc_buffer_alt[ESC_MAX];
899 : bit_vect_t* block_enabled;
900 : struct snapraid_bw bw;
901 :
902 122 : handle = handle_mapping(state, &diskmax);
903 :
904 : /* initialize the bandwidth context */
905 122 : bw_init(&bw, state->opt.bwlimit);
906 :
907 : /* share the bandwidth context with all handles */
908 854 : for (j = 0; j < diskmax; ++j)
909 732 : handle[j].bw = &bw;
910 606 : for (j = 0; j < state->level; ++j)
911 484 : if (parity[j])
912 466 : parity[j]->bw = &bw;
913 :
914 : /* we need 1 * data + 2 * parity + 1 * zero */
915 122 : buffermax = diskmax + 2 * state->level + 1;
916 :
917 122 : buffer = malloc_nofail_vector_align(diskmax, buffermax, state->block_size, &buffer_alloc);
918 122 : if (!state->opt.skip_self)
919 0 : mtest_vector(buffermax, state->block_size, buffer);
920 :
921 : /* fill up the zero buffer */
922 122 : memset(buffer[buffermax - 1], 0, state->block_size);
923 122 : raid_zero(buffer[buffermax - 1]);
924 :
925 122 : failed = malloc_nofail(diskmax * sizeof(struct failed_struct));
926 122 : failed_map = malloc_nofail(diskmax * sizeof(unsigned));
927 :
928 122 : soft_error = 0;
929 122 : io_error = 0;
930 122 : silent_error = 0;
931 122 : unrecoverable_error = 0;
932 122 : recovered_error = 0;
933 :
934 122 : msg_progress("Selecting...\n");
935 :
936 : /* first count the number of blocks to process */
937 122 : countmax = 0;
938 122 : block_enabled = calloc_nofail(1, bit_vect_size(blockmax)); /* preinitialize to 0 */
939 966521 : for (i = blockstart; i < blockmax; ++i) {
940 966399 : if (!block_is_enabled(state, i, handle, diskmax))
941 23975 : continue;
942 942424 : bit_vect_set(block_enabled, i);
943 942424 : ++countmax;
944 : }
945 :
946 122 : if (fix)
947 47 : msg_progress("Fixing...\n");
948 75 : else if (!state->opt.auditonly)
949 70 : msg_progress("Checking...\n");
950 : else
951 5 : msg_progress("Hashing...\n");
952 :
953 : /* check all the blocks in files */
954 122 : countsize = 0;
955 122 : countpos = 0;
956 :
957 122 : int alert = state_progress_begin(state, blockstart, blockmax, countmax);
958 122 : if (alert > 0)
959 0 : goto end;
960 122 : if (alert < 0)
961 0 : goto bail;
962 :
963 966521 : for (i = blockstart; i < blockmax; ++i) {
964 : unsigned failed_count;
965 : int valid_parity;
966 : int used_parity;
967 : snapraid_info info;
968 : int rehash;
969 :
970 966399 : if (!bit_vect_test(block_enabled, i)) {
971 : /* continue with the next block */
972 23975 : continue;
973 : }
974 :
975 : /* If we have valid parity, and it makes sense to check its content. */
976 : /* If we already know that the parity is invalid, we just read the file */
977 : /* but we don't report parity errors */
978 : /* Note that with auditonly, we anyway skip the full parity check, */
979 : /* because we also don't read it at all */
980 942424 : valid_parity = 1;
981 :
982 : /* If the parity is used by at least one file */
983 942424 : used_parity = 0;
984 :
985 : /* keep track of the number of failed blocks */
986 942424 : failed_count = 0;
987 :
988 : /* get block specific info */
989 942424 : info = info_get(&state->infoarr, i);
990 :
991 : /* if we have to use the old hash */
992 942424 : rehash = info_get_rehash(info);
993 :
994 : /* for each disk, process the block */
995 6596968 : for (j = 0; j < diskmax; ++j) {
996 : int read_size;
997 : unsigned char hash[HASH_MAX];
998 : struct snapraid_disk* disk;
999 : struct snapraid_block* block;
1000 : struct snapraid_file* file;
1001 : block_off_t file_pos;
1002 : unsigned block_state;
1003 :
1004 : /* if the disk position is not used */
1005 5654544 : disk = handle[j].disk;
1006 5654544 : if (!disk) {
1007 : /* use an empty block */
1008 14061 : memset(buffer[j], 0, state->block_size);
1009 1006725 : continue;
1010 : }
1011 :
1012 : /* if the disk block is not used */
1013 5640483 : block = fs_par2block_find(disk, i);
1014 5640483 : if (block == BLOCK_NULL) {
1015 : /* use an empty block */
1016 220891 : memset(buffer[j], 0, state->block_size);
1017 220891 : continue;
1018 : }
1019 :
1020 : /* get the state of the block */
1021 5419592 : block_state = block_state_get(block);
1022 :
1023 : /* if the parity is not valid */
1024 5419592 : if (block_has_invalid_parity(block)) {
1025 : /* mark the parity as invalid, and don't try to check/fix it */
1026 : /* because it will be recomputed at the next sync */
1027 93037 : valid_parity = 0;
1028 : /* follow */
1029 : }
1030 :
1031 : /* if the block is DELETED */
1032 5419592 : if (block_state == BLOCK_STATE_DELETED) {
1033 : /* use an empty block */
1034 18618 : memset(buffer[j], 0, state->block_size);
1035 :
1036 : /* store it in the failed set, because potentially */
1037 : /* the parity may be still computed with the previous content */
1038 18618 : failed[failed_count].is_bad = 0; /* note that is_bad==0 <=> file==0 */
1039 18618 : failed[failed_count].is_outofdate = 0;
1040 18618 : failed[failed_count].index = j;
1041 18618 : failed[failed_count].block = block;
1042 18618 : failed[failed_count].disk = disk;
1043 18618 : failed[failed_count].file = 0;
1044 18618 : failed[failed_count].file_pos = 0;
1045 18618 : failed[failed_count].handle = 0;
1046 18618 : ++failed_count;
1047 18618 : continue;
1048 : }
1049 :
1050 : /* here we are sure that the parity is used by a file */
1051 5400974 : used_parity = 1;
1052 :
1053 : /* get the file of this block */
1054 5400974 : file = fs_par2file_get(disk, i, &file_pos);
1055 :
1056 : /* if we are only hashing, we can skip excluded files and don't even read them */
1057 5400974 : if (state->opt.auditonly && file_flag_has(file, FILE_IS_EXCLUDED)) {
1058 : /* use an empty block */
1059 : /* in true, this is unnecessary, because we are not checking any parity */
1060 : /* but we keep it for completeness */
1061 0 : memset(buffer[j], 0, state->block_size);
1062 0 : continue;
1063 : }
1064 :
1065 : /* if the file is closed or different than the current one */
1066 5400974 : if (handle[j].file == 0 || handle[j].file != file) {
1067 : /* keep a pointer at the file we are going to close for error reporting */
1068 2334391 : struct snapraid_file* report = handle[j].file;
1069 2334391 : ret = handle_close(&handle[j]);
1070 2334391 : if (ret == -1) {
1071 : /* LCOV_EXCL_START */
1072 : log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno));
1073 : log_fatal_errno(errno, disk->name);
1074 : log_fatal(errno, "Stopping at block %u\n", i);
1075 :
1076 : ++unrecoverable_error;
1077 : goto bail;
1078 : /* LCOV_EXCL_STOP */
1079 : }
1080 :
1081 : /* if fixing, and the file is not excluded, we must open for writing */
1082 2334391 : if (fix && !file_flag_has(file, FILE_IS_EXCLUDED)) {
1083 : /* if fixing, create the file, open for writing and resize if required */
1084 786823 : ret = handle_create(&handle[j], file, state->file_mode);
1085 786823 : if (ret == -1) {
1086 : /* LCOV_EXCL_START */
1087 : log_tag("%s:%u:%s:%s: Create error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
1088 : log_fatal_errno(errno, disk->name);
1089 : log_fatal(errno, "Stopping at block %u\n", i);
1090 :
1091 : ++unrecoverable_error;
1092 : goto bail;
1093 : /* LCOV_EXCL_STOP */
1094 : }
1095 :
1096 : /* check if the file was just created */
1097 786823 : if (handle[j].created != 0) {
1098 : /* if fragmented, it may be reopened, so remember that the file */
1099 : /* was originally missing */
1100 120891 : file_flag_set(file, FILE_IS_CREATED);
1101 : }
1102 : } else {
1103 : /* open the file only for reading */
1104 1547568 : if (!file_flag_has(file, FILE_IS_MISSING)) {
1105 1420058 : ret = handle_open(&handle[j], file, state->file_mode, log_error, state->opt.expected_missing ? log_expected : 0);
1106 : } else {
1107 127510 : errno = ENOENT;
1108 127510 : ret = -1; /* if the file is missing, we cannot open it */
1109 : }
1110 1547568 : if (ret == -1) {
1111 : /* save the failed block for the check/fix */
1112 214175 : failed[failed_count].is_bad = 1;
1113 214175 : failed[failed_count].is_outofdate = 0;
1114 214175 : failed[failed_count].index = j;
1115 214175 : failed[failed_count].block = block;
1116 214175 : failed[failed_count].disk = disk;
1117 214175 : failed[failed_count].file = file;
1118 214175 : failed[failed_count].file_pos = file_pos;
1119 214175 : failed[failed_count].handle = &handle[j];
1120 214175 : ++failed_count;
1121 :
1122 214175 : log_tag("%s:%u:%s:%s: Open error at position %u. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), file_pos, strerror(errno));
1123 :
1124 214175 : if (is_hw(errno)) {
1125 0 : ++io_error;
1126 : } else {
1127 214175 : ++soft_error;
1128 : }
1129 :
1130 : /* mark the file as missing, to avoid to retry to open it again */
1131 : /* note that this can be done only if we are not fixing it */
1132 : /* otherwise, it could be recreated */
1133 214175 : file_flag_set(file, FILE_IS_MISSING);
1134 214175 : continue;
1135 : }
1136 : }
1137 :
1138 : /* if it's the first open, and not excluded */
1139 2120216 : if (!file_flag_has(file, FILE_IS_OPENED)
1140 2103868 : && !file_flag_has(file, FILE_IS_EXCLUDED)) {
1141 :
1142 : /* check if the file is changed */
1143 2033640 : if (handle[j].st.st_size != file->size
1144 1833280 : || handle[j].st.st_mtime != file->mtime_sec
1145 1810116 : || STAT_NSEC(&handle[j].st) != file->mtime_nsec
1146 : /* don't check the inode to support file-system without persistent inodes */
1147 : ) {
1148 : /* report that the file is not synced */
1149 223524 : file_flag_set(file, FILE_IS_UNSYNCED);
1150 : }
1151 : }
1152 :
1153 : /* if it's the first open, and not excluded and larger */
1154 2120216 : if (!file_flag_has(file, FILE_IS_OPENED)
1155 2103868 : && !file_flag_has(file, FILE_IS_EXCLUDED)
1156 2033640 : && !(state->opt.syncedonly && file_flag_has(file, FILE_IS_UNSYNCED))
1157 2033640 : && handle[j].st.st_size > file->size
1158 : ) {
1159 8757 : log_error(ESOFT, "File '%s' is larger than expected.\n", handle[j].path);
1160 8757 : log_tag("error:%u:%s:%s: Size error\n", i, disk->name, esc_tag(file->sub, esc_buffer));
1161 8757 : ++soft_error;
1162 :
1163 8757 : if (fix) {
1164 3234 : ret = handle_truncate(&handle[j], file);
1165 3234 : if (ret == -1) {
1166 : /* LCOV_EXCL_START */
1167 : log_tag("%s:%u:%s:%s: Truncate error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
1168 : log_fatal_errno(errno, disk->name);
1169 : log_fatal(errno, "Stopping at block %u\n", i);
1170 :
1171 : ++unrecoverable_error;
1172 : goto bail;
1173 : /* LCOV_EXCL_STOP */
1174 : }
1175 :
1176 3234 : log_tag("fixed:%u:%s:%s: Fixed size\n", i, disk->name, esc_tag(file->sub, esc_buffer));
1177 3234 : ++recovered_error;
1178 : }
1179 : }
1180 :
1181 : /* mark the file as opened at least one time */
1182 : /* this is used to avoid to check the unsynced and size */
1183 : /* more than one time, in case the file is reopened later */
1184 2120216 : file_flag_set(file, FILE_IS_OPENED);
1185 : }
1186 :
1187 : /* read from the file */
1188 5186799 : if (file_flag_has(file, FILE_IS_MISSING)) {
1189 : /* if the file is reported missing, don't even try to read it */
1190 267140 : errno = ENOENT;
1191 267140 : read_size = -1;
1192 : } else {
1193 4919659 : read_size = handle_read(&handle[j], file_pos, buffer[j], state->block_size, log_error, state->opt.expected_missing ? log_expected : 0);
1194 : }
1195 5186799 : if (read_size == -1) {
1196 : /* save the failed block for the check/fix */
1197 460191 : failed[failed_count].is_bad = 1; /* it's bad because we cannot read it */
1198 460191 : failed[failed_count].is_outofdate = 0;
1199 460191 : failed[failed_count].index = j;
1200 460191 : failed[failed_count].block = block;
1201 460191 : failed[failed_count].disk = disk;
1202 460191 : failed[failed_count].file = file;
1203 460191 : failed[failed_count].file_pos = file_pos;
1204 460191 : failed[failed_count].handle = &handle[j];
1205 460191 : ++failed_count;
1206 :
1207 460191 : log_tag("%s:%u:%s:%s: Read error at position %u. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), file_pos, strerror(errno));
1208 :
1209 460191 : if (is_hw(errno)) {
1210 0 : ++io_error;
1211 : } else {
1212 460191 : ++soft_error;
1213 : }
1214 :
1215 : /* if we are reading at the end, mark the file as missing to avoid to try to read it again at the next block */
1216 460191 : if (errno == ENOENT) {
1217 450307 : file_flag_set(file, FILE_IS_MISSING);
1218 : }
1219 460191 : continue;
1220 : }
1221 :
1222 4726608 : countsize += read_size;
1223 :
1224 : /* always insert CHG blocks, the repair functions needs all of them */
1225 : /* because the parity may be still referring at the old state */
1226 : /* and the repair must be aware of it */
1227 4726608 : if (block_state == BLOCK_STATE_CHG) {
1228 : /* we DO NOT mark them as bad to avoid to overwrite them with wrong data. */
1229 : /* if we don't have a hash, we always assume the first read of the block correct. */
1230 13779 : failed[failed_count].is_bad = 0; /* we assume the CHG block correct */
1231 13779 : failed[failed_count].is_outofdate = 0;
1232 13779 : failed[failed_count].index = j;
1233 13779 : failed[failed_count].block = block;
1234 13779 : failed[failed_count].disk = disk;
1235 13779 : failed[failed_count].file = file;
1236 13779 : failed[failed_count].file_pos = file_pos;
1237 13779 : failed[failed_count].handle = &handle[j];
1238 13779 : ++failed_count;
1239 13779 : continue;
1240 : }
1241 :
1242 4712829 : assert(block_state == BLOCK_STATE_BLK || block_state == BLOCK_STATE_REP);
1243 :
1244 : /* compute the hash of the block just read */
1245 4712829 : if (rehash) {
1246 27200 : memhash(state->prevhash, state->prevhashseed, hash, buffer[j], read_size);
1247 : } else {
1248 4685629 : memhash(state->hash, state->hashseed, hash, buffer[j], read_size);
1249 : }
1250 :
1251 : /* compare the hash */
1252 4712829 : if (memcmp(hash, block->hash, BLOCK_HASH_SIZE) != 0) {
1253 12862 : unsigned diff = memdiff(hash, block->hash, BLOCK_HASH_SIZE);
1254 :
1255 : /* save the failed block for the check/fix */
1256 12862 : failed[failed_count].is_bad = 1; /* it's bad because the hash doesn't match */
1257 12862 : failed[failed_count].is_outofdate = 0;
1258 12862 : failed[failed_count].index = j;
1259 12862 : failed[failed_count].block = block;
1260 12862 : failed[failed_count].disk = disk;
1261 12862 : failed[failed_count].file = file;
1262 12862 : failed[failed_count].file_pos = file_pos;
1263 12862 : failed[failed_count].handle = &handle[j];
1264 12862 : ++failed_count;
1265 :
1266 12862 : log_tag("error:%u:%s:%s: Data error at position %u, diff hash bits %u/%u\n", i, disk->name, esc_tag(file->sub, esc_buffer), file_pos, diff, BLOCK_HASH_SIZE * 8);
1267 12862 : ++silent_error;
1268 12862 : continue;
1269 : }
1270 :
1271 : /* always insert REP blocks, the repair functions needs all of them */
1272 : /* because the parity may be still referring at the old state */
1273 : /* and the repair must be aware of it */
1274 4699967 : if (block_state == BLOCK_STATE_REP) {
1275 52148 : failed[failed_count].is_bad = 0; /* it's not bad */
1276 52148 : failed[failed_count].is_outofdate = 0;
1277 52148 : failed[failed_count].index = j;
1278 52148 : failed[failed_count].block = block;
1279 52148 : failed[failed_count].disk = disk;
1280 52148 : failed[failed_count].file = file;
1281 52148 : failed[failed_count].file_pos = file_pos;
1282 52148 : failed[failed_count].handle = &handle[j];
1283 52148 : ++failed_count;
1284 52148 : continue;
1285 : }
1286 : }
1287 :
1288 : /* now read and check the parity if requested */
1289 942424 : if (!state->opt.auditonly) {
1290 : void* buffer_recov[LEV_MAX];
1291 : void* buffer_zero;
1292 :
1293 : /* buffers for parity read and not computed */
1294 4325835 : for (l = 0; l < state->level; ++l)
1295 3422926 : buffer_recov[l] = buffer[diskmax + state->level + l];
1296 2897437 : for (; l < LEV_MAX; ++l)
1297 1994528 : buffer_recov[l] = 0;
1298 :
1299 : /* the zero buffer is the last one */
1300 902909 : buffer_zero = buffer[buffermax - 1];
1301 :
1302 : /* read the parity */
1303 4325835 : for (l = 0; l < state->level; ++l) {
1304 3422926 : if (parity[l]) {
1305 3408964 : ret = parity_read(parity[l], i, buffer_recov[l], state->block_size, log_error);
1306 3408964 : if (ret == -1) {
1307 96822 : log_tag("parity_%s:%u:%s: Read error. %s.\n", es(errno), i, lev_config_name(l), strerror(errno));
1308 :
1309 96822 : buffer_recov[l] = 0; /* no parity to use */
1310 :
1311 96822 : if (is_hw(errno)) {
1312 0 : ++io_error;
1313 : } else {
1314 96822 : ++soft_error;
1315 : }
1316 : }
1317 : } else {
1318 13962 : buffer_recov[l] = 0;
1319 : }
1320 : }
1321 :
1322 : /* try all the recovering strategies */
1323 902909 : ret = repair(state, rehash, i, diskmax, failed, failed_map, failed_count, buffer, buffer_recov, buffer_zero);
1324 902909 : if (ret != 0) {
1325 : /* increment the number of errors */
1326 47717 : if (ret > 0)
1327 4840 : silent_error += ret;
1328 47717 : ++unrecoverable_error;
1329 :
1330 : /* print a list of all the errors in files */
1331 218100 : for (j = 0; j < failed_count; ++j) {
1332 170383 : if (failed[j].is_bad)
1333 165820 : log_tag("unrecoverable:%u:%s:%s: Unrecoverable error at position %u\n", i, failed[j].disk->name, esc_tag(failed[j].file->sub, esc_buffer), failed[j].file_pos);
1334 : }
1335 :
1336 : /* keep track of damaged files */
1337 218100 : for (j = 0; j < failed_count; ++j) {
1338 170383 : if (failed[j].is_bad)
1339 165820 : file_flag_set(failed[j].file, FILE_IS_DAMAGED);
1340 : }
1341 : } else {
1342 : /* now counts partial recovers */
1343 : /* note that this could happen only when we have an incomplete 'sync' */
1344 : /* and that we have recovered is the state before the 'sync' */
1345 855192 : int partial_recover_error = 0;
1346 :
1347 : /* print a list of all the errors in files */
1348 1450379 : for (j = 0; j < failed_count; ++j) {
1349 595187 : if (failed[j].is_bad && failed[j].is_outofdate) {
1350 8 : ++partial_recover_error;
1351 8 : log_tag("unrecoverable:%u:%s:%s: Unrecoverable unsynced error at position %u\n", i, failed[j].disk->name, esc_tag(failed[j].file->sub, esc_buffer), failed[j].file_pos);
1352 : }
1353 : }
1354 855192 : if (partial_recover_error != 0) {
1355 8 : silent_error += partial_recover_error;
1356 8 : ++unrecoverable_error;
1357 : }
1358 :
1359 : /*
1360 : * Check parities, but only if all the blocks have it computed and it's used.
1361 : *
1362 : * If you check/fix after a partial sync, it's OK to have parity errors
1363 : * on the blocks with invalid parity and doesn't make sense to try to fix it.
1364 : *
1365 : * It's also OK to have data errors on unused parity, because sync doesn't
1366 : * update it.
1367 : */
1368 855192 : if (used_parity && valid_parity) {
1369 : /* check the parity */
1370 3885021 : for (l = 0; l < state->level; ++l) {
1371 3090885 : if (buffer_recov[l] != 0 && memcmp(buffer_recov[l], buffer[diskmax + l], state->block_size) != 0) {
1372 21279 : unsigned diff = memdiff(buffer_recov[l], buffer[diskmax + l], state->block_size);
1373 :
1374 : /* mark that the read parity is wrong, setting ptr to 0 */
1375 21279 : buffer_recov[l] = 0;
1376 :
1377 21279 : log_tag("parity_error:%u:%s: Data error, diff parity bits %u/%u\n", i, lev_config_name(l), diff, state->block_size * 8);
1378 21279 : ++silent_error;
1379 : }
1380 : }
1381 : }
1382 :
1383 : /* now write recovered files */
1384 855192 : if (fix) {
1385 : /* update the fixed files */
1386 688355 : for (j = 0; j < failed_count; ++j) {
1387 : /* nothing to do if it doesn't need recovering */
1388 356398 : if (!failed[j].is_bad)
1389 39783 : continue;
1390 :
1391 : /* do not fix if the file is excluded */
1392 316615 : if (file_flag_has(failed[j].file, FILE_IS_EXCLUDED)
1393 307452 : || (state->opt.syncedonly && file_flag_has(failed[j].file, FILE_IS_UNSYNCED)))
1394 9163 : continue;
1395 :
1396 307452 : ret = handle_write(failed[j].handle, failed[j].file_pos, buffer[failed[j].index], state->block_size);
1397 307452 : if (ret == -1) {
1398 : /* LCOV_EXCL_START */
1399 : log_tag("%s:%u:%s:%s: Write error. %s.\n", es(errno), i, failed[j].disk->name, esc_tag(failed[j].file->sub, esc_buffer), strerror(errno));
1400 : log_fatal_errno(errno, failed[j].disk->name);
1401 : log_fatal(errno, "Stopping at block %u\n", i);
1402 :
1403 : /* mark the file as damaged */
1404 : file_flag_set(failed[j].file, FILE_IS_DAMAGED);
1405 :
1406 : ++unrecoverable_error;
1407 : goto bail;
1408 : /* LCOV_EXCL_STOP */
1409 : }
1410 :
1411 : /* if we are not sure that the recovered content is uptodate */
1412 307452 : if (failed[j].is_outofdate) {
1413 : /* mark the file as damaged */
1414 8 : file_flag_set(failed[j].file, FILE_IS_DAMAGED);
1415 8 : continue;
1416 : }
1417 :
1418 : /* mark the file as containing some fixes */
1419 : /* note that it could be also marked as damaged in other iterations */
1420 307444 : file_flag_set(failed[j].file, FILE_IS_FIXED);
1421 :
1422 307444 : log_tag("fixed:%u:%s:%s: Fixed data error at position %u\n", i, failed[j].disk->name, esc_tag(failed[j].file->sub, esc_buffer), failed[j].file_pos);
1423 307444 : ++recovered_error;
1424 : }
1425 :
1426 : /*
1427 : * Update parity only if all the blocks have it computed and it's used.
1428 : *
1429 : * If you check/fix after a partial sync, you do not want to fix parity
1430 : * for blocks that are going to have it computed in the sync completion.
1431 : *
1432 : * For unused parity there is no need to write it, because when fixing
1433 : * we already have allocated space for it on parity file creation,
1434 : * and its content doesn't matter.
1435 : */
1436 331957 : if (used_parity && valid_parity) {
1437 : /* update the parity */
1438 1043669 : for (l = 0; l < state->level; ++l) {
1439 : /* if the parity on disk is wrong */
1440 759987 : if (buffer_recov[l] == 0
1441 : /* and we have access at the parity */
1442 79446 : && parity[l] != 0
1443 : /* and the parity is not excluded */
1444 74759 : && !state->parity[l].is_excluded_by_filter
1445 : ) {
1446 74759 : ret = parity_write(parity[l], i, buffer[diskmax + l], state->block_size);
1447 74759 : if (ret == -1) {
1448 : /* LCOV_EXCL_START */
1449 : log_tag("%s:%u:%s: Write error. %s.\n", es(errno), i, lev_config_name(l), strerror(errno));
1450 : log_fatal_errno(errno, lev_config_name(l));
1451 : log_fatal(errno, "Stopping at block %u\n", i);
1452 :
1453 : ++unrecoverable_error;
1454 : goto bail;
1455 : /* LCOV_EXCL_STOP */
1456 : }
1457 :
1458 74759 : log_tag("parity_fixed:%u:%s: Fixed data error\n", i, lev_config_name(l));
1459 74759 : ++recovered_error;
1460 : }
1461 : }
1462 : }
1463 : } else {
1464 : /* if we are not fixing, we just set the FIXED flag */
1465 : /* meaning that we could fix this file if we try */
1466 762024 : for (j = 0; j < failed_count; ++j) {
1467 238789 : if (failed[j].is_bad) {
1468 198590 : file_flag_set(failed[j].file, FILE_IS_FIXED);
1469 : }
1470 : }
1471 : }
1472 : }
1473 : } else {
1474 : /* if we are not checking, we just set the DAMAGED flag */
1475 : /* to report that the file is damaged, and we don't know if we can fix it */
1476 45718 : for (j = 0; j < failed_count; ++j) {
1477 6203 : if (failed[j].is_bad) {
1478 6203 : file_flag_set(failed[j].file, FILE_IS_DAMAGED);
1479 : }
1480 : }
1481 : }
1482 :
1483 : /* post process the files */
1484 942424 : ret = file_post(state, fix, i, handle, diskmax);
1485 942424 : if (ret == -1) {
1486 : /* LCOV_EXCL_START */
1487 : log_fatal(errno, "Stopping at block %u\n", i);
1488 :
1489 : ++unrecoverable_error;
1490 : goto bail;
1491 : /* LCOV_EXCL_STOP */
1492 : }
1493 :
1494 : /* count the number of processed block */
1495 942424 : ++countpos;
1496 :
1497 : /* progress */
1498 942424 : if (state_progress(state, 0, i, countpos, countmax, countsize)) {
1499 : /* LCOV_EXCL_START */
1500 : break;
1501 : /* LCOV_EXCL_STOP */
1502 : }
1503 :
1504 : /* thermal control */
1505 942424 : if (state_thermal_alarm(state)) {
1506 : /* until now is misc */
1507 0 : state_usage_misc(state);
1508 :
1509 0 : state_progress_stop(state);
1510 :
1511 0 : state_thermal_cooldown(state);
1512 :
1513 0 : state_progress_restart(state);
1514 :
1515 : /* drop until now */
1516 0 : state_usage_waste(state);
1517 : }
1518 : }
1519 :
1520 : /* for each disk, recover empty files, symlinks and empty dirs */
1521 854 : for (i = 0; i < diskmax; ++i) {
1522 : tommy_node* node;
1523 : struct snapraid_disk* disk;
1524 :
1525 732 : if (!handle[i].disk)
1526 3 : continue;
1527 :
1528 : /* for each empty file in the disk */
1529 729 : disk = handle[i].disk;
1530 729 : node = disk->filelist;
1531 2250736 : while (node) {
1532 : char path[PATH_MAX];
1533 : struct stat st;
1534 : struct snapraid_file* file;
1535 2250007 : int unsuccessful = 0;
1536 :
1537 2250007 : file = node->data;
1538 2250007 : node = node->next; /* next node */
1539 :
1540 : /* if not empty, it's already checked and continue to the next one */
1541 2250007 : if (file->size != 0) {
1542 2247158 : continue;
1543 : }
1544 :
1545 : /* if excluded continue to the next one */
1546 3046 : if (file_flag_has(file, FILE_IS_EXCLUDED)) {
1547 197 : continue;
1548 : }
1549 :
1550 : /* stat the file */
1551 2849 : pathprint(path, sizeof(path), "%s%s", disk->dir, file->sub);
1552 2849 : ret = stat(path, &st);
1553 2849 : if (ret == -1) {
1554 193 : unsuccessful = 1;
1555 :
1556 193 : log_error(errno, "Error stating empty file '%s'. %s.\n", path, strerror(errno));
1557 193 : log_tag("empty_%s:%s:%s: Empty file stat error\n", es(errno), disk->name, esc_tag(file->sub, esc_buffer));
1558 :
1559 193 : if (is_hw(errno)) {
1560 0 : ++io_error;
1561 : } else {
1562 193 : ++soft_error;
1563 : }
1564 2656 : } else if (!S_ISREG(st.st_mode)) {
1565 0 : unsuccessful = 1;
1566 :
1567 0 : log_error(ESOFT, "Error stating empty file '%s' for not regular file.\n", path);
1568 0 : log_tag("empty_error:%s:%s: Empty file error for not regular file\n", disk->name, esc_tag(file->sub, esc_buffer));
1569 0 : ++soft_error;
1570 2656 : } else if (st.st_size != 0) {
1571 20 : unsuccessful = 1;
1572 :
1573 20 : log_error(ESOFT, "Error stating empty file '%s' for not empty file.\n", path);
1574 20 : log_tag("empty_error:%s:%s: Empty file error for size '%" PRIu64 "'\n", disk->name, esc_tag(file->sub, esc_buffer), (uint64_t)st.st_size);
1575 20 : ++soft_error;
1576 : }
1577 :
1578 2849 : if (fix && unsuccessful) {
1579 : int f;
1580 :
1581 : /* create the ancestor directories */
1582 171 : ret = mkancestor(path);
1583 171 : if (ret != 0) {
1584 : /* LCOV_EXCL_START */
1585 : log_fatal(errno, "Error creating ancestor '%s%s'. %s.\n", disk->dir, file->sub, strerror(errno));
1586 : log_tag("empty_%s:%u:%s:%s: Create ancestor error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
1587 : log_fatal_errno(errno, disk->name);
1588 : log_fatal(errno, "Stopping\n");
1589 :
1590 : ++unrecoverable_error;
1591 : goto bail;
1592 : /* LCOV_EXCL_STOP */
1593 : }
1594 :
1595 : /* create it */
1596 : /* O_NOFOLLOW: do not follow links to ensure to open the real file */
1597 171 : f = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_NOFOLLOW, 0600);
1598 171 : if (f == -1) {
1599 : /* LCOV_EXCL_START */
1600 : log_fatal(errno, "Error creating '%s%s'. %s.\n", disk->dir, file->sub, strerror(errno));
1601 : log_tag("empty_%s:%u:%s:%s: Create error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
1602 : log_fatal_errno(errno, disk->name);
1603 : log_fatal(errno, "Stopping\n");
1604 :
1605 : ++unrecoverable_error;
1606 : goto bail;
1607 : /* LCOV_EXCL_STOP */
1608 : }
1609 :
1610 : /* set the original modification time */
1611 171 : ret = fmtime(f, file->mtime_sec, file->mtime_nsec);
1612 171 : if (ret != 0) {
1613 : /* LCOV_EXCL_START */
1614 : log_fatal(errno, "Error timing '%s%s'. %s.\n", disk->dir, file->sub, strerror(errno));
1615 : log_tag("empty_%s:%u:%s:%s: Time error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
1616 : log_fatal_errno(errno, disk->name);
1617 : log_fatal(errno, "Stopping\n");
1618 :
1619 : close(f);
1620 :
1621 : ++unrecoverable_error;
1622 : goto bail;
1623 : /* LCOV_EXCL_STOP */
1624 : }
1625 :
1626 : /* close it */
1627 171 : ret = close(f);
1628 171 : if (ret != 0) {
1629 : /* LCOV_EXCL_START */
1630 : log_fatal(errno, "Error closing '%s%s'. %s.\n", disk->dir, file->sub, strerror(errno));
1631 : log_tag("empty_%s:%u:%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
1632 : log_fatal_errno(errno, disk->name);
1633 : log_fatal(errno, "Stopping\n");
1634 :
1635 : ++unrecoverable_error;
1636 : goto bail;
1637 : /* LCOV_EXCL_STOP */
1638 : }
1639 :
1640 171 : log_tag("empty_fixed:%s:%s: Fixed empty file\n", disk->name, esc_tag(file->sub, esc_buffer));
1641 171 : ++recovered_error;
1642 :
1643 171 : log_tag("status:recovered:%s:%s\n", disk->name, esc_tag(file->sub, esc_buffer));
1644 171 : msg_info("recovered %s\n", fmt_term(disk, file->sub, esc_buffer));
1645 : }
1646 : }
1647 :
1648 : /* for each link in the disk */
1649 729 : disk = handle[i].disk;
1650 729 : node = disk->linklist;
1651 72521 : while (node) {
1652 : char path[PATH_MAX];
1653 : char pathto[PATH_MAX];
1654 : char linkto[PATH_MAX];
1655 : struct stat st;
1656 : struct stat stto;
1657 : struct snapraid_link* slink;
1658 71792 : int unsuccessful = 0;
1659 71792 : int unrecoverable = 0;
1660 :
1661 71792 : slink = node->data;
1662 71792 : node = node->next; /* next node */
1663 :
1664 : /* if excluded continue to the next one */
1665 71792 : if (link_flag_has(slink, FILE_IS_EXCLUDED)) {
1666 3908 : continue;
1667 : }
1668 :
1669 67884 : if (link_flag_has(slink, FILE_IS_HARDLINK)) {
1670 : /* stat the link */
1671 327 : pathprint(path, sizeof(path), "%s%s", disk->dir, slink->sub);
1672 327 : ret = stat(path, &st);
1673 327 : if (ret == -1) {
1674 36 : unsuccessful = 1;
1675 :
1676 36 : log_error(errno, "Error stating hardlink '%s'. %s.\n", path, strerror(errno));
1677 36 : log_tag("hardlink_%s:%s:%s:%s: Hardlink stat error. %s.\n", es(errno), disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt), strerror(errno));
1678 :
1679 36 : if (is_hw(errno)) {
1680 0 : ++io_error;
1681 : } else {
1682 36 : ++soft_error;
1683 : }
1684 291 : } else if (!S_ISREG(st.st_mode)) {
1685 0 : unsuccessful = 1;
1686 :
1687 0 : log_error(ESOFT, "Error stating hardlink '%s' for not regular file.\n", path);
1688 0 : log_tag("hardlink_error:%s:%s:%s: Hardlink error for not regular file\n", disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt));
1689 0 : ++soft_error;
1690 : }
1691 :
1692 : /* stat the "to" file */
1693 327 : pathprint(pathto, sizeof(pathto), "%s%s", disk->dir, slink->linkto);
1694 327 : ret = stat(pathto, &stto);
1695 327 : if (ret == -1) {
1696 24 : unsuccessful = 1;
1697 :
1698 24 : if (errno == ENOENT) {
1699 24 : unrecoverable = 1;
1700 24 : if (fix) {
1701 : /* if the target doesn't exist, it's unrecoverable */
1702 : /* because we cannot create an hardlink of a file that */
1703 : /* doesn't exists */
1704 : /* but in check, we can assume that fixing will recover */
1705 : /* such missing file, so we assume a less drastic error */
1706 12 : ++unrecoverable_error;
1707 : }
1708 : }
1709 :
1710 24 : log_error(errno, "Error stating hardlink-to '%s'. %s.\n", pathto, strerror(errno));
1711 24 : log_tag("hardlink_%s:%s:%s:%s: Hardlink to stat error. %s.\n", es(errno), disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt), strerror(errno));
1712 :
1713 24 : if (is_hw(errno)) {
1714 0 : ++io_error;
1715 : } else {
1716 24 : ++soft_error;
1717 : }
1718 303 : } else if (!S_ISREG(stto.st_mode)) {
1719 0 : unsuccessful = 1;
1720 :
1721 0 : log_error(ESOFT, "Error stating hardlink-to '%s' for not regular file.\n", path);
1722 0 : log_tag("hardlink_error:%s:%s:%s: Hardlink-to error for not regular file\n", disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt));
1723 0 : ++soft_error;
1724 303 : } else if (!unsuccessful && st.st_ino != stto.st_ino) {
1725 0 : unsuccessful = 1;
1726 :
1727 0 : log_error(ESOFT, "Mismatch hardlink '%s' and '%s'. Different inode.\n", path, pathto);
1728 0 : log_tag("hardlink_error:%s:%s:%s: Hardlink mismatch for different inode\n", disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt));
1729 0 : ++soft_error;
1730 : }
1731 : } else {
1732 : /* read the symlink */
1733 67557 : pathprint(path, sizeof(path), "%s%s", disk->dir, slink->sub);
1734 67557 : ret = readlink(path, linkto, sizeof(linkto));
1735 67557 : if (ret < 0) {
1736 4857 : unsuccessful = 1;
1737 :
1738 4857 : log_error(errno, "Error reading symlink '%s'. %s.\n", path, strerror(errno));
1739 4857 : log_tag("symlink_%s:%s:%s: Symlink read error. %s.\n", es(errno), disk->name, esc_tag(slink->sub, esc_buffer), strerror(errno));
1740 :
1741 4857 : if (is_hw(errno)) {
1742 0 : ++io_error;
1743 : } else {
1744 4857 : ++soft_error;
1745 : }
1746 62700 : } else if (ret >= PATH_MAX) {
1747 0 : unsuccessful = 1;
1748 :
1749 0 : log_error(ESOFT, "Error reading symlink '%s'. Symlink too long.\n", path);
1750 0 : log_tag("symlink_error:%s:%s: Symlink too long\n", disk->name, esc_tag(slink->sub, esc_buffer));
1751 0 : ++soft_error;
1752 : } else {
1753 62700 : linkto[ret] = 0;
1754 :
1755 62700 : if (strcmp(linkto, slink->linkto) != 0) {
1756 555 : unsuccessful = 1;
1757 :
1758 555 : log_tag("symlink_error:%s:%s: Symlink data error '%s' instead of '%s'\n", disk->name, esc_tag(slink->sub, esc_buffer), linkto, slink->linkto);
1759 555 : ++soft_error;
1760 : }
1761 : }
1762 : }
1763 :
1764 67884 : if (fix && unsuccessful && !unrecoverable) {
1765 4231 : const char* link = link_flag_has(slink, FILE_IS_HARDLINK) ? "hard" : "sym";
1766 :
1767 : /* create the ancestor directories */
1768 4231 : ret = mkancestor(path);
1769 4231 : if (ret != 0) {
1770 : /* LCOV_EXCL_START */
1771 : log_fatal(errno, "Error creating ancestor '%s%s'. %s.\n", disk->dir, slink->sub, strerror(errno));
1772 : log_tag("%slink_%s:%u:%s:%s: Create ancestor error. %s.\n", link, es(errno), i, disk->name, esc_tag(slink->sub, esc_buffer), strerror(errno));
1773 : log_fatal_errno(errno, disk->name);
1774 : log_fatal(errno, "Stopping\n");
1775 :
1776 : ++unrecoverable_error;
1777 : goto bail;
1778 : /* LCOV_EXCL_STOP */
1779 : }
1780 :
1781 : /* if it exists, it must be deleted before recreating */
1782 4231 : ret = remove(path);
1783 4231 : if (ret != 0 && errno != ENOENT) {
1784 : /* LCOV_EXCL_START */
1785 : log_fatal(errno, "Error removing '%s%s'. %s.\n", disk->dir, slink->sub, strerror(errno));
1786 : log_tag("%slink_%s:%u:%s:%s: Remove error. %s.\n", link, es(errno), i, disk->name, esc_tag(slink->sub, esc_buffer), strerror(errno));
1787 : log_fatal_errno(errno, disk->name);
1788 : log_fatal(errno, "Stopping\n");
1789 :
1790 : ++unrecoverable_error;
1791 : goto bail;
1792 : /* LCOV_EXCL_STOP */
1793 : }
1794 :
1795 : /* create it */
1796 4231 : if (link_flag_has(slink, FILE_IS_HARDLINK)) {
1797 12 : ret = hardlink(pathto, path);
1798 12 : if (ret != 0) {
1799 : /* LCOV_EXCL_START */
1800 : log_fatal(errno, "Error writing hardlink '%s' to '%s'. %s.\n", path, pathto, strerror(errno));
1801 : log_tag("hardlink_%s:%u:%s:%s: Hardlink error. %s.\n", es(errno), i, disk->name, esc_tag(slink->sub, esc_buffer), strerror(errno));
1802 : log_fatal_errno(errno, disk->name);
1803 : log_fatal(errno, "Stopping\n");
1804 :
1805 : ++unrecoverable_error;
1806 : goto bail;
1807 : /* LCOV_EXCL_STOP */
1808 : }
1809 :
1810 12 : log_tag("hardlink_fixed:%s:%s: Fixed hardlink error\n", disk->name, esc_tag(slink->sub, esc_buffer));
1811 12 : ++recovered_error;
1812 : } else {
1813 4219 : ret = symlink(slink->linkto, path);
1814 4219 : if (ret != 0) {
1815 : /* LCOV_EXCL_START */
1816 : log_fatal(errno, "Error writing symlink '%s' to '%s'. %s.\n", path, slink->linkto, strerror(errno));
1817 : log_tag("symlink_%s:%u:%s:%s: Hardlink error. %s.\n", es(errno), i, disk->name, esc_tag(slink->sub, esc_buffer), strerror(errno));
1818 : log_fatal_errno(errno, disk->name);
1819 : log_fatal(errno, "Stopping\n");
1820 :
1821 : ++unrecoverable_error;
1822 : goto bail;
1823 : /* LCOV_EXCL_STOP */
1824 : }
1825 :
1826 4219 : log_tag("symlink_fixed:%s:%s: Fixed symlink error\n", disk->name, esc_tag(slink->sub, esc_buffer));
1827 4219 : ++recovered_error;
1828 : }
1829 :
1830 4231 : log_tag("status:recovered:%s:%s\n", disk->name, esc_tag(slink->sub, esc_buffer));
1831 4231 : msg_info("recovered %s\n", fmt_term(disk, slink->sub, esc_buffer));
1832 : }
1833 : }
1834 :
1835 : /* for each dir in the disk */
1836 729 : disk = handle[i].disk;
1837 729 : node = disk->dirlist;
1838 1185 : while (node) {
1839 : char path[PATH_MAX];
1840 : struct stat st;
1841 : struct snapraid_dir* dir;
1842 456 : int unsuccessful = 0;
1843 :
1844 456 : dir = node->data;
1845 456 : node = node->next; /* next node */
1846 :
1847 : /* if excluded continue to the next one */
1848 456 : if (dir_flag_has(dir, FILE_IS_EXCLUDED)) {
1849 23 : continue;
1850 : }
1851 :
1852 : /* stat the dir */
1853 433 : pathprint(path, sizeof(path), "%s%s", disk->dir, dir->sub);
1854 433 : ret = stat(path, &st);
1855 433 : if (ret == -1) {
1856 27 : unsuccessful = 1;
1857 :
1858 27 : log_error(errno, "Error stating dir '%s'. %s.\n", path, strerror(errno));
1859 27 : log_tag("dir_%s:%s:%s: Dir stat error. %s.\n", es(errno), disk->name, esc_tag(dir->sub, esc_buffer), strerror(errno));
1860 :
1861 27 : if (is_hw(errno)) {
1862 0 : ++io_error;
1863 : } else {
1864 27 : ++soft_error;
1865 : }
1866 406 : } else if (!S_ISDIR(st.st_mode)) {
1867 0 : unsuccessful = 1;
1868 :
1869 0 : log_tag("dir_error:%s:%s: Dir error for not directory\n", disk->name, esc_tag(dir->sub, esc_buffer));
1870 0 : ++soft_error;
1871 : }
1872 :
1873 433 : if (fix && unsuccessful) {
1874 : /* create the ancestor directories */
1875 23 : ret = mkancestor(path);
1876 23 : if (ret != 0) {
1877 : /* LCOV_EXCL_START */
1878 : log_fatal(errno, "Error creating ancestor '%s%s'. %s.\n", disk->dir, dir->sub, strerror(errno));
1879 : log_tag("dir_%s:%u:%s:%s: Create ancestor error. %s.\n", es(errno), i, disk->name, esc_tag(dir->sub, esc_buffer), strerror(errno));
1880 : log_fatal_errno(errno, disk->name);
1881 : log_fatal(errno, "Stopping\n");
1882 :
1883 : ++unrecoverable_error;
1884 : goto bail;
1885 : /* LCOV_EXCL_STOP */
1886 : }
1887 :
1888 : /* create it */
1889 23 : ret = mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
1890 23 : if (ret != 0) {
1891 : /* LCOV_EXCL_START */
1892 : log_fatal(errno, "Error creating directory '%s%s'. %s.\n", disk->dir, dir->sub, strerror(errno));
1893 : log_tag("dir_%s:%u:%s:%s: Create directory error. %s.\n", es(errno), i, disk->name, esc_tag(dir->sub, esc_buffer), strerror(errno));
1894 : log_fatal_errno(errno, disk->name);
1895 : log_fatal(errno, "Stopping\n");
1896 :
1897 : ++unrecoverable_error;
1898 : goto bail;
1899 : /* LCOV_EXCL_STOP */
1900 : }
1901 :
1902 23 : log_tag("dir_fixed:%s:%s: Fixed dir error\n", disk->name, esc_tag(dir->sub, esc_buffer));
1903 23 : ++recovered_error;
1904 :
1905 23 : log_tag("status:recovered:%s:%s\n", disk->name, esc_tag(dir->sub, esc_buffer));
1906 23 : msg_info("recovered %s\n", fmt_term(disk, dir->sub, esc_buffer));
1907 : }
1908 : }
1909 : }
1910 :
1911 122 : end:
1912 122 : state_progress_end(state, countpos, countmax, countsize, "Nothing to check.\n");
1913 :
1914 122 : bail:
1915 : /* close all the files left open */
1916 854 : for (j = 0; j < diskmax; ++j) {
1917 732 : struct snapraid_file* file = handle[j].file;
1918 732 : struct snapraid_disk* disk = handle[j].disk;
1919 732 : ret = handle_close(&handle[j]);
1920 732 : if (ret == -1) {
1921 : /* LCOV_EXCL_START */
1922 : log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockmax, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
1923 : log_fatal_errno(errno, disk->name);
1924 :
1925 : ++unrecoverable_error;
1926 : /* continue, as we are already exiting */
1927 : /* LCOV_EXCL_STOP */
1928 : }
1929 : }
1930 :
1931 : /* remove all the files created from scratch that have not finished the processing */
1932 : /* it happens only when aborting pressing Ctrl+C or other reason. */
1933 122 : if (fix) {
1934 : /* for each disk */
1935 329 : for (i = 0; i < diskmax; ++i) {
1936 : tommy_node* node;
1937 : struct snapraid_disk* disk;
1938 :
1939 282 : if (!handle[i].disk)
1940 1 : continue;
1941 :
1942 : /* for each file in the disk */
1943 281 : disk = handle[i].disk;
1944 281 : node = disk->filelist;
1945 902098 : while (node) {
1946 : char path[PATH_MAX];
1947 : struct snapraid_file* file;
1948 :
1949 901817 : file = node->data;
1950 901817 : node = node->next; /* next node */
1951 :
1952 : /* if the file was not created, meaning that it was already existing */
1953 901817 : if (!file_flag_has(file, FILE_IS_CREATED)) {
1954 : /* nothing to do */
1955 901817 : continue;
1956 : }
1957 :
1958 : /* if processing was finished */
1959 120891 : if (file_flag_has(file, FILE_IS_FINISHED)) {
1960 : /* nothing to do */
1961 120891 : continue;
1962 : }
1963 :
1964 : /* if the file was originally missing, and processing not yet finished */
1965 : /* we have to throw it away to ensure that at the next run we will retry */
1966 : /* to fix it, in case we select to undelete missing files */
1967 0 : pathprint(path, sizeof(path), "%s%s", disk->dir, file->sub);
1968 :
1969 0 : ret = remove(path);
1970 0 : if (ret != 0) {
1971 : /* LCOV_EXCL_START */
1972 : log_fatal(errno, "Error removing '%s'. %s.\n", path, strerror(errno));
1973 : log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockmax, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
1974 : log_fatal_errno(errno, disk->name);
1975 :
1976 : ++unrecoverable_error;
1977 : /* continue, as we are already exiting */
1978 : /* LCOV_EXCL_STOP */
1979 : }
1980 : }
1981 : }
1982 : }
1983 :
1984 122 : if (soft_error || io_error || silent_error || recovered_error || unrecoverable_error) {
1985 71 : msg_status("\n");
1986 71 : msg_status("%8u soft errors\n", soft_error);
1987 71 : msg_status("%8u io errors\n", io_error);
1988 71 : msg_status("%8u data errors\n", silent_error);
1989 71 : if (fix) {
1990 46 : msg_status("%8u recovered errors\n", recovered_error);
1991 : }
1992 71 : if (unrecoverable_error) {
1993 13 : msg_status("%8u UNRECOVERABLE errors\n", unrecoverable_error);
1994 : } else {
1995 : /* without checking, we don't know if they are really recoverable or not */
1996 58 : if (!state->opt.auditonly)
1997 56 : msg_status("%8u unrecoverable errors\n", unrecoverable_error);
1998 58 : if (fix)
1999 37 : msg_status("Everything OK\n");
2000 : }
2001 : } else {
2002 51 : msg_status("Everything OK\n");
2003 : }
2004 :
2005 122 : if ((soft_error || io_error || silent_error) && !fix) {
2006 25 : if (soft_error)
2007 22 : log_fatal(ESOFT, "WARNING! There are soft errors!\n");
2008 25 : if (io_error)
2009 0 : log_fatal(EIO, "DANGER! Unexpected input/output errors!\n");
2010 25 : if (silent_error)
2011 13 : log_fatal(EDATA, "DANGER! Unexpected silent data errors!\n");
2012 : }
2013 122 : if (unrecoverable_error)
2014 13 : log_fatal(ESOFT, "DANGER! Unrecoverable errors detected!\n");
2015 :
2016 122 : log_tag("summary:error_soft:%u\n", soft_error);
2017 122 : log_tag("summary:error_io:%u\n", io_error);
2018 122 : log_tag("summary:error_data:%u\n", silent_error);
2019 122 : if (fix)
2020 47 : log_tag("summary:error_recovered:%u\n", recovered_error);
2021 122 : if (!state->opt.auditonly)
2022 117 : log_tag("summary:error_unrecoverable:%u\n", unrecoverable_error);
2023 122 : if (fix) {
2024 47 : if (soft_error + io_error + silent_error + recovered_error + unrecoverable_error == 0)
2025 1 : log_tag("summary:exit:ok\n");
2026 46 : else if (unrecoverable_error == 0)
2027 37 : log_tag("summary:exit:recovered\n");
2028 : else
2029 9 : log_tag("summary:exit:unrecoverable\n");
2030 75 : } else if (!state->opt.auditonly) {
2031 70 : if (soft_error + io_error + silent_error + unrecoverable_error == 0)
2032 47 : log_tag("summary:exit:ok\n");
2033 23 : else if (unrecoverable_error == 0)
2034 19 : log_tag("summary:exit:recoverable\n");
2035 : else
2036 4 : log_tag("summary:exit:unrecoverable\n");
2037 : } else { /* audit only */
2038 5 : if (soft_error + silent_error + io_error == 0)
2039 3 : log_tag("summary:exit:ok\n");
2040 2 : else if (silent_error + io_error == 0)
2041 1 : log_tag("summary:exit:warning\n");
2042 : else
2043 1 : log_tag("summary:exit:error\n");
2044 : }
2045 122 : log_flush();
2046 :
2047 122 : free(failed);
2048 122 : free(failed_map);
2049 122 : free(block_enabled);
2050 122 : free(handle);
2051 122 : free(buffer_alloc);
2052 122 : free(buffer);
2053 :
2054 : /* fail if some error are present after the run */
2055 122 : if (fix) {
2056 47 : if (state->opt.expect_unrecoverable) {
2057 9 : if (unrecoverable_error == 0)
2058 0 : return -1;
2059 : } else {
2060 38 : if (unrecoverable_error != 0)
2061 0 : return -1;
2062 : }
2063 : } else {
2064 75 : if (state->opt.expect_unrecoverable) {
2065 4 : if (unrecoverable_error == 0)
2066 0 : return -1;
2067 71 : } else if (state->opt.expect_recoverable) {
2068 21 : if (unrecoverable_error != 0)
2069 0 : return -1;
2070 21 : if (soft_error + silent_error + io_error == 0)
2071 0 : return -1;
2072 : } else {
2073 50 : if (unrecoverable_error != 0)
2074 0 : return -1;
2075 50 : if (soft_error + silent_error + io_error != 0)
2076 0 : return -1;
2077 : }
2078 : }
2079 :
2080 122 : if (alert < 0)
2081 0 : return -1;
2082 :
2083 122 : return 0;
2084 : }
2085 :
2086 124 : int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, block_off_t blockcount)
2087 : {
2088 : block_off_t blockmax;
2089 : data_off_t size;
2090 : int ret;
2091 : struct snapraid_parity_handle parity[LEV_MAX];
2092 : struct snapraid_parity_handle* parity_ptr[LEV_MAX];
2093 : unsigned process_error;
2094 : unsigned l;
2095 :
2096 124 : msg_progress("Initializing...\n");
2097 :
2098 124 : blockmax = parity_allocated_size(state);
2099 124 : size = blockmax * (data_off_t)state->block_size;
2100 :
2101 124 : if (blockstart > blockmax) {
2102 : /* LCOV_EXCL_START */
2103 : log_fatal(EUSER, "Error in the specified starting block %u. It's larger than the parity size %u.\n", blockstart, blockmax);
2104 : exit(EXIT_FAILURE);
2105 : /* LCOV_EXCL_STOP */
2106 : }
2107 :
2108 : /* adjust the number of block to process */
2109 124 : if (blockcount != 0 && blockstart + blockcount < blockmax) {
2110 0 : blockmax = blockstart + blockcount;
2111 : }
2112 :
2113 124 : if (fix) {
2114 : /* if fixing, create the file and open for writing */
2115 : /* if it fails, we cannot continue */
2116 188 : for (l = 0; l < state->level; ++l) {
2117 : /* skip parity disks that are not accessible */
2118 141 : if (state->parity[l].skip_access) {
2119 1 : parity_ptr[l] = 0;
2120 1 : continue;
2121 : }
2122 :
2123 140 : parity_ptr[l] = &parity[l];
2124 :
2125 : /* if the parity is excluded */
2126 140 : if (state->parity[l].is_excluded_by_filter) {
2127 : /* open for reading, and ignore error */
2128 14 : ret = parity_open(parity_ptr[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size);
2129 14 : if (ret == -1) {
2130 0 : log_tag("parity_%s:%u:%s: Open error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno));
2131 0 : if (is_hw(errno)) {
2132 0 : log_fatal_errno(errno, lev_config_name(l));
2133 0 : exit(EXIT_FAILURE);
2134 : }
2135 :
2136 : /* continue anyway */
2137 0 : parity_ptr[l] = 0;
2138 : }
2139 : } else {
2140 : /* open for writing */
2141 126 : ret = parity_create(parity_ptr[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size);
2142 126 : if (ret == -1) {
2143 : /* LCOV_EXCL_START */
2144 : log_tag("parity_%s:%u:%s: Create error. %s.\n", es(errno), 0, lev_config_name(l), strerror(errno));
2145 : log_fatal_errno(errno, lev_config_name(l));
2146 : exit(EXIT_FAILURE);
2147 : /* LCOV_EXCL_STOP */
2148 : }
2149 :
2150 126 : ret = parity_chsize(parity_ptr[l], &state->parity[l], 0, size, state->block_size, state->opt.skip_fallocate, state->opt.skip_space_holder);
2151 126 : if (ret == -1) {
2152 : /* LCOV_EXCL_START */
2153 : log_tag("parity_%s:%u:%s: Create error. %s.\n", es(errno), 0, lev_config_name(l), strerror(errno));
2154 : log_fatal_errno(errno, lev_config_name(l));
2155 : exit(EXIT_FAILURE);
2156 : /* LCOV_EXCL_STOP */
2157 : }
2158 : }
2159 : }
2160 77 : } else if (!state->opt.auditonly) {
2161 : /* if checking, open the file for reading */
2162 : /* it may fail if the file doesn't exist, in this case we continue to check the files */
2163 404 : for (l = 0; l < state->level; ++l) {
2164 333 : parity_ptr[l] = &parity[l];
2165 333 : ret = parity_open(parity_ptr[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size);
2166 333 : if (ret == -1) {
2167 1 : log_tag("parity_%s:%u:%s: Open error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno));
2168 1 : if (is_hw(errno)) {
2169 0 : log_fatal_errno(errno, lev_config_name(l));
2170 0 : exit(EXIT_FAILURE);
2171 : }
2172 :
2173 1 : msg_status("No accessible %s file, only files will be checked.\n", lev_name(l));
2174 :
2175 : /* continue anyway */
2176 1 : parity_ptr[l] = 0;
2177 : }
2178 : }
2179 : } else {
2180 : /* otherwise don't use any parity */
2181 28 : for (l = 0; l < state->level; ++l)
2182 22 : parity_ptr[l] = 0;
2183 : }
2184 :
2185 124 : process_error = 0;
2186 :
2187 : /* skip degenerated cases of empty parity, or skipping all */
2188 124 : if (blockstart < blockmax) {
2189 122 : ret = state_check_process(state, fix, parity_ptr, blockstart, blockmax);
2190 122 : if (ret == -1) {
2191 : /* LCOV_EXCL_START */
2192 : ++process_error;
2193 : /* continue, as we are already exiting */
2194 : /* LCOV_EXCL_STOP */
2195 : }
2196 : }
2197 :
2198 : /* try to close only if opened */
2199 620 : for (l = 0; l < state->level; ++l) {
2200 496 : if (parity_ptr[l]) {
2201 : /* if fixing and not excluded, truncate parity not valid */
2202 472 : if (fix && !state->parity[l].is_excluded_by_filter) {
2203 126 : ret = parity_truncate(parity_ptr[l]);
2204 126 : if (ret == -1) {
2205 : /* LCOV_EXCL_START */
2206 : log_tag("parity_%s:%u:%s: Truncate error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno));
2207 : log_fatal_errno(errno, lev_config_name(l));
2208 :
2209 : ++process_error;
2210 : /* continue, as we are already exiting */
2211 : /* LCOV_EXCL_STOP */
2212 : }
2213 : }
2214 :
2215 472 : ret = parity_close(parity_ptr[l]);
2216 472 : if (ret == -1) {
2217 : /* LCOV_EXCL_START */
2218 : log_tag("parity_%s:%u:%s: Close error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno));
2219 : log_fatal_errno(errno, lev_config_name(l));
2220 :
2221 : ++process_error;
2222 : /* continue, as we are already exiting */
2223 : /* LCOV_EXCL_STOP */
2224 : }
2225 : }
2226 : }
2227 :
2228 124 : if (process_error != 0)
2229 0 : return -1;
2230 124 : return 0;
2231 : }
2232 :
|