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