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