docs: describe xfs directory tree online fsck

I've added a scrubber that checks the directory tree structure and fixes
them; describe this in the design documentation.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
Darrick J. Wong 2024-04-15 14:55:10 -07:00
parent c91fe20e5a
commit 67bdcd4999

View File

@ -4785,6 +4785,130 @@ This scan would have to be converted into a multi-pass scan:
This code has not yet been constructed.
.. _dirtree:
Case Study: Directory Tree Structure
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
As mentioned earlier, the filesystem directory tree is supposed to be a
directed acylic graph structure.
However, each node in this graph is a separate ``xfs_inode`` object with its
own locks, which makes validating the tree qualities difficult.
Fortunately, non-directories are allowed to have multiple parents and cannot
have children, so only directories need to be scanned.
Directories typically constitute 5-10% of the files in a filesystem, which
reduces the amount of work dramatically.
If the directory tree could be frozen, it would be easy to discover cycles and
disconnected regions by running a depth (or breadth) first search downwards
from the root directory and marking a bitmap for each directory found.
At any point in the walk, trying to set an already set bit means there is a
cycle.
After the scan completes, XORing the marked inode bitmap with the inode
allocation bitmap reveals disconnected inodes.
However, one of online repair's design goals is to avoid locking the entire
filesystem unless it's absolutely necessary.
Directory tree updates can move subtrees across the scanner wavefront on a live
filesystem, so the bitmap algorithm cannot be applied.
Directory parent pointers enable an incremental approach to validation of the
tree structure.
Instead of using one thread to scan the entire filesystem, multiple threads can
walk from individual subdirectories upwards towards the root.
For this to work, all directory entries and parent pointers must be internally
consistent, each directory entry must have a parent pointer, and the link
counts of all directories must be correct.
Each scanner thread must be able to take the IOLOCK of an alleged parent
directory while holding the IOLOCK of the child directory to prevent either
directory from being moved within the tree.
This is not possible since the VFS does not take the IOLOCK of a child
subdirectory when moving that subdirectory, so instead the scanner stabilizes
the parent -> child relationship by taking the ILOCKs and installing a dirent
update hook to detect changes.
The scanning process uses a dirent hook to detect changes to the directories
mentioned in the scan data.
The scan works as follows:
1. For each subdirectory in the filesystem,
a. For each parent pointer of that subdirectory,
1. Create a path object for that parent pointer, and mark the
subdirectory inode number in the path object's bitmap.
2. Record the parent pointer name and inode number in a path structure.
3. If the alleged parent is the subdirectory being scrubbed, the path is
a cycle.
Mark the path for deletion and repeat step 1a with the next
subdirectory parent pointer.
4. Try to mark the alleged parent inode number in a bitmap in the path
object.
If the bit is already set, then there is a cycle in the directory
tree.
Mark the path as a cycle and repeat step 1a with the next subdirectory
parent pointer.
5. Load the alleged parent.
If the alleged parent is not a linked directory, abort the scan
because the parent pointer information is inconsistent.
6. For each parent pointer of this alleged ancestor directory,
a. Record the parent pointer name and inode number in the path object
if no parent has been set for that level.
b. If an ancestor has more than one parent, mark the path as corrupt.
Repeat step 1a with the next subdirectory parent pointer.
c. Repeat steps 1a3-1a6 for the ancestor identified in step 1a6a.
This repeats until the directory tree root is reached or no parents
are found.
7. If the walk terminates at the root directory, mark the path as ok.
8. If the walk terminates without reaching the root, mark the path as
disconnected.
2. If the directory entry update hook triggers, check all paths already found
by the scan.
If the entry matches part of a path, mark that path and the scan stale.
When the scanner thread sees that the scan has been marked stale, it deletes
all scan data and starts over.
Repairing the directory tree works as follows:
1. Walk each path of the target subdirectory.
a. Corrupt paths and cycle paths are counted as suspect.
b. Paths already marked for deletion are counted as bad.
c. Paths that reached the root are counted as good.
2. If the subdirectory is either the root directory or has zero link count,
delete all incoming directory entries in the immediate parents.
Repairs are complete.
3. If the subdirectory has exactly one path, set the dotdot entry to the
parent and exit.
4. If the subdirectory has at least one good path, delete all the other
incoming directory entries in the immediate parents.
5. If the subdirectory has no good paths and more than one suspect path, delete
all the other incoming directory entries in the immediate parents.
6. If the subdirectory has zero paths, attach it to the lost and found.
The proposed patches are in the
`directory tree repair
<https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux.git/log/?h=scrub-directory-tree>`_
series.
.. _orphanage:
The Orphanage