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 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 error!(oid = store_id, layer_file_id; "Layer file contains out-of-oder records");
833 }
834 FsckFatal::MisOrderedObjectStore(store_id) => {
835 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 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}