1use crate::log::*;
6use crate::lsm_tree::types::ItemRef;
7use crate::object_store::allocator::{AllocatorKey, AllocatorValue};
8use crate::object_store::ObjectDescriptor;
9use std::ops::Range;
10
11#[derive(Clone, Debug, PartialEq)]
12pub enum FsckIssue {
13 Warning(FsckWarning),
16 Error(FsckError),
19 Fatal(FsckFatal),
22}
23
24impl FsckIssue {
25 pub fn to_string(&self) -> String {
29 match self {
30 FsckIssue::Warning(w) => format!("WARNING: {}", w.to_string()),
31 FsckIssue::Error(e) => format!("ERROR: {}", e.to_string()),
32 FsckIssue::Fatal(f) => format!("FATAL: {}", f.to_string()),
33 }
34 }
35 pub fn is_error(&self) -> bool {
36 match self {
37 FsckIssue::Error(_) | FsckIssue::Fatal(_) => true,
38 FsckIssue::Warning(_) => false,
39 }
40 }
41 pub fn log(&self) {
42 match self {
43 FsckIssue::Warning(w) => w.log(),
44 FsckIssue::Error(e) => e.log(),
45 FsckIssue::Fatal(f) => f.log(),
46 }
47 }
48}
49
50#[derive(Clone, Debug, PartialEq)]
51#[allow(dead_code)]
52pub struct Allocation {
53 range: Range<u64>,
54 value: AllocatorValue,
55}
56
57impl From<ItemRef<'_, AllocatorKey, AllocatorValue>> for Allocation {
58 fn from(item: ItemRef<'_, AllocatorKey, AllocatorValue>) -> Self {
59 Self { range: item.key.device_range.clone(), value: item.value.clone() }
60 }
61}
62
63#[derive(Clone, Debug, PartialEq)]
64#[allow(dead_code)]
65pub struct Key(String);
66
67impl<K: std::fmt::Debug, V> From<ItemRef<'_, K, V>> for Key {
68 fn from(item: ItemRef<'_, K, V>) -> Self {
69 Self(format!("{:?}", item.key))
70 }
71}
72
73impl<K: std::fmt::Debug> From<&K> for Key {
74 fn from(k: &K) -> Self {
75 Self(format!("{:?}", k))
76 }
77}
78
79#[derive(Clone, Debug, PartialEq)]
80#[allow(dead_code)]
81pub struct Value(String);
82
83impl<K, V: std::fmt::Debug> From<ItemRef<'_, K, V>> for Value {
84 fn from(item: ItemRef<'_, K, V>) -> Self {
85 Self(format!("{:?}", item.value))
86 }
87}
88
89impl From<ObjectDescriptor> for Value {
92 fn from(d: ObjectDescriptor) -> Self {
93 Self(format!("{:?}", d))
94 }
95}
96
97impl<V: std::fmt::Debug> From<&V> for Value {
98 fn from(v: &V) -> Self {
99 Self(format!("{:?}", v))
100 }
101}
102
103#[derive(Clone, Debug, PartialEq)]
104pub enum FsckWarning {
105 ExtentForMissingAttribute(u64, u64, u64),
106 ExtentForNonexistentObject(u64, u64),
107 GraveyardRecordForAbsentObject(u64, u64),
108 InvalidObjectIdInStore(u64, Key, Value),
109 LimitForNonExistentStore(u64, u64),
110 OrphanedAttribute(u64, u64, u64),
111 OrphanedObject(u64, u64),
112 OrphanedKeys(u64, u64),
113 OrphanedExtendedAttribute(u64, u64, u64),
114 OrphanedExtendedAttributeRecord(u64, u64),
115 ProjectUsageInconsistent(u64, u64, (i64, i64), (i64, i64)),
116}
117
118impl FsckWarning {
119 fn to_string(&self) -> String {
120 match self {
121 FsckWarning::ExtentForMissingAttribute(store_id, object_id, attr_id) => {
122 format!(
123 "Found an extent in store {} for missing attribute {} on object {}",
124 store_id, attr_id, object_id
125 )
126 }
127 FsckWarning::ExtentForNonexistentObject(store_id, object_id) => {
128 format!(
129 "Found an extent in store {} for a non-existent object {}",
130 store_id, object_id
131 )
132 }
133 FsckWarning::GraveyardRecordForAbsentObject(store_id, object_id) => {
134 format!(
135 "Graveyard contains an entry for object {} in store {}, but that object is \
136 absent",
137 store_id, object_id
138 )
139 }
140 FsckWarning::InvalidObjectIdInStore(store_id, key, value) => {
141 format!("Store {} has an invalid object ID ({:?}, {:?})", store_id, key, value)
142 }
143 FsckWarning::LimitForNonExistentStore(store_id, limit) => {
144 format!("Bytes limit of {} found for nonexistent store id {}", limit, store_id)
145 }
146 FsckWarning::OrphanedAttribute(store_id, object_id, attribute_id) => {
147 format!(
148 "Attribute {} found for object {} which doesn't exist in store {}",
149 attribute_id, object_id, store_id
150 )
151 }
152 FsckWarning::OrphanedObject(store_id, object_id) => {
153 format!("Orphaned object {} was found in store {}", object_id, store_id)
154 }
155 FsckWarning::OrphanedKeys(store_id, object_id) => {
156 format!("Orphaned keys for object {} were found in store {}", object_id, store_id)
157 }
158 FsckWarning::OrphanedExtendedAttribute(store_id, object_id, attribute_id) => {
159 format!(
160 "Orphaned extended attribute for object {} was found in store {} with \
161 attribute id {}",
162 object_id, store_id, attribute_id,
163 )
164 }
165 FsckWarning::OrphanedExtendedAttributeRecord(store_id, object_id) => {
166 format!(
167 "Orphaned extended attribute record for object {} was found in store {}",
168 object_id, store_id
169 )
170 }
171 FsckWarning::ProjectUsageInconsistent(store_id, project_id, stored, used) => {
172 format!(
173 "Project id {} in store {} expected usage ({}, {}) found ({}, {})",
174 project_id, store_id, stored.0, stored.1, used.0, used.1
175 )
176 }
177 }
178 }
179
180 fn log(&self) {
181 match self {
182 FsckWarning::ExtentForMissingAttribute(store_id, oid, attr_id) => {
183 warn!(store_id, oid, attr_id; "Found an extent for a missing attribute");
184 }
185 FsckWarning::ExtentForNonexistentObject(store_id, oid) => {
186 warn!(store_id, oid; "Extent for missing object");
187 }
188 FsckWarning::GraveyardRecordForAbsentObject(store_id, oid) => {
189 warn!(store_id, oid; "Graveyard entry for missing object");
190 }
191 FsckWarning::InvalidObjectIdInStore(store_id, key, value) => {
192 warn!(store_id, key:?, value:?; "Invalid object ID");
193 }
194 FsckWarning::LimitForNonExistentStore(store_id, limit) => {
195 warn!(store_id, limit; "Found limit for non-existent owner store.");
196 }
197 FsckWarning::OrphanedAttribute(store_id, oid, attribute_id) => {
198 warn!(store_id, oid, attribute_id; "Attribute for missing object");
199 }
200 FsckWarning::OrphanedObject(store_id, oid) => {
201 warn!(oid, store_id; "Orphaned object");
202 }
203 FsckWarning::OrphanedKeys(store_id, oid) => {
204 warn!(oid, store_id; "Orphaned keys");
205 }
206 FsckWarning::OrphanedExtendedAttribute(store_id, oid, attribute_id) => {
207 warn!(oid, store_id, attribute_id; "Orphaned extended attribute");
208 }
209 FsckWarning::OrphanedExtendedAttributeRecord(store_id, oid) => {
210 warn!(oid, store_id; "Orphaned extended attribute record");
211 }
212 FsckWarning::ProjectUsageInconsistent(store_id, project_id, stored, used) => {
213 warn!(project_id, store_id, stored:?, used:?; "Project Inconsistent");
214 }
215 }
216 }
217}
218
219#[derive(Clone, Debug, PartialEq)]
220pub enum FsckError {
221 AllocatedBytesMismatch(Vec<(u64, u64)>, Vec<(u64, u64)>),
222 AllocatedSizeMismatch(u64, u64, u64, u64),
223 AllocationForNonexistentOwner(Allocation),
224 AllocationMismatch(Allocation, Allocation),
225 CasefoldInconsistency(u64, u64, u64),
226 ConflictingTypeForLink(u64, u64, Value, Value),
227 ExtentExceedsLength(u64, u64, u64, u64, Value),
228 ExtraAllocations(Vec<Allocation>),
229 ObjectHasChildren(u64, u64),
230 UnexpectedJournalFileOffset(u64),
231 LinkCycle(u64, u64),
232 MalformedAllocation(Allocation),
233 MalformedExtent(u64, u64, Range<u64>, u64),
234 MalformedObjectRecord(u64, Key, Value),
235 MisalignedAllocation(Allocation),
236 MisalignedExtent(u64, u64, Range<u64>, u64),
237 MissingAllocation(Allocation),
238 MissingAttributeForExtendedAttribute(u64, u64, u64),
239 MissingDataAttribute(u64, u64),
240 MissingObjectInfo(u64, u64),
241 MultipleLinksToDirectory(u64, u64),
242 NonRootProjectIdMetadata(u64, u64, u64),
243 ObjectCountMismatch(u64, u64, u64),
244 ProjectOnGraveyard(u64, u64, u64),
245 ProjectUsedWithNoUsageTracking(u64, u64, u64),
246 RefCountMismatch(u64, u64, u64),
247 RootObjectHasParent(u64, u64, u64),
248 SubDirCountMismatch(u64, u64, u64, u64),
249 TombstonedObjectHasRecords(u64, u64),
250 UnexpectedObjectInGraveyard(u64),
251 UnexpectedRecordInObjectStore(u64, Key, Value),
252 VolumeInChildStore(u64, u64),
253 BadGraveyardValue(u64, u64),
254 MissingEncryptionKeys(u64, u64),
255 MissingKey(u64, u64, u64),
256 EncryptedChildDirectoryNoWrappingKey(u64, u64),
257 EncryptedDirectoryHasUnencryptedChild(u64, u64, u64),
258 UnencryptedDirectoryHasEncryptedChild(u64, u64, u64),
259 ChildEncryptedWithDifferentWrappingKeyThanParent(u64, u64, u64, u128, u128),
260 DuplicateKey(u64, u64, u64),
261 ZombieFile(u64, u64, Vec<u64>),
262 ZombieDir(u64, u64, u64),
263 ZombieSymlink(u64, u64, Vec<u64>),
264 VerifiedFileDoesNotHaveAMerkleAttribute(u64, u64),
265 NonFileMarkedAsVerified(u64, u64),
266 IncorrectMerkleTreeSize(u64, u64, u64, u64),
267 TombstonedAttributeDoesNotExist(u64, u64, u64),
268 TrimValueForGraveyardAttributeEntry(u64, u64, u64),
269 MissingOverwriteExtents(u64, u64, u64),
270 OverwriteExtentFlagUnset(u64, u64, u64),
271}
272
273impl FsckError {
274 fn to_string(&self) -> String {
275 match self {
276 FsckError::AllocatedBytesMismatch(observed, stored) => {
277 format!(
278 "Per-owner allocated bytes was {:?}, but sum of allocations gave {:?}",
279 stored, observed
280 )
281 }
282 FsckError::AllocatedSizeMismatch(store_id, oid, observed, stored) => {
283 format!(
284 "Expected {} bytes allocated for object {} in store {}, but found {} bytes",
285 stored, oid, store_id, observed
286 )
287 }
288 FsckError::AllocationForNonexistentOwner(alloc) => {
289 format!("Allocation {:?} for non-existent owner", alloc)
290 }
291 FsckError::AllocationMismatch(observed, stored) => {
292 format!("Observed allocation {:?} but allocator has {:?}", observed, stored)
293 }
294 FsckError::CasefoldInconsistency(store_id, parent_id, child_id) => {
295 format!(
296 "CasefoldChild inconsistent for store {}, directory {}, child {}",
297 store_id, parent_id, child_id
298 )
299 }
300 FsckError::ConflictingTypeForLink(store_id, object_id, expected, actual) => {
301 format!(
302 "Object {} in store {} is of type {:?} but has a link of type {:?}",
303 store_id, object_id, expected, actual
304 )
305 }
306 FsckError::ExtentExceedsLength(store_id, oid, attr_id, size, extent) => {
307 format!(
308 "Extent {:?} exceeds length {} of attr {} on object {} in store {}",
309 extent, size, attr_id, oid, store_id
310 )
311 }
312 FsckError::ExtraAllocations(allocations) => {
313 format!("Unexpected allocations {:?}", allocations)
314 }
315 FsckError::ObjectHasChildren(store_id, object_id) => {
316 format!("Object {} in store {} has unexpected children", object_id, store_id)
317 }
318 FsckError::UnexpectedJournalFileOffset(object_id) => {
319 format!(
320 "SuperBlock journal_file_offsets contains unexpected object_id ({:?}).",
321 object_id
322 )
323 }
324 FsckError::LinkCycle(store_id, object_id) => {
325 format!("Detected cycle involving object {} in store {}", store_id, object_id)
326 }
327 FsckError::MalformedAllocation(allocations) => {
328 format!("Malformed allocation {:?}", allocations)
329 }
330 FsckError::MalformedExtent(store_id, oid, extent, device_offset) => {
331 format!(
332 "Extent {:?} (offset {}) for object {} in store {} is malformed",
333 extent, device_offset, oid, store_id
334 )
335 }
336 FsckError::MalformedObjectRecord(store_id, key, value) => {
337 format!(
338 "Object record in store {} has mismatched key {:?} and value {:?}",
339 store_id, key, value
340 )
341 }
342 FsckError::MisalignedAllocation(allocations) => {
343 format!("Misaligned allocation {:?}", allocations)
344 }
345 FsckError::MisalignedExtent(store_id, oid, extent, device_offset) => {
346 format!(
347 "Extent {:?} (offset {}) for object {} in store {} is misaligned",
348 extent, device_offset, oid, store_id
349 )
350 }
351 FsckError::MissingAllocation(allocation) => {
352 format!("Observed {:?} but didn't find record in allocator", allocation)
353 }
354 FsckError::MissingAttributeForExtendedAttribute(store_id, oid, attribute_id) => {
355 format!(
356 "Object {} in store {} has an extended attribute stored in a nonexistent \
357 attribute {}",
358 store_id, oid, attribute_id
359 )
360 }
361 FsckError::MissingDataAttribute(store_id, oid) => {
362 format!("File {} in store {} didn't have the default data attribute", store_id, oid)
363 }
364 FsckError::MissingObjectInfo(store_id, object_id) => {
365 format!("Object {} in store {} had no object record", store_id, object_id)
366 }
367 FsckError::MultipleLinksToDirectory(store_id, object_id) => {
368 format!("Directory {} in store {} has multiple links", store_id, object_id)
369 }
370 FsckError::NonRootProjectIdMetadata(store_id, object_id, project_id) => {
371 format!(
372 "Project Id {} metadata in store {} attached to object {}",
373 project_id, store_id, object_id
374 )
375 }
376 FsckError::ObjectCountMismatch(store_id, observed, stored) => {
377 format!("Store {} had {} objects, expected {}", store_id, observed, stored)
378 }
379 FsckError::ProjectOnGraveyard(store_id, project_id, object_id) => {
380 format!(
381 "Store {} had graveyard object {} with project id {}",
382 store_id, object_id, project_id
383 )
384 }
385 FsckError::ProjectUsedWithNoUsageTracking(store_id, project_id, node_id) => {
386 format!(
387 "Store {} had node {} with project ids {} but no usage tracking metadata",
388 store_id, node_id, project_id
389 )
390 }
391 FsckError::RefCountMismatch(oid, observed, stored) => {
392 format!("Object {} had {} references, expected {}", oid, observed, stored)
393 }
394 FsckError::RootObjectHasParent(store_id, object_id, apparent_parent_id) => {
395 format!(
396 "Object {} is child of {} but is a root object of store {}",
397 object_id, apparent_parent_id, store_id
398 )
399 }
400 FsckError::SubDirCountMismatch(store_id, object_id, observed, stored) => {
401 format!(
402 "Directory {} in store {} should have {} sub dirs but had {}",
403 object_id, store_id, stored, observed
404 )
405 }
406 FsckError::TombstonedObjectHasRecords(store_id, object_id) => {
407 format!(
408 "Tombstoned object {} in store {} was referenced by other records",
409 store_id, object_id
410 )
411 }
412 FsckError::UnexpectedObjectInGraveyard(object_id) => {
413 format!("Found a non-file object {} in graveyard", object_id)
414 }
415 FsckError::UnexpectedRecordInObjectStore(store_id, key, value) => {
416 format!("Unexpected record ({:?}, {:?}) in object store {}", key, value, store_id)
417 }
418 FsckError::VolumeInChildStore(store_id, object_id) => {
419 format!(
420 "Volume {} found in child store {} instead of root store",
421 object_id, store_id
422 )
423 }
424 FsckError::BadGraveyardValue(store_id, object_id) => {
425 format!("Bad graveyard value with key <{}, {}>", store_id, object_id)
426 }
427 FsckError::MissingEncryptionKeys(store_id, object_id) => {
428 format!("Missing encryption keys for <{}, {}>", store_id, object_id)
429 }
430 FsckError::MissingKey(store_id, object_id, key_id) => {
431 format!("Missing encryption key for <{}, {}, {}>", store_id, object_id, key_id)
432 }
433 FsckError::EncryptedChildDirectoryNoWrappingKey(store_id, object_id) => {
434 format!(
435 "Encrypted directory {} in store {} does not have a wrapping key id set",
436 object_id, store_id
437 )
438 }
439 FsckError::EncryptedDirectoryHasUnencryptedChild(store_id, parent_oid, child_oid) => {
440 format!(
441 "Encrypted parent directory {} in store {} has unencrypted child {}",
442 parent_oid, store_id, child_oid
443 )
444 }
445 FsckError::UnencryptedDirectoryHasEncryptedChild(store_id, parent_oid, child_oid) => {
446 format!(
447 "Unencrypted parent directory {} in store {} has encrypted child {}",
448 parent_oid, store_id, child_oid
449 )
450 }
451 FsckError::ChildEncryptedWithDifferentWrappingKeyThanParent(
452 store_id,
453 parent_id,
454 child_id,
455 parent_wrapping_key_id,
456 child_wrapping_key_id,
457 ) => {
458 format!(
459 "Parent directory {} in store {} encrypted with {}, child {} encrypted with {}",
460 parent_id, store_id, parent_wrapping_key_id, child_id, child_wrapping_key_id
461 )
462 }
463 FsckError::DuplicateKey(store_id, object_id, key_id) => {
464 format!("Duplicate key for <{}, {}, {}>", store_id, object_id, key_id)
465 }
466 FsckError::ZombieFile(store_id, object_id, parent_object_ids) => {
467 format!(
468 "File {object_id} in store {store_id} is in graveyard but still has links \
469 from {parent_object_ids:?}",
470 )
471 }
472 FsckError::ZombieDir(store_id, object_id, parent_object_id) => {
473 format!(
474 "Directory {object_id} in store {store_id} is in graveyard but still has \
475 a link from {parent_object_id}",
476 )
477 }
478 FsckError::ZombieSymlink(store_id, object_id, parent_object_ids) => {
479 format!(
480 "Symlink {object_id} in store {store_id} is in graveyard but still has \
481 links from {parent_object_ids:?}",
482 )
483 }
484 FsckError::VerifiedFileDoesNotHaveAMerkleAttribute(store_id, object_id) => {
485 format!(
486 "Object {} in store {} is marked as fsverity-enabled but is missing a \
487 merkle attribute",
488 store_id, object_id
489 )
490 }
491 FsckError::NonFileMarkedAsVerified(store_id, object_id) => {
492 format!(
493 "Object {} in store {} is marked as verified but is not a file",
494 store_id, object_id
495 )
496 }
497 FsckError::IncorrectMerkleTreeSize(store_id, object_id, expected_size, actual_size) => {
498 format!(
499 "Object {} in store {} has merkle tree of size {} expected {}",
500 object_id, store_id, actual_size, expected_size
501 )
502 }
503 FsckError::TombstonedAttributeDoesNotExist(store_id, object_id, attribute_id) => {
504 format!(
505 "Object {} in store {} has an attribute {} that is tombstoned but does not
506 exist.",
507 object_id, store_id, attribute_id
508 )
509 }
510 FsckError::TrimValueForGraveyardAttributeEntry(store_id, object_id, attribute_id) => {
511 format!(
512 "Object {} in store {} has a GraveyardAttributeEntry for attribute {} that has
513 ObjectValue::Trim",
514 object_id, store_id, attribute_id,
515 )
516 }
517 FsckError::MissingOverwriteExtents(store_id, object_id, attribute_id) => {
518 format!(
519 "Object {} in store {} has an attribute {} that indicated it had overwrite \
520 extents but none were found",
521 object_id, store_id, attribute_id,
522 )
523 }
524 FsckError::OverwriteExtentFlagUnset(store_id, object_id, attribute_id) => {
525 format!(
526 "Object {} in store {} has an attribute {} with overwrite extents but the \
527 metadata indicated it would not",
528 object_id, store_id, attribute_id,
529 )
530 }
531 }
532 }
533
534 fn log(&self) {
535 match self {
536 FsckError::AllocatedBytesMismatch(observed, stored) => {
537 error!(observed:?, stored:?; "Unexpected allocated bytes");
538 }
539 FsckError::AllocatedSizeMismatch(store_id, oid, observed, stored) => {
540 error!(observed, oid, store_id, stored; "Unexpected allocated size");
541 }
542 FsckError::AllocationForNonexistentOwner(alloc) => {
543 error!(alloc:?; "Allocation for non-existent owner")
544 }
545 FsckError::AllocationMismatch(observed, stored) => {
546 error!(observed:?, stored:?; "Unexpected allocation");
547 }
548 FsckError::CasefoldInconsistency(store_id, parent_id, child_id) => {
549 error!(store_id:?, parent_id:?, child_id:?; "CasefoldChild inconsistent");
550 }
551 FsckError::ConflictingTypeForLink(store_id, oid, expected, actual) => {
552 error!(store_id, oid, expected:?, actual:?; "Bad link");
553 }
554 FsckError::ExtentExceedsLength(store_id, oid, attr_id, size, extent) => {
555 error!(store_id, oid, attr_id, size, extent:?; "Extent exceeds length");
556 }
557 FsckError::ExtraAllocations(allocations) => {
558 error!(allocations:?; "Unexpected allocations");
559 }
560 FsckError::ObjectHasChildren(store_id, oid) => {
561 error!(store_id, oid; "Object has unexpected children");
562 }
563 FsckError::UnexpectedJournalFileOffset(object_id) => {
564 error!(
565 oid = object_id;
566 "SuperBlock journal_file_offsets contains unexpected object-id"
567 );
568 }
569 FsckError::LinkCycle(store_id, oid) => {
570 error!(store_id, oid; "Link cycle");
571 }
572 FsckError::MalformedAllocation(allocations) => {
573 error!(allocations:?; "Malformed allocations");
574 }
575 FsckError::MalformedExtent(store_id, oid, extent, device_offset) => {
576 error!(store_id, oid, extent:?, device_offset; "Malformed extent");
577 }
578 FsckError::MalformedObjectRecord(store_id, key, value) => {
579 error!(store_id, key:?, value:?; "Mismatched key and value");
580 }
581 FsckError::MisalignedAllocation(allocations) => {
582 error!(allocations:?; "Misaligned allocation");
583 }
584 FsckError::MisalignedExtent(store_id, oid, extent, device_offset) => {
585 error!(store_id, oid, extent:?, device_offset; "Misaligned extent");
586 }
587 FsckError::MissingAllocation(allocation) => {
588 error!(allocation:?; "Missing allocation");
589 }
590 FsckError::MissingAttributeForExtendedAttribute(store_id, oid, attribute_id) => {
591 error!(store_id, oid, attribute_id; "Missing attribute for extended attribute");
592 }
593 FsckError::MissingDataAttribute(store_id, oid) => {
594 error!(store_id, oid; "Missing default attribute");
595 }
596 FsckError::MissingObjectInfo(store_id, oid) => {
597 error!(store_id, oid; "Missing object record");
598 }
599 FsckError::MultipleLinksToDirectory(store_id, oid) => {
600 error!(store_id, oid; "Directory with multiple links");
601 }
602 FsckError::NonRootProjectIdMetadata(store_id, object_id, project_id) => {
603 error!(
604 store_id,
605 object_id, project_id; "Non root object in volume with project id metadata"
606 );
607 }
608 FsckError::ObjectCountMismatch(store_id, observed, stored) => {
609 error!(store_id, observed, stored; "Object count mismatch");
610 }
611 FsckError::ProjectOnGraveyard(store_id, project_id, object_id) => {
612 error!(store_id, project_id, object_id; "Project was set on graveyard object");
613 }
614 FsckError::ProjectUsedWithNoUsageTracking(store_id, project_id, node_id) => {
615 error!(store_id, project_id, node_id; "Project used without tracking metadata");
616 }
617 FsckError::RefCountMismatch(oid, observed, stored) => {
618 error!(oid, observed, stored; "Reference count mismatch");
619 }
620 FsckError::RootObjectHasParent(store_id, oid, apparent_parent_id) => {
621 error!(store_id, oid, apparent_parent_id; "Root object is a child");
622 }
623 FsckError::SubDirCountMismatch(store_id, oid, observed, stored) => {
624 error!(store_id, oid, observed, stored; "Sub-dir count mismatch");
625 }
626 FsckError::TombstonedObjectHasRecords(store_id, oid) => {
627 error!(store_id, oid; "Tombstoned object with references");
628 }
629 FsckError::UnexpectedObjectInGraveyard(oid) => {
630 error!(oid; "Unexpected object in graveyard");
631 }
632 FsckError::UnexpectedRecordInObjectStore(store_id, key, value) => {
633 error!(store_id, key:?, value:?; "Unexpected record");
634 }
635 FsckError::VolumeInChildStore(store_id, oid) => {
636 error!(store_id, oid; "Volume in child store");
637 }
638 FsckError::BadGraveyardValue(store_id, oid) => {
639 error!(store_id, oid; "Bad graveyard value");
640 }
641 FsckError::MissingEncryptionKeys(store_id, oid) => {
642 error!(store_id, oid; "Missing encryption keys");
643 }
644 FsckError::MissingKey(store_id, oid, key_id) => {
645 error!(store_id, oid, key_id; "Missing encryption key");
646 }
647 FsckError::EncryptedChildDirectoryNoWrappingKey(store_id, oid) => {
648 error!(store_id, oid; "Encrypted directory does not have a wrapping key id");
649 }
650 FsckError::EncryptedDirectoryHasUnencryptedChild(store_id, parent_oid, child_oid) => {
651 error!(
652 store_id,
653 parent_oid, child_oid; "Encrypted directory has unencrypted child"
654 );
655 }
656 FsckError::UnencryptedDirectoryHasEncryptedChild(store_id, parent_oid, child_oid) => {
657 error!(
658 store_id,
659 parent_oid, child_oid; "Unencrypted directory has encrypted child"
660 );
661 }
662 FsckError::ChildEncryptedWithDifferentWrappingKeyThanParent(
663 store_id,
664 parent_id,
665 child_id,
666 parent_wrapping_key_id,
667 child_wrapping_key_id,
668 ) => {
669 error!(
670 store_id,
671 parent_id,
672 child_id,
673 parent_wrapping_key_id,
674 child_wrapping_key_id;
675 "Child directory encrypted with different wrapping key than parent"
676 );
677 }
678 FsckError::DuplicateKey(store_id, oid, key_id) => {
679 error!(store_id, oid, key_id; "Duplicate key")
680 }
681 FsckError::ZombieFile(store_id, oid, parent_oids) => {
682 error!(store_id, oid, parent_oids:?; "Links exist to file in graveyard")
683 }
684 FsckError::ZombieDir(store_id, oid, parent_oid) => {
685 error!(store_id, oid, parent_oid; "A link exists to directory in graveyard")
686 }
687 FsckError::ZombieSymlink(store_id, oid, parent_oids) => {
688 error!(store_id, oid, parent_oids:?; "Links exists to symlink in graveyard")
689 }
690 FsckError::VerifiedFileDoesNotHaveAMerkleAttribute(store_id, oid) => {
691 error!(store_id, oid; "Verified file does not have a merkle attribute")
692 }
693 FsckError::NonFileMarkedAsVerified(store_id, oid) => {
694 error!(store_id, oid; "Non-file marked as verified")
695 }
696 FsckError::IncorrectMerkleTreeSize(store_id, oid, expected_size, actual_size) => {
697 error!(
698 store_id,
699 oid, expected_size, actual_size; "Verified file has incorrect merkle tree size"
700 )
701 }
702 FsckError::TombstonedAttributeDoesNotExist(store_id, oid, attribute_id) => {
703 error!(store_id, oid, attribute_id; "Tombstoned attribute does not exist")
704 }
705 FsckError::TrimValueForGraveyardAttributeEntry(store_id, oid, attribute_id) => {
706 error!(
707 store_id,
708 oid, attribute_id; "Invalid Trim value for a graveyard attribute entry",
709 )
710 }
711 FsckError::MissingOverwriteExtents(store_id, oid, attribute_id) => {
712 error!(
713 store_id,
714 oid,
715 attribute_id;
716 "Overwrite extents indicated, but no overwrite extents were found",
717 )
718 }
719 FsckError::OverwriteExtentFlagUnset(store_id, oid, attribute_id) => {
720 error!(
721 store_id,
722 oid,
723 attribute_id;
724 "Overwrite extents were found, but metadata flag was not set",
725 )
726 }
727 }
728 }
729}
730
731#[derive(Clone, Debug, PartialEq)]
732pub enum FsckFatal {
733 MalformedGraveyard,
734 MalformedLayerFile(u64, u64),
735 MalformedStore(u64),
736 MisOrderedLayerFile(u64, u64),
737 MisOrderedObjectStore(u64),
738 OverlappingKeysInLayerFile(u64, u64, Key, Key),
739}
740
741impl FsckFatal {
742 fn to_string(&self) -> String {
743 match self {
744 FsckFatal::MalformedGraveyard => {
745 "Graveyard is malformed; root store is inconsistent".to_string()
746 }
747 FsckFatal::MalformedLayerFile(store_id, layer_file_id) => {
748 format!("Layer file {} in object store {} is malformed", layer_file_id, store_id)
749 }
750 FsckFatal::MalformedStore(id) => {
751 format!("Object store {} is malformed; root store is inconsistent", id)
752 }
753 FsckFatal::MisOrderedLayerFile(store_id, layer_file_id) => {
754 format!(
755 "Layer file {} for store/allocator {} contains out-of-order records",
756 layer_file_id, store_id
757 )
758 }
759 FsckFatal::MisOrderedObjectStore(store_id) => {
760 format!("Store/allocator {} contains out-of-order or duplicate records", store_id)
761 }
762 FsckFatal::OverlappingKeysInLayerFile(store_id, layer_file_id, key1, key2) => {
763 format!(
764 "Layer file {} for store/allocator {} contains overlapping keys {:?} and {:?}",
765 store_id, layer_file_id, key1, key2
766 )
767 }
768 }
769 }
770
771 fn log(&self) {
772 match self {
773 FsckFatal::MalformedGraveyard => {
774 error!("Graveyard is malformed; root store is inconsistent");
775 }
776 FsckFatal::MalformedLayerFile(store_id, layer_file_id) => {
777 error!(store_id, layer_file_id; "Layer file malformed");
778 }
779 FsckFatal::MalformedStore(id) => {
780 error!(id; "Malformed store; root store is inconsistent");
781 }
782 FsckFatal::MisOrderedLayerFile(store_id, layer_file_id) => {
783 error!(oid = store_id, layer_file_id; "Layer file contains out-of-oder records");
785 }
786 FsckFatal::MisOrderedObjectStore(store_id) => {
787 error!(
789 oid = store_id;
790 "Store/allocator contains out-of-order or duplicate records"
791 );
792 }
793 FsckFatal::OverlappingKeysInLayerFile(store_id, layer_file_id, key1, key2) => {
794 error!(oid = store_id, layer_file_id, key1:?, key2:?; "Overlapping keys");
796 }
797 }
798 }
799}