Line data Source code
1 : #include "clusterautoconfig.h"
2 :
3 : #include <inttypes.h>
4 : #include <stdlib.h>
5 : #include <stdio.h>
6 : #include <libintl.h>
7 : #define _(String) gettext(String)
8 :
9 : #include <logging.h>
10 : #include "libgfs2.h"
11 : #include "fsck.h"
12 : #include "link.h"
13 : #include "lost_n_found.h"
14 : #include "inode_hash.h"
15 : #include "metawalk.h"
16 : #include "util.h"
17 : #include "afterpass1_common.h"
18 :
19 : static struct metawalk_fxns pass4_fxns_delete = {
20 : .private = NULL,
21 : .check_metalist = delete_metadata,
22 : .check_data = delete_data,
23 : .check_eattr_indir = delete_eattr_indir,
24 : .check_eattr_leaf = delete_eattr_leaf,
25 : };
26 :
27 : /* Updates the link count of an inode to what the fsck has seen for
28 : * link count */
29 0 : static int fix_link_count(uint32_t counted_links, struct lgfs2_inode *ip)
30 : {
31 0 : log_info(_("Fixing inode link count (%d->%d) for %"PRIu64" (0x%"PRIx64") \n"),
32 : ip->i_nlink, counted_links, ip->i_num.in_addr, ip->i_num.in_addr);
33 0 : if (ip->i_nlink == counted_links)
34 0 : return 0;
35 0 : ip->i_nlink = counted_links;
36 0 : lgfs2_bmodified(ip->i_bh);
37 :
38 0 : log_debug(_("Changing inode %"PRIu64" (0x%"PRIx64") to have %u links\n"),
39 : ip->i_num.in_addr, ip->i_num.in_addr, counted_links);
40 0 : return 0;
41 : }
42 :
43 : /**
44 : * handle_unlinked - handle an unlinked dinode
45 : *
46 : * Note: We need to pass in *counted_links here, not counted_links because
47 : * add_inode_to_lf may be called here, and that might change the original
48 : * value, whether that's in the dirtree or the inodetree.
49 : *
50 : * Returns: 1 if caller should do "continue", 0 if not.
51 : */
52 0 : static int handle_unlinked(struct fsck_cx *cx, uint64_t no_addr,
53 : uint32_t *counted_links, int *lf_addition)
54 : {
55 0 : struct lgfs2_sbd *sdp = cx->sdp;
56 : struct lgfs2_inode *ip;
57 : int q;
58 :
59 0 : log_err(_("Found unlinked inode at %"PRIu64" (0x%"PRIx64")\n"),
60 : no_addr, no_addr);
61 0 : q = bitmap_type(sdp, no_addr);
62 0 : if (q == GFS2_BLKST_FREE) {
63 0 : log_err(_("Unlinked inode %"PRIu64" (0x%"PRIx64") contains bad blocks\n"),
64 : no_addr, no_addr);
65 0 : if (query(cx, _("Delete unlinked inode with bad blocks? (y/n) "))) {
66 0 : ip = fsck_load_inode(sdp, no_addr);
67 0 : check_inode_eattr(cx, ip, &pass4_fxns_delete);
68 0 : check_metatree(cx, ip, &pass4_fxns_delete);
69 0 : fsck_bitmap_set(cx, ip, no_addr, _("bad unlinked"),
70 : GFS2_BLKST_FREE);
71 0 : fsck_inode_put(&ip);
72 0 : return 1;
73 : } else {
74 0 : log_err(_("Unlinked inode with bad blocks not cleared\n"));
75 : }
76 : }
77 0 : if (q != GFS2_BLKST_DINODE) {
78 0 : log_err(_("Unlinked block %"PRIu64" (0x%"PRIx64") marked as inode is not an inode (%d)\n"),
79 : no_addr, no_addr, q);
80 0 : ip = fsck_load_inode(sdp, no_addr);
81 0 : if (query(cx, _("Delete unlinked inode? (y/n) "))) {
82 0 : check_inode_eattr(cx, ip, &pass4_fxns_delete);
83 0 : check_metatree(cx, ip, &pass4_fxns_delete);
84 0 : fsck_bitmap_set(cx, ip, no_addr, _("invalid unlinked"),
85 : GFS2_BLKST_FREE);
86 0 : fsck_inode_put(&ip);
87 0 : log_err( _("The inode was deleted\n"));
88 : } else {
89 0 : log_err( _("The inode was not deleted\n"));
90 0 : fsck_inode_put(&ip);
91 : }
92 0 : return 1;
93 : }
94 0 : ip = fsck_load_inode(sdp, no_addr);
95 :
96 : /* We don't want to clear zero-size files with eattrs - there might be
97 : relevent info in them. */
98 0 : if (!ip->i_size && !ip->i_eattr){
99 0 : log_err( _("Unlinked inode has zero size\n"));
100 0 : if (query(cx, _("Clear zero-size unlinked inode? (y/n) "))) {
101 0 : fsck_bitmap_set(cx, ip, no_addr, _("unlinked zero-length"),
102 : GFS2_BLKST_FREE);
103 0 : fsck_inode_put(&ip);
104 0 : return 1;
105 : }
106 : }
107 0 : if (query(cx, _("Add unlinked inode to lost+found? (y/n)"))) {
108 0 : if (add_inode_to_lf(cx, ip)) {
109 0 : stack;
110 0 : fsck_inode_put(&ip);
111 0 : return -1;
112 : } else {
113 0 : fix_link_count(*counted_links, ip);
114 0 : *lf_addition = 1;
115 : }
116 : } else
117 0 : log_err( _("Unlinked inode left unlinked\n"));
118 0 : fsck_inode_put(&ip);
119 0 : return 0;
120 : }
121 :
122 0 : static void handle_inconsist(struct fsck_cx *cx, uint64_t no_addr,
123 : uint32_t *di_nlink, uint32_t counted_links)
124 : {
125 0 : log_err(_("Link count inconsistent for inode %"PRIu64" (0x%"PRIx64") has %u but fsck found %u.\n"),
126 : no_addr, no_addr, *di_nlink, counted_links);
127 : /* Read in the inode, adjust the link count, and write it back out */
128 0 : if (query(cx, _("Update link count for inode %"PRIu64" (0x%"PRIx64")? (y/n) "),
129 : no_addr, no_addr)) {
130 : struct lgfs2_inode *ip;
131 :
132 0 : ip = fsck_load_inode(cx->sdp, no_addr); /* lgfs2_bread, inode_get */
133 0 : fix_link_count(counted_links, ip);
134 0 : *di_nlink = counted_links;
135 0 : fsck_inode_put(&ip); /* out, lgfs2_brelse, free */
136 0 : log_warn(_("Link count updated to %d for inode %"PRIu64" (0x%"PRIx64")\n"),
137 : *di_nlink, no_addr, no_addr);
138 : } else {
139 0 : log_err(_("Link count for inode %"PRIu64" (0x%"PRIx64") still incorrect\n"),
140 : no_addr, no_addr);
141 : }
142 0 : }
143 :
144 168 : static int adjust_lf_links(struct fsck_cx *cx, int lf_addition)
145 : {
146 : struct dir_info *lf_di;
147 :
148 168 : if (lf_dip == NULL)
149 168 : return 0;
150 :
151 0 : if (!lf_addition)
152 0 : return 0;
153 :
154 0 : if (!(lf_di = dirtree_find(cx, lf_dip->i_num.in_addr))) {
155 0 : log_crit(_("Unable to find lost+found inode in "
156 : "inode_hash!!\n"));
157 0 : return -1;
158 : } else {
159 0 : fix_link_count(lf_di->counted_links, lf_dip);
160 : }
161 0 : return 0;
162 : }
163 :
164 56 : static int scan_inode_list(struct fsck_cx *cx)
165 : {
166 56 : struct osi_node *tmp, *next = NULL;
167 : struct inode_info *ii;
168 56 : int lf_addition = 0;
169 :
170 : /* FIXME: should probably factor this out into a generic
171 : * scanning fxn */
172 56 : for (tmp = osi_first(&cx->inodetree); tmp; tmp = next) {
173 0 : if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
174 0 : return 0;
175 0 : next = osi_next(tmp);
176 0 : ii = (struct inode_info *)tmp;
177 0 : if (ii->counted_links == 0) {
178 0 : if (handle_unlinked(cx, ii->num.in_addr,
179 : &ii->counted_links, &lf_addition))
180 0 : continue;
181 : } /* if (ii->counted_links == 0) */
182 0 : else if (ii->di_nlink != ii->counted_links) {
183 0 : handle_inconsist(cx, ii->num.in_addr,
184 : &ii->di_nlink, ii->counted_links);
185 : }
186 0 : log_debug(_("block %"PRIu64" (0x%"PRIx64") has link count %d\n"),
187 : ii->num.in_addr, ii->num.in_addr, ii->di_nlink);
188 : } /* osi_list_foreach(tmp, list) */
189 :
190 56 : return adjust_lf_links(cx, lf_addition);
191 : }
192 :
193 56 : static int scan_dir_list(struct fsck_cx *cx)
194 : {
195 56 : struct osi_node *tmp, *next = NULL;
196 : struct dir_info *di;
197 56 : int lf_addition = 0;
198 :
199 : /* FIXME: should probably factor this out into a generic
200 : * scanning fxn */
201 280 : for (tmp = osi_first(&cx->dirtree); tmp; tmp = next) {
202 224 : if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
203 0 : return 0;
204 224 : next = osi_next(tmp);
205 224 : di = (struct dir_info *)tmp;
206 224 : if (di->counted_links == 0) {
207 0 : if (handle_unlinked(cx, di->dinode.in_addr,
208 : &di->counted_links, &lf_addition))
209 0 : continue;
210 224 : } else if (di->di_nlink != di->counted_links) {
211 0 : handle_inconsist(cx, di->dinode.in_addr,
212 : &di->di_nlink, di->counted_links);
213 : }
214 224 : log_debug(_("block %"PRIu64" (0x%"PRIx64") has link count %d\n"),
215 : di->dinode.in_addr, di->dinode.in_addr, di->di_nlink);
216 : } /* osi_list_foreach(tmp, list) */
217 :
218 56 : return adjust_lf_links(cx, lf_addition);
219 : }
220 :
221 56 : static int scan_nlink1_list(struct fsck_cx *cx)
222 : {
223 : uint64_t blk;
224 : uint32_t counted_links;
225 56 : int lf_addition = 0;
226 :
227 477638570 : for (blk = 0; blk < last_fs_block; blk++) {
228 477638514 : if (skip_this_pass || fsck_abort)
229 0 : return 0;
230 477638514 : if (link1_type(&nlink1map, blk) == 0)
231 477638038 : continue;
232 :
233 476 : if (link1_type(&clink1map, blk) == 0) {
234 : /* In other cases, counted_links is a pointer to a
235 : real count that gets incremented when it's added
236 : to lost+found. In this case, however, there's not a
237 : real count, so we fake it out to be 1. */
238 0 : counted_links = 1;
239 0 : if (handle_unlinked(cx, blk, &counted_links, &lf_addition))
240 0 : continue;
241 : }
242 : }
243 56 : return adjust_lf_links(cx, lf_addition);
244 : }
245 :
246 : /**
247 : * pass4 - Check reference counts (pass 2 & 6 in current fsck)
248 : *
249 : * handle unreferenced files
250 : * lost+found errors (missing, not a directory, no space)
251 : * adjust link count
252 : * handle unreferenced inodes of other types
253 : * handle bad blocks
254 : */
255 56 : int pass4(struct fsck_cx *cx)
256 : {
257 56 : if (lf_dip)
258 0 : log_debug( _("At beginning of pass4, lost+found entries is %u\n"),
259 : lf_dip->i_entries);
260 56 : log_info( _("Checking inode reference counts: multi-links.\n"));
261 56 : if (scan_inode_list(cx)) {
262 0 : stack;
263 0 : return FSCK_ERROR;
264 : }
265 56 : log_info( _("Checking inode reference counts: directories.\n"));
266 56 : if (scan_dir_list(cx)) {
267 0 : stack;
268 0 : return FSCK_ERROR;
269 : }
270 56 : log_info( _("Checking inode reference counts: normal links.\n"));
271 56 : if (scan_nlink1_list(cx)) {
272 0 : stack;
273 0 : return FSCK_ERROR;
274 : }
275 :
276 56 : if (lf_dip)
277 0 : log_debug( _("At end of pass4, lost+found entries is %u\n"),
278 : lf_dip->i_entries);
279 56 : return FSCK_OK;
280 : }
|