Line data Source code
1 : #include <inttypes.h>
2 : #include <stdio.h>
3 : #include <stdlib.h>
4 : #include <string.h>
5 : #include <sys/types.h>
6 : #include <sys/stat.h>
7 : #include <unistd.h>
8 : #include <libintl.h>
9 : #include <ctype.h>
10 : #include <fcntl.h>
11 : #define _(String) gettext(String)
12 :
13 : #include <logging.h>
14 : #include "libgfs2.h"
15 : #include "fsck.h"
16 : #include "afterpass1_common.h"
17 : #include "metawalk.h"
18 : #include "util.h"
19 :
20 : /**
21 : * find_remove_dup - find out if this is a duplicate ref. If so, remove it.
22 : *
23 : * Returns: 1 if there are any remaining references to this block, else 0.
24 : */
25 0 : static int find_remove_dup(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block,
26 : const char *btype, int *removed_last_meta)
27 : {
28 : struct duptree *dt;
29 : struct inode_with_dups *id;
30 0 : int deleted_a_meta_ref = 0;
31 0 : int meta_refs_left = 0;
32 :
33 0 : dt = dupfind(cx, block);
34 0 : if (!dt)
35 0 : return 0;
36 :
37 : /* remove the inode reference id structure for this reference. */
38 0 : id = find_dup_ref_inode(dt, ip);
39 0 : if (!id)
40 0 : goto more_refs;
41 :
42 0 : if (id->reftypecount[REF_AS_META])
43 0 : deleted_a_meta_ref = 1;
44 0 : dup_listent_delete(dt, id);
45 0 : if (dt->refs == 0) {
46 0 : log_info( _("This was the last reference: it's no longer a "
47 : "duplicate.\n"));
48 0 : dup_delete(cx, dt); /* not duplicate now */
49 0 : if (deleted_a_meta_ref) {
50 0 : log_debug("Removed the last reference as metadata.\n");
51 0 : *removed_last_meta = 1;
52 : }
53 0 : return 0;
54 0 : } else if (deleted_a_meta_ref) {
55 : /* If we deleted a metadata reference, see if there are more
56 : references as meta, or if it was the last one. */
57 0 : meta_refs_left = count_dup_meta_refs(dt);
58 : }
59 0 : more_refs:
60 0 : log_info(_("%d block reference(s) remain (%d as metadata).\n"),
61 : dt->refs, meta_refs_left);
62 0 : if (deleted_a_meta_ref && meta_refs_left == 0) {
63 0 : log_debug("Removed the last reference as metadata.\n");
64 0 : *removed_last_meta = 1;
65 : }
66 0 : return 1; /* references still exist so do not free the block. */
67 : }
68 :
69 : /**
70 : * delete_block_if_notdup - delete blocks associated with an inode
71 : *
72 : * Ignore blocks that are already marked free.
73 : * If it has been identified as duplicate, remove the duplicate reference.
74 : * If all duplicate references have been removed, delete the block.
75 : */
76 0 : static int delete_block_if_notdup(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block,
77 : struct lgfs2_buffer_head **bh,
78 : const char *btype, int *was_duplicate,
79 : void *private)
80 : {
81 : int q;
82 0 : int removed_lastmeta = 0;
83 :
84 0 : if (!valid_block_ip(ip, block))
85 0 : return META_ERROR;
86 :
87 0 : q = bitmap_type(ip->i_sbd, block);
88 0 : if (q == GFS2_BLKST_FREE) {
89 0 : log_info(_("%s block %"PRIu64" (0x%"PRIx64"), part of inode "
90 : "%"PRIu64" (0x%"PRIx64"), was already free.\n"),
91 : btype, block, block, ip->i_num.in_addr, ip->i_num.in_addr);
92 0 : return META_IS_GOOD;
93 : }
94 0 : if (find_remove_dup(cx, ip, block, btype, &removed_lastmeta)) { /* a dup */
95 0 : if (was_duplicate) {
96 0 : if (removed_lastmeta)
97 0 : log_debug("Removed last reference as meta.\n");
98 : else
99 0 : *was_duplicate = 1;
100 : }
101 0 : log_err(_("Not clearing duplicate reference in inode at block #%"PRIu64
102 : " (0x%"PRIx64") to block #%"PRIu64" (0x%"PRIx64") "
103 : "because it's referenced by another inode.\n"),
104 : ip->i_num.in_addr, ip->i_num.in_addr, block, block);
105 : } else {
106 0 : check_n_fix_bitmap(cx, ip->i_rgd, block, 0,
107 : GFS2_BLKST_FREE);
108 : }
109 0 : return META_IS_GOOD;
110 : }
111 :
112 0 : static int remove_dentry(struct fsck_cx *cx, struct lgfs2_inode *ip, struct gfs2_dirent *dent,
113 : struct gfs2_dirent *prev_de,
114 : struct lgfs2_buffer_head *bh,
115 : char *filename, uint32_t *count, int *lindex,
116 : void *private)
117 : {
118 : /* the metawalk_fxn's private field must be set to the dentry
119 : * block we want to clear */
120 0 : uint64_t *dentryblock = (uint64_t *) private;
121 : struct lgfs2_dirent d;
122 :
123 0 : lgfs2_dirent_in(&d, dent);
124 :
125 0 : if (d.dr_inum.in_addr == *dentryblock)
126 0 : lgfs2_dirent2_del(ip, bh, prev_de, dent);
127 : else
128 0 : (*count)++;
129 :
130 0 : return 0;
131 :
132 : }
133 :
134 0 : int remove_dentry_from_dir(struct fsck_cx *cx, uint64_t dir, uint64_t dentryblock)
135 : {
136 0 : struct metawalk_fxns remove_dentry_fxns = {0};
137 0 : struct lgfs2_sbd *sdp = cx->sdp;
138 : struct lgfs2_inode *ip;
139 : int q;
140 : int error;
141 :
142 0 : log_debug(_("Removing dentry %"PRIu64" (0x%"PRIx64") from directory %"PRIu64" (0x%"PRIx64")\n"),
143 : dentryblock, dentryblock, dir, dir);
144 0 : if (!valid_block(sdp, dir)) {
145 0 : log_err( _("Parent directory is invalid\n"));
146 0 : return 1;
147 : }
148 0 : remove_dentry_fxns.private = &dentryblock;
149 0 : remove_dentry_fxns.check_dentry = remove_dentry;
150 :
151 0 : q = bitmap_type(sdp, dir);
152 0 : if (q != GFS2_BLKST_DINODE) {
153 0 : log_info( _("Parent block is not an inode...ignoring\n"));
154 0 : return 1;
155 : }
156 :
157 0 : ip = fsck_load_inode(sdp, dir);
158 0 : if (ip == NULL) {
159 0 : stack;
160 0 : return -1;
161 : }
162 : /* Need to run check_dir with a private var of dentryblock,
163 : * and fxns that remove that dentry if found */
164 0 : error = check_dir(cx, ip, &remove_dentry_fxns);
165 0 : fsck_inode_put(&ip);
166 0 : return error;
167 : }
168 :
169 0 : int delete_metadata(struct fsck_cx *cx, struct iptr iptr, struct lgfs2_buffer_head **bh, int h, int *is_valid,
170 : int *was_duplicate, void *private)
171 : {
172 0 : struct lgfs2_inode *ip = iptr.ipt_ip;
173 0 : uint64_t block = iptr_block(iptr);
174 :
175 0 : *is_valid = 1;
176 0 : *was_duplicate = 0;
177 0 : return delete_block_if_notdup(cx, ip, block, bh, _("metadata"),
178 : was_duplicate, private);
179 : }
180 :
181 0 : int delete_leaf(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block, void *private)
182 : {
183 0 : return delete_block_if_notdup(cx, ip, block, NULL, _("leaf"), NULL,
184 : private);
185 : }
186 :
187 0 : int delete_data(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t metablock,
188 : uint64_t block, void *private, struct lgfs2_buffer_head *bh,
189 : __be64 *ptr)
190 : {
191 0 : return delete_block_if_notdup(cx, ip, block, NULL, _("data"), NULL,
192 : private);
193 : }
194 :
195 0 : static int del_eattr_generic(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block,
196 : uint64_t parent, struct lgfs2_buffer_head **bh,
197 : void *private, const char *eatype)
198 : {
199 0 : int ret = 0;
200 0 : int was_free = 0;
201 : int q;
202 :
203 0 : if (valid_block_ip(ip, block)) {
204 0 : q = bitmap_type(ip->i_sbd, block);
205 0 : if (q == GFS2_BLKST_FREE)
206 0 : was_free = 1;
207 0 : ret = delete_block_if_notdup(cx, ip, block, NULL, eatype,
208 : NULL, private);
209 0 : if (!ret) {
210 0 : *bh = lgfs2_bread(ip->i_sbd, block);
211 0 : if (!was_free)
212 0 : ip->i_blocks--;
213 0 : lgfs2_bmodified(ip->i_bh);
214 : }
215 : }
216 : /* Even if it's a duplicate reference, we want to eliminate the
217 : reference itself, and adjust di_blocks accordingly. */
218 0 : if (ip->i_eattr) {
219 0 : if (block == ip->i_eattr)
220 0 : ip->i_eattr = 0;
221 0 : lgfs2_bmodified(ip->i_bh);
222 : }
223 0 : return ret;
224 : }
225 :
226 0 : int delete_eattr_indir(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block, uint64_t parent,
227 : struct lgfs2_buffer_head **bh, void *private)
228 : {
229 0 : return del_eattr_generic(cx, ip, block, parent, bh, private,
230 0 : _("extended attribute"));
231 : }
232 :
233 0 : int delete_eattr_leaf(struct fsck_cx *cx, struct lgfs2_inode *ip, uint64_t block, uint64_t parent,
234 : struct lgfs2_buffer_head **bh, void *private)
235 : {
236 0 : return del_eattr_generic(cx, ip, block, parent, bh, private,
237 0 : _("indirect extended attribute"));
238 : }
239 :
240 0 : int delete_eattr_entry(struct fsck_cx *cx, struct lgfs2_inode *ip, struct lgfs2_buffer_head *leaf_bh,
241 : struct gfs2_ea_header *ea_hdr,
242 : struct gfs2_ea_header *ea_hdr_prev, void *private)
243 : {
244 0 : struct lgfs2_sbd *sdp = ip->i_sbd;
245 : char ea_name[256];
246 : uint32_t avail_size;
247 : int max_ptrs;
248 :
249 0 : if (!ea_hdr->ea_name_len){
250 : /* Skip this entry for now */
251 0 : return 1;
252 : }
253 :
254 0 : memset(ea_name, 0, sizeof(ea_name));
255 0 : strncpy(ea_name, (char *)ea_hdr + sizeof(struct gfs2_ea_header),
256 0 : ea_hdr->ea_name_len);
257 :
258 0 : if (!GFS2_EATYPE_VALID(ea_hdr->ea_type) &&
259 0 : ((ea_hdr_prev) || (!ea_hdr_prev && ea_hdr->ea_type))){
260 : /* Skip invalid entry */
261 0 : return 1;
262 : }
263 :
264 0 : if (!ea_hdr->ea_num_ptrs)
265 0 : return 0;
266 :
267 0 : avail_size = sdp->sd_bsize - sizeof(struct gfs2_meta_header);
268 0 : max_ptrs = (be32_to_cpu(ea_hdr->ea_data_len) + avail_size - 1) /
269 : avail_size;
270 :
271 0 : if (max_ptrs > ea_hdr->ea_num_ptrs)
272 0 : return 1;
273 :
274 0 : log_debug( _(" Pointers Required: %d\n Pointers Reported: %d\n"),
275 : max_ptrs, ea_hdr->ea_num_ptrs);
276 :
277 0 : return 0;
278 : }
279 :
280 0 : int delete_eattr_extentry(struct fsck_cx *cx, struct lgfs2_inode *ip, int i, __be64 *ea_data_ptr,
281 : struct lgfs2_buffer_head *leaf_bh, uint32_t tot_ealen,
282 : struct gfs2_ea_header *ea_hdr,
283 : struct gfs2_ea_header *ea_hdr_prev, void *private)
284 : {
285 0 : uint64_t block = be64_to_cpu(*ea_data_ptr);
286 : int error;
287 :
288 0 : error = delete_block_if_notdup(cx, ip, block, NULL,
289 0 : _("extended attribute"), NULL, private);
290 0 : if (error) {
291 0 : log_err(_("Bad extended attribute found at block %"PRIu64 " (0x%"PRIx64")"),
292 : be64_to_cpu(*ea_data_ptr), be64_to_cpu(*ea_data_ptr));
293 0 : if (query(cx, _("Repair the bad Extended Attribute? (y/n) "))) {
294 0 : ea_hdr->ea_num_ptrs = i;
295 0 : ea_hdr->ea_data_len = cpu_to_be32(tot_ealen);
296 0 : *ea_data_ptr = 0;
297 0 : lgfs2_bmodified(leaf_bh);
298 : /* Endianness doesn't matter in this case because it's
299 : a single byte. */
300 0 : fsck_bitmap_set(cx, ip, ip->i_eattr,
301 : _("extended attribute"),
302 : GFS2_BLKST_USED);
303 0 : log_err( _("The EA was fixed.\n"));
304 : } else {
305 0 : error = 1;
306 0 : log_err( _("The bad EA was not fixed.\n"));
307 : }
308 : }
309 0 : return error;
310 : }
|