diff options
Diffstat (limited to 'fs/xfs/scrub/dir_repair.c')
-rw-r--r-- | fs/xfs/scrub/dir_repair.c | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/fs/xfs/scrub/dir_repair.c b/fs/xfs/scrub/dir_repair.c index 00922089a5e5..8f069636ae1a 100644 --- a/fs/xfs/scrub/dir_repair.c +++ b/fs/xfs/scrub/dir_repair.c @@ -1090,6 +1090,7 @@ xrep_dir( .parent_ino = NULLFSINO, .new_nlink = 2, }; + bool move_orphanage = false; int error; /* Set up some storage */ @@ -1147,17 +1148,36 @@ xrep_dir( /* * Validate the parent pointer that we observed while salvaging the * directory or scan the filesystem to find one. If the scan fails - * to find a single parent, we'll set the parent to the root dir and - * let the parent pointer repair fix it. + * to find a single parent, we'll move the directory to the orphanage. */ error = xrep_findparent(rd.sc, &rd.parent_ino); if (error) return error; - if (rd.parent_ino == NULLFSINO) + if (rd.parent_ino == NULLFSINO) { rd.parent_ino = rd.sc->mp->m_sb.sb_rootino; + move_orphanage = true; + } /* Now rebuild the directory information. */ - return xrep_dir_rebuild_tree(&rd); + error = xrep_dir_rebuild_tree(&rd); + if (error || !move_orphanage) + return error; + + /* + * Before we can move the directory to the orphanage, we must roll to a + * clean unjoined transaction and drop the ILOCKs on the dir and the + * temp dir. We still hold IOLOCK_EXCL on the dir, so nobody will be + * able to access it in the mean time. + */ + error = xfs_trans_roll(&sc->tp); + if (error) + return error; + xfs_iunlock(sc->tempip, XFS_ILOCK_EXCL); + sc->temp_ilock_flags &= ~XFS_ILOCK_EXCL; + xfs_iunlock(sc->ip, XFS_ILOCK_EXCL); + sc->ilock_flags &= ~XFS_ILOCK_EXCL; + + return xrep_move_to_orphanage(sc); out_names: xblob_destroy(rd.dir_names); |