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 18636771 : xchk_xattr_buf_cleanup(
27 : void *priv)
28 : {
29 18636771 : struct xchk_xattr_buf *ab = priv;
30 :
31 18636771 : kvfree(ab->freemap);
32 18634297 : ab->freemap = NULL;
33 18634297 : kvfree(ab->usedmap);
34 18637087 : ab->usedmap = NULL;
35 18637087 : kvfree(ab->value);
36 18637932 : ab->value = NULL;
37 18637932 : ab->value_sz = 0;
38 18637932 : }
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 18638390 : xchk_xattr_want_freemap(
46 : struct xfs_scrub *sc)
47 : {
48 18638390 : struct xfs_ifork *ifp;
49 :
50 18638390 : if (sc->flags & XCHK_TRY_HARDER)
51 : return true;
52 :
53 18638390 : if (!sc->ip)
54 : return true;
55 :
56 18638390 : ifp = xfs_ifork_ptr(sc->ip, XFS_ATTR_FORK);
57 18638390 : if (!ifp)
58 : return false;
59 :
60 18638390 : 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 38515048 : xchk_setup_xattr_buf(
70 : struct xfs_scrub *sc,
71 : size_t value_size)
72 : {
73 38515048 : size_t bmp_sz;
74 38515048 : struct xchk_xattr_buf *ab = sc->buf;
75 38515048 : void *new_val;
76 :
77 38515048 : bmp_sz = sizeof(long) * BITS_TO_LONGS(sc->mp->m_attr_geo->blksize);
78 :
79 38515048 : if (ab)
80 19876593 : goto resize_value;
81 :
82 18638455 : ab = kvzalloc(sizeof(struct xchk_xattr_buf), XCHK_GFP_FLAGS);
83 18633460 : if (!ab)
84 : return -ENOMEM;
85 18633460 : sc->buf = ab;
86 18633460 : sc->buf_cleanup = xchk_xattr_buf_cleanup;
87 :
88 18633460 : ab->usedmap = kvmalloc(bmp_sz, XCHK_GFP_FLAGS);
89 18623835 : if (!ab->usedmap)
90 : return -ENOMEM;
91 :
92 18623835 : if (xchk_xattr_want_freemap(sc)) {
93 1394215 : ab->freemap = kvmalloc(bmp_sz, XCHK_GFP_FLAGS);
94 1394383 : if (!ab->freemap)
95 : return -ENOMEM;
96 : }
97 :
98 18624003 : resize_value:
99 38500596 : if (ab->value_sz >= value_size)
100 : return 0;
101 :
102 18109169 : if (ab->value) {
103 1220616 : kvfree(ab->value);
104 1220567 : ab->value = NULL;
105 1220567 : ab->value_sz = 0;
106 : }
107 :
108 18109120 : new_val = kvmalloc(value_size, XCHK_GFP_FLAGS);
109 18114574 : if (!new_val)
110 : return -ENOMEM;
111 :
112 18114574 : ab->value = new_val;
113 18114574 : ab->value_sz = value_size;
114 18114574 : return 0;
115 : }
116 :
117 : /* Set us up to scrub an inode's extended attributes. */
118 : int
119 298552499 : xchk_setup_xattr(
120 : struct xfs_scrub *sc)
121 : {
122 298552499 : 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 298552499 : 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 298552499 : 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 35439342 : 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 70908511 : struct xfs_da_args args = {
162 : .op_flags = XFS_DA_OP_NOTIME,
163 35439342 : .attr_filter = flags & XFS_ATTR_NSP_ONDISK_MASK,
164 35439342 : .geo = context->dp->i_mount->m_attr_geo,
165 : .whichfork = XFS_ATTR_FORK,
166 35469169 : .dp = context->dp,
167 : .name = name,
168 : .namelen = namelen,
169 35439342 : .hashval = xfs_da_hashname(name, namelen),
170 35469169 : .trans = context->tp,
171 : .valuelen = valuelen,
172 : };
173 35469169 : struct xchk_xattr_buf *ab;
174 35469169 : struct xchk_xattr *sx;
175 35469169 : int error = 0;
176 :
177 35469169 : sx = container_of(context, struct xchk_xattr, context);
178 35469169 : ab = sx->sc->buf;
179 :
180 35469169 : if (xchk_should_terminate(sx->sc, &error)) {
181 0 : context->seen_enough = error;
182 0 : return;
183 : }
184 :
185 35458659 : 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 35458659 : 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 35458659 : 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 35464867 : if (flags & XFS_ATTR_LOCAL)
209 15587014 : 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 19877853 : error = xchk_setup_xattr_buf(sx->sc, valuelen);
217 19880037 : if (error == -ENOMEM)
218 0 : error = -EDEADLOCK;
219 19880037 : if (error) {
220 0 : context->seen_enough = error;
221 0 : return;
222 : }
223 :
224 19880037 : args.value = ab->value;
225 :
226 19880037 : error = xfs_attr_get_ilocked(&args);
227 : /* ENODATA means the hash lookup failed and the attr is bad */
228 19873367 : if (error == -ENODATA)
229 0 : error = -EFSCORRUPTED;
230 19873367 : if (!xchk_fblock_process_error(sx->sc, XFS_ATTR_FORK, args.blkno,
231 : &error))
232 0 : goto fail_xref;
233 19872258 : if (args.valuelen != valuelen)
234 0 : xchk_fblock_set_corrupt(sx->sc, XFS_ATTR_FORK,
235 0 : args.blkno);
236 19872258 : fail_xref:
237 35459272 : 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 113908624 : xchk_xattr_set_map(
251 : struct xfs_scrub *sc,
252 : unsigned long *map,
253 : unsigned int start,
254 : unsigned int len)
255 : {
256 113908624 : unsigned int mapsize = sc->mp->m_attr_geo->blksize;
257 113908624 : bool ret = true;
258 :
259 113908624 : if (start >= mapsize)
260 : return false;
261 113908624 : if (start + len > mapsize) {
262 0 : len = mapsize - start;
263 0 : ret = false;
264 : }
265 :
266 113908624 : if (find_next_bit(map, mapsize, start) < start + len)
267 0 : ret = false;
268 113908181 : 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 1510311 : xchk_xattr_check_freemap(
279 : struct xfs_scrub *sc,
280 : struct xfs_attr3_icleaf_hdr *leafhdr)
281 : {
282 1510311 : struct xchk_xattr_buf *ab = sc->buf;
283 1510311 : unsigned int mapsize = sc->mp->m_attr_geo->blksize;
284 1510311 : int i;
285 :
286 : /* Construct bitmap of freemap contents. */
287 1510311 : bitmap_zero(ab->freemap, mapsize);
288 7550710 : for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
289 4530065 : if (!xchk_xattr_set_map(sc, ab->freemap,
290 4530568 : leafhdr->freemap[i].base,
291 4529938 : leafhdr->freemap[i].size))
292 : return false;
293 : }
294 :
295 : /* Look for bits that are set in freemap and are marked in use. */
296 1510461 : 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 15582241 : 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 15582241 : struct xfs_mount *mp = ds->state->mp;
316 15582241 : struct xchk_xattr_buf *ab = ds->sc->buf;
317 15582241 : char *name_end;
318 15582241 : struct xfs_attr_leaf_name_local *lentry;
319 15582241 : struct xfs_attr_leaf_name_remote *rentry;
320 15582241 : unsigned int nameidx;
321 15582241 : unsigned int namesize;
322 :
323 15582241 : if (ent->pad2 != 0)
324 0 : xchk_da_set_corrupt(ds, level);
325 :
326 : /* Hash values in order? */
327 15582241 : if (be32_to_cpu(ent->hashval) < *last_hashval)
328 0 : xchk_da_set_corrupt(ds, level);
329 15582241 : *last_hashval = be32_to_cpu(ent->hashval);
330 :
331 15582241 : nameidx = be16_to_cpu(ent->nameidx);
332 15582241 : if (nameidx < leafhdr->firstused ||
333 15582241 : 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 15582241 : if (ent->flags & XFS_ATTR_LOCAL) {
340 15581556 : lentry = xfs_attr3_leaf_name_local(leaf, idx);
341 15581556 : namesize = xfs_attr_leaf_entsize_local(lentry->namelen,
342 15581556 : be16_to_cpu(lentry->valuelen));
343 15581556 : name_end = (char *)lentry + namesize;
344 15581556 : if (lentry->namelen == 0)
345 0 : xchk_da_set_corrupt(ds, level);
346 : } else {
347 685 : rentry = xfs_attr3_leaf_name_remote(leaf, idx);
348 685 : namesize = xfs_attr_leaf_entsize_remote(rentry->namelen);
349 685 : name_end = (char *)rentry + namesize;
350 685 : if (rentry->namelen == 0 || rentry->valueblk == 0)
351 0 : xchk_da_set_corrupt(ds, level);
352 : }
353 15582241 : if (name_end > buf_end)
354 0 : xchk_da_set_corrupt(ds, level);
355 :
356 15582241 : if (!xchk_xattr_set_map(ds->sc, ab->usedmap, nameidx, namesize))
357 0 : xchk_da_set_corrupt(ds, level);
358 15583231 : if (!(ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
359 15588756 : *usedbytes += namesize;
360 : }
361 :
362 : /* Scrub an attribute leaf. */
363 : STATIC int
364 15610923 : xchk_xattr_block(
365 : struct xchk_da_btree *ds,
366 : int level)
367 : {
368 15610923 : struct xfs_attr3_icleaf_hdr leafhdr;
369 15610923 : struct xfs_mount *mp = ds->state->mp;
370 15610923 : struct xfs_da_state_blk *blk = &ds->state->path.blk[level];
371 15609272 : struct xfs_buf *bp = blk->bp;
372 15609272 : xfs_dablk_t *last_checked = ds->private;
373 15609272 : struct xfs_attr_leafblock *leaf = bp->b_addr;
374 15609272 : struct xfs_attr_leaf_entry *ent;
375 15609272 : struct xfs_attr_leaf_entry *entries;
376 15609272 : struct xchk_xattr_buf *ab = ds->sc->buf;
377 15609272 : char *buf_end;
378 15609272 : size_t off;
379 15609272 : __u32 last_hashval = 0;
380 15609272 : unsigned int usedbytes = 0;
381 15609272 : unsigned int hdrsize;
382 15609272 : int i;
383 :
384 15609272 : if (*last_checked == blk->blkno)
385 : return 0;
386 :
387 1502947 : *last_checked = blk->blkno;
388 1502947 : bitmap_zero(ab->usedmap, mp->m_attr_geo->blksize);
389 :
390 : /* Check all the padding. */
391 1506050 : if (xfs_has_crc(ds->sc->mp)) {
392 1506050 : struct xfs_attr3_leafblock *leaf3 = bp->b_addr;
393 :
394 1506050 : if (leaf3->hdr.pad1 != 0 || leaf3->hdr.pad2 != 0 ||
395 1506035 : leaf3->hdr.info.hdr.pad != 0)
396 15 : 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 1506035 : xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
404 1508674 : hdrsize = xfs_attr3_leaf_hdr_size(leaf);
405 :
406 1508674 : if (leafhdr.usedbytes > mp->m_attr_geo->blksize)
407 0 : xchk_da_set_corrupt(ds, level);
408 1508674 : if (leafhdr.firstused > mp->m_attr_geo->blksize)
409 0 : xchk_da_set_corrupt(ds, level);
410 1508674 : if (leafhdr.firstused < hdrsize)
411 0 : xchk_da_set_corrupt(ds, level);
412 1508674 : if (!xchk_xattr_set_map(ds->sc, ab->usedmap, 0, hdrsize))
413 0 : xchk_da_set_corrupt(ds, level);
414 :
415 1505007 : if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
416 0 : goto out;
417 :
418 1505007 : entries = xfs_attr3_leaf_entryp(leaf);
419 1505007 : if ((char *)&entries[leafhdr.count] > (char *)leaf + leafhdr.firstused)
420 0 : xchk_da_set_corrupt(ds, level);
421 :
422 1505007 : buf_end = (char *)bp->b_addr + mp->m_attr_geo->blksize;
423 17088316 : for (i = 0, ent = entries; i < leafhdr.count; ent++, i++) {
424 : /* Mark the leaf entry itself. */
425 15577731 : off = (char *)ent - (char *)leaf;
426 15577731 : 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 15568669 : xchk_xattr_entry(ds, level, buf_end, leaf, &leafhdr,
434 : ent, i, &usedbytes, &last_hashval);
435 :
436 15583309 : if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
437 0 : goto out;
438 : }
439 :
440 1510585 : if (!xchk_xattr_check_freemap(ds->sc, &leafhdr))
441 0 : xchk_da_set_corrupt(ds, level);
442 :
443 1509893 : if (leafhdr.usedbytes != usedbytes)
444 0 : xchk_da_set_corrupt(ds, level);
445 :
446 1509893 : out:
447 : return 0;
448 : }
449 :
450 : /* Scrub a attribute btree record. */
451 : STATIC int
452 15606865 : xchk_xattr_rec(
453 : struct xchk_da_btree *ds,
454 : int level)
455 : {
456 15606865 : struct xfs_mount *mp = ds->state->mp;
457 15606865 : struct xfs_da_state_blk *blk = &ds->state->path.blk[level];
458 15606791 : struct xfs_attr_leaf_name_local *lentry;
459 15606791 : struct xfs_attr_leaf_name_remote *rentry;
460 15606791 : struct xfs_buf *bp;
461 15606791 : struct xfs_attr_leaf_entry *ent;
462 15606791 : xfs_dahash_t calc_hash;
463 15606791 : xfs_dahash_t hash;
464 15606791 : int nameidx;
465 15606791 : int hdrsize;
466 15606791 : unsigned int badflags;
467 15606791 : int error;
468 :
469 15606791 : ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
470 :
471 15606791 : ent = xfs_attr3_leaf_entryp(blk->bp->b_addr) + blk->index;
472 :
473 : /* Check the whole block, if necessary. */
474 15606791 : error = xchk_xattr_block(ds, level);
475 15613189 : if (error)
476 0 : goto out;
477 15613189 : if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
478 0 : goto out;
479 :
480 : /* Check the hash of the entry. */
481 15613189 : error = xchk_da_btree_hash(ds, level, &ent->hashval);
482 15612538 : if (error)
483 0 : goto out;
484 :
485 : /* Find the attr entry's location. */
486 15612538 : bp = blk->bp;
487 15612538 : hdrsize = xfs_attr3_leaf_hdr_size(bp->b_addr);
488 15612538 : nameidx = be16_to_cpu(ent->nameidx);
489 15612538 : if (nameidx < hdrsize || nameidx >= mp->m_attr_geo->blksize) {
490 0 : xchk_da_set_corrupt(ds, level);
491 0 : goto out;
492 : }
493 :
494 : /* Retrieve the entry and check it. */
495 15612538 : hash = be32_to_cpu(ent->hashval);
496 15612538 : badflags = ~(XFS_ATTR_LOCAL | XFS_ATTR_ROOT | XFS_ATTR_SECURE |
497 : XFS_ATTR_INCOMPLETE);
498 15612538 : if ((ent->flags & badflags) != 0)
499 0 : xchk_da_set_corrupt(ds, level);
500 15612538 : if (ent->flags & XFS_ATTR_LOCAL) {
501 15611853 : lentry = (struct xfs_attr_leaf_name_local *)
502 15611853 : (((char *)bp->b_addr) + nameidx);
503 15611853 : if (lentry->namelen <= 0) {
504 0 : xchk_da_set_corrupt(ds, level);
505 0 : goto out;
506 : }
507 15611853 : calc_hash = xfs_da_hashname(lentry->nameval, lentry->namelen);
508 : } else {
509 685 : rentry = (struct xfs_attr_leaf_name_remote *)
510 685 : (((char *)bp->b_addr) + nameidx);
511 685 : if (rentry->namelen <= 0) {
512 0 : xchk_da_set_corrupt(ds, level);
513 0 : goto out;
514 : }
515 685 : calc_hash = xfs_da_hashname(rentry->name, rentry->namelen);
516 : }
517 15608256 : if (calc_hash != hash)
518 0 : xchk_da_set_corrupt(ds, level);
519 :
520 15608256 : out:
521 15608256 : return error;
522 : }
523 :
524 : /* Check space usage of shortform attrs. */
525 : STATIC int
526 17233249 : xchk_xattr_check_sf(
527 : struct xfs_scrub *sc)
528 : {
529 17233249 : struct xchk_xattr_buf *ab = sc->buf;
530 17233249 : struct xfs_attr_shortform *sf;
531 17233249 : struct xfs_attr_sf_entry *sfe;
532 17233249 : struct xfs_attr_sf_entry *next;
533 17233249 : struct xfs_ifork *ifp;
534 17233249 : unsigned char *end;
535 17233249 : int i;
536 17233249 : int error = 0;
537 :
538 17233249 : ifp = xfs_ifork_ptr(sc->ip, XFS_ATTR_FORK);
539 :
540 17233249 : bitmap_zero(ab->usedmap, ifp->if_bytes);
541 17229209 : sf = (struct xfs_attr_shortform *)sc->ip->i_af.if_u1.if_data;
542 17229209 : end = (unsigned char *)ifp->if_u1.if_data + ifp->if_bytes;
543 17229209 : xchk_xattr_set_map(sc, ab->usedmap, 0, sizeof(sf->hdr));
544 :
545 17229968 : sfe = &sf->list[0];
546 17229968 : if ((unsigned char *)sfe > end) {
547 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
548 0 : return 0;
549 : }
550 :
551 37110081 : for (i = 0; i < sf->hdr.count; i++) {
552 19868292 : unsigned char *name = sfe->nameval;
553 19868292 : unsigned char *value = &sfe->nameval[sfe->namelen];
554 :
555 19868292 : if (xchk_should_terminate(sc, &error))
556 1 : return error;
557 :
558 19878105 : next = xfs_attr_sf_nextentry(sfe);
559 19878105 : if ((unsigned char *)next > end) {
560 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
561 0 : break;
562 : }
563 :
564 19880248 : if (!xchk_xattr_set_map(sc, ab->usedmap,
565 19878105 : (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 19882634 : if (!xchk_xattr_set_map(sc, ab->usedmap,
572 19880248 : (char *)name - (char *)sf,
573 19880248 : sfe->namelen)) {
574 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
575 0 : break;
576 : }
577 :
578 19880113 : if (!xchk_xattr_set_map(sc, ab->usedmap,
579 19882634 : (char *)value - (char *)sf,
580 19882634 : sfe->valuelen)) {
581 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
582 0 : break;
583 : }
584 :
585 19880113 : sfe = next;
586 : }
587 :
588 : return 0;
589 : }
590 :
591 : /* Scrub the extended attribute metadata. */
592 : int
593 296774891 : xchk_xattr(
594 : struct xfs_scrub *sc)
595 : {
596 296774891 : struct xchk_xattr sx = {
597 : .sc = sc,
598 : .context = {
599 296774891 : .dp = sc->ip,
600 296774891 : .tp = sc->tp,
601 : .resynch = 1,
602 : .put_listent = xchk_xattr_listent,
603 : .allow_incomplete = true,
604 : },
605 : };
606 296774891 : xfs_dablk_t last_checked = -1U;
607 296774891 : int error = 0;
608 :
609 296774891 : if (!xfs_inode_hasattr(sc->ip))
610 : return -ENOENT;
611 :
612 : /* Allocate memory for xattr checking. */
613 18634428 : error = xchk_setup_xattr_buf(sc, 0);
614 18627740 : if (error == -ENOMEM)
615 : return -EDEADLOCK;
616 18627740 : if (error)
617 : return error;
618 :
619 : /* Check the physical structure of the xattr. */
620 18627740 : if (sc->ip->i_af.if_format == XFS_DINODE_FMT_LOCAL)
621 17230189 : error = xchk_xattr_check_sf(sc);
622 : else
623 1397551 : error = xchk_da_btree(sc, XFS_ATTR_FORK, xchk_xattr_rec,
624 : &last_checked);
625 18642535 : if (error)
626 : return error;
627 :
628 18640936 : 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 18640791 : error = xfs_attr_list_ilocked(&sx.context);
648 18635788 : if (!xchk_fblock_process_error(sc, XFS_ATTR_FORK, 0, &error))
649 11 : return error;
650 :
651 : /* Did our listent function try to return any errors? */
652 18635112 : if (sx.context.seen_enough < 0)
653 : return sx.context.seen_enough;
654 :
655 : return 0;
656 : }
|