Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-or-later
2 : /*
3 : * Copyright (C) 2017-2023 Oracle. All Rights Reserved.
4 : * Author: Darrick J. Wong <djwong@kernel.org>
5 : */
6 : #include "xfs.h"
7 : #include "xfs_fs.h"
8 : #include "xfs_shared.h"
9 : #include "xfs_format.h"
10 : #include "xfs_trans_resv.h"
11 : #include "xfs_mount.h"
12 : #include "xfs_log_format.h"
13 : #include "xfs_inode.h"
14 : #include "xfs_da_format.h"
15 : #include "xfs_da_btree.h"
16 : #include "xfs_attr.h"
17 : #include "xfs_attr_leaf.h"
18 : #include "xfs_attr_sf.h"
19 : #include "scrub/scrub.h"
20 : #include "scrub/common.h"
21 : #include "scrub/dabtree.h"
22 : #include "scrub/attr.h"
23 :
24 : /* Free the buffers linked from the xattr buffer. */
25 : static void
26 13312677 : xchk_xattr_buf_cleanup(
27 : void *priv)
28 : {
29 13312677 : struct xchk_xattr_buf *ab = priv;
30 :
31 13312677 : kvfree(ab->freemap);
32 13312908 : ab->freemap = NULL;
33 13312908 : kvfree(ab->usedmap);
34 13312952 : ab->usedmap = NULL;
35 13312952 : kvfree(ab->value);
36 13312882 : ab->value = NULL;
37 13312882 : ab->value_sz = 0;
38 13312882 : }
39 :
40 : /*
41 : * Allocate the free space bitmap if we're trying harder; there are leaf blocks
42 : * in the attr fork; or we can't tell if there are leaf blocks.
43 : */
44 : static inline bool
45 13312811 : xchk_xattr_want_freemap(
46 : struct xfs_scrub *sc)
47 : {
48 13312811 : struct xfs_ifork *ifp;
49 :
50 13312811 : if (sc->flags & XCHK_TRY_HARDER)
51 : return true;
52 :
53 13312811 : if (!sc->ip)
54 : return true;
55 :
56 13312811 : ifp = xfs_ifork_ptr(sc->ip, XFS_ATTR_FORK);
57 13312811 : if (!ifp)
58 : return false;
59 :
60 13312811 : return xfs_ifork_has_extents(ifp);
61 : }
62 :
63 : /*
64 : * Allocate enough memory to hold an attr value and attr block bitmaps,
65 : * reallocating the buffer if necessary. Buffer contents are not preserved
66 : * across a reallocation.
67 : */
68 : static int
69 27396903 : xchk_setup_xattr_buf(
70 : struct xfs_scrub *sc,
71 : size_t value_size)
72 : {
73 27396903 : size_t bmp_sz;
74 27396903 : struct xchk_xattr_buf *ab = sc->buf;
75 27396903 : void *new_val;
76 :
77 27396903 : bmp_sz = sizeof(long) * BITS_TO_LONGS(sc->mp->m_attr_geo->blksize);
78 :
79 27396903 : if (ab)
80 14084027 : goto resize_value;
81 :
82 13312876 : ab = kvzalloc(sizeof(struct xchk_xattr_buf), XCHK_GFP_FLAGS);
83 13312813 : if (!ab)
84 : return -ENOMEM;
85 13312813 : sc->buf = ab;
86 13312813 : sc->buf_cleanup = xchk_xattr_buf_cleanup;
87 :
88 13312813 : ab->usedmap = kvmalloc(bmp_sz, XCHK_GFP_FLAGS);
89 13312919 : if (!ab->usedmap)
90 : return -ENOMEM;
91 :
92 13312919 : if (xchk_xattr_want_freemap(sc)) {
93 1062682 : ab->freemap = kvmalloc(bmp_sz, XCHK_GFP_FLAGS);
94 1062681 : if (!ab->freemap)
95 : return -ENOMEM;
96 : }
97 :
98 13312918 : resize_value:
99 27396945 : if (ab->value_sz >= value_size)
100 : return 0;
101 :
102 12899426 : if (ab->value) {
103 869245 : kvfree(ab->value);
104 869247 : ab->value = NULL;
105 869247 : ab->value_sz = 0;
106 : }
107 :
108 12899428 : new_val = kvmalloc(value_size, XCHK_GFP_FLAGS);
109 12899714 : if (!new_val)
110 : return -ENOMEM;
111 :
112 12899714 : ab->value = new_val;
113 12899714 : ab->value_sz = value_size;
114 12899714 : return 0;
115 : }
116 :
117 : /* Set us up to scrub an inode's extended attributes. */
118 : int
119 251894667 : xchk_setup_xattr(
120 : struct xfs_scrub *sc)
121 : {
122 251894667 : int error;
123 :
124 : /*
125 : * We failed to get memory while checking attrs, so this time try to
126 : * get all the memory we're ever going to need. Allocate the buffer
127 : * without the inode lock held, which means we can sleep.
128 : */
129 251894667 : if (sc->flags & XCHK_TRY_HARDER) {
130 0 : error = xchk_setup_xattr_buf(sc, XATTR_SIZE_MAX);
131 0 : if (error)
132 : return error;
133 : }
134 :
135 251894667 : return xchk_setup_inode_contents(sc, 0);
136 : }
137 :
138 : /* Extended Attributes */
139 :
140 : struct xchk_xattr {
141 : struct xfs_attr_list_context context;
142 : struct xfs_scrub *sc;
143 : };
144 :
145 : /*
146 : * Check that an extended attribute key can be looked up by hash.
147 : *
148 : * We use the XFS attribute list iterator (i.e. xfs_attr_list_ilocked)
149 : * to call this function for every attribute key in an inode. Once
150 : * we're here, we load the attribute value to see if any errors happen,
151 : * or if we get more or less data than we expected.
152 : */
153 : static void
154 27300933 : xchk_xattr_listent(
155 : struct xfs_attr_list_context *context,
156 : int flags,
157 : unsigned char *name,
158 : int namelen,
159 : int valuelen)
160 : {
161 54603889 : struct xfs_da_args args = {
162 : .op_flags = XFS_DA_OP_NOTIME,
163 27300933 : .attr_filter = flags & XFS_ATTR_NSP_ONDISK_MASK,
164 27300933 : .geo = context->dp->i_mount->m_attr_geo,
165 : .whichfork = XFS_ATTR_FORK,
166 27302956 : .dp = context->dp,
167 : .name = name,
168 : .namelen = namelen,
169 27300933 : .hashval = xfs_da_hashname(name, namelen),
170 27302956 : .trans = context->tp,
171 : .valuelen = valuelen,
172 : };
173 27302956 : struct xchk_xattr_buf *ab;
174 27302956 : struct xchk_xattr *sx;
175 27302956 : int error = 0;
176 :
177 27302956 : sx = container_of(context, struct xchk_xattr, context);
178 27302956 : ab = sx->sc->buf;
179 :
180 27302956 : if (xchk_should_terminate(sx->sc, &error)) {
181 0 : context->seen_enough = error;
182 0 : return;
183 : }
184 :
185 27306311 : if (flags & XFS_ATTR_INCOMPLETE) {
186 : /* Incomplete attr key, just mark the inode for preening. */
187 0 : xchk_ino_set_preen(sx->sc, context->dp->i_ino);
188 0 : return;
189 : }
190 :
191 : /* Only one namespace bit allowed. */
192 54609516 : if (hweight32(flags & XFS_ATTR_NSP_ONDISK_MASK) > 1) {
193 0 : xchk_fblock_set_corrupt(sx->sc, XFS_ATTR_FORK, args.blkno);
194 0 : goto fail_xref;
195 : }
196 :
197 : /* Does this name make sense? */
198 27302770 : if (!xfs_attr_namecheck(name, namelen)) {
199 0 : xchk_fblock_set_corrupt(sx->sc, XFS_ATTR_FORK, args.blkno);
200 0 : goto fail_xref;
201 : }
202 :
203 : /*
204 : * Local xattr values are stored in the attr leaf block, so we don't
205 : * need to retrieve the value from a remote block to detect corruption
206 : * problems.
207 : */
208 27307544 : if (flags & XFS_ATTR_LOCAL)
209 13223207 : goto fail_xref;
210 :
211 : /*
212 : * Try to allocate enough memory to extrat the attr value. If that
213 : * doesn't work, we overload the seen_enough variable to convey
214 : * the error message back to the main scrub function.
215 : */
216 14084337 : error = xchk_setup_xattr_buf(sx->sc, valuelen);
217 14084216 : if (error == -ENOMEM)
218 0 : error = -EDEADLOCK;
219 14084216 : if (error) {
220 0 : context->seen_enough = error;
221 0 : return;
222 : }
223 :
224 14084216 : args.value = ab->value;
225 :
226 14084216 : error = xfs_attr_get_ilocked(&args);
227 : /* ENODATA means the hash lookup failed and the attr is bad */
228 14084202 : if (error == -ENODATA)
229 0 : error = -EFSCORRUPTED;
230 14084202 : if (!xchk_fblock_process_error(sx->sc, XFS_ATTR_FORK, args.blkno,
231 : &error))
232 0 : goto fail_xref;
233 14084161 : if (args.valuelen != valuelen)
234 0 : xchk_fblock_set_corrupt(sx->sc, XFS_ATTR_FORK,
235 0 : args.blkno);
236 14084161 : fail_xref:
237 27307368 : if (sx->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
238 0 : context->seen_enough = 1;
239 : return;
240 : }
241 :
242 : /*
243 : * Mark a range [start, start+len) in this map. Returns true if the
244 : * region was free, and false if there's a conflict or a problem.
245 : *
246 : * Within a char, the lowest bit of the char represents the byte with
247 : * the smallest address
248 : */
249 : STATIC bool
250 85262402 : xchk_xattr_set_map(
251 : struct xfs_scrub *sc,
252 : unsigned long *map,
253 : unsigned int start,
254 : unsigned int len)
255 : {
256 85262402 : unsigned int mapsize = sc->mp->m_attr_geo->blksize;
257 85262402 : bool ret = true;
258 :
259 85262402 : if (start >= mapsize)
260 : return false;
261 85262402 : if (start + len > mapsize) {
262 0 : len = mapsize - start;
263 0 : ret = false;
264 : }
265 :
266 85262402 : if (find_next_bit(map, mapsize, start) < start + len)
267 0 : ret = false;
268 85268295 : bitmap_set(map, start, len);
269 :
270 : return ret;
271 : }
272 :
273 : /*
274 : * Check the leaf freemap from the usage bitmap. Returns false if the
275 : * attr freemap has problems or points to used space.
276 : */
277 : STATIC bool
278 1089033 : xchk_xattr_check_freemap(
279 : struct xfs_scrub *sc,
280 : struct xfs_attr3_icleaf_hdr *leafhdr)
281 : {
282 1089033 : struct xchk_xattr_buf *ab = sc->buf;
283 1089033 : unsigned int mapsize = sc->mp->m_attr_geo->blksize;
284 1089033 : int i;
285 :
286 : /* Construct bitmap of freemap contents. */
287 1089033 : bitmap_zero(ab->freemap, mapsize);
288 5445109 : for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
289 3267040 : if (!xchk_xattr_set_map(sc, ab->freemap,
290 3267045 : leafhdr->freemap[i].base,
291 3267030 : leafhdr->freemap[i].size))
292 : return false;
293 : }
294 :
295 : /* Look for bits that are set in freemap and are marked in use. */
296 1089031 : return !bitmap_intersects(ab->freemap, ab->usedmap, mapsize);
297 : }
298 :
299 : /*
300 : * Check this leaf entry's relations to everything else.
301 : * Returns the number of bytes used for the name/value data.
302 : */
303 : STATIC void
304 13217406 : xchk_xattr_entry(
305 : struct xchk_da_btree *ds,
306 : int level,
307 : char *buf_end,
308 : struct xfs_attr_leafblock *leaf,
309 : struct xfs_attr3_icleaf_hdr *leafhdr,
310 : struct xfs_attr_leaf_entry *ent,
311 : int idx,
312 : unsigned int *usedbytes,
313 : __u32 *last_hashval)
314 : {
315 13217406 : struct xfs_mount *mp = ds->state->mp;
316 13217406 : struct xchk_xattr_buf *ab = ds->sc->buf;
317 13217406 : char *name_end;
318 13217406 : struct xfs_attr_leaf_name_local *lentry;
319 13217406 : struct xfs_attr_leaf_name_remote *rentry;
320 13217406 : unsigned int nameidx;
321 13217406 : unsigned int namesize;
322 :
323 13217406 : if (ent->pad2 != 0)
324 0 : xchk_da_set_corrupt(ds, level);
325 :
326 : /* Hash values in order? */
327 26434812 : if (be32_to_cpu(ent->hashval) < *last_hashval)
328 0 : xchk_da_set_corrupt(ds, level);
329 13217199 : *last_hashval = be32_to_cpu(ent->hashval);
330 :
331 13217199 : nameidx = be16_to_cpu(ent->nameidx);
332 13217199 : if (nameidx < leafhdr->firstused ||
333 13217199 : nameidx >= mp->m_attr_geo->blksize) {
334 0 : xchk_da_set_corrupt(ds, level);
335 0 : return;
336 : }
337 :
338 : /* Check the name information. */
339 13217426 : if (ent->flags & XFS_ATTR_LOCAL) {
340 13217223 : lentry = xfs_attr3_leaf_name_local(leaf, idx);
341 13217223 : namesize = xfs_attr_leaf_entsize_local(lentry->namelen,
342 13217223 : be16_to_cpu(lentry->valuelen));
343 13217223 : name_end = (char *)lentry + namesize;
344 13217223 : if (lentry->namelen == 0)
345 0 : xchk_da_set_corrupt(ds, level);
346 : } else {
347 203 : rentry = xfs_attr3_leaf_name_remote(leaf, idx);
348 203 : namesize = xfs_attr_leaf_entsize_remote(rentry->namelen);
349 203 : name_end = (char *)rentry + namesize;
350 203 : if (rentry->namelen == 0 || rentry->valueblk == 0)
351 0 : xchk_da_set_corrupt(ds, level);
352 : }
353 13217426 : if (name_end > buf_end)
354 0 : xchk_da_set_corrupt(ds, level);
355 :
356 13217426 : if (!xchk_xattr_set_map(ds->sc, ab->usedmap, nameidx, namesize))
357 0 : xchk_da_set_corrupt(ds, level);
358 13218651 : if (!(ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
359 13222053 : *usedbytes += namesize;
360 : }
361 :
362 : /* Scrub an attribute leaf. */
363 : STATIC int
364 13221754 : xchk_xattr_block(
365 : struct xchk_da_btree *ds,
366 : int level)
367 : {
368 13221754 : struct xfs_attr3_icleaf_hdr leafhdr;
369 13221754 : struct xfs_mount *mp = ds->state->mp;
370 13221754 : struct xfs_da_state_blk *blk = &ds->state->path.blk[level];
371 13223333 : struct xfs_buf *bp = blk->bp;
372 13223333 : xfs_dablk_t *last_checked = ds->private;
373 13223333 : struct xfs_attr_leafblock *leaf = bp->b_addr;
374 13223333 : struct xfs_attr_leaf_entry *ent;
375 13223333 : struct xfs_attr_leaf_entry *entries;
376 13223333 : struct xchk_xattr_buf *ab = ds->sc->buf;
377 13223333 : char *buf_end;
378 13223333 : size_t off;
379 13223333 : __u32 last_hashval = 0;
380 13223333 : unsigned int usedbytes = 0;
381 13223333 : unsigned int hdrsize;
382 13223333 : int i;
383 :
384 13223333 : if (*last_checked == blk->blkno)
385 : return 0;
386 :
387 1089044 : *last_checked = blk->blkno;
388 1089044 : bitmap_zero(ab->usedmap, mp->m_attr_geo->blksize);
389 :
390 : /* Check all the padding. */
391 1089048 : if (xfs_has_crc(ds->sc->mp)) {
392 1089048 : struct xfs_attr3_leafblock *leaf3 = bp->b_addr;
393 :
394 1089048 : if (leaf3->hdr.pad1 != 0 || leaf3->hdr.pad2 != 0 ||
395 1089048 : leaf3->hdr.info.hdr.pad != 0)
396 0 : xchk_da_set_corrupt(ds, level);
397 : } else {
398 0 : if (leaf->hdr.pad1 != 0 || leaf->hdr.info.pad != 0)
399 0 : xchk_da_set_corrupt(ds, level);
400 : }
401 :
402 : /* Check the leaf header */
403 1089048 : xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
404 1089051 : hdrsize = xfs_attr3_leaf_hdr_size(leaf);
405 :
406 1089051 : if (leafhdr.usedbytes > mp->m_attr_geo->blksize)
407 0 : xchk_da_set_corrupt(ds, level);
408 1089051 : if (leafhdr.firstused > mp->m_attr_geo->blksize)
409 0 : xchk_da_set_corrupt(ds, level);
410 1089051 : if (leafhdr.firstused < hdrsize)
411 0 : xchk_da_set_corrupt(ds, level);
412 1089051 : if (!xchk_xattr_set_map(ds->sc, ab->usedmap, 0, hdrsize))
413 0 : xchk_da_set_corrupt(ds, level);
414 :
415 1089051 : if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
416 0 : goto out;
417 :
418 1089051 : entries = xfs_attr3_leaf_entryp(leaf);
419 1089051 : if ((char *)&entries[leafhdr.count] > (char *)leaf + leafhdr.firstused)
420 0 : xchk_da_set_corrupt(ds, level);
421 :
422 1089051 : buf_end = (char *)bp->b_addr + mp->m_attr_geo->blksize;
423 14308452 : for (i = 0, ent = entries; i < leafhdr.count; ent++, i++) {
424 : /* Mark the leaf entry itself. */
425 13219421 : off = (char *)ent - (char *)leaf;
426 13219421 : if (!xchk_xattr_set_map(ds->sc, ab->usedmap, off,
427 : sizeof(xfs_attr_leaf_entry_t))) {
428 0 : xchk_da_set_corrupt(ds, level);
429 0 : goto out;
430 : }
431 :
432 : /* Check the entry and nameval. */
433 13220580 : xchk_xattr_entry(ds, level, buf_end, leaf, &leafhdr,
434 : ent, i, &usedbytes, &last_hashval);
435 :
436 13219401 : if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
437 0 : goto out;
438 : }
439 :
440 1089031 : if (!xchk_xattr_check_freemap(ds->sc, &leafhdr))
441 0 : xchk_da_set_corrupt(ds, level);
442 :
443 1089038 : if (leafhdr.usedbytes != usedbytes)
444 0 : xchk_da_set_corrupt(ds, level);
445 :
446 1089038 : out:
447 : return 0;
448 : }
449 :
450 : /* Scrub a attribute btree record. */
451 : STATIC int
452 13220978 : xchk_xattr_rec(
453 : struct xchk_da_btree *ds,
454 : int level)
455 : {
456 13220978 : struct xfs_mount *mp = ds->state->mp;
457 13220978 : struct xfs_da_state_blk *blk = &ds->state->path.blk[level];
458 13221267 : struct xfs_attr_leaf_name_local *lentry;
459 13221267 : struct xfs_attr_leaf_name_remote *rentry;
460 13221267 : struct xfs_buf *bp;
461 13221267 : struct xfs_attr_leaf_entry *ent;
462 13221267 : xfs_dahash_t calc_hash;
463 13221267 : xfs_dahash_t hash;
464 13221267 : int nameidx;
465 13221267 : int hdrsize;
466 13221267 : unsigned int badflags;
467 13221267 : int error;
468 :
469 13221267 : ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
470 :
471 13221267 : ent = xfs_attr3_leaf_entryp(blk->bp->b_addr) + blk->index;
472 :
473 : /* Check the whole block, if necessary. */
474 13221267 : error = xchk_xattr_block(ds, level);
475 13222464 : if (error)
476 0 : goto out;
477 13222464 : if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
478 0 : goto out;
479 :
480 : /* Check the hash of the entry. */
481 13222464 : error = xchk_da_btree_hash(ds, level, &ent->hashval);
482 13223630 : if (error)
483 0 : goto out;
484 :
485 : /* Find the attr entry's location. */
486 13223630 : bp = blk->bp;
487 13223630 : hdrsize = xfs_attr3_leaf_hdr_size(bp->b_addr);
488 13223630 : nameidx = be16_to_cpu(ent->nameidx);
489 13223630 : if (nameidx < hdrsize || nameidx >= mp->m_attr_geo->blksize) {
490 1627 : xchk_da_set_corrupt(ds, level);
491 0 : goto out;
492 : }
493 :
494 : /* Retrieve the entry and check it. */
495 13222003 : hash = be32_to_cpu(ent->hashval);
496 13222003 : badflags = ~(XFS_ATTR_LOCAL | XFS_ATTR_ROOT | XFS_ATTR_SECURE |
497 : XFS_ATTR_INCOMPLETE);
498 13222003 : if ((ent->flags & badflags) != 0)
499 0 : xchk_da_set_corrupt(ds, level);
500 13222055 : if (ent->flags & XFS_ATTR_LOCAL) {
501 13221852 : lentry = (struct xfs_attr_leaf_name_local *)
502 13221852 : (((char *)bp->b_addr) + nameidx);
503 13221852 : if (lentry->namelen <= 0) {
504 0 : xchk_da_set_corrupt(ds, level);
505 0 : goto out;
506 : }
507 13221852 : calc_hash = xfs_da_hashname(lentry->nameval, lentry->namelen);
508 : } else {
509 203 : rentry = (struct xfs_attr_leaf_name_remote *)
510 203 : (((char *)bp->b_addr) + nameidx);
511 203 : if (rentry->namelen <= 0) {
512 0 : xchk_da_set_corrupt(ds, level);
513 0 : goto out;
514 : }
515 203 : calc_hash = xfs_da_hashname(rentry->name, rentry->namelen);
516 : }
517 13221724 : if (calc_hash != hash)
518 0 : xchk_da_set_corrupt(ds, level);
519 :
520 13221724 : out:
521 13221724 : return error;
522 : }
523 :
524 : /* Check space usage of shortform attrs. */
525 : STATIC int
526 12250122 : xchk_xattr_check_sf(
527 : struct xfs_scrub *sc)
528 : {
529 12250122 : struct xchk_xattr_buf *ab = sc->buf;
530 12250122 : struct xfs_attr_shortform *sf;
531 12250122 : struct xfs_attr_sf_entry *sfe;
532 12250122 : struct xfs_attr_sf_entry *next;
533 12250122 : struct xfs_ifork *ifp;
534 12250122 : unsigned char *end;
535 12250122 : int i;
536 12250122 : int error = 0;
537 :
538 12250122 : ifp = xfs_ifork_ptr(sc->ip, XFS_ATTR_FORK);
539 :
540 12250122 : bitmap_zero(ab->usedmap, ifp->if_bytes);
541 12250173 : sf = (struct xfs_attr_shortform *)sc->ip->i_af.if_u1.if_data;
542 12250173 : end = (unsigned char *)ifp->if_u1.if_data + ifp->if_bytes;
543 12250173 : xchk_xattr_set_map(sc, ab->usedmap, 0, sizeof(sf->hdr));
544 :
545 12249957 : sfe = &sf->list[0];
546 12249957 : if ((unsigned char *)sfe > end) {
547 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
548 0 : return 0;
549 : }
550 :
551 26333913 : for (i = 0; i < sf->hdr.count; i++) {
552 14083883 : unsigned char *name = sfe->nameval;
553 14083883 : unsigned char *value = &sfe->nameval[sfe->namelen];
554 :
555 14083883 : if (xchk_should_terminate(sc, &error))
556 0 : return error;
557 :
558 14083751 : next = xfs_attr_sf_nextentry(sfe);
559 14083751 : if ((unsigned char *)next > end) {
560 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
561 0 : break;
562 : }
563 :
564 14083837 : if (!xchk_xattr_set_map(sc, ab->usedmap,
565 14083751 : (char *)sfe - (char *)sf,
566 : sizeof(struct xfs_attr_sf_entry))) {
567 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
568 0 : break;
569 : }
570 :
571 14083978 : if (!xchk_xattr_set_map(sc, ab->usedmap,
572 14083837 : (char *)name - (char *)sf,
573 14083837 : sfe->namelen)) {
574 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
575 0 : break;
576 : }
577 :
578 14083956 : if (!xchk_xattr_set_map(sc, ab->usedmap,
579 14083978 : (char *)value - (char *)sf,
580 14083978 : sfe->valuelen)) {
581 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
582 0 : break;
583 : }
584 :
585 14083956 : sfe = next;
586 : }
587 :
588 : return 0;
589 : }
590 :
591 : /* Scrub the extended attribute metadata. */
592 : int
593 250433283 : xchk_xattr(
594 : struct xfs_scrub *sc)
595 : {
596 250433283 : struct xchk_xattr sx = {
597 : .sc = sc,
598 : .context = {
599 250433283 : .dp = sc->ip,
600 250433283 : .tp = sc->tp,
601 : .resynch = 1,
602 : .put_listent = xchk_xattr_listent,
603 : .allow_incomplete = true,
604 : },
605 : };
606 250433283 : xfs_dablk_t last_checked = -1U;
607 250433283 : int error = 0;
608 :
609 250433283 : if (!xfs_inode_hasattr(sc->ip))
610 : return -ENOENT;
611 :
612 : /* Allocate memory for xattr checking. */
613 13312860 : error = xchk_setup_xattr_buf(sc, 0);
614 13312777 : if (error == -ENOMEM)
615 : return -EDEADLOCK;
616 13312777 : if (error)
617 : return error;
618 :
619 : /* Check the physical structure of the xattr. */
620 13312777 : if (sc->ip->i_af.if_format == XFS_DINODE_FMT_LOCAL)
621 12250096 : error = xchk_xattr_check_sf(sc);
622 : else
623 1062681 : error = xchk_da_btree(sc, XFS_ATTR_FORK, xchk_xattr_rec,
624 : &last_checked);
625 13312707 : if (error)
626 : return error;
627 :
628 13312565 : if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
629 : return 0;
630 :
631 : /*
632 : * Look up every xattr in this file by name and hash.
633 : *
634 : * Use the backend implementation of xfs_attr_list to call
635 : * xchk_xattr_listent on every attribute key in this inode.
636 : * In other words, we use the same iterator/callback mechanism
637 : * that listattr uses to scrub extended attributes, though in our
638 : * _listent function, we check the value of the attribute.
639 : *
640 : * The VFS only locks i_rwsem when modifying attrs, so keep all
641 : * three locks held because that's the only way to ensure we're
642 : * the only thread poking into the da btree. We traverse the da
643 : * btree while holding a leaf buffer locked for the xattr name
644 : * iteration, which doesn't really follow the usual buffer
645 : * locking order.
646 : */
647 13312570 : error = xfs_attr_list_ilocked(&sx.context);
648 13312660 : if (!xchk_fblock_process_error(sc, XFS_ATTR_FORK, 0, &error))
649 2 : return error;
650 :
651 : /* Did our listent function try to return any errors? */
652 13312663 : if (sx.context.seen_enough < 0)
653 : return sx.context.seen_enough;
654 :
655 : return 0;
656 : }
|