Skip to main content

fxfs/fsck/
errors.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::log::*;
6use crate::lsm_tree::types::ItemRef;
7use crate::object_store::allocator::{AllocatorKey, AllocatorValue};
8use crate::object_store::{AttributeId, ObjectDescriptor, ProjectId};
9use fxfs_crypto::WrappingKeyId;
10use std::ops::Range;
11
12#[derive(Clone, Debug, PartialEq)]
13pub enum FsckIssue {
14    /// Warnings don't prevent the filesystem from mounting and don't fail fsck, but they indicate a
15    /// consistency issue.
16    Warning(FsckWarning),
17    /// Errors prevent the filesystem from mounting, and will result in fsck failing, but will let
18    /// fsck continue to run to find more issues.
19    Error(FsckError),
20    /// Fatal errors are like Errors, but they're serious enough that fsck should be halted, as any
21    /// further results will probably be false positives.
22    Fatal(FsckFatal),
23}
24
25impl FsckIssue {
26    /// Translates an error to a human-readable string, intended for reporting errors to the user.
27    /// For debugging, std::fmt::Debug is preferred.
28    // TODO(https://fxbug.dev/42177349): Localization
29    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
90// `From<V: std::fmt::Debug> for Value` creates a recursive definition since Value is Debug, so we
91// have to go concrete here.
92impl 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, AttributeId),
107    ExtentForNonexistentObject(u64, u64),
108    GraveyardRecordForAbsentObject(u64, u64),
109    InvalidObjectIdInStore(u64, Key, Value),
110    LimitForNonExistentStore(u64, u64),
111    OrphanedAttribute(u64, u64, AttributeId),
112    OrphanedObject(u64, u64),
113    OrphanedKeys(u64, u64),
114    OrphanedExtendedAttribute(u64, u64, AttributeId),
115    OrphanedExtendedAttributeRecord(u64, u64),
116    ProjectUsageInconsistent(u64, ProjectId, (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, u32, u32),
227    BadGraveyardValue(u64, u64),
228    BadLastObjectId(u64, u64),
229    CasefoldInconsistency(u64, u64, u64),
230    ChildEncryptedWithDifferentWrappingKeyThanParent(u64, u64, u64, WrappingKeyId, WrappingKeyId),
231    ConflictingTypeForLink(u64, u64, Value, Value),
232    DuplicateKey(u64, u64, u64),
233    EncryptedChildDirectoryNoWrappingKey(u64, u64),
234    EncryptedDirectoryHasUnencryptedChild(u64, u64, u64),
235    ExtentExceedsLength(u64, u64, AttributeId, u64, Value),
236    ExtraAllocations(Vec<Allocation>),
237    IllegalKeyInRootStore(u64, u64),
238    IncorrectMerkleTreeSize(u64, u64, u64, u64),
239    LinkCycle(u64, u64),
240    MalformedAllocation(Allocation),
241    MalformedExtent(u64, u64, Range<u64>, u64),
242    MalformedObjectRecord(u64, Key, Value),
243    MisalignedAllocation(Allocation),
244    MisalignedExtent(u64, u64, Range<u64>, u64),
245    MissingAllocation(Allocation),
246    MissingAttributeForExtendedAttribute(u64, u64, AttributeId),
247    MissingDataAttribute(u64, u64),
248    MissingEncryptionKeys(u64, u64),
249    MissingKey(u64, u64, u64),
250    MissingObjectInfo(u64, u64),
251    MissingOverwriteExtents(u64, u64, AttributeId),
252    MultipleLinksToDirectory(u64, u64),
253    NextObjectIdInUse(u64, u64),
254    NonFileMarkedAsVerified(u64, u64),
255    NonRootProjectIdMetadata(u64, u64, ProjectId),
256    ObjectCountMismatch(u64, u64, u64),
257    ObjectHasChildren(u64, u64),
258    OverwriteExtentFlagUnset(u64, u64, AttributeId),
259    ProjectOnGraveyard(u64, ProjectId, u64),
260    ProjectUsedWithNoUsageTracking(u64, ProjectId, u64),
261    RefCountMismatch(u64, u64, u64),
262    RootObjectHasParent(u64, u64, u64),
263    SubDirCountMismatch(u64, u64, u64, u64),
264    TombstonedAttributeDoesNotExist(u64, u64, AttributeId),
265    TombstonedObjectHasRecords(u64, u64),
266    TrimValueForGraveyardAttributeEntry(u64, u64, AttributeId),
267    UnencryptedDirectoryHasEncryptedChild(u64, u64, u64),
268    UnexpectedJournalFileOffset(u64),
269    UnexpectedObjectInGraveyard(u64),
270    UnexpectedRecordInObjectStore(u64, Key, Value),
271    VerifiedFileDoesNotHaveAMerkleAttribute(u64, u64),
272    VolumeInChildStore(u64, u64),
273    ZombieDir(u64, u64, u64),
274    ZombieFile(u64, u64, Vec<u64>),
275    ZombieSymlink(u64, u64, Vec<u64>),
276    InvalidInoLblk32KeyUsage(u64, u64),
277}
278
279impl FsckError {
280    fn to_string(&self) -> String {
281        match self {
282            FsckError::AllocatedBytesMismatch(observed, stored) => {
283                format!(
284                    "Per-owner allocated bytes was {:?}, but sum of allocations gave {:?}",
285                    stored, observed
286                )
287            }
288            FsckError::AllocatedSizeMismatch(store_id, oid, observed, stored) => {
289                format!(
290                    "Expected {} bytes allocated for object {} in store {}, but found {} bytes",
291                    stored, oid, store_id, observed
292                )
293            }
294            FsckError::AllocationForNonexistentOwner(alloc) => {
295                format!("Allocation {:?} for non-existent owner", alloc)
296            }
297            FsckError::AllocationMismatch(observed, stored) => {
298                format!("Observed allocation {:?} but allocator has {:?}", observed, stored)
299            }
300            FsckError::BadCasefoldHash(store_id, parent_id, child_id, expected, actual) => {
301                format!(
302                    "Bad casefold hash code for store {store_id}, directory {parent_id}, child \
303                     {child_id}. Expected {expected:08x}, actual {actual:08x}",
304                )
305            }
306            FsckError::BadLastObjectId(highest, last_object_id) => {
307                format!("Last object ID {last_object_id} is less than highest found {highest}")
308            }
309            FsckError::CasefoldInconsistency(store_id, parent_id, child_id) => {
310                format!(
311                    "CasefoldChild inconsistent for store {}, directory {}, child {}",
312                    store_id, parent_id, child_id
313                )
314            }
315            FsckError::ConflictingTypeForLink(store_id, object_id, expected, actual) => {
316                format!(
317                    "Object {} in store {} is of type {:?} but has a link of type {:?}",
318                    store_id, object_id, expected, actual
319                )
320            }
321            FsckError::ExtentExceedsLength(store_id, oid, attr_id, size, extent) => {
322                format!(
323                    "Extent {:?} exceeds length {} of attr {} on object {} in store {}",
324                    extent, size, attr_id, oid, store_id
325                )
326            }
327            FsckError::ExtraAllocations(allocations) => {
328                format!("Unexpected allocations {:?}", allocations)
329            }
330            FsckError::IllegalKeyInRootStore(store_id, object_id) => {
331                format!("Object {object_id} in root store {store_id} uses an illegal key type")
332            }
333            FsckError::ObjectHasChildren(store_id, object_id) => {
334                format!("Object {} in store {} has unexpected children", object_id, store_id)
335            }
336            FsckError::UnexpectedJournalFileOffset(object_id) => {
337                format!(
338                    "SuperBlock journal_file_offsets contains unexpected object_id ({:?}).",
339                    object_id
340                )
341            }
342            FsckError::LinkCycle(store_id, object_id) => {
343                format!("Detected cycle involving object {} in store {}", store_id, object_id)
344            }
345            FsckError::MalformedAllocation(allocations) => {
346                format!("Malformed allocation {:?}", allocations)
347            }
348            FsckError::MalformedExtent(store_id, oid, extent, device_offset) => {
349                format!(
350                    "Extent {:?} (offset {}) for object {} in store {} is malformed",
351                    extent, device_offset, oid, store_id
352                )
353            }
354            FsckError::MalformedObjectRecord(store_id, key, value) => {
355                format!(
356                    "Object record in store {} has mismatched key {:?} and value {:?}",
357                    store_id, key, value
358                )
359            }
360            FsckError::MisalignedAllocation(allocations) => {
361                format!("Misaligned allocation {:?}", allocations)
362            }
363            FsckError::MisalignedExtent(store_id, oid, extent, device_offset) => {
364                format!(
365                    "Extent {:?} (offset {}) for object {} in store {} is misaligned",
366                    extent, device_offset, oid, store_id
367                )
368            }
369            FsckError::MissingAllocation(allocation) => {
370                format!("Observed {:?} but didn't find record in allocator", allocation)
371            }
372            FsckError::MissingAttributeForExtendedAttribute(store_id, oid, attribute_id) => {
373                format!(
374                    "Object {} in store {} has an extended attribute stored in a nonexistent \
375                    attribute {}",
376                    store_id, oid, attribute_id
377                )
378            }
379            FsckError::MissingDataAttribute(store_id, oid) => {
380                format!("File {} in store {} didn't have the default data attribute", store_id, oid)
381            }
382            FsckError::MissingObjectInfo(store_id, object_id) => {
383                format!("Object {} in store {} had no object record", store_id, object_id)
384            }
385            FsckError::MultipleLinksToDirectory(store_id, object_id) => {
386                format!("Directory {} in store {} has multiple links", store_id, object_id)
387            }
388            FsckError::NonRootProjectIdMetadata(store_id, object_id, project_id) => {
389                format!(
390                    "Project Id {} metadata in store {} attached to object {}",
391                    project_id, store_id, object_id
392                )
393            }
394            FsckError::ObjectCountMismatch(store_id, observed, stored) => {
395                format!("Store {} had {} objects, expected {}", store_id, observed, stored)
396            }
397            FsckError::ProjectOnGraveyard(store_id, project_id, object_id) => {
398                format!(
399                    "Store {} had graveyard object {} with project id {}",
400                    store_id, object_id, project_id
401                )
402            }
403            FsckError::ProjectUsedWithNoUsageTracking(store_id, project_id, node_id) => {
404                format!(
405                    "Store {} had node {} with project ids {} but no usage tracking metadata",
406                    store_id, node_id, project_id
407                )
408            }
409            FsckError::RefCountMismatch(oid, observed, stored) => {
410                format!("Object {} had {} references, expected {}", oid, observed, stored)
411            }
412            FsckError::RootObjectHasParent(store_id, object_id, apparent_parent_id) => {
413                format!(
414                    "Object {} is child of {} but is a root object of store {}",
415                    object_id, apparent_parent_id, store_id
416                )
417            }
418            FsckError::SubDirCountMismatch(store_id, object_id, observed, stored) => {
419                format!(
420                    "Directory {} in store {} should have {} sub dirs but had {}",
421                    object_id, store_id, stored, observed
422                )
423            }
424            FsckError::TombstonedObjectHasRecords(store_id, object_id) => {
425                format!(
426                    "Tombstoned object {} in store {} was referenced by other records",
427                    store_id, object_id
428                )
429            }
430            FsckError::UnexpectedObjectInGraveyard(object_id) => {
431                format!("Found a non-file object {} in graveyard", object_id)
432            }
433            FsckError::UnexpectedRecordInObjectStore(store_id, key, value) => {
434                format!("Unexpected record ({:?}, {:?}) in object store {}", key, value, store_id)
435            }
436            FsckError::VolumeInChildStore(store_id, object_id) => {
437                format!(
438                    "Volume {} found in child store {} instead of root store",
439                    object_id, store_id
440                )
441            }
442            FsckError::BadGraveyardValue(store_id, object_id) => {
443                format!("Bad graveyard value with key <{}, {}>", store_id, object_id)
444            }
445            FsckError::MissingEncryptionKeys(store_id, object_id) => {
446                format!("Missing encryption keys for <{}, {}>", store_id, object_id)
447            }
448            FsckError::MissingKey(store_id, object_id, key_id) => {
449                format!("Missing encryption key for <{}, {}, {}>", store_id, object_id, key_id)
450            }
451            FsckError::EncryptedChildDirectoryNoWrappingKey(store_id, object_id) => {
452                format!(
453                    "Encrypted directory {} in store {} does not have a wrapping key id set",
454                    object_id, store_id
455                )
456            }
457            FsckError::EncryptedDirectoryHasUnencryptedChild(store_id, parent_oid, child_oid) => {
458                format!(
459                    "Encrypted parent directory {} in store {} has unencrypted child {}",
460                    parent_oid, store_id, child_oid
461                )
462            }
463            FsckError::UnencryptedDirectoryHasEncryptedChild(store_id, parent_oid, child_oid) => {
464                format!(
465                    "Unencrypted parent directory {} in store {} has encrypted child {}",
466                    parent_oid, store_id, child_oid
467                )
468            }
469            FsckError::ChildEncryptedWithDifferentWrappingKeyThanParent(
470                store_id,
471                parent_id,
472                child_id,
473                parent_wrapping_key_id,
474                child_wrapping_key_id,
475            ) => {
476                format!(
477                    "Parent directory {} in store {} encrypted with {:?}, child {} encrypted with \
478                    {:?}",
479                    parent_id, store_id, parent_wrapping_key_id, child_id, child_wrapping_key_id,
480                )
481            }
482            FsckError::DuplicateKey(store_id, object_id, key_id) => {
483                format!("Duplicate key for <{}, {}, {}>", store_id, object_id, key_id)
484            }
485            FsckError::ZombieFile(store_id, object_id, parent_object_ids) => {
486                format!(
487                    "File {object_id} in store {store_id} is in graveyard but still has links \
488                     from {parent_object_ids:?}",
489                )
490            }
491            FsckError::ZombieDir(store_id, object_id, parent_object_id) => {
492                format!(
493                    "Directory {object_id} in store {store_id} is in graveyard but still has \
494                     a link from {parent_object_id}",
495                )
496            }
497            FsckError::ZombieSymlink(store_id, object_id, parent_object_ids) => {
498                format!(
499                    "Symlink {object_id} in store {store_id} is in graveyard but still has \
500                     links from {parent_object_ids:?}",
501                )
502            }
503            FsckError::VerifiedFileDoesNotHaveAMerkleAttribute(store_id, object_id) => {
504                format!(
505                    "Object {} in store {} is marked as fsverity-enabled but is missing a \
506                        merkle attribute",
507                    store_id, object_id
508                )
509            }
510            FsckError::NonFileMarkedAsVerified(store_id, object_id) => {
511                format!(
512                    "Object {} in store {} is marked as verified but is not a file",
513                    store_id, object_id
514                )
515            }
516            FsckError::InvalidInoLblk32KeyUsage(store_id, object_id) => {
517                format!("Object {object_id} in store {store_id} uses an InoLblk32 key invalidly")
518            }
519            FsckError::IncorrectMerkleTreeSize(store_id, object_id, expected_size, actual_size) => {
520                format!(
521                    "Object {} in store {} has merkle tree of size {} expected {}",
522                    object_id, store_id, actual_size, expected_size
523                )
524            }
525            FsckError::TombstonedAttributeDoesNotExist(store_id, object_id, attribute_id) => {
526                format!(
527                    "Object {} in store {} has an attribute {} that is tombstoned but does not \
528                     exist.",
529                    object_id, store_id, attribute_id
530                )
531            }
532            FsckError::TrimValueForGraveyardAttributeEntry(store_id, object_id, attribute_id) => {
533                format!(
534                    "Object {} in store {} has a GraveyardAttributeEntry for attribute {} that has \
535                     ObjectValue::Trim",
536                    object_id, store_id, attribute_id,
537                )
538            }
539            FsckError::MissingOverwriteExtents(store_id, object_id, attribute_id) => {
540                format!(
541                    "Object {} in store {} has an attribute {} that indicated it had overwrite \
542                     extents but none were found",
543                    object_id, store_id, attribute_id,
544                )
545            }
546            FsckError::OverwriteExtentFlagUnset(store_id, object_id, attribute_id) => {
547                format!(
548                    "Object {} in store {} has an attribute {} with overwrite extents but the \
549                     metadata indicated it would not",
550                    object_id, store_id, attribute_id,
551                )
552            }
553            FsckError::NextObjectIdInUse(store_id, next_object_id) => {
554                format!("Next object ID {store_id} will use ({next_object_id}) is already in use",)
555            }
556        }
557    }
558
559    fn log(&self) {
560        match self {
561            FsckError::AllocatedBytesMismatch(observed, stored) => {
562                error!(observed:?, stored:?; "Unexpected allocated bytes");
563            }
564            FsckError::AllocatedSizeMismatch(store_id, oid, observed, stored) => {
565                error!(observed, oid, store_id, stored; "Unexpected allocated size");
566            }
567            FsckError::AllocationForNonexistentOwner(alloc) => {
568                error!(alloc:?; "Allocation for non-existent owner")
569            }
570            FsckError::AllocationMismatch(observed, stored) => {
571                error!(observed:?, stored:?; "Unexpected allocation");
572            }
573            FsckError::BadCasefoldHash(store_id, parent_id, child_id, expected, actual) => {
574                warn!(store_id, parent_id, child_id, expected, actual; "Bad casefold hash code");
575            }
576            FsckError::BadLastObjectId(highest, last_object_id) => {
577                error!(highest, last_object_id; "Last object ID is less than highest found");
578            }
579            FsckError::CasefoldInconsistency(store_id, parent_id, child_id) => {
580                error!(store_id:?, parent_id:?, child_id:?; "CasefoldChild inconsistent");
581            }
582            FsckError::ConflictingTypeForLink(store_id, oid, expected, actual) => {
583                error!(store_id, oid, expected:?, actual:?; "Bad link");
584            }
585            FsckError::ExtentExceedsLength(store_id, oid, attr_id, size, extent) => {
586                error!(store_id, oid, attr_id, size, extent:?; "Extent exceeds length");
587            }
588            FsckError::ExtraAllocations(allocations) => {
589                error!(allocations:?; "Unexpected allocations");
590            }
591            FsckError::IllegalKeyInRootStore(store_id, oid) => {
592                error!(store_id, oid; "Illegal key in root store");
593            }
594            FsckError::ObjectHasChildren(store_id, oid) => {
595                error!(store_id, oid; "Object has unexpected children");
596            }
597            FsckError::UnexpectedJournalFileOffset(object_id) => {
598                error!(
599                    oid = object_id;
600                    "SuperBlock journal_file_offsets contains unexpected object-id"
601                );
602            }
603            FsckError::LinkCycle(store_id, oid) => {
604                error!(store_id, oid; "Link cycle");
605            }
606            FsckError::MalformedAllocation(allocations) => {
607                error!(allocations:?; "Malformed allocations");
608            }
609            FsckError::MalformedExtent(store_id, oid, extent, device_offset) => {
610                error!(store_id, oid, extent:?, device_offset; "Malformed extent");
611            }
612            FsckError::MalformedObjectRecord(store_id, key, value) => {
613                error!(store_id, key:?, value:?; "Mismatched key and value");
614            }
615            FsckError::MisalignedAllocation(allocations) => {
616                error!(allocations:?; "Misaligned allocation");
617            }
618            FsckError::MisalignedExtent(store_id, oid, extent, device_offset) => {
619                error!(store_id, oid, extent:?, device_offset; "Misaligned extent");
620            }
621            FsckError::MissingAllocation(allocation) => {
622                error!(allocation:?; "Missing allocation");
623            }
624            FsckError::MissingAttributeForExtendedAttribute(store_id, oid, attribute_id) => {
625                error!(store_id, oid, attribute_id; "Missing attribute for extended attribute");
626            }
627            FsckError::MissingDataAttribute(store_id, oid) => {
628                error!(store_id, oid; "Missing default attribute");
629            }
630            FsckError::MissingObjectInfo(store_id, oid) => {
631                error!(store_id, oid; "Missing object record");
632            }
633            FsckError::MultipleLinksToDirectory(store_id, oid) => {
634                error!(store_id, oid; "Directory with multiple links");
635            }
636            FsckError::NonRootProjectIdMetadata(store_id, object_id, project_id) => {
637                error!(
638                    store_id,
639                    object_id, project_id; "Non root object in volume with project id metadata"
640                );
641            }
642            FsckError::ObjectCountMismatch(store_id, observed, stored) => {
643                error!(store_id, observed, stored; "Object count mismatch");
644            }
645            FsckError::ProjectOnGraveyard(store_id, project_id, object_id) => {
646                error!(store_id, project_id, object_id; "Project was set on graveyard object");
647            }
648            FsckError::ProjectUsedWithNoUsageTracking(store_id, project_id, node_id) => {
649                error!(store_id, project_id, node_id; "Project used without tracking metadata");
650            }
651            FsckError::RefCountMismatch(oid, observed, stored) => {
652                error!(oid, observed, stored; "Reference count mismatch");
653            }
654            FsckError::RootObjectHasParent(store_id, oid, apparent_parent_id) => {
655                error!(store_id, oid, apparent_parent_id; "Root object is a child");
656            }
657            FsckError::SubDirCountMismatch(store_id, oid, observed, stored) => {
658                error!(store_id, oid, observed, stored; "Sub-dir count mismatch");
659            }
660            FsckError::TombstonedObjectHasRecords(store_id, oid) => {
661                error!(store_id, oid; "Tombstoned object with references");
662            }
663            FsckError::UnexpectedObjectInGraveyard(oid) => {
664                error!(oid; "Unexpected object in graveyard");
665            }
666            FsckError::UnexpectedRecordInObjectStore(store_id, key, value) => {
667                error!(store_id, key:?, value:?; "Unexpected record");
668            }
669            FsckError::VolumeInChildStore(store_id, oid) => {
670                error!(store_id, oid; "Volume in child store");
671            }
672            FsckError::BadGraveyardValue(store_id, oid) => {
673                error!(store_id, oid; "Bad graveyard value");
674            }
675            FsckError::MissingEncryptionKeys(store_id, oid) => {
676                error!(store_id, oid; "Missing encryption keys");
677            }
678            FsckError::MissingKey(store_id, oid, key_id) => {
679                error!(store_id, oid, key_id; "Missing encryption key");
680            }
681            FsckError::EncryptedChildDirectoryNoWrappingKey(store_id, oid) => {
682                error!(store_id, oid; "Encrypted directory does not have a wrapping key id");
683            }
684            FsckError::EncryptedDirectoryHasUnencryptedChild(store_id, parent_oid, child_oid) => {
685                error!(
686                    store_id,
687                    parent_oid, child_oid; "Encrypted directory has unencrypted child"
688                );
689            }
690            FsckError::UnencryptedDirectoryHasEncryptedChild(store_id, parent_oid, child_oid) => {
691                error!(
692                    store_id,
693                    parent_oid, child_oid; "Unencrypted directory has encrypted child"
694                );
695            }
696            FsckError::ChildEncryptedWithDifferentWrappingKeyThanParent(
697                store_id,
698                parent_id,
699                child_id,
700                parent_wrapping_key_id,
701                child_wrapping_key_id,
702            ) => {
703                error!(
704                    store_id,
705                    parent_id,
706                    child_id,
707                    parent_wrapping_key_id:?,
708                    child_wrapping_key_id:?;
709                    "Child object encrypted with different wrapping key than parent"
710                );
711            }
712            FsckError::DuplicateKey(store_id, oid, key_id) => {
713                error!(store_id, oid, key_id; "Duplicate key")
714            }
715            FsckError::ZombieFile(store_id, oid, parent_oids) => {
716                error!(store_id, oid, parent_oids:?; "Links exist to file in graveyard")
717            }
718            FsckError::ZombieDir(store_id, oid, parent_oid) => {
719                error!(store_id, oid, parent_oid; "A link exists to directory in graveyard")
720            }
721            FsckError::ZombieSymlink(store_id, oid, parent_oids) => {
722                error!(store_id, oid, parent_oids:?; "Links exists to symlink in graveyard")
723            }
724            FsckError::VerifiedFileDoesNotHaveAMerkleAttribute(store_id, oid) => {
725                error!(store_id, oid; "Verified file does not have a merkle attribute")
726            }
727            FsckError::NonFileMarkedAsVerified(store_id, oid) => {
728                error!(store_id, oid; "Non-file marked as verified")
729            }
730            FsckError::InvalidInoLblk32KeyUsage(store_id, oid) => {
731                error!(store_id, oid; "Invalid InoLblk32 key usage")
732            }
733            FsckError::IncorrectMerkleTreeSize(store_id, oid, expected_size, actual_size) => {
734                error!(
735                    store_id,
736                    oid, expected_size, actual_size; "Verified file has incorrect merkle tree size"
737                )
738            }
739            FsckError::TombstonedAttributeDoesNotExist(store_id, oid, attribute_id) => {
740                error!(store_id, oid, attribute_id; "Tombstoned attribute does not exist")
741            }
742            FsckError::TrimValueForGraveyardAttributeEntry(store_id, oid, attribute_id) => {
743                error!(
744                    store_id,
745                    oid, attribute_id; "Invalid Trim value for a graveyard attribute entry",
746                )
747            }
748            FsckError::MissingOverwriteExtents(store_id, oid, attribute_id) => {
749                error!(
750                    store_id,
751                    oid,
752                    attribute_id;
753                    "Overwrite extents indicated, but no overwrite extents were found",
754                )
755            }
756            FsckError::OverwriteExtentFlagUnset(store_id, oid, attribute_id) => {
757                error!(
758                    store_id,
759                    oid,
760                    attribute_id;
761                    "Overwrite extents were found, but metadata flag was not set",
762                )
763            }
764            FsckError::NextObjectIdInUse(store_id, next_object_id) => {
765                error!(store_id, next_object_id; "Next object ID is already in use");
766            }
767        }
768    }
769}
770
771#[derive(Clone, Debug, PartialEq)]
772pub enum FsckFatal {
773    MalformedGraveyard,
774    MalformedLayerFile(u64, u64),
775    MalformedStore(u64),
776    MisOrderedLayerFile(u64, u64),
777    MisOrderedObjectStore(u64),
778    OverlappingKeysInLayerFile(u64, u64, Key, Key),
779    InvalidBloomFilter(u64, u64, Key),
780}
781
782impl FsckFatal {
783    fn to_string(&self) -> String {
784        match self {
785            FsckFatal::MalformedGraveyard => {
786                "Graveyard is malformed; root store is inconsistent".to_string()
787            }
788            FsckFatal::MalformedLayerFile(store_id, layer_file_id) => {
789                format!("Layer file {} in object store {} is malformed", layer_file_id, store_id)
790            }
791            FsckFatal::MalformedStore(id) => {
792                format!("Object store {} is malformed; root store is inconsistent", id)
793            }
794            FsckFatal::MisOrderedLayerFile(store_id, layer_file_id) => {
795                format!(
796                    "Layer file {} for store/allocator {} contains out-of-order records",
797                    layer_file_id, store_id
798                )
799            }
800            FsckFatal::MisOrderedObjectStore(store_id) => {
801                format!("Store/allocator {} contains out-of-order or duplicate records", store_id)
802            }
803            FsckFatal::OverlappingKeysInLayerFile(store_id, layer_file_id, key1, key2) => {
804                format!(
805                    "Layer file {} for store/allocator {} contains overlapping keys {:?} and {:?}",
806                    layer_file_id, store_id, key1, key2
807                )
808            }
809            FsckFatal::InvalidBloomFilter(store_id, layer_file_id, key) => {
810                format!(
811                    "Filter for layer files is invalid: reported that key {:?} in layer file {} \
812                    for store/allocator {} does not exist",
813                    key, layer_file_id, store_id
814                )
815            }
816        }
817    }
818
819    fn log(&self) {
820        match self {
821            FsckFatal::MalformedGraveyard => {
822                error!("Graveyard is malformed; root store is inconsistent");
823            }
824            FsckFatal::MalformedLayerFile(store_id, layer_file_id) => {
825                error!(store_id, layer_file_id; "Layer file malformed");
826            }
827            FsckFatal::MalformedStore(id) => {
828                error!(id; "Malformed store; root store is inconsistent");
829            }
830            FsckFatal::MisOrderedLayerFile(store_id, layer_file_id) => {
831                // This can be for stores or the allocator.
832                error!(oid = store_id, layer_file_id; "Layer file contains out-of-oder records");
833            }
834            FsckFatal::MisOrderedObjectStore(store_id) => {
835                // This can be for stores or the allocator.
836                error!(
837                    oid = store_id;
838                    "Store/allocator contains out-of-order or duplicate records"
839                );
840            }
841            FsckFatal::OverlappingKeysInLayerFile(store_id, layer_file_id, key1, key2) => {
842                // This can be for stores or the allocator.
843                error!(oid = store_id, layer_file_id, key1:?, key2:?; "Overlapping keys");
844            }
845            FsckFatal::InvalidBloomFilter(store_id, layer_file_id, key) => {
846                error!(oid = store_id, layer_file_id, key:?; "Filter for layer files invalid");
847            }
848        }
849    }
850}