summaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2024-04-15 23:54:49 +0200
committerDarrick J. Wong <djwong@kernel.org>2024-04-15 23:58:55 +0200
commit669dfe883c8e20231495f80a28ec7cc0b8fdddc4 (patch)
tree7d020f35c8b000987052d0dfd4f8d6e7d8086bb7 /fs/xfs
parentxfs: ensure unlinked list state is consistent with nlink during scrub (diff)
downloadlinux-669dfe883c8e20231495f80a28ec7cc0b8fdddc4.tar.xz
linux-669dfe883c8e20231495f80a28ec7cc0b8fdddc4.zip
xfs: update the unlinked list when repairing link counts
When we're repairing the link counts of a file, we must ensure either that the file has zero link count and is on the unlinked list; or that it has nonzero link count and is not on the unlinked list. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/scrub/nlinks_repair.c42
1 files changed, 33 insertions, 9 deletions
diff --git a/fs/xfs/scrub/nlinks_repair.c b/fs/xfs/scrub/nlinks_repair.c
index b87618322f55..58cacb8e94c1 100644
--- a/fs/xfs/scrub/nlinks_repair.c
+++ b/fs/xfs/scrub/nlinks_repair.c
@@ -17,6 +17,7 @@
#include "xfs_iwalk.h"
#include "xfs_ialloc.h"
#include "xfs_sb.h"
+#include "xfs_ag.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/repair.h"
@@ -36,6 +37,20 @@
* inode is locked.
*/
+/* Remove an inode from the unlinked list. */
+STATIC int
+xrep_nlinks_iunlink_remove(
+ struct xfs_scrub *sc)
+{
+ struct xfs_perag *pag;
+ int error;
+
+ pag = xfs_perag_get(sc->mp, XFS_INO_TO_AGNO(sc->mp, sc->ip->i_ino));
+ error = xfs_iunlink_remove(sc->tp, pag, sc->ip);
+ xfs_perag_put(pag);
+ return error;
+}
+
/*
* Correct the link count of the given inode. Because we have to grab locks
* and resources in a certain order, it's possible that this will be a no-op.
@@ -99,16 +114,25 @@ xrep_nlinks_repair_inode(
}
/*
- * We did not find any links to this inode. If the inode agrees, we
- * have nothing further to do. If not, the inode has a nonzero link
- * count and we don't have anywhere to graft the child onto. Dropping
- * a live inode's link count to zero can cause unexpected shutdowns in
- * inactivation, so leave it alone.
+ * If this inode is linked from the directory tree and on the unlinked
+ * list, remove it from the unlinked list.
*/
- if (total_links == 0) {
- if (actual_nlink != 0)
- trace_xrep_nlinks_unfixable_inode(mp, ip, &obs);
- goto out_trans;
+ if (total_links > 0 && xfs_inode_on_unlinked_list(ip)) {
+ error = xrep_nlinks_iunlink_remove(sc);
+ if (error)
+ goto out_trans;
+ dirty = true;
+ }
+
+ /*
+ * If this inode is not linked from the directory tree yet not on the
+ * unlinked list, put it on the unlinked list.
+ */
+ if (total_links == 0 && !xfs_inode_on_unlinked_list(ip)) {
+ error = xfs_iunlink(sc->tp, ip);
+ if (error)
+ goto out_trans;
+ dirty = true;
}
/* Commit the new link count if it changed. */