]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - repair/phase7.c
c2996470cf1e651612ce7e7518e4af01b0abddd3
[thirdparty/xfsprogs-dev.git] / repair / phase7.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
5 */
6
7 #include "libxfs.h"
8 #include "avl.h"
9 #include "globals.h"
10 #include "agheader.h"
11 #include "incore.h"
12 #include "protos.h"
13 #include "err_protos.h"
14 #include "dinode.h"
15 #include "versions.h"
16 #include "progress.h"
17 #include "threads.h"
18
19 static void
20 update_inode_nlinks(
21 xfs_mount_t *mp,
22 xfs_ino_t ino,
23 uint32_t nlinks)
24 {
25 xfs_trans_t *tp;
26 xfs_inode_t *ip;
27 int error;
28 int dirty;
29 int nres;
30
31 nres = no_modify ? 0 : 10;
32 error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_remove, nres, 0, 0, &tp);
33 ASSERT(error == 0);
34
35 error = -libxfs_iget(mp, tp, ino, 0, &ip, &xfs_default_ifork_ops);
36 if (error) {
37 if (!no_modify)
38 do_error(
39 _("couldn't map inode %" PRIu64 ", err = %d\n"),
40 ino, error);
41 else {
42 do_warn(
43 _("couldn't map inode %" PRIu64 ", err = %d, can't compare link counts\n"),
44 ino, error);
45 return;
46 }
47 }
48
49 dirty = 0;
50
51 /* compare and set links if they differ. */
52 if (VFS_I(ip)->i_nlink != nlinks) {
53 if (!no_modify) {
54 do_warn(
55 _("resetting inode %" PRIu64 " nlinks from %u to %u\n"),
56 ino, VFS_I(ip)->i_nlink, nlinks);
57 set_nlink(VFS_I(ip), nlinks);
58 dirty = 1;
59 } else {
60 do_warn(
61 _("would have reset inode %" PRIu64 " nlinks from %u to %u\n"),
62 ino, VFS_I(ip)->i_nlink, nlinks);
63 }
64 }
65
66 if (!dirty) {
67 libxfs_trans_cancel(tp);
68 } else {
69 libxfs_trans_ijoin(tp, ip, 0);
70 libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
71 /*
72 * no need to do a bmap finish since
73 * we're not allocating anything
74 */
75 ASSERT(error == 0);
76 error = -libxfs_trans_commit(tp);
77
78 ASSERT(error == 0);
79 }
80 libxfs_irele(ip);
81 }
82
83 /*
84 * for each ag, look at each inode 1 at a time. If the number of
85 * links is bad, reset it, log the inode core, commit the transaction
86 */
87 static void
88 do_link_updates(
89 struct workqueue *wq,
90 xfs_agnumber_t agno,
91 void *arg)
92 {
93 struct xfs_mount *mp = wq->wq_ctx;
94 ino_tree_node_t *irec;
95 int j;
96 uint32_t nrefs;
97
98 for (irec = findfirst_inode_rec(agno); irec;
99 irec = next_ino_rec(irec)) {
100 for (j = 0; j < XFS_INODES_PER_CHUNK; j++) {
101 ASSERT(is_inode_confirmed(irec, j));
102
103 if (is_inode_free(irec, j))
104 continue;
105
106 ASSERT(no_modify || is_inode_reached(irec, j));
107
108 nrefs = num_inode_references(irec, j);
109 ASSERT(no_modify || nrefs > 0);
110
111 if (get_inode_disk_nlinks(irec, j) != nrefs)
112 update_inode_nlinks(wq->wq_ctx,
113 XFS_AGINO_TO_INO(mp, agno,
114 irec->ino_startnum + j),
115 nrefs);
116 }
117 }
118
119 PROG_RPT_INC(prog_rpt_done[agno], 1);
120 }
121
122 void
123 phase7(
124 struct xfs_mount *mp,
125 int scan_threads)
126 {
127 struct workqueue wq;
128 int agno;
129
130 if (!no_modify)
131 do_log(_("Phase 7 - verify and correct link counts...\n"));
132 else
133 do_log(_("Phase 7 - verify link counts...\n"));
134
135 set_progress_msg(PROGRESS_FMT_CORR_LINK, (uint64_t) glob_agcount);
136
137 create_work_queue(&wq, mp, scan_threads);
138
139 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++)
140 queue_work(&wq, do_link_updates, agno, NULL);
141
142 destroy_work_queue(&wq);
143
144 print_final_rpt();
145 }