// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2021-2024 Oracle. All Rights Reserved. * Author: Darrick J. Wong <[email protected]> */ #include "xfs.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_log_format.h" #include "xfs_trans.h" #include "xfs_inode.h" #include "xfs_ialloc.h" #include "xfs_quota.h" #include "xfs_trans_space.h" #include "xfs_dir2.h" #include "xfs_icache.h" #include "xfs_bmap.h" #include "xfs_bmap_btree.h" #include "xfs_parent.h" #include "xfs_attr_sf.h" #include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/repair.h" #include "scrub/trace.h" #include "scrub/orphanage.h" #include "scrub/readdir.h" #include <linux/namei.h> /* * The Orphanage * ============= * * If the directory tree is damaged, children of that directory become * inaccessible via that file path. If a child has no other parents, the file * is said to be orphaned. xfs_repair fixes this situation by creating a * orphanage directory (specifically, /lost+found) and creating a directory * entry pointing to the orphaned file. * * Online repair follows this tactic by creating a root-owned /lost+found * directory if one does not exist. If an orphan is found, it will move that * files into orphanage. */ /* Make the orphanage owned by root. */ STATIC int xrep_chown_orphanage( struct xfs_scrub *sc, struct xfs_inode *dp) { … } #define ORPHANAGE … /* Create the orphanage directory, and set sc->orphanage to it. */ int xrep_orphanage_create( struct xfs_scrub *sc) { … } void xrep_orphanage_ilock( struct xfs_scrub *sc, unsigned int ilock_flags) { … } bool xrep_orphanage_ilock_nowait( struct xfs_scrub *sc, unsigned int ilock_flags) { … } void xrep_orphanage_iunlock( struct xfs_scrub *sc, unsigned int ilock_flags) { … } /* Grab the IOLOCK of the orphanage and sc->ip. */ int xrep_orphanage_iolock_two( struct xfs_scrub *sc) { … } /* Release the orphanage. */ void xrep_orphanage_rele( struct xfs_scrub *sc) { … } /* Adoption moves a file into /lost+found */ /* Can the orphanage adopt @sc->ip? */ bool xrep_orphanage_can_adopt( struct xfs_scrub *sc) { … } /* * Create a new transaction to send a child to the orphanage. * * Allocate a new transaction with sufficient disk space to handle the * adoption, take ILOCK_EXCL of the orphanage and sc->ip, joins them to the * transaction, and reserve quota to reparent the latter. Caller must hold the * IOLOCK of the orphanage and sc->ip. */ int xrep_adoption_trans_alloc( struct xfs_scrub *sc, struct xrep_adoption *adopt) { … } /* * Compute the xfs_name for the directory entry that we're adding to the * orphanage. Caller must hold ILOCKs of sc->ip and the orphanage and must not * reuse namebuf until the adoption completes or is dissolved. */ int xrep_adoption_compute_name( struct xrep_adoption *adopt, struct xfs_name *xname) { … } /* * Make sure the dcache does not have a positive dentry for the name we've * chosen. The caller should have checked with the ondisk directory, so any * discrepancy is a sign that something is seriously wrong. */ static int xrep_adoption_check_dcache( struct xrep_adoption *adopt) { … } /* * Invalidate all dentries for the name that was added to the orphanage * directory, and all dentries pointing to the child inode that was moved. * * There should not be any positive entries for the name, since we've * maintained our lock on the orphanage directory. */ static void xrep_adoption_zap_dcache( struct xrep_adoption *adopt) { … } /* * If we have to add an attr fork ahead of a parent pointer update, how much * space should we ask for? */ static inline int xrep_adoption_attr_sizeof( const struct xrep_adoption *adopt) { … } /* * Move the current file to the orphanage under the computed name. * * Returns with a dirty transaction so that the caller can handle any other * work, such as fixing up unlinked lists or resetting link counts. */ int xrep_adoption_move( struct xrep_adoption *adopt) { … } /* * Roll to a clean scrub transaction so that we can release the orphanage, * even if xrep_adoption_move was not called. * * Commits all the work and deferred ops attached to an adoption request and * rolls to a clean scrub transaction. On success, returns 0 with the scrub * context holding a clean transaction with no inodes joined. On failure, * returns negative errno with no scrub transaction. All inode locks are * still held after this function returns. */ int xrep_adoption_trans_roll( struct xrep_adoption *adopt) { … }