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