| A living document. The basic algorithm. | |
| TODO: (D == DONE) | |
| 0) Need to bring some sanity into the case of flags that can | |
| be set in the secondaries at mkfs time but reset or cleared | |
| in the primary later in the filesystem's life. | |
| 0) Clear the persistent read-only bit if set. Clear the | |
| shared bit if set and the version number is zero. This | |
| brings the filesystem back to a known state. | |
| 0) make sure that superblock geometry code checks the logstart | |
| value against whether or not we have an internal log. | |
| If we have an internal log and a logdev, that's ok. | |
| (Maybe we just aren't using it). If we have an external | |
| log (logstart == 0) but no logdev, that's right out. | |
| 0) write secondary superblock search code. Rewrite initial | |
| superblock parsing code to be less complicated. Just | |
| use variables to indicate primary, secondary, etc., | |
| and use a function to get the SB given a specific location | |
| or something. | |
| 2) For inode alignment, if the SB bit is set and the | |
| inode alignment size field in the SB is set, then | |
| believe that the fs inodes MUST be aligned and | |
| disallow any non-aligned inodes. Likewise, if | |
| the SB bit isn't set (or earlier version) and | |
| the inode alignment size field is zero, then | |
| never set the bit even if the inodes are aligned. | |
| Note that the bits and alignment values are | |
| replicated in the secondary superblocks. | |
| 0) add feature specification options to parse_arguments | |
| 0) add logic to add_inode_ref(), add_inode_reached() | |
| to detect nlink overflows in cases where the fs | |
| (or user had indicated fs) doesn't support new nlinks. | |
| 6) check to make sure that the inodes containing btree blocks | |
| with # recs < minrecs aren't legit -- e.g. the only | |
| descendant of a root block. | |
| 7) inode di_size value sanity checking -- should always be less than | |
| the biggest filebno offset mentioned in the bmaps. Doesn't | |
| have to be equal though since we're allowed to overallocate | |
| (it just wastes a little space). This is for both regular | |
| files and directories (have to modify the existing directory | |
| check). | |
| Add tracking of largest offset in bmap scanning code. Compare | |
| value against di_size. Should be >= di_size. | |
| Alternatively, you could pass the inode into down through | |
| the extent record processing layer and make the checks | |
| there. | |
| Add knowledge of quota inodes. size of quota inode is | |
| always zero. We should maintain that. | |
| 8) Basic quota stuff. | |
| Invariants | |
| if quota feature bit is set, the quota inodes | |
| if set, should point to disconnected, 0 len inodes. | |
| D - if quota inodes exist, the quota bits must be | |
| turned on. It's ok for the quota flags to be | |
| zeroed but they should be in a legal state | |
| (see xfs_quota.h). | |
| D - if the quota flags are non-zero, the corresponding | |
| quota inodes must exist. | |
| quota inodes are never deleted, only their space | |
| is freed. | |
| if quotas are being downgraded, then check quota inodes | |
| at the end of phase 3. If they haven't been cleared yet, | |
| clear them. Regardless, then clear sb flags (quota inode | |
| fields, quota flags, and quota bit). | |
| 5) look at verify_inode_chunk(). it's probably really broken. | |
| 9) Complicated quota stuff. Add code to bmap scan code to | |
| track used blocks. Add another pair of AVL trees | |
| to track user and project quota limits. Set AVL | |
| trees up at the beginning of phase 3. Quota inodes | |
| can be rebuilt or corrected later if damaged. | |
| D - 0) fix directory processing. phase 3, if an entry references | |
| a free inode, *don't* mark it used. wait for the rest of | |
| phase 3 processing to hit that inode. If it looks like it's | |
| in use, we'll mark in use then. If not, we'll clear it and | |
| mark the inode map. then in phase 4, you can depend on the | |
| inode map. should probably set the parent info in phase 4. | |
| So we have a check_dups flag. Maybe we should change the | |
| name of check_dir to discover_inodes. During phase 3 | |
| (discover_inodes == 1), uncertain inodes are added to list. | |
| During phase 4 (discover_inodes == 0), they aren't. And | |
| we never mark inodes in use from the directory code. | |
| During phase 4, we shouldn't complain about names with | |
| a leading '/' since we made those names in phase 3. | |
| Have to change dino_chunks.c (parent setting), dinode.c | |
| and dir.c. | |
| D - 0) make sure we don't screw up filesystems with real-time inodes. | |
| remember to initialize real-time map with all blocks XR_E_FREE. | |
| D - 4) check contents of symlinks as well as lengths in process_symlinks() | |
| in dinode.c. Right now, we only check lengths. | |
| D - 1) Feature mismatches -- for quotas and attributes, | |
| if the stuff exists in the filesystem, set the | |
| superblock version bits. | |
| D - 0) rewrite directory leaf block holemap comparison code. | |
| probably should just check the leaf block hole info | |
| against our incore bitmap. If the hole flag is not | |
| set, then we know that there can only be one hole and | |
| it has to be between the entry table and the top of heap. | |
| If the hole flag is set, then it's ok if the on-disk | |
| holemap doesn't describe everything as long as what | |
| it does describe doesn't conflict with reality. | |
| D - 0) rewrite setting nlinks handling -- for version 1 | |
| inodes, set both nlinks and onlinks (zero projid_lo/hi | |
| and pad) if we have to change anything. For | |
| version 2, I think we're ok. | |
| D - 0) Put awareness of quota inode into mark_standalone_inodes. | |
| D - 8) redo handling of superblocks with bad version numbers. need | |
| to bail out (without harming) fs's that have sbs that | |
| are newer than we are. | |
| D - 0) How do we handle feature mismatches between fs and | |
| superblock? For nlink, check each inode after you | |
| know it's good. If onlinks is 0 and nlinks is > 0 | |
| and it's a version 2 inode, then it really is a version | |
| 2 inode and the nlinks flag in the SB needs to be set. | |
| If it's a version 2 inode and the SB agrees but onlink | |
| is non-zero, then clear onlink. | |
| D - 3) keep cumulative counts of freeblocks, inodes, etc. to set in | |
| the superblock at the end of phase 5. Remember that | |
| agf freeblock counters don't include blocks used by | |
| the non-root levels of the freespace trees but that | |
| the sb free block counters include those. | |
| D - 0) Do parent setting in directory code (called by phase 3). | |
| actually, I put it in process_inode_set and propagated | |
| the parent up to it from the process_dinode/process_dir | |
| routines. seemed cleaner than pushing the irec down | |
| and letting them bang on it. | |
| D - 0) If we clear a file in phase 4, make sure that if it's | |
| a directory that the parent info is cleared also. | |
| D - 0) put inode tree flashover (call to add_ino_backptrs) into phase 5. | |
| D - 0) do set/get_inode_parent functions in incore_ino.c. | |
| also do is/set/ inode_processed. | |
| D - 0) do a versions.c to extract feature info and set global vars | |
| from the superblock version number and possibly feature bits | |
| D - 0) change longform_dir_entry_check + shortform_dir_entry_check | |
| to return a count of how many illegal '/' entries exist. | |
| if > 0, then process_dirstack needs to call prune_dir_entry | |
| with a hash value of 0 to delete the entries. | |
| D - 0) add the "processed" bitfield | |
| to the backptrs_t struct that gets attached after | |
| phase 4. | |
| D- ) Phase 6 !!! | |
| D - 0) look at usage of XFS_MAKE_IPTR(). It does the right | |
| arithmetic assuming you count your offsets from the | |
| beginning of the buffer. | |
| D - 0) look at references to XFS_INODES_PER_CHUNK. change the | |
| ones that really mean sizeof(__uint64_t)*NBBY to | |
| something else (like that only defined as a constant | |
| INOS_PER_IREC. this isn't as important since | |
| XFS_INODES_PER_CHUNK will never chang | |
| D - 0) look at junk_zerolen_dir_leaf_entries() to make sure it isn't hosing | |
| the freemap since it assumed that bytes between the | |
| end of the table and firstused didn't show up in the | |
| freemap when they actually do. | |
| D - 0) track down XFS_INO_TO_OFFSET() usage. I don't think I'm | |
| using it right. (e.g. I think | |
| it gives you the offset of an inode into a block but | |
| on small block filesystems, I may be reading in inodes | |
| in multiblock buffers and working from the start of | |
| the buffer plus I'm using it to get offsets into | |
| my ino_rec's which may not be a good idea since I | |
| use 64-inode ino_rec's whereas the offset macro | |
| works off blocksize). | |
| D - 0.0) put buffer -> dirblock conversion macros into xfs kernel code | |
| D - 0.2) put in sibling pointer checking and path fixup into | |
| bmap (long form) scan routines in scan.c | |
| D - 0.3) find out if bmap btrees with only root blocks are legal. I'm | |
| betting that they're not because they'd be extent inodes | |
| instead. If that's the case, rip some code out of | |
| process_btinode() | |
| Algorithm (XXX means not done yet): | |
| Phase 1 -- get a superblock and zero log | |
| get a superblock -- either read in primary or | |
| find a secondary (ag header), check ag headers | |
| To find secondary: | |
| Go for brute force and read in the filesystem N meg | |
| at a time looking for a superblock. as a | |
| slight optimization, we could maybe skip | |
| ahead some number of blocks to try and get | |
| towards the end of the first ag. | |
| After you find a secondary, try and find at least | |
| other ags as a verification that the | |
| secondary is a good superblock. | |
| XXX - Ugh. Have to take growfs'ed filesystems into account. | |
| The root superblock geometry info may not be right if | |
| recovery hasn't run or it's been trashed. The old ag's | |
| may or may not be right since the system could have crashed | |
| during growfs or the bwrite() to the superblocks could have | |
| failed and the buffer been reused. So we need to check | |
| to see if another ag exists beyond the "last" ag | |
| to see if a growfs happened. If not, then we know that | |
| the geometry info is good and treat the fs as a non-growfs'ed | |
| fs. If we do have inconsistencies, then the smaller geometry | |
| is the old fs and the larger the new. We can check the | |
| new superblocks to see if they're good. If not, then we | |
| know the system crashed at or soon after the growfs and | |
| we can choose to either accept the new geometry info or | |
| trash it and truncate the fs back to the old geometry | |
| parameters. | |
| Cross-check geometry information in secondary sb's with | |
| primary to ensure that it's correct. | |
| Use sim code to allow mount filesystems *without* reading | |
| in root inode. This sets up the xfs_mount_t structure | |
| and allows us to use XFS_* macros that we wouldn't | |
| otherwise be able to use. | |
| Note, I split phase 1 and 2 into separate pieces because I want | |
| to initialize the xfs_repair incore data structures after phase 1. | |
| parse superblock version and feature flags and set appropriate | |
| global vars to reflect the flags (attributes, quotas, etc.) | |
| Workaround for the mkfs "not zeroing the superblock buffer" bug. | |
| Determine what field is the last valid non-zero field in | |
| the superblock. The trick here is to be able to differentiate | |
| the last valid non-zero field in the primary superblock and | |
| secondaries because they may not be the same. Fields in | |
| the primary can be set as the filesystem gets upgraded but | |
| the upgrades won't touch the secondaries. This means that | |
| we need to find some number of secondaries and check them. | |
| So we do the checking here and the setting in phase2. | |
| Phase 2 -- check integrity of allocation group allocation structures | |
| zero the log if in no modify mode | |
| sanity check ag headers -- superblocks match, agi isn't | |
| trashed -- the agf and agfl | |
| don't really matter because we can | |
| just recreate them later. | |
| Zero part of the superblock buffer if necessary | |
| Walk the freeblock trees to get an | |
| initial idea of what the fs thinks is free. | |
| Files that disagree (claim free'd blocks) | |
| can be salvaged or deleted. If the btree is | |
| internally inconsistent, when in doubt, mark | |
| blocks free. If they're used, they'll be stolen | |
| back later. don't have to check sibling pointers | |
| for each level since we're going to regenerate | |
| all the trees anyway. | |
| Walk the inode allocation trees and | |
| make sure they're ok, otherwise the sim | |
| inode routines will probably just barf. | |
| mark inode allocation tree blocks and ag header | |
| blocks as used blocks. If the trees are | |
| corrupted, this phase will generate "uncertain" | |
| inode chunks. Those chunks go on a list and | |
| will have to verified later. Record the blocks | |
| that are used to detect corruption and multiply | |
| claimed blocks. These trees will be regenerated | |
| later. Mark the blocks containing inodes referenced | |
| by uncorrupted inode trees as being used by inodes. | |
| The other blocks will get marked when/if the inodes | |
| are verified. | |
| calculate root and realtime inode numbers from the | |
| filesystem geometry, fix up mount structure's | |
| incore superblock if they're wrong. | |
| ASSUMPTION: at end of phase 2, we've got superblocks and ag headers | |
| that are not garbage (some data in them like counters and the | |
| freeblock and inode trees may be inconsistent but the header | |
| is readable and otherwise makes sense). | |
| XXX if in no_modify mode, check for blocks claimed by one freespace | |
| btree and not the other | |
| Phase 3 -- traverse inodes to make the inodes, bmaps and freespace maps | |
| consistent. For each ag, use either the incore inode map or | |
| scan the ag for inodes. | |
| Let's use the incore inode map, now that we've made one | |
| up in phase2. If we lose the maps, we'll locate inodes | |
| when we traverse the directory heirarchy. If we lose both, | |
| we could scan the disk. Ugh. Maybe make that a command-line | |
| option that we support later. | |
| ASSUMPTION: we know if the ag allocation btrees are intact (phase 2) | |
| First - Walk and clear the ag unlinked lists. We'll process | |
| the inodes later. Check and make sure that the unlinked | |
| lists reference known inodes. If not, add to the list | |
| of uncertain inodes. | |
| Second, check the uncertain inode list generated in phase2 and | |
| above and get them into the inode tree if they're good. | |
| The incore inode cluster tree *always* has good | |
| clusters (alignment, etc.) in it. | |
| Third, make sure that the root inode is known. If not, | |
| and we know the inode number from the superblock, | |
| discover that inode and its chunk. | |
| Then, walk the incore inode-cluster tree. | |
| Maintain an in-core bitmap over the entire fs for block allocation. | |
| traverse each inode, make sure inode mode field matches free/allocated | |
| bit in the incore inode allocation tree. If there's a mismatch, | |
| assume that the inode is in use. | |
| - for each in-use inode, traverse each bmap/dir/attribute | |
| map or tree. Maintain a map (extent list?) for the | |
| current inode. | |
| - For each block marked as used, check to see if already known | |
| (referenced by another file or directory) and sanity | |
| check the contents of the block as well if possible | |
| (in the case of meta-blocks). | |
| - if the inode claims already used blocks, mark the blocks | |
| as multiply claimed (duplicate) and go on. the inode | |
| will be cleared in phase 4. | |
| - if metablocks are garbaged, clear the inode after | |
| traversing what you can of the bmap and | |
| proceed to next inode. We don't have to worry | |
| about trashing the maps or trees in cleared inodes | |
| because the blocks will show up as free in the | |
| ag freespace trees that we set up in phase 5. | |
| - clear the di_next_unlinked pointer -- all unlinked | |
| but active files go bye-bye. | |
| - All blocks start out unknown. We need the last state | |
| in case we run into a case where we need to step | |
| on a block to store filesystem meta-data and it | |
| turns out later that it's referenced by some inode's | |
| bmap. In that case, the inode loses because we've | |
| already trashed the block. This shouldn't happen | |
| in the first version unless some inode has a bogus | |
| bmap referencing blocks in the ag header but the | |
| 4th state will keep us from inadvertently doing | |
| something stupid in that case. | |
| - If inode is allocated, mark all blocks allocated to the | |
| current inode as allocated in the incore freespace | |
| bitmap. | |
| - If inode is good and a directory, scan through it to | |
| find leaf entries and discover any unknown inodes. | |
| For shortform, we correct what we can. | |
| If the directory is corrupt, we try and fix it in | |
| place. If it has zero good entries, then we blast it. | |
| All unknown inodes get put onto the uncertain inode | |
| list. This is safe because we only put inodes onto | |
| the list when we're processing known inodes so the | |
| uncertain inode list isn't in use. | |
| We fix only one problem -- an entry that has | |
| a mathematically invalid inode numbers in them. | |
| If that's the case, we replace the inode number | |
| with NULLFSINO and we'll fix up the entry in | |
| phase 6. | |
| That info may conflict with the inode information, | |
| but we'll straighten out any inconsistencies there | |
| in phase4 when we process the inodes again. | |
| Errors involving bogus forward/back links, | |
| zero-length entries make the directory get | |
| trashed. | |
| if an entry references a free inode, ignore that | |
| fact for now. wait for the rest of phase 3 | |
| processing to hit that inode. If it looks like it's | |
| in use, we'll mark in use then. If not, we'll | |
| clear it and mark the inode map. then in phase | |
| 4, you can depend on the inode map. | |
| Entries that point to non-existent or free | |
| inodes, and extra blocks in the directory | |
| will get fixed in place in a later pass. | |
| Entries that point to a quota inode are | |
| marked TBD. | |
| If the directory internally points to the same | |
| block twice, the directory gets blown away. | |
| Note that processing uncertain inodes can add more inodes | |
| to the uncertain list if they're directories. So we loop | |
| until the uncertain list is empty. | |
| During inode verification, if the inode blocks are unknown, | |
| mark then as in-use by inodes. | |
| XXX HEURISTIC -- if we blow an inode away that has space, | |
| assume that the freespace btree is now out of wack. | |
| If it was ok earlier, it's certain to be wrong now. | |
| And the odds of this space free cancelling out the | |
| existing error is so small I'm willing to ignore it. | |
| Should probably do this via a global var and complain | |
| about this later. | |
| Assumption: All known inodes are now marked as in-use or free. Any | |
| inodes that we haven't found by now are hosed (lost) since | |
| we can't reach them via either the inode btrees or via directory | |
| entries. | |
| Directories are semi-clean. All '.' entries are good. | |
| Root '..' entry is good if root inode exists. All entries | |
| referencing non-existent inodes, free inodes, etc. | |
| XXX verify that either quota inode is 0 or NULLFSINO or | |
| if sb quota flag is non zero, verify that quota inode | |
| is NULLFSINO or is referencing a used, but disconnected | |
| inode. | |
| XXX if in no_modify mode, check for unclaimed blocks | |
| - Phase 4 - Check for inodes referencing duplicate blocks | |
| At this point, all known duplicate blocks are marked in | |
| the block map. However, some of the claimed blocks in | |
| the bmap may in fact be free because they belong to inodes | |
| that have to be cleared either due to being a trashed | |
| directory or because it's the first inode to claim a | |
| block that was then claimed later. There's a similar | |
| problem with meta-data blocks that are referenced by | |
| inode bmaps that are going to be freed once the inode | |
| (or directory) gets cleared. | |
| So at this point, we collect the duplicate blocks into | |
| extents and put them into the duplicate extent list. | |
| Mark the ag header blocks as in use. | |
| We then process each inode twice -- the first time | |
| we check to see if the inode claims a duplicate extent | |
| and we do NOT set the block bitmap. If the inode claims | |
| a duplicate extent, we clear the inode. Since the bitmap | |
| hasn't been set, that automatically frees all blocks associated | |
| with the cleared inode. If the inode is ok, process it a second | |
| time and set the bitmap since we know that this inode will live. | |
| The unlinked list gets cleared in every inode at this point as | |
| well. We no longer need to preserve it since we've discovered | |
| every inode we're going to find from it. | |
| verify existence of root inode. if it exists, check for | |
| existence of "lost+found". If it exists, mark the entry | |
| to be deleted, and clear the inode. All the inodes that | |
| were connected to the lost+found will be reconnected later. | |
| XXX HEURISTIC -- if we blow an inode away that has space, | |
| assume that the freespace btree is now out of wack. | |
| If it was ok earlier, it's certain to be wrong now. | |
| And the odds of this space free cancelling out the | |
| existing error is so small I'm willing to ignore it. | |
| Should probably do this via a global var and complain | |
| about this later. | |
| Clear the quota inodes if the inode btree says that | |
| they're not in use. The space freed will get picked | |
| up by phase 5. | |
| XXX Clear the quota inodes if the filesystem is being downgraded. | |
| - Phase 5 - Build inode allocation trees, freespace trees and | |
| agfl's for each ag. After this, we should be able to | |
| unmount the filesystem and remount it for real. | |
| For each ag: (if no in no_modify mode) | |
| scan bitmap first to figure out number of extents. | |
| calculate space required for all trees. Start with inode trees. | |
| Setup the btree cursor which includes the list of preallocated | |
| blocks. As a by-product, this will delete the extents required | |
| for the inode tree from the incore extent tree. | |
| Calculate how many extents will be required to represent the | |
| remaining free extent tree on disk (twice, one for bybno and | |
| one for bycnt). You have to iterate on this because consuming | |
| extents can alter the number of blocks required to represent | |
| the remaining extents. If there's slop left over, you can | |
| put it in the agfl though. | |
| Then, manually build the trees, agi, agfs, and agfls. | |
| XXX if in no_modify mode, scan the on-disk inode allocation | |
| trees and compare against the incore versions. Don't have | |
| to scan the freespace trees because we caught the problems | |
| there in phase2 and phase3. But if we cleared any inodes | |
| with space during phases 3 or 4, now is the time to complain. | |
| XXX - Free duplicate extent lists. ??? | |
| Assumptions: at this point, sim code having to do with inode | |
| creation/modification/deletion and space allocation | |
| work because the inode maps, space maps, and bmaps | |
| for all files in the filesystem are good. The only | |
| structures that are screwed up are the directory contents, | |
| which means that lookup may not work for beans, the | |
| root inode which exists but may be completely bogus and | |
| the link counts on all inodes which may also be bogus. | |
| Free the bitmap, the freespace tree. | |
| Flash the incore inode tree over from parent list to having | |
| full backpointers. | |
| realtime processing, if any -- | |
| (Skip to below if running in no_modify mode). | |
| Generate the realtime bitmap from the incore realtime | |
| extent map and slam the info into the realtime bitmap | |
| inode. Generate summary info from the realtime extent map. | |
| XXX if in no_modify mode, compare contents of realtime bitmap | |
| inode to the incore realtime extent map. generate the | |
| summary info from the incore realtime extent map. | |
| compare against the contents of the realtime summary inode. | |
| complain if bad. | |
| reset superblock counters, sync version numbers | |
| - Phase 6 - directory traversal -- check reference counts, | |
| attach disconnected inodes, fix up bogus directories | |
| Assumptions: all on-disk space and inode trees are structurally | |
| sound. Incore and on-disk inode trees agree on whether | |
| an inode is in use. | |
| Directories are structurally sound. All hashvalues | |
| are monotonically increasing and interior nodes are | |
| correct so lookups work. All legal directory entries | |
| point to inodes that are in use and exist. Shortform | |
| directories are fine except that the links haven't been | |
| checked for conflicts (cycles, ".." being correct, etc.). | |
| Longform directories haven't been checked for those problems | |
| either PLUS longform directories may still contain | |
| entries beginning with '/'. No zero-length entries | |
| exist (they've been deleted or converted to '/'). | |
| Root directory may or may not exist. orphange may | |
| or may not exist. Contents of either may be completely | |
| bogus. | |
| Entries may point to free or non-existent inodes. | |
| At this we point, we may need new incore structures and | |
| may be able to trash an old one (like the filesystem | |
| block map) | |
| If '/' is trashed, then reinitialize it. | |
| If no realtime inodes, make them and if necessary, slam the | |
| summary info into the realtime summary | |
| inode. Ditto with the realtime bitmap inode. | |
| Make orphanage (lost+found ???). | |
| Traverse each directory from '/' (unless it was created). | |
| Check directory structure and each directory entry. | |
| If the entry is bogus (points to a non-existent or | |
| free inode, for example), mark that entry TBD. Maintain | |
| link counts on all inodes. Currently, traversal is | |
| depth-first. | |
| Mark every inode reached as "reached" (includes | |
| bumping up link counts). | |
| If a entry points to a directory but the parent (..) | |
| disagrees, then blow away the entry. if the directory | |
| being pointed to winds up disconnected, it'll be moved | |
| to the orphanage (and the link count incremented to | |
| account for the link and the reached bit set then). | |
| If an entry points to a directory that we've already | |
| reached, then some entry is bad and should be blown | |
| away. It's easiest to blow away the current entry | |
| plus since presumably the parent entry in the | |
| reached directory points to another directory, | |
| then it's far more likely that the current | |
| entry is bogus (otherwise the parent should point | |
| at it). | |
| If an entry points to a non-existent of free inode, | |
| blow the entry away. | |
| Every time a good entry is encountered update the | |
| link count for the inode that the entry points to. | |
| After traversal, scan incore inode map for directories not | |
| reached. Go to first one and try and find its root | |
| by following .. entries. Once at root, run traversal | |
| algorithm. When algorithm terminates, move subtree | |
| root inode to the orphanage. Repeat as necessary | |
| until all disconnected directories are attached. | |
| Move all disconnected inodes to orphanage. | |
| - Phase 7: reset reference counts if required. | |
| Now traverse the on-disk inodes again, and make sure on-disk | |
| reference counts are correct. Reset if necessary. | |
| SKIP all unused inodes -- that also makes us | |
| skip the orphanage inode which we think is | |
| unused but is really used. However, the ref counts | |
| on that should be right so that's ok. | |
| --- | |
| multiple TB xfs_repair | |
| modify above to work in a couple of AGs at a time. The bitmaps | |
| should span only the current set of AGs. | |
| The key it scan the inode bmaps and keep a list of inodes | |
| that span multiple AG sets and keep the list in a data structure | |
| that's keyed off AG set # as well as inode # and also has a bit | |
| to indicate whether or not the inode will be cleared. | |
| Then in each AG set, when doing duplicate extent processing, | |
| you have to process all multi-AG-set inodes that claim blocks in | |
| the current AG set. If there's a conflict, you mark clear the | |
| inode in the current AG and you mark the multi-AG inode as | |
| "to be cleared". | |
| After going through all AGs, you can clear the to-be-cleared | |
| multi-AG-set inodes and pull them off the list. | |
| When building up the AG freespace trees, you walk the bmaps | |
| of all multi-AG-set inodes that are in the AG-set and include | |
| blocks claimed in the AG by the inode as used. | |
| This probably involves adding a phase 3-0 which would have to | |
| check all the inodes to see which ones are multi-AG-set inodes | |
| and set up the multi-AG-set inode data structure. Plus the | |
| process_dinode routines may have to be altered just a bit | |
| to do the right thing if running in tera-byte mode (call | |
| out to routines that check the multi-AG-set inodes when | |
| appropriate). | |
| To make things go faster, phase 3-0 could probably run | |
| in parallel. It should be possible to run phases 2-5 | |
| in parallel as well once the appropriate synchronization | |
| is added to the incore routines and the static directory | |
| leaf block bitmap is changed to be on the stack. | |
| Phase 7 probably can be in parallel as well. | |
| By in parallel, I mean that assuming that an AG-set | |
| contains 4 AGs, you could run 4 threads, 1 per AG | |
| in parallel to process the AG set. | |
| I don't see how phase 6 can be run in parallel though. | |
| And running Phase 8 in parallel is just silly. |