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