1cc22edabSDarrick J. Wong // SPDX-License-Identifier: GPL-2.0-or-later 2cc22edabSDarrick J. Wong /* 3cc22edabSDarrick J. Wong * Copyright (c) 2020-2024 Oracle. All Rights Reserved. 4cc22edabSDarrick J. Wong * Author: Darrick J. Wong <djwong@kernel.org> 5cc22edabSDarrick J. Wong */ 6cc22edabSDarrick J. Wong #include "xfs.h" 7cc22edabSDarrick J. Wong #include "xfs_fs.h" 8cc22edabSDarrick J. Wong #include "xfs_shared.h" 9cc22edabSDarrick J. Wong #include "xfs_format.h" 10cc22edabSDarrick J. Wong #include "xfs_trans_resv.h" 11cc22edabSDarrick J. Wong #include "xfs_mount.h" 12cc22edabSDarrick J. Wong #include "xfs_defer.h" 13cc22edabSDarrick J. Wong #include "xfs_bit.h" 14cc22edabSDarrick J. Wong #include "xfs_log_format.h" 15cc22edabSDarrick J. Wong #include "xfs_trans.h" 16cc22edabSDarrick J. Wong #include "xfs_sb.h" 17cc22edabSDarrick J. Wong #include "xfs_inode.h" 18cc22edabSDarrick J. Wong #include "xfs_icache.h" 19cc22edabSDarrick J. Wong #include "xfs_da_format.h" 20cc22edabSDarrick J. Wong #include "xfs_da_btree.h" 21cc22edabSDarrick J. Wong #include "xfs_dir2.h" 22cc22edabSDarrick J. Wong #include "xfs_bmap_btree.h" 23cc22edabSDarrick J. Wong #include "xfs_dir2_priv.h" 24cc22edabSDarrick J. Wong #include "xfs_trans_space.h" 25cc22edabSDarrick J. Wong #include "xfs_health.h" 26cc22edabSDarrick J. Wong #include "xfs_exchmaps.h" 27b334f7faSDarrick J. Wong #include "xfs_parent.h" 28a26dc213SDarrick J. Wong #include "xfs_attr.h" 29a26dc213SDarrick J. Wong #include "xfs_bmap.h" 303f50ddbfSDarrick J. Wong #include "xfs_ag.h" 31cc22edabSDarrick J. Wong #include "scrub/xfs_scrub.h" 32cc22edabSDarrick J. Wong #include "scrub/scrub.h" 33cc22edabSDarrick J. Wong #include "scrub/common.h" 34cc22edabSDarrick J. Wong #include "scrub/trace.h" 35cc22edabSDarrick J. Wong #include "scrub/repair.h" 36cc22edabSDarrick J. Wong #include "scrub/iscan.h" 37cc22edabSDarrick J. Wong #include "scrub/findparent.h" 38cc22edabSDarrick J. Wong #include "scrub/readdir.h" 391e58a8ccSDarrick J. Wong #include "scrub/tempfile.h" 40a26dc213SDarrick J. Wong #include "scrub/tempexch.h" 411e58a8ccSDarrick J. Wong #include "scrub/orphanage.h" 42b334f7faSDarrick J. Wong #include "scrub/xfile.h" 43b334f7faSDarrick J. Wong #include "scrub/xfarray.h" 44b334f7faSDarrick J. Wong #include "scrub/xfblob.h" 45a26dc213SDarrick J. Wong #include "scrub/attr_repair.h" 46a26dc213SDarrick J. Wong #include "scrub/listxattr.h" 47cc22edabSDarrick J. Wong 48cc22edabSDarrick J. Wong /* 49cc22edabSDarrick J. Wong * Repairing The Directory Parent Pointer 50cc22edabSDarrick J. Wong * ====================================== 51cc22edabSDarrick J. Wong * 52cc22edabSDarrick J. Wong * Currently, only directories support parent pointers (in the form of '..' 53cc22edabSDarrick J. Wong * entries), so we simply scan the filesystem and update the '..' entry. 54cc22edabSDarrick J. Wong * 55cc22edabSDarrick J. Wong * Note that because the only parent pointer is the dotdot entry, we won't 56cc22edabSDarrick J. Wong * touch an unhealthy directory, since the directory repair code is perfectly 57cc22edabSDarrick J. Wong * capable of rebuilding a directory with the proper parent inode. 58cc22edabSDarrick J. Wong * 59cc22edabSDarrick J. Wong * See the section on locking issues in dir_repair.c for more information about 60cc22edabSDarrick J. Wong * conflicts with the VFS. The findparent code wll keep our incore parent 61cc22edabSDarrick J. Wong * inode up to date. 62b334f7faSDarrick J. Wong * 63b334f7faSDarrick J. Wong * If parent pointers are enabled, we instead reconstruct the parent pointer 64b334f7faSDarrick J. Wong * information by visiting every directory entry of every directory in the 65b334f7faSDarrick J. Wong * system and translating the relevant dirents into parent pointers. In this 66b334f7faSDarrick J. Wong * case, it is advantageous to stash all parent pointers created from dirents 67b334f7faSDarrick J. Wong * from a single parent file before replaying them into the temporary file. To 68b334f7faSDarrick J. Wong * save memory, the live filesystem scan reuses the findparent object. Parent 69b334f7faSDarrick J. Wong * pointer repair chooses either directory scanning or findparent, but not 70b334f7faSDarrick J. Wong * both. 71b334f7faSDarrick J. Wong * 72b334f7faSDarrick J. Wong * When salvaging completes, the remaining stashed entries are replayed to the 73b334f7faSDarrick J. Wong * temporary file. All non-parent pointer extended attributes are copied to 74a26dc213SDarrick J. Wong * the temporary file's extended attributes. An atomic file mapping exchange 75a26dc213SDarrick J. Wong * is used to commit the new xattr blocks to the file being repaired. This 76a26dc213SDarrick J. Wong * will disrupt attrmulti cursors. 77cc22edabSDarrick J. Wong */ 78cc22edabSDarrick J. Wong 7965a1fb7aSDarrick J. Wong /* Create a parent pointer in the tempfile. */ 8065a1fb7aSDarrick J. Wong #define XREP_PPTR_ADD (1) 8165a1fb7aSDarrick J. Wong 8265a1fb7aSDarrick J. Wong /* Remove a parent pointer from the tempfile. */ 8365a1fb7aSDarrick J. Wong #define XREP_PPTR_REMOVE (2) 8465a1fb7aSDarrick J. Wong 85b334f7faSDarrick J. Wong /* A stashed parent pointer update. */ 86b334f7faSDarrick J. Wong struct xrep_pptr { 87b334f7faSDarrick J. Wong /* Cookie for retrieval of the pptr name. */ 88b334f7faSDarrick J. Wong xfblob_cookie name_cookie; 89b334f7faSDarrick J. Wong 90b334f7faSDarrick J. Wong /* Parent pointer record. */ 91b334f7faSDarrick J. Wong struct xfs_parent_rec pptr_rec; 92b334f7faSDarrick J. Wong 93b334f7faSDarrick J. Wong /* Length of the pptr name. */ 94b334f7faSDarrick J. Wong uint8_t namelen; 9565a1fb7aSDarrick J. Wong 9665a1fb7aSDarrick J. Wong /* XREP_PPTR_{ADD,REMOVE} */ 9765a1fb7aSDarrick J. Wong uint8_t action; 98b334f7faSDarrick J. Wong }; 99b334f7faSDarrick J. Wong 100b334f7faSDarrick J. Wong /* 101b334f7faSDarrick J. Wong * Stash up to 8 pages of recovered parent pointers in pptr_recs and 102b334f7faSDarrick J. Wong * pptr_names before we write them to the temp file. 103b334f7faSDarrick J. Wong */ 104b334f7faSDarrick J. Wong #define XREP_PARENT_MAX_STASH_BYTES (PAGE_SIZE * 8) 105b334f7faSDarrick J. Wong 106cc22edabSDarrick J. Wong struct xrep_parent { 107cc22edabSDarrick J. Wong struct xfs_scrub *sc; 108cc22edabSDarrick J. Wong 109b334f7faSDarrick J. Wong /* Fixed-size array of xrep_pptr structures. */ 110b334f7faSDarrick J. Wong struct xfarray *pptr_recs; 111b334f7faSDarrick J. Wong 112b334f7faSDarrick J. Wong /* Blobs containing parent pointer names. */ 113b334f7faSDarrick J. Wong struct xfblob *pptr_names; 114b334f7faSDarrick J. Wong 115a26dc213SDarrick J. Wong /* xattr keys */ 116a26dc213SDarrick J. Wong struct xfarray *xattr_records; 117a26dc213SDarrick J. Wong 118a26dc213SDarrick J. Wong /* xattr values */ 119a26dc213SDarrick J. Wong struct xfblob *xattr_blobs; 120a26dc213SDarrick J. Wong 121a26dc213SDarrick J. Wong /* Scratch buffers for saving extended attributes */ 122a26dc213SDarrick J. Wong unsigned char *xattr_name; 123a26dc213SDarrick J. Wong void *xattr_value; 124a26dc213SDarrick J. Wong unsigned int xattr_value_sz; 125a26dc213SDarrick J. Wong 126a26dc213SDarrick J. Wong /* 127a26dc213SDarrick J. Wong * Information used to exchange the attr fork mappings, if the fs 128a26dc213SDarrick J. Wong * supports parent pointers. 129a26dc213SDarrick J. Wong */ 130a26dc213SDarrick J. Wong struct xrep_tempexch tx; 131a26dc213SDarrick J. Wong 132cc22edabSDarrick J. Wong /* 133cc22edabSDarrick J. Wong * Information used to scan the filesystem to find the inumber of the 134b334f7faSDarrick J. Wong * dotdot entry for this directory. On filesystems without parent 135b334f7faSDarrick J. Wong * pointers, we use the findparent_* functions on this object and 136b334f7faSDarrick J. Wong * access only the parent_ino field directly. 137b334f7faSDarrick J. Wong * 138b334f7faSDarrick J. Wong * When parent pointers are enabled, the directory entry scanner uses 139b334f7faSDarrick J. Wong * the iscan, hooks, and lock fields of this object directly. 140b334f7faSDarrick J. Wong * @pscan.lock coordinates access to pptr_recs, pptr_names, pptr, and 141b334f7faSDarrick J. Wong * pptr_scratch. This reduces the memory requirements of this 142b334f7faSDarrick J. Wong * structure. 143a26dc213SDarrick J. Wong * 144a26dc213SDarrick J. Wong * The lock also controls access to xattr_records and xattr_blobs(?) 145cc22edabSDarrick J. Wong */ 146cc22edabSDarrick J. Wong struct xrep_parent_scan_info pscan; 1471e58a8ccSDarrick J. Wong 1481e58a8ccSDarrick J. Wong /* Orphanage reparenting request. */ 1491e58a8ccSDarrick J. Wong struct xrep_adoption adoption; 1501e58a8ccSDarrick J. Wong 1511e58a8ccSDarrick J. Wong /* Directory entry name, plus the trailing null. */ 1521e58a8ccSDarrick J. Wong struct xfs_name xname; 1531e58a8ccSDarrick J. Wong unsigned char namebuf[MAXNAMELEN]; 154b334f7faSDarrick J. Wong 155b334f7faSDarrick J. Wong /* Scratch buffer for scanning pptr xattrs */ 156b334f7faSDarrick J. Wong struct xfs_da_args pptr_args; 157a26dc213SDarrick J. Wong 158a26dc213SDarrick J. Wong /* Have we seen any live updates of parent pointers recently? */ 159a26dc213SDarrick J. Wong bool saw_pptr_updates; 1603f50ddbfSDarrick J. Wong 1613f50ddbfSDarrick J. Wong /* Number of parents we found after all other repairs */ 1623f50ddbfSDarrick J. Wong unsigned long long parents; 163cc22edabSDarrick J. Wong }; 164cc22edabSDarrick J. Wong 165a26dc213SDarrick J. Wong struct xrep_parent_xattr { 166a26dc213SDarrick J. Wong /* Cookie for retrieval of the xattr name. */ 167a26dc213SDarrick J. Wong xfblob_cookie name_cookie; 168a26dc213SDarrick J. Wong 169a26dc213SDarrick J. Wong /* Cookie for retrieval of the xattr value. */ 170a26dc213SDarrick J. Wong xfblob_cookie value_cookie; 171a26dc213SDarrick J. Wong 172a26dc213SDarrick J. Wong /* XFS_ATTR_* flags */ 173a26dc213SDarrick J. Wong int flags; 174a26dc213SDarrick J. Wong 175a26dc213SDarrick J. Wong /* Length of the value and name. */ 176a26dc213SDarrick J. Wong uint32_t valuelen; 177a26dc213SDarrick J. Wong uint16_t namelen; 178a26dc213SDarrick J. Wong }; 179a26dc213SDarrick J. Wong 180a26dc213SDarrick J. Wong /* 181a26dc213SDarrick J. Wong * Stash up to 8 pages of attrs in xattr_records/xattr_blobs before we write 182a26dc213SDarrick J. Wong * them to the temp file. 183a26dc213SDarrick J. Wong */ 184a26dc213SDarrick J. Wong #define XREP_PARENT_XATTR_MAX_STASH_BYTES (PAGE_SIZE * 8) 185a26dc213SDarrick J. Wong 186cc22edabSDarrick J. Wong /* Tear down all the incore stuff we created. */ 187cc22edabSDarrick J. Wong static void 188cc22edabSDarrick J. Wong xrep_parent_teardown( 189cc22edabSDarrick J. Wong struct xrep_parent *rp) 190cc22edabSDarrick J. Wong { 191cc22edabSDarrick J. Wong xrep_findparent_scan_teardown(&rp->pscan); 192a26dc213SDarrick J. Wong kvfree(rp->xattr_name); 193a26dc213SDarrick J. Wong rp->xattr_name = NULL; 194a26dc213SDarrick J. Wong kvfree(rp->xattr_value); 195a26dc213SDarrick J. Wong rp->xattr_value = NULL; 196a26dc213SDarrick J. Wong if (rp->xattr_blobs) 197a26dc213SDarrick J. Wong xfblob_destroy(rp->xattr_blobs); 198a26dc213SDarrick J. Wong rp->xattr_blobs = NULL; 199a26dc213SDarrick J. Wong if (rp->xattr_records) 200a26dc213SDarrick J. Wong xfarray_destroy(rp->xattr_records); 201a26dc213SDarrick J. Wong rp->xattr_records = NULL; 202b334f7faSDarrick J. Wong if (rp->pptr_names) 203b334f7faSDarrick J. Wong xfblob_destroy(rp->pptr_names); 204b334f7faSDarrick J. Wong rp->pptr_names = NULL; 205b334f7faSDarrick J. Wong if (rp->pptr_recs) 206b334f7faSDarrick J. Wong xfarray_destroy(rp->pptr_recs); 207b334f7faSDarrick J. Wong rp->pptr_recs = NULL; 208cc22edabSDarrick J. Wong } 209cc22edabSDarrick J. Wong 210cc22edabSDarrick J. Wong /* Set up for a parent repair. */ 211cc22edabSDarrick J. Wong int 212cc22edabSDarrick J. Wong xrep_setup_parent( 213cc22edabSDarrick J. Wong struct xfs_scrub *sc) 214cc22edabSDarrick J. Wong { 215cc22edabSDarrick J. Wong struct xrep_parent *rp; 216b334f7faSDarrick J. Wong int error; 217cc22edabSDarrick J. Wong 218cc22edabSDarrick J. Wong xchk_fsgates_enable(sc, XCHK_FSGATES_DIRENTS); 219cc22edabSDarrick J. Wong 220cc22edabSDarrick J. Wong rp = kvzalloc(sizeof(struct xrep_parent), XCHK_GFP_FLAGS); 221cc22edabSDarrick J. Wong if (!rp) 222cc22edabSDarrick J. Wong return -ENOMEM; 223cc22edabSDarrick J. Wong rp->sc = sc; 2241e58a8ccSDarrick J. Wong rp->xname.name = rp->namebuf; 225cc22edabSDarrick J. Wong sc->buf = rp; 226cc22edabSDarrick J. Wong 227b334f7faSDarrick J. Wong error = xrep_tempfile_create(sc, S_IFREG); 228b334f7faSDarrick J. Wong if (error) 229b334f7faSDarrick J. Wong return error; 230b334f7faSDarrick J. Wong 2311e58a8ccSDarrick J. Wong return xrep_orphanage_try_create(sc); 232cc22edabSDarrick J. Wong } 233cc22edabSDarrick J. Wong 234cc22edabSDarrick J. Wong /* 235cc22edabSDarrick J. Wong * Scan all files in the filesystem for a child dirent that we can turn into 236cc22edabSDarrick J. Wong * the dotdot entry for this directory. 237cc22edabSDarrick J. Wong */ 238cc22edabSDarrick J. Wong STATIC int 239cc22edabSDarrick J. Wong xrep_parent_find_dotdot( 240cc22edabSDarrick J. Wong struct xrep_parent *rp) 241cc22edabSDarrick J. Wong { 242cc22edabSDarrick J. Wong struct xfs_scrub *sc = rp->sc; 243cc22edabSDarrick J. Wong xfs_ino_t ino; 244cc22edabSDarrick J. Wong unsigned int sick, checked; 245cc22edabSDarrick J. Wong int error; 246cc22edabSDarrick J. Wong 247cc22edabSDarrick J. Wong /* 248cc22edabSDarrick J. Wong * Avoid sick directories. There shouldn't be anyone else clearing the 249cc22edabSDarrick J. Wong * directory's sick status. 250cc22edabSDarrick J. Wong */ 251cc22edabSDarrick J. Wong xfs_inode_measure_sickness(sc->ip, &sick, &checked); 252cc22edabSDarrick J. Wong if (sick & XFS_SICK_INO_DIR) 253cc22edabSDarrick J. Wong return -EFSCORRUPTED; 254cc22edabSDarrick J. Wong 255cc22edabSDarrick J. Wong ino = xrep_findparent_self_reference(sc); 256cc22edabSDarrick J. Wong if (ino != NULLFSINO) { 257cc22edabSDarrick J. Wong xrep_findparent_scan_finish_early(&rp->pscan, ino); 258cc22edabSDarrick J. Wong return 0; 259cc22edabSDarrick J. Wong } 260cc22edabSDarrick J. Wong 261cc22edabSDarrick J. Wong /* 262cc22edabSDarrick J. Wong * Drop the ILOCK on this directory so that we can scan for the dotdot 263cc22edabSDarrick J. Wong * entry. Figure out who is going to be the parent of this directory, 264cc22edabSDarrick J. Wong * then retake the ILOCK so that we can salvage directory entries. 265cc22edabSDarrick J. Wong */ 266cc22edabSDarrick J. Wong xchk_iunlock(sc, XFS_ILOCK_EXCL); 26734c9382cSDarrick J. Wong 26834c9382cSDarrick J. Wong /* Does the VFS dcache have an answer for us? */ 26934c9382cSDarrick J. Wong ino = xrep_findparent_from_dcache(sc); 27034c9382cSDarrick J. Wong if (ino != NULLFSINO) { 27134c9382cSDarrick J. Wong error = xrep_findparent_confirm(sc, &ino); 27234c9382cSDarrick J. Wong if (!error && ino != NULLFSINO) { 27334c9382cSDarrick J. Wong xrep_findparent_scan_finish_early(&rp->pscan, ino); 27434c9382cSDarrick J. Wong goto out_relock; 27534c9382cSDarrick J. Wong } 27634c9382cSDarrick J. Wong } 27734c9382cSDarrick J. Wong 27834c9382cSDarrick J. Wong /* Scan the entire filesystem for a parent. */ 279cc22edabSDarrick J. Wong error = xrep_findparent_scan(&rp->pscan); 28034c9382cSDarrick J. Wong out_relock: 281cc22edabSDarrick J. Wong xchk_ilock(sc, XFS_ILOCK_EXCL); 282cc22edabSDarrick J. Wong 283cc22edabSDarrick J. Wong return error; 284cc22edabSDarrick J. Wong } 285cc22edabSDarrick J. Wong 286b334f7faSDarrick J. Wong /* 287b334f7faSDarrick J. Wong * Add this stashed incore parent pointer to the temporary file. 288b334f7faSDarrick J. Wong * The caller must hold the tempdir's IOLOCK, must not hold any ILOCKs, and 289b334f7faSDarrick J. Wong * must not be in transaction context. 290b334f7faSDarrick J. Wong */ 291b334f7faSDarrick J. Wong STATIC int 292b334f7faSDarrick J. Wong xrep_parent_replay_update( 293b334f7faSDarrick J. Wong struct xrep_parent *rp, 294b334f7faSDarrick J. Wong const struct xfs_name *xname, 295b334f7faSDarrick J. Wong struct xrep_pptr *pptr) 296b334f7faSDarrick J. Wong { 297b334f7faSDarrick J. Wong struct xfs_scrub *sc = rp->sc; 298b334f7faSDarrick J. Wong 29965a1fb7aSDarrick J. Wong switch (pptr->action) { 30065a1fb7aSDarrick J. Wong case XREP_PPTR_ADD: 301b334f7faSDarrick J. Wong /* Create parent pointer. */ 30265a1fb7aSDarrick J. Wong trace_xrep_parent_replay_parentadd(sc->tempip, xname, 30365a1fb7aSDarrick J. Wong &pptr->pptr_rec); 304b334f7faSDarrick J. Wong 305b334f7faSDarrick J. Wong return xfs_parent_set(sc->tempip, sc->ip->i_ino, xname, 306b334f7faSDarrick J. Wong &pptr->pptr_rec, &rp->pptr_args); 30765a1fb7aSDarrick J. Wong case XREP_PPTR_REMOVE: 30865a1fb7aSDarrick J. Wong /* Remove parent pointer. */ 30965a1fb7aSDarrick J. Wong trace_xrep_parent_replay_parentremove(sc->tempip, xname, 31065a1fb7aSDarrick J. Wong &pptr->pptr_rec); 31165a1fb7aSDarrick J. Wong 31265a1fb7aSDarrick J. Wong return xfs_parent_unset(sc->tempip, sc->ip->i_ino, xname, 31365a1fb7aSDarrick J. Wong &pptr->pptr_rec, &rp->pptr_args); 31465a1fb7aSDarrick J. Wong } 31565a1fb7aSDarrick J. Wong 31665a1fb7aSDarrick J. Wong ASSERT(0); 31765a1fb7aSDarrick J. Wong return -EIO; 318b334f7faSDarrick J. Wong } 319b334f7faSDarrick J. Wong 320b334f7faSDarrick J. Wong /* 321b334f7faSDarrick J. Wong * Flush stashed parent pointer updates that have been recorded by the scanner. 322b334f7faSDarrick J. Wong * This is done to reduce the memory requirements of the parent pointer 323b334f7faSDarrick J. Wong * rebuild, since files can have a lot of hardlinks and the fs can be busy. 324b334f7faSDarrick J. Wong * 325b334f7faSDarrick J. Wong * Caller must not hold transactions or ILOCKs. Caller must hold the tempfile 326b334f7faSDarrick J. Wong * IOLOCK. 327b334f7faSDarrick J. Wong */ 328b334f7faSDarrick J. Wong STATIC int 329b334f7faSDarrick J. Wong xrep_parent_replay_updates( 330b334f7faSDarrick J. Wong struct xrep_parent *rp) 331b334f7faSDarrick J. Wong { 332b334f7faSDarrick J. Wong xfarray_idx_t array_cur; 333b334f7faSDarrick J. Wong int error; 334b334f7faSDarrick J. Wong 335b334f7faSDarrick J. Wong mutex_lock(&rp->pscan.lock); 336b334f7faSDarrick J. Wong foreach_xfarray_idx(rp->pptr_recs, array_cur) { 337b334f7faSDarrick J. Wong struct xrep_pptr pptr; 338b334f7faSDarrick J. Wong 339b334f7faSDarrick J. Wong error = xfarray_load(rp->pptr_recs, array_cur, &pptr); 340b334f7faSDarrick J. Wong if (error) 341b334f7faSDarrick J. Wong goto out_unlock; 342b334f7faSDarrick J. Wong 343b334f7faSDarrick J. Wong error = xfblob_loadname(rp->pptr_names, pptr.name_cookie, 344b334f7faSDarrick J. Wong &rp->xname, pptr.namelen); 345b334f7faSDarrick J. Wong if (error) 346b334f7faSDarrick J. Wong goto out_unlock; 347b334f7faSDarrick J. Wong rp->xname.len = pptr.namelen; 348b334f7faSDarrick J. Wong mutex_unlock(&rp->pscan.lock); 349b334f7faSDarrick J. Wong 350b334f7faSDarrick J. Wong error = xrep_parent_replay_update(rp, &rp->xname, &pptr); 351b334f7faSDarrick J. Wong if (error) 352b334f7faSDarrick J. Wong return error; 353b334f7faSDarrick J. Wong 354b334f7faSDarrick J. Wong mutex_lock(&rp->pscan.lock); 355b334f7faSDarrick J. Wong } 356b334f7faSDarrick J. Wong 357b334f7faSDarrick J. Wong /* Empty out both arrays now that we've added the entries. */ 358b334f7faSDarrick J. Wong xfarray_truncate(rp->pptr_recs); 359b334f7faSDarrick J. Wong xfblob_truncate(rp->pptr_names); 360b334f7faSDarrick J. Wong mutex_unlock(&rp->pscan.lock); 361b334f7faSDarrick J. Wong return 0; 362b334f7faSDarrick J. Wong out_unlock: 363b334f7faSDarrick J. Wong mutex_unlock(&rp->pscan.lock); 364b334f7faSDarrick J. Wong return error; 365b334f7faSDarrick J. Wong } 366b334f7faSDarrick J. Wong 367b334f7faSDarrick J. Wong /* 368b334f7faSDarrick J. Wong * Remember that we want to create a parent pointer in the tempfile. These 369b334f7faSDarrick J. Wong * stashed actions will be replayed later. 370b334f7faSDarrick J. Wong */ 371b334f7faSDarrick J. Wong STATIC int 372b334f7faSDarrick J. Wong xrep_parent_stash_parentadd( 373b334f7faSDarrick J. Wong struct xrep_parent *rp, 374b334f7faSDarrick J. Wong const struct xfs_name *name, 375b334f7faSDarrick J. Wong const struct xfs_inode *dp) 376b334f7faSDarrick J. Wong { 377b334f7faSDarrick J. Wong struct xrep_pptr pptr = { 37865a1fb7aSDarrick J. Wong .action = XREP_PPTR_ADD, 379b334f7faSDarrick J. Wong .namelen = name->len, 380b334f7faSDarrick J. Wong }; 381b334f7faSDarrick J. Wong int error; 382b334f7faSDarrick J. Wong 383b334f7faSDarrick J. Wong trace_xrep_parent_stash_parentadd(rp->sc->tempip, dp, name); 384b334f7faSDarrick J. Wong 385b334f7faSDarrick J. Wong xfs_inode_to_parent_rec(&pptr.pptr_rec, dp); 386b334f7faSDarrick J. Wong error = xfblob_storename(rp->pptr_names, &pptr.name_cookie, name); 387b334f7faSDarrick J. Wong if (error) 388b334f7faSDarrick J. Wong return error; 389b334f7faSDarrick J. Wong 390b334f7faSDarrick J. Wong return xfarray_append(rp->pptr_recs, &pptr); 391b334f7faSDarrick J. Wong } 392b334f7faSDarrick J. Wong 393b334f7faSDarrick J. Wong /* 39465a1fb7aSDarrick J. Wong * Remember that we want to remove a parent pointer from the tempfile. These 39565a1fb7aSDarrick J. Wong * stashed actions will be replayed later. 39665a1fb7aSDarrick J. Wong */ 39765a1fb7aSDarrick J. Wong STATIC int 39865a1fb7aSDarrick J. Wong xrep_parent_stash_parentremove( 39965a1fb7aSDarrick J. Wong struct xrep_parent *rp, 40065a1fb7aSDarrick J. Wong const struct xfs_name *name, 40165a1fb7aSDarrick J. Wong const struct xfs_inode *dp) 40265a1fb7aSDarrick J. Wong { 40365a1fb7aSDarrick J. Wong struct xrep_pptr pptr = { 40465a1fb7aSDarrick J. Wong .action = XREP_PPTR_REMOVE, 40565a1fb7aSDarrick J. Wong .namelen = name->len, 40665a1fb7aSDarrick J. Wong }; 40765a1fb7aSDarrick J. Wong int error; 40865a1fb7aSDarrick J. Wong 40965a1fb7aSDarrick J. Wong trace_xrep_parent_stash_parentremove(rp->sc->tempip, dp, name); 41065a1fb7aSDarrick J. Wong 41165a1fb7aSDarrick J. Wong xfs_inode_to_parent_rec(&pptr.pptr_rec, dp); 41265a1fb7aSDarrick J. Wong error = xfblob_storename(rp->pptr_names, &pptr.name_cookie, name); 41365a1fb7aSDarrick J. Wong if (error) 41465a1fb7aSDarrick J. Wong return error; 41565a1fb7aSDarrick J. Wong 41665a1fb7aSDarrick J. Wong return xfarray_append(rp->pptr_recs, &pptr); 41765a1fb7aSDarrick J. Wong } 41865a1fb7aSDarrick J. Wong 41965a1fb7aSDarrick J. Wong /* 420b334f7faSDarrick J. Wong * Examine an entry of a directory. If this dirent leads us back to the file 421b334f7faSDarrick J. Wong * whose parent pointers we're rebuilding, add a pptr to the temporary 422b334f7faSDarrick J. Wong * directory. 423b334f7faSDarrick J. Wong */ 424b334f7faSDarrick J. Wong STATIC int 425b334f7faSDarrick J. Wong xrep_parent_scan_dirent( 426b334f7faSDarrick J. Wong struct xfs_scrub *sc, 427b334f7faSDarrick J. Wong struct xfs_inode *dp, 428b334f7faSDarrick J. Wong xfs_dir2_dataptr_t dapos, 429b334f7faSDarrick J. Wong const struct xfs_name *name, 430b334f7faSDarrick J. Wong xfs_ino_t ino, 431b334f7faSDarrick J. Wong void *priv) 432b334f7faSDarrick J. Wong { 433b334f7faSDarrick J. Wong struct xrep_parent *rp = priv; 434b334f7faSDarrick J. Wong int error; 435b334f7faSDarrick J. Wong 436b334f7faSDarrick J. Wong /* Dirent doesn't point to this directory. */ 437b334f7faSDarrick J. Wong if (ino != rp->sc->ip->i_ino) 438b334f7faSDarrick J. Wong return 0; 439b334f7faSDarrick J. Wong 440b334f7faSDarrick J. Wong /* No weird looking names. */ 441b334f7faSDarrick J. Wong if (name->len == 0 || !xfs_dir2_namecheck(name->name, name->len)) 442b334f7faSDarrick J. Wong return -EFSCORRUPTED; 443b334f7faSDarrick J. Wong 444b334f7faSDarrick J. Wong /* No mismatching ftypes. */ 445b334f7faSDarrick J. Wong if (name->type != xfs_mode_to_ftype(VFS_I(sc->ip)->i_mode)) 446b334f7faSDarrick J. Wong return -EFSCORRUPTED; 447b334f7faSDarrick J. Wong 448b334f7faSDarrick J. Wong /* Don't pick up dot or dotdot entries; we only want child dirents. */ 449b334f7faSDarrick J. Wong if (xfs_dir2_samename(name, &xfs_name_dotdot) || 450b334f7faSDarrick J. Wong xfs_dir2_samename(name, &xfs_name_dot)) 451b334f7faSDarrick J. Wong return 0; 452b334f7faSDarrick J. Wong 453b334f7faSDarrick J. Wong /* 454b334f7faSDarrick J. Wong * Transform this dirent into a parent pointer and queue it for later 455b334f7faSDarrick J. Wong * addition to the temporary file. 456b334f7faSDarrick J. Wong */ 457b334f7faSDarrick J. Wong mutex_lock(&rp->pscan.lock); 458b334f7faSDarrick J. Wong error = xrep_parent_stash_parentadd(rp, name, dp); 459b334f7faSDarrick J. Wong mutex_unlock(&rp->pscan.lock); 460b334f7faSDarrick J. Wong return error; 461b334f7faSDarrick J. Wong } 462b334f7faSDarrick J. Wong 463b334f7faSDarrick J. Wong /* 464b334f7faSDarrick J. Wong * Decide if we want to look for dirents in this directory. Skip the file 465b334f7faSDarrick J. Wong * being repaired and any files being used to stage repairs. 466b334f7faSDarrick J. Wong */ 467b334f7faSDarrick J. Wong static inline bool 468b334f7faSDarrick J. Wong xrep_parent_want_scan( 469b334f7faSDarrick J. Wong struct xrep_parent *rp, 470b334f7faSDarrick J. Wong const struct xfs_inode *ip) 471b334f7faSDarrick J. Wong { 472b334f7faSDarrick J. Wong return ip != rp->sc->ip && !xrep_is_tempfile(ip); 473b334f7faSDarrick J. Wong } 474b334f7faSDarrick J. Wong 475b334f7faSDarrick J. Wong /* 476b334f7faSDarrick J. Wong * Take ILOCK on a file that we want to scan. 477b334f7faSDarrick J. Wong * 478b334f7faSDarrick J. Wong * Select ILOCK_EXCL if the file is a directory with an unloaded data bmbt. 479b334f7faSDarrick J. Wong * Otherwise, take ILOCK_SHARED. 480b334f7faSDarrick J. Wong */ 481b334f7faSDarrick J. Wong static inline unsigned int 482b334f7faSDarrick J. Wong xrep_parent_scan_ilock( 483b334f7faSDarrick J. Wong struct xrep_parent *rp, 484b334f7faSDarrick J. Wong struct xfs_inode *ip) 485b334f7faSDarrick J. Wong { 486b334f7faSDarrick J. Wong uint lock_mode = XFS_ILOCK_SHARED; 487b334f7faSDarrick J. Wong 488b334f7faSDarrick J. Wong /* Still need to take the shared ILOCK to advance the iscan cursor. */ 489b334f7faSDarrick J. Wong if (!xrep_parent_want_scan(rp, ip)) 490b334f7faSDarrick J. Wong goto lock; 491b334f7faSDarrick J. Wong 492b334f7faSDarrick J. Wong if (S_ISDIR(VFS_I(ip)->i_mode) && xfs_need_iread_extents(&ip->i_df)) { 493b334f7faSDarrick J. Wong lock_mode = XFS_ILOCK_EXCL; 494b334f7faSDarrick J. Wong goto lock; 495b334f7faSDarrick J. Wong } 496b334f7faSDarrick J. Wong 497b334f7faSDarrick J. Wong lock: 498b334f7faSDarrick J. Wong xfs_ilock(ip, lock_mode); 499b334f7faSDarrick J. Wong return lock_mode; 500b334f7faSDarrick J. Wong } 501b334f7faSDarrick J. Wong 502b334f7faSDarrick J. Wong /* 503b334f7faSDarrick J. Wong * Scan this file for relevant child dirents that point to the file whose 504b334f7faSDarrick J. Wong * parent pointers we're rebuilding. 505b334f7faSDarrick J. Wong */ 506b334f7faSDarrick J. Wong STATIC int 507b334f7faSDarrick J. Wong xrep_parent_scan_file( 508b334f7faSDarrick J. Wong struct xrep_parent *rp, 509b334f7faSDarrick J. Wong struct xfs_inode *ip) 510b334f7faSDarrick J. Wong { 511b334f7faSDarrick J. Wong unsigned int lock_mode; 512b334f7faSDarrick J. Wong int error = 0; 513b334f7faSDarrick J. Wong 514b334f7faSDarrick J. Wong lock_mode = xrep_parent_scan_ilock(rp, ip); 515b334f7faSDarrick J. Wong 516b334f7faSDarrick J. Wong if (!xrep_parent_want_scan(rp, ip)) 517b334f7faSDarrick J. Wong goto scan_done; 518b334f7faSDarrick J. Wong 519b334f7faSDarrick J. Wong if (S_ISDIR(VFS_I(ip)->i_mode)) { 520b334f7faSDarrick J. Wong /* 521b334f7faSDarrick J. Wong * If the directory looks as though it has been zapped by the 522b334f7faSDarrick J. Wong * inode record repair code, we cannot scan for child dirents. 523b334f7faSDarrick J. Wong */ 524b334f7faSDarrick J. Wong if (xchk_dir_looks_zapped(ip)) { 525b334f7faSDarrick J. Wong error = -EBUSY; 526b334f7faSDarrick J. Wong goto scan_done; 527b334f7faSDarrick J. Wong } 528b334f7faSDarrick J. Wong 529b334f7faSDarrick J. Wong error = xchk_dir_walk(rp->sc, ip, xrep_parent_scan_dirent, rp); 530b334f7faSDarrick J. Wong if (error) 531b334f7faSDarrick J. Wong goto scan_done; 532b334f7faSDarrick J. Wong } 533b334f7faSDarrick J. Wong 534b334f7faSDarrick J. Wong scan_done: 535b334f7faSDarrick J. Wong xchk_iscan_mark_visited(&rp->pscan.iscan, ip); 536b334f7faSDarrick J. Wong xfs_iunlock(ip, lock_mode); 537b334f7faSDarrick J. Wong return error; 538b334f7faSDarrick J. Wong } 539b334f7faSDarrick J. Wong 540b334f7faSDarrick J. Wong /* Decide if we've stashed too much pptr data in memory. */ 541b334f7faSDarrick J. Wong static inline bool 542b334f7faSDarrick J. Wong xrep_parent_want_flush_stashed( 543b334f7faSDarrick J. Wong struct xrep_parent *rp) 544b334f7faSDarrick J. Wong { 545b334f7faSDarrick J. Wong unsigned long long bytes; 546b334f7faSDarrick J. Wong 547b334f7faSDarrick J. Wong bytes = xfarray_bytes(rp->pptr_recs) + xfblob_bytes(rp->pptr_names); 548b334f7faSDarrick J. Wong return bytes > XREP_PARENT_MAX_STASH_BYTES; 549b334f7faSDarrick J. Wong } 550b334f7faSDarrick J. Wong 551b334f7faSDarrick J. Wong /* 552b334f7faSDarrick J. Wong * Scan all directories in the filesystem to look for dirents that we can turn 553b334f7faSDarrick J. Wong * into parent pointers. 554b334f7faSDarrick J. Wong */ 555b334f7faSDarrick J. Wong STATIC int 556b334f7faSDarrick J. Wong xrep_parent_scan_dirtree( 557b334f7faSDarrick J. Wong struct xrep_parent *rp) 558b334f7faSDarrick J. Wong { 559b334f7faSDarrick J. Wong struct xfs_scrub *sc = rp->sc; 560b334f7faSDarrick J. Wong struct xfs_inode *ip; 561b334f7faSDarrick J. Wong int error; 562b334f7faSDarrick J. Wong 563b334f7faSDarrick J. Wong /* 564b334f7faSDarrick J. Wong * Filesystem scans are time consuming. Drop the file ILOCK and all 565b334f7faSDarrick J. Wong * other resources for the duration of the scan and hope for the best. 566b334f7faSDarrick J. Wong * The live update hooks will keep our scan information up to date. 567b334f7faSDarrick J. Wong */ 568b334f7faSDarrick J. Wong xchk_trans_cancel(sc); 569b334f7faSDarrick J. Wong if (sc->ilock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) 570b334f7faSDarrick J. Wong xchk_iunlock(sc, sc->ilock_flags & (XFS_ILOCK_SHARED | 571b334f7faSDarrick J. Wong XFS_ILOCK_EXCL)); 572b334f7faSDarrick J. Wong error = xchk_trans_alloc_empty(sc); 573b334f7faSDarrick J. Wong if (error) 574b334f7faSDarrick J. Wong return error; 575b334f7faSDarrick J. Wong 576b334f7faSDarrick J. Wong while ((error = xchk_iscan_iter(&rp->pscan.iscan, &ip)) == 1) { 577b334f7faSDarrick J. Wong bool flush; 578b334f7faSDarrick J. Wong 579b334f7faSDarrick J. Wong error = xrep_parent_scan_file(rp, ip); 580b334f7faSDarrick J. Wong xchk_irele(sc, ip); 581b334f7faSDarrick J. Wong if (error) 582b334f7faSDarrick J. Wong break; 583b334f7faSDarrick J. Wong 584b334f7faSDarrick J. Wong /* Flush stashed pptr updates to constrain memory usage. */ 585b334f7faSDarrick J. Wong mutex_lock(&rp->pscan.lock); 586b334f7faSDarrick J. Wong flush = xrep_parent_want_flush_stashed(rp); 587b334f7faSDarrick J. Wong mutex_unlock(&rp->pscan.lock); 588b334f7faSDarrick J. Wong if (flush) { 589b334f7faSDarrick J. Wong xchk_trans_cancel(sc); 590b334f7faSDarrick J. Wong 591b334f7faSDarrick J. Wong error = xrep_tempfile_iolock_polled(sc); 592b334f7faSDarrick J. Wong if (error) 593b334f7faSDarrick J. Wong break; 594b334f7faSDarrick J. Wong 595b334f7faSDarrick J. Wong error = xrep_parent_replay_updates(rp); 596b334f7faSDarrick J. Wong xrep_tempfile_iounlock(sc); 597b334f7faSDarrick J. Wong if (error) 598b334f7faSDarrick J. Wong break; 599b334f7faSDarrick J. Wong 600b334f7faSDarrick J. Wong error = xchk_trans_alloc_empty(sc); 601b334f7faSDarrick J. Wong if (error) 602b334f7faSDarrick J. Wong break; 603b334f7faSDarrick J. Wong } 604b334f7faSDarrick J. Wong 605b334f7faSDarrick J. Wong if (xchk_should_terminate(sc, &error)) 606b334f7faSDarrick J. Wong break; 607b334f7faSDarrick J. Wong } 608b334f7faSDarrick J. Wong xchk_iscan_iter_finish(&rp->pscan.iscan); 609b334f7faSDarrick J. Wong if (error) { 610b334f7faSDarrick J. Wong /* 611b334f7faSDarrick J. Wong * If we couldn't grab an inode that was busy with a state 612b334f7faSDarrick J. Wong * change, change the error code so that we exit to userspace 613b334f7faSDarrick J. Wong * as quickly as possible. 614b334f7faSDarrick J. Wong */ 615b334f7faSDarrick J. Wong if (error == -EBUSY) 616b334f7faSDarrick J. Wong return -ECANCELED; 617b334f7faSDarrick J. Wong return error; 618b334f7faSDarrick J. Wong } 619b334f7faSDarrick J. Wong 620b334f7faSDarrick J. Wong /* 621a26dc213SDarrick J. Wong * Retake sc->ip's ILOCK now that we're done flushing stashed parent 622a26dc213SDarrick J. Wong * pointers. We end this function with an empty transaction and the 623a26dc213SDarrick J. Wong * ILOCK. 624b334f7faSDarrick J. Wong */ 625a26dc213SDarrick J. Wong xchk_ilock(rp->sc, XFS_ILOCK_EXCL); 626b334f7faSDarrick J. Wong return 0; 627b334f7faSDarrick J. Wong } 628b334f7faSDarrick J. Wong 62965a1fb7aSDarrick J. Wong /* 63065a1fb7aSDarrick J. Wong * Capture dirent updates being made by other threads which are relevant to the 63165a1fb7aSDarrick J. Wong * file being repaired. 63265a1fb7aSDarrick J. Wong */ 63365a1fb7aSDarrick J. Wong STATIC int 63465a1fb7aSDarrick J. Wong xrep_parent_live_update( 63565a1fb7aSDarrick J. Wong struct notifier_block *nb, 63665a1fb7aSDarrick J. Wong unsigned long action, 63765a1fb7aSDarrick J. Wong void *data) 63865a1fb7aSDarrick J. Wong { 63965a1fb7aSDarrick J. Wong struct xfs_dir_update_params *p = data; 64065a1fb7aSDarrick J. Wong struct xrep_parent *rp; 64165a1fb7aSDarrick J. Wong struct xfs_scrub *sc; 64265a1fb7aSDarrick J. Wong int error; 64365a1fb7aSDarrick J. Wong 64465a1fb7aSDarrick J. Wong rp = container_of(nb, struct xrep_parent, pscan.dhook.dirent_hook.nb); 64565a1fb7aSDarrick J. Wong sc = rp->sc; 64665a1fb7aSDarrick J. Wong 64765a1fb7aSDarrick J. Wong /* 64865a1fb7aSDarrick J. Wong * This thread updated a dirent that points to the file that we're 64965a1fb7aSDarrick J. Wong * repairing, so stash the update for replay against the temporary 65065a1fb7aSDarrick J. Wong * file. 65165a1fb7aSDarrick J. Wong */ 65265a1fb7aSDarrick J. Wong if (p->ip->i_ino == sc->ip->i_ino && 65365a1fb7aSDarrick J. Wong xchk_iscan_want_live_update(&rp->pscan.iscan, p->dp->i_ino)) { 65465a1fb7aSDarrick J. Wong mutex_lock(&rp->pscan.lock); 65565a1fb7aSDarrick J. Wong if (p->delta > 0) 65665a1fb7aSDarrick J. Wong error = xrep_parent_stash_parentadd(rp, p->name, p->dp); 65765a1fb7aSDarrick J. Wong else 65865a1fb7aSDarrick J. Wong error = xrep_parent_stash_parentremove(rp, p->name, 65965a1fb7aSDarrick J. Wong p->dp); 660a26dc213SDarrick J. Wong if (!error) 661a26dc213SDarrick J. Wong rp->saw_pptr_updates = true; 66265a1fb7aSDarrick J. Wong mutex_unlock(&rp->pscan.lock); 66365a1fb7aSDarrick J. Wong if (error) 66465a1fb7aSDarrick J. Wong goto out_abort; 66565a1fb7aSDarrick J. Wong } 66665a1fb7aSDarrick J. Wong 66765a1fb7aSDarrick J. Wong return NOTIFY_DONE; 66865a1fb7aSDarrick J. Wong out_abort: 66965a1fb7aSDarrick J. Wong xchk_iscan_abort(&rp->pscan.iscan); 67065a1fb7aSDarrick J. Wong return NOTIFY_DONE; 67165a1fb7aSDarrick J. Wong } 67265a1fb7aSDarrick J. Wong 673cc22edabSDarrick J. Wong /* Reset a directory's dotdot entry, if needed. */ 674cc22edabSDarrick J. Wong STATIC int 675cc22edabSDarrick J. Wong xrep_parent_reset_dotdot( 676cc22edabSDarrick J. Wong struct xrep_parent *rp) 677cc22edabSDarrick J. Wong { 678cc22edabSDarrick J. Wong struct xfs_scrub *sc = rp->sc; 679cc22edabSDarrick J. Wong xfs_ino_t ino; 680cc22edabSDarrick J. Wong unsigned int spaceres; 681cc22edabSDarrick J. Wong int error = 0; 682cc22edabSDarrick J. Wong 683cc22edabSDarrick J. Wong ASSERT(sc->ilock_flags & XFS_ILOCK_EXCL); 684cc22edabSDarrick J. Wong 685cc22edabSDarrick J. Wong error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot, &ino); 686cc22edabSDarrick J. Wong if (error || ino == rp->pscan.parent_ino) 687cc22edabSDarrick J. Wong return error; 688cc22edabSDarrick J. Wong 689cc22edabSDarrick J. Wong xfs_trans_ijoin(sc->tp, sc->ip, 0); 690cc22edabSDarrick J. Wong 691cc22edabSDarrick J. Wong trace_xrep_parent_reset_dotdot(sc->ip, rp->pscan.parent_ino); 692cc22edabSDarrick J. Wong 693cc22edabSDarrick J. Wong /* 694cc22edabSDarrick J. Wong * Reserve more space just in case we have to expand the dir. We're 695cc22edabSDarrick J. Wong * allowed to exceed quota to repair inconsistent metadata. 696cc22edabSDarrick J. Wong */ 6975a8338c8SAllison Henderson spaceres = xfs_rename_space_res(sc->mp, 0, false, xfs_name_dotdot.len, 6985a8338c8SAllison Henderson false); 699cc22edabSDarrick J. Wong error = xfs_trans_reserve_more_inode(sc->tp, sc->ip, spaceres, 0, 700cc22edabSDarrick J. Wong true); 701cc22edabSDarrick J. Wong if (error) 702cc22edabSDarrick J. Wong return error; 703cc22edabSDarrick J. Wong 704cc22edabSDarrick J. Wong error = xfs_dir_replace(sc->tp, sc->ip, &xfs_name_dotdot, 705cc22edabSDarrick J. Wong rp->pscan.parent_ino, spaceres); 706cc22edabSDarrick J. Wong if (error) 707cc22edabSDarrick J. Wong return error; 708cc22edabSDarrick J. Wong 709cc22edabSDarrick J. Wong /* 710cc22edabSDarrick J. Wong * Roll transaction to detach the inode from the transaction but retain 711cc22edabSDarrick J. Wong * ILOCK_EXCL. 712cc22edabSDarrick J. Wong */ 713cc22edabSDarrick J. Wong return xfs_trans_roll(&sc->tp); 714cc22edabSDarrick J. Wong } 715cc22edabSDarrick J. Wong 716a26dc213SDarrick J. Wong /* Pass back the parent inumber if this a parent pointer */ 717a26dc213SDarrick J. Wong STATIC int 718a26dc213SDarrick J. Wong xrep_parent_lookup_pptr( 719a26dc213SDarrick J. Wong struct xfs_scrub *sc, 720a26dc213SDarrick J. Wong struct xfs_inode *ip, 721a26dc213SDarrick J. Wong unsigned int attr_flags, 722a26dc213SDarrick J. Wong const unsigned char *name, 723a26dc213SDarrick J. Wong unsigned int namelen, 724a26dc213SDarrick J. Wong const void *value, 725a26dc213SDarrick J. Wong unsigned int valuelen, 726a26dc213SDarrick J. Wong void *priv) 727a26dc213SDarrick J. Wong { 728a26dc213SDarrick J. Wong xfs_ino_t *inop = priv; 729a26dc213SDarrick J. Wong xfs_ino_t parent_ino; 730a26dc213SDarrick J. Wong int error; 731a26dc213SDarrick J. Wong 732a26dc213SDarrick J. Wong if (!(attr_flags & XFS_ATTR_PARENT)) 733a26dc213SDarrick J. Wong return 0; 734a26dc213SDarrick J. Wong 735a26dc213SDarrick J. Wong error = xfs_parent_from_attr(sc->mp, attr_flags, name, namelen, value, 736a26dc213SDarrick J. Wong valuelen, &parent_ino, NULL); 737a26dc213SDarrick J. Wong if (error) 738a26dc213SDarrick J. Wong return error; 739a26dc213SDarrick J. Wong 740a26dc213SDarrick J. Wong *inop = parent_ino; 741a26dc213SDarrick J. Wong return -ECANCELED; 742a26dc213SDarrick J. Wong } 743a26dc213SDarrick J. Wong 744a26dc213SDarrick J. Wong /* 745a26dc213SDarrick J. Wong * Find the first parent of the scrub target by walking parent pointers for 746a26dc213SDarrick J. Wong * the purpose of deciding if we're going to move it to the orphanage. 747a26dc213SDarrick J. Wong * We don't care if the attr fork is zapped. 748a26dc213SDarrick J. Wong */ 749a26dc213SDarrick J. Wong STATIC int 750a26dc213SDarrick J. Wong xrep_parent_lookup_pptrs( 751a26dc213SDarrick J. Wong struct xfs_scrub *sc, 752a26dc213SDarrick J. Wong xfs_ino_t *inop) 753a26dc213SDarrick J. Wong { 754a26dc213SDarrick J. Wong int error; 755a26dc213SDarrick J. Wong 756a26dc213SDarrick J. Wong *inop = NULLFSINO; 757a26dc213SDarrick J. Wong 758a26dc213SDarrick J. Wong error = xchk_xattr_walk(sc, sc->ip, xrep_parent_lookup_pptr, NULL, 759a26dc213SDarrick J. Wong inop); 760a26dc213SDarrick J. Wong if (error && error != -ECANCELED) 761a26dc213SDarrick J. Wong return error; 762a26dc213SDarrick J. Wong return 0; 763a26dc213SDarrick J. Wong } 764a26dc213SDarrick J. Wong 765cc22edabSDarrick J. Wong /* 7661e58a8ccSDarrick J. Wong * Move the current file to the orphanage. 7671e58a8ccSDarrick J. Wong * 7681e58a8ccSDarrick J. Wong * Caller must hold IOLOCK_EXCL on @sc->ip, and no other inode locks. Upon 7691e58a8ccSDarrick J. Wong * successful return, the scrub transaction will have enough extra reservation 7701e58a8ccSDarrick J. Wong * to make the move; it will hold IOLOCK_EXCL and ILOCK_EXCL of @sc->ip and the 7711e58a8ccSDarrick J. Wong * orphanage; and both inodes will be ijoined. 7721e58a8ccSDarrick J. Wong */ 7731e58a8ccSDarrick J. Wong STATIC int 7741e58a8ccSDarrick J. Wong xrep_parent_move_to_orphanage( 7751e58a8ccSDarrick J. Wong struct xrep_parent *rp) 7761e58a8ccSDarrick J. Wong { 7771e58a8ccSDarrick J. Wong struct xfs_scrub *sc = rp->sc; 7781e58a8ccSDarrick J. Wong xfs_ino_t orig_parent, new_parent; 7791e58a8ccSDarrick J. Wong int error; 7801e58a8ccSDarrick J. Wong 781a26dc213SDarrick J. Wong if (S_ISDIR(VFS_I(sc->ip)->i_mode)) { 7821e58a8ccSDarrick J. Wong /* 783a26dc213SDarrick J. Wong * We are about to drop the ILOCK on sc->ip to lock the 784a26dc213SDarrick J. Wong * orphanage and prepare for the adoption. Therefore, look up 785a26dc213SDarrick J. Wong * the old dotdot entry for sc->ip so that we can compare it 786a26dc213SDarrick J. Wong * after we re-lock sc->ip. 7871e58a8ccSDarrick J. Wong */ 788a26dc213SDarrick J. Wong error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot, 789a26dc213SDarrick J. Wong &orig_parent); 7901e58a8ccSDarrick J. Wong if (error) 7911e58a8ccSDarrick J. Wong return error; 792a26dc213SDarrick J. Wong } else { 793a26dc213SDarrick J. Wong /* 794a26dc213SDarrick J. Wong * We haven't dropped the ILOCK since we committed the new 795a26dc213SDarrick J. Wong * xattr structure (and hence the new parent pointer records), 796a26dc213SDarrick J. Wong * which means that the file cannot have been moved in the 797a26dc213SDarrick J. Wong * directory tree, and there are no parents. 798a26dc213SDarrick J. Wong */ 799a26dc213SDarrick J. Wong orig_parent = NULLFSINO; 800a26dc213SDarrick J. Wong } 8011e58a8ccSDarrick J. Wong 8021e58a8ccSDarrick J. Wong /* 8031e58a8ccSDarrick J. Wong * Drop the ILOCK on the scrub target and commit the transaction. 8041e58a8ccSDarrick J. Wong * Adoption computes its own resource requirements and gathers the 8051e58a8ccSDarrick J. Wong * necessary components. 8061e58a8ccSDarrick J. Wong */ 8071e58a8ccSDarrick J. Wong error = xrep_trans_commit(sc); 8081e58a8ccSDarrick J. Wong if (error) 8091e58a8ccSDarrick J. Wong return error; 8101e58a8ccSDarrick J. Wong xchk_iunlock(sc, XFS_ILOCK_EXCL); 8111e58a8ccSDarrick J. Wong 8121e58a8ccSDarrick J. Wong /* If we can take the orphanage's iolock then we're ready to move. */ 8131e58a8ccSDarrick J. Wong if (!xrep_orphanage_ilock_nowait(sc, XFS_IOLOCK_EXCL)) { 8141e58a8ccSDarrick J. Wong xchk_iunlock(sc, sc->ilock_flags); 8151e58a8ccSDarrick J. Wong error = xrep_orphanage_iolock_two(sc); 8161e58a8ccSDarrick J. Wong if (error) 8171e58a8ccSDarrick J. Wong return error; 8181e58a8ccSDarrick J. Wong } 8191e58a8ccSDarrick J. Wong 8201e58a8ccSDarrick J. Wong /* Grab transaction and ILOCK the two files. */ 8211e58a8ccSDarrick J. Wong error = xrep_adoption_trans_alloc(sc, &rp->adoption); 8221e58a8ccSDarrick J. Wong if (error) 8231e58a8ccSDarrick J. Wong return error; 8241e58a8ccSDarrick J. Wong 8251e58a8ccSDarrick J. Wong error = xrep_adoption_compute_name(&rp->adoption, &rp->xname); 8261e58a8ccSDarrick J. Wong if (error) 8271e58a8ccSDarrick J. Wong return error; 8281e58a8ccSDarrick J. Wong 8291e58a8ccSDarrick J. Wong /* 8301e58a8ccSDarrick J. Wong * Now that we've reacquired the ILOCK on sc->ip, look up the dotdot 8311e58a8ccSDarrick J. Wong * entry again. If the parent changed or the child was unlinked while 8321e58a8ccSDarrick J. Wong * the child directory was unlocked, we don't need to move the child to 833a26dc213SDarrick J. Wong * the orphanage after all. For a non-directory, we have to scan for 834a26dc213SDarrick J. Wong * the first parent pointer to see if one has been added. 8351e58a8ccSDarrick J. Wong */ 836a26dc213SDarrick J. Wong if (S_ISDIR(VFS_I(sc->ip)->i_mode)) 837a26dc213SDarrick J. Wong error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot, 838a26dc213SDarrick J. Wong &new_parent); 839a26dc213SDarrick J. Wong else 840a26dc213SDarrick J. Wong error = xrep_parent_lookup_pptrs(sc, &new_parent); 8411e58a8ccSDarrick J. Wong if (error) 8421e58a8ccSDarrick J. Wong return error; 8431e58a8ccSDarrick J. Wong 8441e58a8ccSDarrick J. Wong /* 8451e58a8ccSDarrick J. Wong * Attach to the orphanage if we still have a linked directory and it 8461e58a8ccSDarrick J. Wong * hasn't been moved. 8471e58a8ccSDarrick J. Wong */ 8481e58a8ccSDarrick J. Wong if (orig_parent == new_parent && VFS_I(sc->ip)->i_nlink > 0) { 8491e58a8ccSDarrick J. Wong error = xrep_adoption_move(&rp->adoption); 8501e58a8ccSDarrick J. Wong if (error) 8511e58a8ccSDarrick J. Wong return error; 8521e58a8ccSDarrick J. Wong } 8531e58a8ccSDarrick J. Wong 8541e58a8ccSDarrick J. Wong /* 8551e58a8ccSDarrick J. Wong * Launder the scrub transaction so we can drop the orphanage ILOCK 8561e58a8ccSDarrick J. Wong * and IOLOCK. Return holding the scrub target's ILOCK and IOLOCK. 8571e58a8ccSDarrick J. Wong */ 8581e58a8ccSDarrick J. Wong error = xrep_adoption_trans_roll(&rp->adoption); 8591e58a8ccSDarrick J. Wong if (error) 8601e58a8ccSDarrick J. Wong return error; 8611e58a8ccSDarrick J. Wong 8621e58a8ccSDarrick J. Wong xrep_orphanage_iunlock(sc, XFS_ILOCK_EXCL); 8631e58a8ccSDarrick J. Wong xrep_orphanage_iunlock(sc, XFS_IOLOCK_EXCL); 8641e58a8ccSDarrick J. Wong return 0; 8651e58a8ccSDarrick J. Wong } 8661e58a8ccSDarrick J. Wong 867a26dc213SDarrick J. Wong /* Ensure that the xattr value buffer is large enough. */ 868a26dc213SDarrick J. Wong STATIC int 869a26dc213SDarrick J. Wong xrep_parent_alloc_xattr_value( 870a26dc213SDarrick J. Wong struct xrep_parent *rp, 871a26dc213SDarrick J. Wong size_t bufsize) 872a26dc213SDarrick J. Wong { 873a26dc213SDarrick J. Wong void *new_val; 874a26dc213SDarrick J. Wong 875a26dc213SDarrick J. Wong if (rp->xattr_value_sz >= bufsize) 876a26dc213SDarrick J. Wong return 0; 877a26dc213SDarrick J. Wong 878a26dc213SDarrick J. Wong if (rp->xattr_value) { 879a26dc213SDarrick J. Wong kvfree(rp->xattr_value); 880a26dc213SDarrick J. Wong rp->xattr_value = NULL; 881a26dc213SDarrick J. Wong rp->xattr_value_sz = 0; 882a26dc213SDarrick J. Wong } 883a26dc213SDarrick J. Wong 884a26dc213SDarrick J. Wong new_val = kvmalloc(bufsize, XCHK_GFP_FLAGS); 885a26dc213SDarrick J. Wong if (!new_val) 886a26dc213SDarrick J. Wong return -ENOMEM; 887a26dc213SDarrick J. Wong 888a26dc213SDarrick J. Wong rp->xattr_value = new_val; 889a26dc213SDarrick J. Wong rp->xattr_value_sz = bufsize; 890a26dc213SDarrick J. Wong return 0; 891a26dc213SDarrick J. Wong } 892a26dc213SDarrick J. Wong 893a26dc213SDarrick J. Wong /* Retrieve the (remote) value of a non-pptr xattr. */ 894a26dc213SDarrick J. Wong STATIC int 895a26dc213SDarrick J. Wong xrep_parent_fetch_xattr_remote( 896a26dc213SDarrick J. Wong struct xrep_parent *rp, 897a26dc213SDarrick J. Wong struct xfs_inode *ip, 898a26dc213SDarrick J. Wong unsigned int attr_flags, 899a26dc213SDarrick J. Wong const unsigned char *name, 900a26dc213SDarrick J. Wong unsigned int namelen, 901a26dc213SDarrick J. Wong unsigned int valuelen) 902a26dc213SDarrick J. Wong { 903a26dc213SDarrick J. Wong struct xfs_scrub *sc = rp->sc; 904a26dc213SDarrick J. Wong struct xfs_da_args args = { 905a26dc213SDarrick J. Wong .attr_filter = attr_flags & XFS_ATTR_NSP_ONDISK_MASK, 906a26dc213SDarrick J. Wong .geo = sc->mp->m_attr_geo, 907a26dc213SDarrick J. Wong .whichfork = XFS_ATTR_FORK, 908a26dc213SDarrick J. Wong .dp = ip, 909a26dc213SDarrick J. Wong .name = name, 910a26dc213SDarrick J. Wong .namelen = namelen, 911a26dc213SDarrick J. Wong .trans = sc->tp, 912a26dc213SDarrick J. Wong .valuelen = valuelen, 913a26dc213SDarrick J. Wong .owner = ip->i_ino, 914a26dc213SDarrick J. Wong }; 915a26dc213SDarrick J. Wong int error; 916a26dc213SDarrick J. Wong 917a26dc213SDarrick J. Wong /* 918a26dc213SDarrick J. Wong * If we need a larger value buffer, try to allocate one. If that 919a26dc213SDarrick J. Wong * fails, return with -EDEADLOCK to try harder. 920a26dc213SDarrick J. Wong */ 921a26dc213SDarrick J. Wong error = xrep_parent_alloc_xattr_value(rp, valuelen); 922a26dc213SDarrick J. Wong if (error == -ENOMEM) 923a26dc213SDarrick J. Wong return -EDEADLOCK; 924a26dc213SDarrick J. Wong if (error) 925a26dc213SDarrick J. Wong return error; 926a26dc213SDarrick J. Wong 927a26dc213SDarrick J. Wong args.value = rp->xattr_value; 928a26dc213SDarrick J. Wong xfs_attr_sethash(&args); 929a26dc213SDarrick J. Wong return xfs_attr_get_ilocked(&args); 930a26dc213SDarrick J. Wong } 931a26dc213SDarrick J. Wong 932a26dc213SDarrick J. Wong /* Stash non-pptr attributes for later replay into the temporary file. */ 933a26dc213SDarrick J. Wong STATIC int 934a26dc213SDarrick J. Wong xrep_parent_stash_xattr( 935a26dc213SDarrick J. Wong struct xfs_scrub *sc, 936a26dc213SDarrick J. Wong struct xfs_inode *ip, 937a26dc213SDarrick J. Wong unsigned int attr_flags, 938a26dc213SDarrick J. Wong const unsigned char *name, 939a26dc213SDarrick J. Wong unsigned int namelen, 940a26dc213SDarrick J. Wong const void *value, 941a26dc213SDarrick J. Wong unsigned int valuelen, 942a26dc213SDarrick J. Wong void *priv) 943a26dc213SDarrick J. Wong { 944a26dc213SDarrick J. Wong struct xrep_parent_xattr key = { 945a26dc213SDarrick J. Wong .valuelen = valuelen, 946a26dc213SDarrick J. Wong .namelen = namelen, 947a26dc213SDarrick J. Wong .flags = attr_flags & XFS_ATTR_NSP_ONDISK_MASK, 948a26dc213SDarrick J. Wong }; 949a26dc213SDarrick J. Wong struct xrep_parent *rp = priv; 950a26dc213SDarrick J. Wong int error; 951a26dc213SDarrick J. Wong 952a26dc213SDarrick J. Wong if (attr_flags & (XFS_ATTR_INCOMPLETE | XFS_ATTR_PARENT)) 953a26dc213SDarrick J. Wong return 0; 954a26dc213SDarrick J. Wong 955a26dc213SDarrick J. Wong if (!value) { 956a26dc213SDarrick J. Wong error = xrep_parent_fetch_xattr_remote(rp, ip, attr_flags, 957a26dc213SDarrick J. Wong name, namelen, valuelen); 958a26dc213SDarrick J. Wong if (error) 959a26dc213SDarrick J. Wong return error; 960a26dc213SDarrick J. Wong 961a26dc213SDarrick J. Wong value = rp->xattr_value; 962a26dc213SDarrick J. Wong } 963a26dc213SDarrick J. Wong 964a26dc213SDarrick J. Wong trace_xrep_parent_stash_xattr(rp->sc->tempip, key.flags, (void *)name, 965a26dc213SDarrick J. Wong key.namelen, key.valuelen); 966a26dc213SDarrick J. Wong 967a26dc213SDarrick J. Wong error = xfblob_store(rp->xattr_blobs, &key.name_cookie, name, 968a26dc213SDarrick J. Wong key.namelen); 969a26dc213SDarrick J. Wong if (error) 970a26dc213SDarrick J. Wong return error; 971a26dc213SDarrick J. Wong 972a26dc213SDarrick J. Wong error = xfblob_store(rp->xattr_blobs, &key.value_cookie, value, 973a26dc213SDarrick J. Wong key.valuelen); 974a26dc213SDarrick J. Wong if (error) 975a26dc213SDarrick J. Wong return error; 976a26dc213SDarrick J. Wong 977a26dc213SDarrick J. Wong return xfarray_append(rp->xattr_records, &key); 978a26dc213SDarrick J. Wong } 979a26dc213SDarrick J. Wong 980a26dc213SDarrick J. Wong /* Insert one xattr key/value. */ 981a26dc213SDarrick J. Wong STATIC int 982a26dc213SDarrick J. Wong xrep_parent_insert_xattr( 983a26dc213SDarrick J. Wong struct xrep_parent *rp, 984a26dc213SDarrick J. Wong const struct xrep_parent_xattr *key) 985a26dc213SDarrick J. Wong { 986a26dc213SDarrick J. Wong struct xfs_da_args args = { 987a26dc213SDarrick J. Wong .dp = rp->sc->tempip, 988a26dc213SDarrick J. Wong .attr_filter = key->flags, 989a26dc213SDarrick J. Wong .namelen = key->namelen, 990a26dc213SDarrick J. Wong .valuelen = key->valuelen, 991a26dc213SDarrick J. Wong .owner = rp->sc->ip->i_ino, 992a26dc213SDarrick J. Wong .geo = rp->sc->mp->m_attr_geo, 993a26dc213SDarrick J. Wong .whichfork = XFS_ATTR_FORK, 994a26dc213SDarrick J. Wong .op_flags = XFS_DA_OP_OKNOENT, 995a26dc213SDarrick J. Wong }; 996a26dc213SDarrick J. Wong int error; 997a26dc213SDarrick J. Wong 998a26dc213SDarrick J. Wong ASSERT(!(key->flags & XFS_ATTR_PARENT)); 999a26dc213SDarrick J. Wong 1000a26dc213SDarrick J. Wong /* 1001a26dc213SDarrick J. Wong * Grab pointers to the scrub buffer so that we can use them to insert 1002a26dc213SDarrick J. Wong * attrs into the temp file. 1003a26dc213SDarrick J. Wong */ 1004a26dc213SDarrick J. Wong args.name = rp->xattr_name; 1005a26dc213SDarrick J. Wong args.value = rp->xattr_value; 1006a26dc213SDarrick J. Wong 1007a26dc213SDarrick J. Wong /* 1008a26dc213SDarrick J. Wong * The attribute name is stored near the end of the in-core buffer, 1009a26dc213SDarrick J. Wong * though we reserve one more byte to ensure null termination. 1010a26dc213SDarrick J. Wong */ 1011a26dc213SDarrick J. Wong rp->xattr_name[XATTR_NAME_MAX] = 0; 1012a26dc213SDarrick J. Wong 1013a26dc213SDarrick J. Wong error = xfblob_load(rp->xattr_blobs, key->name_cookie, rp->xattr_name, 1014a26dc213SDarrick J. Wong key->namelen); 1015a26dc213SDarrick J. Wong if (error) 1016a26dc213SDarrick J. Wong return error; 1017a26dc213SDarrick J. Wong 1018a26dc213SDarrick J. Wong error = xfblob_free(rp->xattr_blobs, key->name_cookie); 1019a26dc213SDarrick J. Wong if (error) 1020a26dc213SDarrick J. Wong return error; 1021a26dc213SDarrick J. Wong 1022a26dc213SDarrick J. Wong error = xfblob_load(rp->xattr_blobs, key->value_cookie, args.value, 1023a26dc213SDarrick J. Wong key->valuelen); 1024a26dc213SDarrick J. Wong if (error) 1025a26dc213SDarrick J. Wong return error; 1026a26dc213SDarrick J. Wong 1027a26dc213SDarrick J. Wong error = xfblob_free(rp->xattr_blobs, key->value_cookie); 1028a26dc213SDarrick J. Wong if (error) 1029a26dc213SDarrick J. Wong return error; 1030a26dc213SDarrick J. Wong 1031a26dc213SDarrick J. Wong rp->xattr_name[key->namelen] = 0; 1032a26dc213SDarrick J. Wong 1033a26dc213SDarrick J. Wong trace_xrep_parent_insert_xattr(rp->sc->tempip, key->flags, 1034a26dc213SDarrick J. Wong rp->xattr_name, key->namelen, key->valuelen); 1035a26dc213SDarrick J. Wong 1036a26dc213SDarrick J. Wong xfs_attr_sethash(&args); 1037a26dc213SDarrick J. Wong return xfs_attr_set(&args, XFS_ATTRUPDATE_UPSERT, false); 1038a26dc213SDarrick J. Wong } 1039a26dc213SDarrick J. Wong 1040a26dc213SDarrick J. Wong /* 1041a26dc213SDarrick J. Wong * Periodically flush salvaged attributes to the temporary file. This is done 1042a26dc213SDarrick J. Wong * to reduce the memory requirements of the xattr rebuild because files can 1043a26dc213SDarrick J. Wong * contain millions of attributes. 1044a26dc213SDarrick J. Wong */ 1045a26dc213SDarrick J. Wong STATIC int 1046a26dc213SDarrick J. Wong xrep_parent_flush_xattrs( 1047a26dc213SDarrick J. Wong struct xrep_parent *rp) 1048a26dc213SDarrick J. Wong { 1049a26dc213SDarrick J. Wong xfarray_idx_t array_cur; 1050a26dc213SDarrick J. Wong int error; 1051a26dc213SDarrick J. Wong 1052a26dc213SDarrick J. Wong /* 1053a26dc213SDarrick J. Wong * Entering this function, the scrub context has a reference to the 1054a26dc213SDarrick J. Wong * inode being repaired, the temporary file, and the empty scrub 1055a26dc213SDarrick J. Wong * transaction that we created for the xattr scan. We hold ILOCK_EXCL 1056a26dc213SDarrick J. Wong * on the inode being repaired. 1057a26dc213SDarrick J. Wong * 1058a26dc213SDarrick J. Wong * To constrain kernel memory use, we occasionally flush salvaged 1059a26dc213SDarrick J. Wong * xattrs from the xfarray and xfblob structures into the temporary 1060a26dc213SDarrick J. Wong * file in preparation for exchanging the xattr structures at the end. 1061a26dc213SDarrick J. Wong * Updating the temporary file requires a transaction, so we commit the 1062a26dc213SDarrick J. Wong * scrub transaction and drop the ILOCK so that xfs_attr_set can 1063a26dc213SDarrick J. Wong * allocate whatever transaction it wants. 1064a26dc213SDarrick J. Wong * 1065a26dc213SDarrick J. Wong * We still hold IOLOCK_EXCL on the inode being repaired, which 1066a26dc213SDarrick J. Wong * prevents anyone from adding xattrs (or parent pointers) while we're 1067a26dc213SDarrick J. Wong * flushing. 1068a26dc213SDarrick J. Wong */ 1069a26dc213SDarrick J. Wong xchk_trans_cancel(rp->sc); 1070a26dc213SDarrick J. Wong xchk_iunlock(rp->sc, XFS_ILOCK_EXCL); 1071a26dc213SDarrick J. Wong 1072a26dc213SDarrick J. Wong /* 1073a26dc213SDarrick J. Wong * Take the IOLOCK of the temporary file while we modify xattrs. This 1074a26dc213SDarrick J. Wong * isn't strictly required because the temporary file is never revealed 1075a26dc213SDarrick J. Wong * to userspace, but we follow the same locking rules. We still hold 1076a26dc213SDarrick J. Wong * sc->ip's IOLOCK. 1077a26dc213SDarrick J. Wong */ 1078a26dc213SDarrick J. Wong error = xrep_tempfile_iolock_polled(rp->sc); 1079a26dc213SDarrick J. Wong if (error) 1080a26dc213SDarrick J. Wong return error; 1081a26dc213SDarrick J. Wong 1082a26dc213SDarrick J. Wong /* Add all the salvaged attrs to the temporary file. */ 1083a26dc213SDarrick J. Wong foreach_xfarray_idx(rp->xattr_records, array_cur) { 1084a26dc213SDarrick J. Wong struct xrep_parent_xattr key; 1085a26dc213SDarrick J. Wong 1086a26dc213SDarrick J. Wong error = xfarray_load(rp->xattr_records, array_cur, &key); 1087a26dc213SDarrick J. Wong if (error) 1088a26dc213SDarrick J. Wong return error; 1089a26dc213SDarrick J. Wong 1090a26dc213SDarrick J. Wong error = xrep_parent_insert_xattr(rp, &key); 1091a26dc213SDarrick J. Wong if (error) 1092a26dc213SDarrick J. Wong return error; 1093a26dc213SDarrick J. Wong } 1094a26dc213SDarrick J. Wong 1095a26dc213SDarrick J. Wong /* Empty out both arrays now that we've added the entries. */ 1096a26dc213SDarrick J. Wong xfarray_truncate(rp->xattr_records); 1097a26dc213SDarrick J. Wong xfblob_truncate(rp->xattr_blobs); 1098a26dc213SDarrick J. Wong 1099a26dc213SDarrick J. Wong xrep_tempfile_iounlock(rp->sc); 1100a26dc213SDarrick J. Wong 1101a26dc213SDarrick J. Wong /* Recreate the empty transaction and relock the inode. */ 1102a26dc213SDarrick J. Wong error = xchk_trans_alloc_empty(rp->sc); 1103a26dc213SDarrick J. Wong if (error) 1104a26dc213SDarrick J. Wong return error; 1105a26dc213SDarrick J. Wong xchk_ilock(rp->sc, XFS_ILOCK_EXCL); 1106a26dc213SDarrick J. Wong return 0; 1107a26dc213SDarrick J. Wong } 1108a26dc213SDarrick J. Wong 1109a26dc213SDarrick J. Wong /* Decide if we've stashed too much xattr data in memory. */ 1110a26dc213SDarrick J. Wong static inline bool 1111a26dc213SDarrick J. Wong xrep_parent_want_flush_xattrs( 1112a26dc213SDarrick J. Wong struct xrep_parent *rp) 1113a26dc213SDarrick J. Wong { 1114a26dc213SDarrick J. Wong unsigned long long bytes; 1115a26dc213SDarrick J. Wong 1116a26dc213SDarrick J. Wong bytes = xfarray_bytes(rp->xattr_records) + 1117a26dc213SDarrick J. Wong xfblob_bytes(rp->xattr_blobs); 1118a26dc213SDarrick J. Wong return bytes > XREP_PARENT_XATTR_MAX_STASH_BYTES; 1119a26dc213SDarrick J. Wong } 1120a26dc213SDarrick J. Wong 1121a26dc213SDarrick J. Wong /* Flush staged attributes to the temporary file if we're over the limit. */ 1122a26dc213SDarrick J. Wong STATIC int 1123a26dc213SDarrick J. Wong xrep_parent_try_flush_xattrs( 1124a26dc213SDarrick J. Wong struct xfs_scrub *sc, 1125a26dc213SDarrick J. Wong void *priv) 1126a26dc213SDarrick J. Wong { 1127a26dc213SDarrick J. Wong struct xrep_parent *rp = priv; 1128a26dc213SDarrick J. Wong int error; 1129a26dc213SDarrick J. Wong 1130a26dc213SDarrick J. Wong if (!xrep_parent_want_flush_xattrs(rp)) 1131a26dc213SDarrick J. Wong return 0; 1132a26dc213SDarrick J. Wong 1133a26dc213SDarrick J. Wong error = xrep_parent_flush_xattrs(rp); 1134a26dc213SDarrick J. Wong if (error) 1135a26dc213SDarrick J. Wong return error; 1136a26dc213SDarrick J. Wong 1137a26dc213SDarrick J. Wong /* 1138a26dc213SDarrick J. Wong * If there were any parent pointer updates to the xattr structure 1139a26dc213SDarrick J. Wong * while we dropped the ILOCK, the xattr structure is now stale. 1140a26dc213SDarrick J. Wong * Signal to the attr copy process that we need to start over, but 1141a26dc213SDarrick J. Wong * this time without opportunistic attr flushing. 1142a26dc213SDarrick J. Wong * 1143a26dc213SDarrick J. Wong * This is unlikely to happen, so we're ok with restarting the copy. 1144a26dc213SDarrick J. Wong */ 1145a26dc213SDarrick J. Wong mutex_lock(&rp->pscan.lock); 1146a26dc213SDarrick J. Wong if (rp->saw_pptr_updates) 1147a26dc213SDarrick J. Wong error = -ESTALE; 1148a26dc213SDarrick J. Wong mutex_unlock(&rp->pscan.lock); 1149a26dc213SDarrick J. Wong return error; 1150a26dc213SDarrick J. Wong } 1151a26dc213SDarrick J. Wong 1152a26dc213SDarrick J. Wong /* Copy all the non-pptr extended attributes into the temporary file. */ 1153a26dc213SDarrick J. Wong STATIC int 1154a26dc213SDarrick J. Wong xrep_parent_copy_xattrs( 1155a26dc213SDarrick J. Wong struct xrep_parent *rp) 1156a26dc213SDarrick J. Wong { 1157a26dc213SDarrick J. Wong struct xfs_scrub *sc = rp->sc; 1158a26dc213SDarrick J. Wong int error; 1159a26dc213SDarrick J. Wong 1160a26dc213SDarrick J. Wong /* 1161a26dc213SDarrick J. Wong * Clear the pptr updates flag. We hold sc->ip ILOCKed, so there 1162a26dc213SDarrick J. Wong * can't be any parent pointer updates in progress. 1163a26dc213SDarrick J. Wong */ 1164a26dc213SDarrick J. Wong mutex_lock(&rp->pscan.lock); 1165a26dc213SDarrick J. Wong rp->saw_pptr_updates = false; 1166a26dc213SDarrick J. Wong mutex_unlock(&rp->pscan.lock); 1167a26dc213SDarrick J. Wong 1168a26dc213SDarrick J. Wong /* Copy xattrs, stopping periodically to flush the incore buffers. */ 1169a26dc213SDarrick J. Wong error = xchk_xattr_walk(sc, sc->ip, xrep_parent_stash_xattr, 1170a26dc213SDarrick J. Wong xrep_parent_try_flush_xattrs, rp); 1171a26dc213SDarrick J. Wong if (error && error != -ESTALE) 1172a26dc213SDarrick J. Wong return error; 1173a26dc213SDarrick J. Wong 1174a26dc213SDarrick J. Wong if (error == -ESTALE) { 1175a26dc213SDarrick J. Wong /* 1176a26dc213SDarrick J. Wong * The xattr copy collided with a parent pointer update. 1177a26dc213SDarrick J. Wong * Restart the copy, but this time hold the ILOCK all the way 1178a26dc213SDarrick J. Wong * to the end to lock out any directory parent pointer updates. 1179a26dc213SDarrick J. Wong */ 1180a26dc213SDarrick J. Wong error = xchk_xattr_walk(sc, sc->ip, xrep_parent_stash_xattr, 1181a26dc213SDarrick J. Wong NULL, rp); 1182a26dc213SDarrick J. Wong if (error) 1183a26dc213SDarrick J. Wong return error; 1184a26dc213SDarrick J. Wong } 1185a26dc213SDarrick J. Wong 1186a26dc213SDarrick J. Wong /* Flush any remaining stashed xattrs to the temporary file. */ 1187a26dc213SDarrick J. Wong if (xfarray_bytes(rp->xattr_records) == 0) 1188a26dc213SDarrick J. Wong return 0; 1189a26dc213SDarrick J. Wong 1190a26dc213SDarrick J. Wong return xrep_parent_flush_xattrs(rp); 1191a26dc213SDarrick J. Wong } 1192a26dc213SDarrick J. Wong 1193a26dc213SDarrick J. Wong /* 1194a26dc213SDarrick J. Wong * Ensure that @sc->ip and @sc->tempip both have attribute forks before we head 1195a26dc213SDarrick J. Wong * into the attr fork exchange transaction. All files on a filesystem with 1196a26dc213SDarrick J. Wong * parent pointers must have an attr fork because the parent pointer code does 1197a26dc213SDarrick J. Wong * not itself add attribute forks. 1198a26dc213SDarrick J. Wong * 1199a26dc213SDarrick J. Wong * Note: Unlinkable unlinked files don't need one, but the overhead of having 1200a26dc213SDarrick J. Wong * an unnecessary attr fork is not justified by the additional code complexity 1201a26dc213SDarrick J. Wong * that would be needed to track that state correctly. 1202a26dc213SDarrick J. Wong */ 1203a26dc213SDarrick J. Wong STATIC int 1204a26dc213SDarrick J. Wong xrep_parent_ensure_attr_fork( 1205a26dc213SDarrick J. Wong struct xrep_parent *rp) 1206a26dc213SDarrick J. Wong { 1207a26dc213SDarrick J. Wong struct xfs_scrub *sc = rp->sc; 1208a26dc213SDarrick J. Wong int error; 1209a26dc213SDarrick J. Wong 1210a26dc213SDarrick J. Wong error = xfs_attr_add_fork(sc->tempip, 1211a26dc213SDarrick J. Wong sizeof(struct xfs_attr_sf_hdr), 1); 1212a26dc213SDarrick J. Wong if (error) 1213a26dc213SDarrick J. Wong return error; 1214a26dc213SDarrick J. Wong return xfs_attr_add_fork(sc->ip, sizeof(struct xfs_attr_sf_hdr), 1); 1215a26dc213SDarrick J. Wong } 1216a26dc213SDarrick J. Wong 1217a26dc213SDarrick J. Wong /* 1218a26dc213SDarrick J. Wong * Finish replaying stashed parent pointer updates, allocate a transaction for 1219a26dc213SDarrick J. Wong * exchanging extent mappings, and take the ILOCKs of both files before we 1220a26dc213SDarrick J. Wong * commit the new attribute structure. 1221a26dc213SDarrick J. Wong */ 1222a26dc213SDarrick J. Wong STATIC int 1223a26dc213SDarrick J. Wong xrep_parent_finalize_tempfile( 1224a26dc213SDarrick J. Wong struct xrep_parent *rp) 1225a26dc213SDarrick J. Wong { 1226a26dc213SDarrick J. Wong struct xfs_scrub *sc = rp->sc; 1227a26dc213SDarrick J. Wong int error; 1228a26dc213SDarrick J. Wong 1229a26dc213SDarrick J. Wong /* 1230a26dc213SDarrick J. Wong * Repair relies on the ILOCK to quiesce all possible xattr updates. 1231a26dc213SDarrick J. Wong * Replay all queued parent pointer updates into the tempfile before 1232a26dc213SDarrick J. Wong * exchanging the contents, even if that means dropping the ILOCKs and 1233a26dc213SDarrick J. Wong * the transaction. 1234a26dc213SDarrick J. Wong */ 1235a26dc213SDarrick J. Wong do { 1236a26dc213SDarrick J. Wong error = xrep_parent_replay_updates(rp); 1237a26dc213SDarrick J. Wong if (error) 1238a26dc213SDarrick J. Wong return error; 1239a26dc213SDarrick J. Wong 1240a26dc213SDarrick J. Wong error = xrep_parent_ensure_attr_fork(rp); 1241a26dc213SDarrick J. Wong if (error) 1242a26dc213SDarrick J. Wong return error; 1243a26dc213SDarrick J. Wong 1244a26dc213SDarrick J. Wong error = xrep_tempexch_trans_alloc(sc, XFS_ATTR_FORK, &rp->tx); 1245a26dc213SDarrick J. Wong if (error) 1246a26dc213SDarrick J. Wong return error; 1247a26dc213SDarrick J. Wong 1248a26dc213SDarrick J. Wong if (xfarray_length(rp->pptr_recs) == 0) 1249a26dc213SDarrick J. Wong break; 1250a26dc213SDarrick J. Wong 1251a26dc213SDarrick J. Wong xchk_trans_cancel(sc); 1252a26dc213SDarrick J. Wong xrep_tempfile_iunlock_both(sc); 1253a26dc213SDarrick J. Wong } while (!xchk_should_terminate(sc, &error)); 1254a26dc213SDarrick J. Wong return error; 1255a26dc213SDarrick J. Wong } 1256a26dc213SDarrick J. Wong 1257a26dc213SDarrick J. Wong /* 1258a26dc213SDarrick J. Wong * Replay all the stashed parent pointers into the temporary file, copy all 1259a26dc213SDarrick J. Wong * the non-pptr xattrs from the file being repaired into the temporary file, 1260a26dc213SDarrick J. Wong * and exchange the attr fork contents atomically. 1261a26dc213SDarrick J. Wong */ 1262a26dc213SDarrick J. Wong STATIC int 1263a26dc213SDarrick J. Wong xrep_parent_rebuild_pptrs( 1264a26dc213SDarrick J. Wong struct xrep_parent *rp) 1265a26dc213SDarrick J. Wong { 1266a26dc213SDarrick J. Wong struct xfs_scrub *sc = rp->sc; 1267a26dc213SDarrick J. Wong xfs_ino_t parent_ino = NULLFSINO; 1268a26dc213SDarrick J. Wong int error; 1269a26dc213SDarrick J. Wong 1270a26dc213SDarrick J. Wong /* 1271a26dc213SDarrick J. Wong * Copy non-ppttr xattrs from the file being repaired into the 1272a26dc213SDarrick J. Wong * temporary file's xattr structure. We hold sc->ip's IOLOCK, which 1273a26dc213SDarrick J. Wong * prevents setxattr/removexattr calls from occurring, but renames 1274a26dc213SDarrick J. Wong * update the parent pointers without holding IOLOCK. If we detect 1275a26dc213SDarrick J. Wong * stale attr structures, we restart the scan but only flush at the 1276a26dc213SDarrick J. Wong * end. 1277a26dc213SDarrick J. Wong */ 1278a26dc213SDarrick J. Wong error = xrep_parent_copy_xattrs(rp); 1279a26dc213SDarrick J. Wong if (error) 1280a26dc213SDarrick J. Wong return error; 1281a26dc213SDarrick J. Wong 1282a26dc213SDarrick J. Wong /* 1283a26dc213SDarrick J. Wong * Cancel the empty transaction that we used to walk and copy attrs, 1284a26dc213SDarrick J. Wong * and drop the ILOCK so that we can take the IOLOCK on the temporary 1285a26dc213SDarrick J. Wong * file. We still hold sc->ip's IOLOCK. 1286a26dc213SDarrick J. Wong */ 1287a26dc213SDarrick J. Wong xchk_trans_cancel(sc); 1288a26dc213SDarrick J. Wong xchk_iunlock(sc, XFS_ILOCK_EXCL); 1289a26dc213SDarrick J. Wong 1290a26dc213SDarrick J. Wong error = xrep_tempfile_iolock_polled(sc); 1291a26dc213SDarrick J. Wong if (error) 1292a26dc213SDarrick J. Wong return error; 1293a26dc213SDarrick J. Wong 1294a26dc213SDarrick J. Wong /* 1295a26dc213SDarrick J. Wong * Allocate transaction, lock inodes, and make sure that we've replayed 1296a26dc213SDarrick J. Wong * all the stashed pptr updates to the tempdir. After this point, 1297a26dc213SDarrick J. Wong * we're ready to exchange the attr fork mappings. 1298a26dc213SDarrick J. Wong */ 1299a26dc213SDarrick J. Wong error = xrep_parent_finalize_tempfile(rp); 1300a26dc213SDarrick J. Wong if (error) 1301a26dc213SDarrick J. Wong return error; 1302a26dc213SDarrick J. Wong 1303a26dc213SDarrick J. Wong /* Last chance to abort before we start committing pptr fixes. */ 1304a26dc213SDarrick J. Wong if (xchk_should_terminate(sc, &error)) 1305a26dc213SDarrick J. Wong return error; 1306a26dc213SDarrick J. Wong 1307a26dc213SDarrick J. Wong if (xchk_iscan_aborted(&rp->pscan.iscan)) 1308a26dc213SDarrick J. Wong return -ECANCELED; 1309a26dc213SDarrick J. Wong 1310a26dc213SDarrick J. Wong /* 1311a26dc213SDarrick J. Wong * Exchange the attr fork contents and junk the old attr fork contents, 1312a26dc213SDarrick J. Wong * which are now in the tempfile. 1313a26dc213SDarrick J. Wong */ 1314a26dc213SDarrick J. Wong error = xrep_xattr_swap(sc, &rp->tx); 1315a26dc213SDarrick J. Wong if (error) 1316a26dc213SDarrick J. Wong return error; 1317a26dc213SDarrick J. Wong error = xrep_xattr_reset_tempfile_fork(sc); 1318a26dc213SDarrick J. Wong if (error) 1319a26dc213SDarrick J. Wong return error; 1320a26dc213SDarrick J. Wong 1321a26dc213SDarrick J. Wong /* 1322a26dc213SDarrick J. Wong * Roll to get a transaction without any inodes joined to it. Then we 1323a26dc213SDarrick J. Wong * can drop the tempfile's ILOCK and IOLOCK before doing more work on 1324a26dc213SDarrick J. Wong * the scrub target file. 1325a26dc213SDarrick J. Wong */ 1326a26dc213SDarrick J. Wong error = xfs_trans_roll(&sc->tp); 1327a26dc213SDarrick J. Wong if (error) 1328a26dc213SDarrick J. Wong return error; 1329a26dc213SDarrick J. Wong xrep_tempfile_iunlock(sc); 1330a26dc213SDarrick J. Wong xrep_tempfile_iounlock(sc); 1331a26dc213SDarrick J. Wong 1332a26dc213SDarrick J. Wong /* 1333a26dc213SDarrick J. Wong * We've committed the new parent pointers. Find at least one parent 1334a26dc213SDarrick J. Wong * so that we can decide if we're moving this file to the orphanage. 1335a26dc213SDarrick J. Wong * For this purpose, root directories are their own parents. 1336a26dc213SDarrick J. Wong */ 1337679b098bSDarrick J. Wong if (xchk_inode_is_dirtree_root(sc->ip)) { 1338a26dc213SDarrick J. Wong xrep_findparent_scan_found(&rp->pscan, sc->ip->i_ino); 1339a26dc213SDarrick J. Wong } else { 1340a26dc213SDarrick J. Wong error = xrep_parent_lookup_pptrs(sc, &parent_ino); 1341a26dc213SDarrick J. Wong if (error) 1342a26dc213SDarrick J. Wong return error; 1343a26dc213SDarrick J. Wong if (parent_ino != NULLFSINO) 1344a26dc213SDarrick J. Wong xrep_findparent_scan_found(&rp->pscan, parent_ino); 1345a26dc213SDarrick J. Wong } 1346a26dc213SDarrick J. Wong return 0; 1347a26dc213SDarrick J. Wong } 1348a26dc213SDarrick J. Wong 13491e58a8ccSDarrick J. Wong /* 1350cc22edabSDarrick J. Wong * Commit the new parent pointer structure (currently only the dotdot entry) to 1351cc22edabSDarrick J. Wong * the file that we're repairing. 1352cc22edabSDarrick J. Wong */ 1353cc22edabSDarrick J. Wong STATIC int 1354cc22edabSDarrick J. Wong xrep_parent_rebuild_tree( 1355cc22edabSDarrick J. Wong struct xrep_parent *rp) 1356cc22edabSDarrick J. Wong { 1357*aec2eb7dSDarrick J. Wong struct xfs_scrub *sc = rp->sc; 1358*aec2eb7dSDarrick J. Wong bool try_adoption; 1359a26dc213SDarrick J. Wong int error; 1360a26dc213SDarrick J. Wong 1361*aec2eb7dSDarrick J. Wong if (xfs_has_parent(sc->mp)) { 1362a26dc213SDarrick J. Wong error = xrep_parent_rebuild_pptrs(rp); 1363a26dc213SDarrick J. Wong if (error) 1364a26dc213SDarrick J. Wong return error; 1365a26dc213SDarrick J. Wong } 1366a26dc213SDarrick J. Wong 1367*aec2eb7dSDarrick J. Wong /* 1368*aec2eb7dSDarrick J. Wong * Any file with no parent could be adopted. This check happens after 1369*aec2eb7dSDarrick J. Wong * rebuilding the parent pointer structure because we might have cycled 1370*aec2eb7dSDarrick J. Wong * the ILOCK during that process. 1371*aec2eb7dSDarrick J. Wong */ 1372*aec2eb7dSDarrick J. Wong try_adoption = rp->pscan.parent_ino == NULLFSINO; 1373*aec2eb7dSDarrick J. Wong 1374*aec2eb7dSDarrick J. Wong /* 1375*aec2eb7dSDarrick J. Wong * Starting with metadir, we allow checking of parent pointers 1376*aec2eb7dSDarrick J. Wong * of non-directory files that are children of the superblock. 1377*aec2eb7dSDarrick J. Wong * Lack of parent is ok here. 1378*aec2eb7dSDarrick J. Wong */ 1379*aec2eb7dSDarrick J. Wong if (try_adoption && xfs_has_metadir(sc->mp) && 1380*aec2eb7dSDarrick J. Wong xchk_inode_is_sb_rooted(sc->ip)) 1381*aec2eb7dSDarrick J. Wong try_adoption = false; 1382*aec2eb7dSDarrick J. Wong 1383*aec2eb7dSDarrick J. Wong if (try_adoption) { 1384*aec2eb7dSDarrick J. Wong if (xrep_orphanage_can_adopt(sc)) 13851e58a8ccSDarrick J. Wong return xrep_parent_move_to_orphanage(rp); 1386cc22edabSDarrick J. Wong return -EFSCORRUPTED; 1387*aec2eb7dSDarrick J. Wong 1388cc22edabSDarrick J. Wong } 1389cc22edabSDarrick J. Wong 1390*aec2eb7dSDarrick J. Wong if (S_ISDIR(VFS_I(sc->ip)->i_mode)) 1391cc22edabSDarrick J. Wong return xrep_parent_reset_dotdot(rp); 1392a26dc213SDarrick J. Wong 1393a26dc213SDarrick J. Wong return 0; 1394cc22edabSDarrick J. Wong } 1395cc22edabSDarrick J. Wong 13963f50ddbfSDarrick J. Wong /* Count the number of parent pointers. */ 13973f50ddbfSDarrick J. Wong STATIC int 13983f50ddbfSDarrick J. Wong xrep_parent_count_pptr( 13993f50ddbfSDarrick J. Wong struct xfs_scrub *sc, 14003f50ddbfSDarrick J. Wong struct xfs_inode *ip, 14013f50ddbfSDarrick J. Wong unsigned int attr_flags, 14023f50ddbfSDarrick J. Wong const unsigned char *name, 14033f50ddbfSDarrick J. Wong unsigned int namelen, 14043f50ddbfSDarrick J. Wong const void *value, 14053f50ddbfSDarrick J. Wong unsigned int valuelen, 14063f50ddbfSDarrick J. Wong void *priv) 14073f50ddbfSDarrick J. Wong { 14083f50ddbfSDarrick J. Wong struct xrep_parent *rp = priv; 14093f50ddbfSDarrick J. Wong int error; 14103f50ddbfSDarrick J. Wong 14113f50ddbfSDarrick J. Wong if (!(attr_flags & XFS_ATTR_PARENT)) 14123f50ddbfSDarrick J. Wong return 0; 14133f50ddbfSDarrick J. Wong 14143f50ddbfSDarrick J. Wong error = xfs_parent_from_attr(sc->mp, attr_flags, name, namelen, value, 14153f50ddbfSDarrick J. Wong valuelen, NULL, NULL); 14163f50ddbfSDarrick J. Wong if (error) 14173f50ddbfSDarrick J. Wong return error; 14183f50ddbfSDarrick J. Wong 14193f50ddbfSDarrick J. Wong rp->parents++; 14203f50ddbfSDarrick J. Wong return 0; 14213f50ddbfSDarrick J. Wong } 14223f50ddbfSDarrick J. Wong 14233f50ddbfSDarrick J. Wong /* 14243f50ddbfSDarrick J. Wong * After all parent pointer rebuilding and adoption activity completes, reset 14253f50ddbfSDarrick J. Wong * the link count of this nondirectory, having scanned the fs to rebuild all 14263f50ddbfSDarrick J. Wong * parent pointers. 14273f50ddbfSDarrick J. Wong */ 14283f50ddbfSDarrick J. Wong STATIC int 14293f50ddbfSDarrick J. Wong xrep_parent_set_nondir_nlink( 14303f50ddbfSDarrick J. Wong struct xrep_parent *rp) 14313f50ddbfSDarrick J. Wong { 14323f50ddbfSDarrick J. Wong struct xfs_scrub *sc = rp->sc; 14333f50ddbfSDarrick J. Wong struct xfs_inode *ip = sc->ip; 14343f50ddbfSDarrick J. Wong struct xfs_perag *pag; 14353f50ddbfSDarrick J. Wong bool joined = false; 14363f50ddbfSDarrick J. Wong int error; 14373f50ddbfSDarrick J. Wong 14383f50ddbfSDarrick J. Wong /* Count parent pointers so we can reset the file link count. */ 14393f50ddbfSDarrick J. Wong rp->parents = 0; 14403f50ddbfSDarrick J. Wong error = xchk_xattr_walk(sc, ip, xrep_parent_count_pptr, NULL, rp); 14413f50ddbfSDarrick J. Wong if (error) 14423f50ddbfSDarrick J. Wong return error; 14433f50ddbfSDarrick J. Wong 1444*aec2eb7dSDarrick J. Wong /* 1445*aec2eb7dSDarrick J. Wong * Starting with metadir, we allow checking of parent pointers of 1446*aec2eb7dSDarrick J. Wong * non-directory files that are children of the superblock. Pretend 1447*aec2eb7dSDarrick J. Wong * that we found a parent pointer attr. 1448*aec2eb7dSDarrick J. Wong */ 1449*aec2eb7dSDarrick J. Wong if (xfs_has_metadir(sc->mp) && xchk_inode_is_sb_rooted(sc->ip)) 1450*aec2eb7dSDarrick J. Wong rp->parents++; 1451*aec2eb7dSDarrick J. Wong 14523f50ddbfSDarrick J. Wong if (rp->parents > 0 && xfs_inode_on_unlinked_list(ip)) { 14533f50ddbfSDarrick J. Wong xfs_trans_ijoin(sc->tp, sc->ip, 0); 14543f50ddbfSDarrick J. Wong joined = true; 14553f50ddbfSDarrick J. Wong 14563f50ddbfSDarrick J. Wong /* 14573f50ddbfSDarrick J. Wong * The file is on the unlinked list but we found parents. 14583f50ddbfSDarrick J. Wong * Remove the file from the unlinked list. 14593f50ddbfSDarrick J. Wong */ 14603f50ddbfSDarrick J. Wong pag = xfs_perag_get(sc->mp, XFS_INO_TO_AGNO(sc->mp, ip->i_ino)); 14613f50ddbfSDarrick J. Wong if (!pag) { 14623f50ddbfSDarrick J. Wong ASSERT(0); 14633f50ddbfSDarrick J. Wong return -EFSCORRUPTED; 14643f50ddbfSDarrick J. Wong } 14653f50ddbfSDarrick J. Wong 14663f50ddbfSDarrick J. Wong error = xfs_iunlink_remove(sc->tp, pag, ip); 14673f50ddbfSDarrick J. Wong xfs_perag_put(pag); 14683f50ddbfSDarrick J. Wong if (error) 14693f50ddbfSDarrick J. Wong return error; 14703f50ddbfSDarrick J. Wong } else if (rp->parents == 0 && !xfs_inode_on_unlinked_list(ip)) { 14713f50ddbfSDarrick J. Wong xfs_trans_ijoin(sc->tp, sc->ip, 0); 14723f50ddbfSDarrick J. Wong joined = true; 14733f50ddbfSDarrick J. Wong 14743f50ddbfSDarrick J. Wong /* 14753f50ddbfSDarrick J. Wong * The file is not on the unlinked list but we found no 14763f50ddbfSDarrick J. Wong * parents. Add the file to the unlinked list. 14773f50ddbfSDarrick J. Wong */ 14783f50ddbfSDarrick J. Wong error = xfs_iunlink(sc->tp, ip); 14793f50ddbfSDarrick J. Wong if (error) 14803f50ddbfSDarrick J. Wong return error; 14813f50ddbfSDarrick J. Wong } 14823f50ddbfSDarrick J. Wong 14833f50ddbfSDarrick J. Wong /* Set the correct link count. */ 14843f50ddbfSDarrick J. Wong if (VFS_I(ip)->i_nlink != rp->parents) { 14853f50ddbfSDarrick J. Wong if (!joined) { 14863f50ddbfSDarrick J. Wong xfs_trans_ijoin(sc->tp, sc->ip, 0); 14873f50ddbfSDarrick J. Wong joined = true; 14883f50ddbfSDarrick J. Wong } 14893f50ddbfSDarrick J. Wong 14903f50ddbfSDarrick J. Wong set_nlink(VFS_I(ip), min_t(unsigned long long, rp->parents, 14913f50ddbfSDarrick J. Wong XFS_NLINK_PINNED)); 14923f50ddbfSDarrick J. Wong } 14933f50ddbfSDarrick J. Wong 14943f50ddbfSDarrick J. Wong /* Log the inode to keep it moving forward if we dirtied anything. */ 14953f50ddbfSDarrick J. Wong if (joined) 14963f50ddbfSDarrick J. Wong xfs_trans_log_inode(sc->tp, ip, XFS_ILOG_CORE); 14973f50ddbfSDarrick J. Wong return 0; 14983f50ddbfSDarrick J. Wong } 14993f50ddbfSDarrick J. Wong 1500cc22edabSDarrick J. Wong /* Set up the filesystem scan so we can look for parents. */ 1501cc22edabSDarrick J. Wong STATIC int 1502cc22edabSDarrick J. Wong xrep_parent_setup_scan( 1503cc22edabSDarrick J. Wong struct xrep_parent *rp) 1504cc22edabSDarrick J. Wong { 1505cc22edabSDarrick J. Wong struct xfs_scrub *sc = rp->sc; 1506b334f7faSDarrick J. Wong char *descr; 1507a26dc213SDarrick J. Wong struct xfs_da_geometry *geo = sc->mp->m_attr_geo; 1508a26dc213SDarrick J. Wong int max_len; 1509b334f7faSDarrick J. Wong int error; 1510cc22edabSDarrick J. Wong 1511b334f7faSDarrick J. Wong if (!xfs_has_parent(sc->mp)) 1512cc22edabSDarrick J. Wong return xrep_findparent_scan_start(sc, &rp->pscan); 1513b334f7faSDarrick J. Wong 1514a26dc213SDarrick J. Wong /* Buffers for copying non-pptr attrs to the tempfile */ 1515a26dc213SDarrick J. Wong rp->xattr_name = kvmalloc(XATTR_NAME_MAX + 1, XCHK_GFP_FLAGS); 1516a26dc213SDarrick J. Wong if (!rp->xattr_name) 1517a26dc213SDarrick J. Wong return -ENOMEM; 1518a26dc213SDarrick J. Wong 1519a26dc213SDarrick J. Wong /* 1520a26dc213SDarrick J. Wong * Allocate enough memory to handle loading local attr values from the 1521a26dc213SDarrick J. Wong * xfblob data while flushing stashed attrs to the temporary file. 1522a26dc213SDarrick J. Wong * We only realloc the buffer when salvaging remote attr values, so 1523a26dc213SDarrick J. Wong * TRY_HARDER means we allocate the maximal attr value size. 1524a26dc213SDarrick J. Wong */ 1525a26dc213SDarrick J. Wong if (sc->flags & XCHK_TRY_HARDER) 1526a26dc213SDarrick J. Wong max_len = XATTR_SIZE_MAX; 1527a26dc213SDarrick J. Wong else 1528a26dc213SDarrick J. Wong max_len = xfs_attr_leaf_entsize_local_max(geo->blksize); 1529a26dc213SDarrick J. Wong error = xrep_parent_alloc_xattr_value(rp, max_len); 1530a26dc213SDarrick J. Wong if (error) 1531a26dc213SDarrick J. Wong goto out_xattr_name; 1532a26dc213SDarrick J. Wong 1533b334f7faSDarrick J. Wong /* Set up some staging memory for logging parent pointer updates. */ 1534b334f7faSDarrick J. Wong descr = xchk_xfile_ino_descr(sc, "parent pointer entries"); 1535b334f7faSDarrick J. Wong error = xfarray_create(descr, 0, sizeof(struct xrep_pptr), 1536b334f7faSDarrick J. Wong &rp->pptr_recs); 1537b334f7faSDarrick J. Wong kfree(descr); 1538b334f7faSDarrick J. Wong if (error) 1539a26dc213SDarrick J. Wong goto out_xattr_value; 1540b334f7faSDarrick J. Wong 1541b334f7faSDarrick J. Wong descr = xchk_xfile_ino_descr(sc, "parent pointer names"); 1542b334f7faSDarrick J. Wong error = xfblob_create(descr, &rp->pptr_names); 1543b334f7faSDarrick J. Wong kfree(descr); 1544b334f7faSDarrick J. Wong if (error) 1545b334f7faSDarrick J. Wong goto out_recs; 1546b334f7faSDarrick J. Wong 1547a26dc213SDarrick J. Wong /* Set up some storage for copying attrs before the mapping exchange */ 1548a26dc213SDarrick J. Wong descr = xchk_xfile_ino_descr(sc, 1549a26dc213SDarrick J. Wong "parent pointer retained xattr entries"); 1550a26dc213SDarrick J. Wong error = xfarray_create(descr, 0, sizeof(struct xrep_parent_xattr), 1551a26dc213SDarrick J. Wong &rp->xattr_records); 1552a26dc213SDarrick J. Wong kfree(descr); 1553b334f7faSDarrick J. Wong if (error) 1554b334f7faSDarrick J. Wong goto out_names; 1555b334f7faSDarrick J. Wong 1556a26dc213SDarrick J. Wong descr = xchk_xfile_ino_descr(sc, 1557a26dc213SDarrick J. Wong "parent pointer retained xattr values"); 1558a26dc213SDarrick J. Wong error = xfblob_create(descr, &rp->xattr_blobs); 1559a26dc213SDarrick J. Wong kfree(descr); 1560a26dc213SDarrick J. Wong if (error) 1561a26dc213SDarrick J. Wong goto out_attr_keys; 1562a26dc213SDarrick J. Wong 1563a26dc213SDarrick J. Wong error = __xrep_findparent_scan_start(sc, &rp->pscan, 1564a26dc213SDarrick J. Wong xrep_parent_live_update); 1565a26dc213SDarrick J. Wong if (error) 1566a26dc213SDarrick J. Wong goto out_attr_values; 1567a26dc213SDarrick J. Wong 1568b334f7faSDarrick J. Wong return 0; 1569b334f7faSDarrick J. Wong 1570a26dc213SDarrick J. Wong out_attr_values: 1571a26dc213SDarrick J. Wong xfblob_destroy(rp->xattr_blobs); 1572a26dc213SDarrick J. Wong rp->xattr_blobs = NULL; 1573a26dc213SDarrick J. Wong out_attr_keys: 1574a26dc213SDarrick J. Wong xfarray_destroy(rp->xattr_records); 1575a26dc213SDarrick J. Wong rp->xattr_records = NULL; 1576b334f7faSDarrick J. Wong out_names: 1577b334f7faSDarrick J. Wong xfblob_destroy(rp->pptr_names); 1578b334f7faSDarrick J. Wong rp->pptr_names = NULL; 1579b334f7faSDarrick J. Wong out_recs: 1580b334f7faSDarrick J. Wong xfarray_destroy(rp->pptr_recs); 1581b334f7faSDarrick J. Wong rp->pptr_recs = NULL; 1582a26dc213SDarrick J. Wong out_xattr_value: 1583a26dc213SDarrick J. Wong kvfree(rp->xattr_value); 1584a26dc213SDarrick J. Wong rp->xattr_value = NULL; 1585a26dc213SDarrick J. Wong out_xattr_name: 1586a26dc213SDarrick J. Wong kvfree(rp->xattr_name); 1587a26dc213SDarrick J. Wong rp->xattr_name = NULL; 1588b334f7faSDarrick J. Wong return error; 1589cc22edabSDarrick J. Wong } 1590cc22edabSDarrick J. Wong 1591cc22edabSDarrick J. Wong int 1592cc22edabSDarrick J. Wong xrep_parent( 1593cc22edabSDarrick J. Wong struct xfs_scrub *sc) 1594cc22edabSDarrick J. Wong { 1595cc22edabSDarrick J. Wong struct xrep_parent *rp = sc->buf; 1596cc22edabSDarrick J. Wong int error; 1597cc22edabSDarrick J. Wong 1598b334f7faSDarrick J. Wong /* 1599b334f7faSDarrick J. Wong * When the parent pointers feature is enabled, repairs are committed 1600b334f7faSDarrick J. Wong * by atomically committing a new xattr structure and reaping the old 16016d335233SDarrick J. Wong * attr fork. Reaping requires rmap and exchange-range to be enabled. 1602b334f7faSDarrick J. Wong */ 16036d335233SDarrick J. Wong if (xfs_has_parent(sc->mp)) { 16046d335233SDarrick J. Wong if (!xfs_has_rmapbt(sc->mp)) 1605b334f7faSDarrick J. Wong return -EOPNOTSUPP; 16066d335233SDarrick J. Wong if (!xfs_has_exchange_range(sc->mp)) 16076d335233SDarrick J. Wong return -EOPNOTSUPP; 16086d335233SDarrick J. Wong } 1609b334f7faSDarrick J. Wong 1610cc22edabSDarrick J. Wong error = xrep_parent_setup_scan(rp); 1611cc22edabSDarrick J. Wong if (error) 1612cc22edabSDarrick J. Wong return error; 1613cc22edabSDarrick J. Wong 1614b334f7faSDarrick J. Wong if (xfs_has_parent(sc->mp)) 1615b334f7faSDarrick J. Wong error = xrep_parent_scan_dirtree(rp); 1616b334f7faSDarrick J. Wong else 1617cc22edabSDarrick J. Wong error = xrep_parent_find_dotdot(rp); 1618cc22edabSDarrick J. Wong if (error) 1619cc22edabSDarrick J. Wong goto out_teardown; 1620cc22edabSDarrick J. Wong 1621a26dc213SDarrick J. Wong /* Last chance to abort before we start committing dotdot fixes. */ 1622cc22edabSDarrick J. Wong if (xchk_should_terminate(sc, &error)) 1623cc22edabSDarrick J. Wong goto out_teardown; 1624cc22edabSDarrick J. Wong 1625cc22edabSDarrick J. Wong error = xrep_parent_rebuild_tree(rp); 1626cc22edabSDarrick J. Wong if (error) 1627cc22edabSDarrick J. Wong goto out_teardown; 16283f50ddbfSDarrick J. Wong if (xfs_has_parent(sc->mp) && !S_ISDIR(VFS_I(sc->ip)->i_mode)) { 16293f50ddbfSDarrick J. Wong error = xrep_parent_set_nondir_nlink(rp); 16303f50ddbfSDarrick J. Wong if (error) 16313f50ddbfSDarrick J. Wong goto out_teardown; 16323f50ddbfSDarrick J. Wong } 16333f50ddbfSDarrick J. Wong 16343f50ddbfSDarrick J. Wong error = xrep_defer_finish(sc); 1635cc22edabSDarrick J. Wong 1636cc22edabSDarrick J. Wong out_teardown: 1637cc22edabSDarrick J. Wong xrep_parent_teardown(rp); 1638cc22edabSDarrick J. Wong return error; 1639cc22edabSDarrick J. Wong } 1640