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_trans.h"
14 : #include "xfs_inode.h"
15 : #include "xfs_da_format.h"
16 : #include "xfs_da_btree.h"
17 : #include "xfs_attr.h"
18 : #include "xfs_attr_leaf.h"
19 : #include "xfs_attr_sf.h"
20 : #include "scrub/scrub.h"
21 : #include "scrub/common.h"
22 : #include "scrub/dabtree.h"
23 : #include "scrub/attr.h"
24 : #include "scrub/listxattr.h"
25 : #include "scrub/repair.h"
26 :
27 : /* Free the buffers linked from the xattr buffer. */
28 : static void
29 77708909 : xchk_xattr_buf_cleanup(
30 : void *priv)
31 : {
32 77708909 : struct xchk_xattr_buf *ab = priv;
33 :
34 77708909 : kvfree(ab->freemap);
35 77709755 : ab->freemap = NULL;
36 77709755 : kvfree(ab->usedmap);
37 77709803 : ab->usedmap = NULL;
38 77709803 : kvfree(ab->value);
39 77709804 : ab->value = NULL;
40 77709804 : ab->value_sz = 0;
41 77709804 : kvfree(ab->name);
42 77709699 : ab->name = NULL;
43 77709699 : }
44 :
45 : /*
46 : * Allocate the free space bitmap if we're trying harder; there are leaf blocks
47 : * in the attr fork; or we can't tell if there are leaf blocks.
48 : */
49 : static inline bool
50 77708714 : xchk_xattr_want_freemap(
51 : struct xfs_scrub *sc)
52 : {
53 77708714 : struct xfs_ifork *ifp;
54 :
55 77708714 : if (sc->flags & XCHK_TRY_HARDER)
56 : return true;
57 :
58 77708714 : if (!sc->ip)
59 : return true;
60 :
61 77708714 : ifp = xfs_ifork_ptr(sc->ip, XFS_ATTR_FORK);
62 77708714 : if (!ifp)
63 : return false;
64 :
65 77708714 : return xfs_ifork_has_extents(ifp);
66 : }
67 :
68 : /*
69 : * Allocate enough memory to hold an attr value and attr block bitmaps,
70 : * reallocating the buffer if necessary. Buffer contents are not preserved
71 : * across a reallocation.
72 : */
73 : int
74 77887481 : xchk_setup_xattr_buf(
75 : struct xfs_scrub *sc,
76 : size_t value_size)
77 : {
78 77887481 : size_t bmp_sz;
79 77887481 : struct xchk_xattr_buf *ab = sc->buf;
80 77887481 : void *new_val;
81 :
82 77887481 : bmp_sz = sizeof(long) * BITS_TO_LONGS(sc->mp->m_attr_geo->blksize);
83 :
84 77887481 : if (ab)
85 178957 : goto resize_value;
86 :
87 77708904 : ab = kvzalloc(sizeof(struct xchk_xattr_buf), XCHK_GFP_FLAGS);
88 77708791 : if (!ab)
89 : return -ENOMEM;
90 77708791 : sc->buf = ab;
91 77708791 : sc->buf_cleanup = xchk_xattr_buf_cleanup;
92 :
93 77708791 : ab->usedmap = kvmalloc(bmp_sz, XCHK_GFP_FLAGS);
94 77709051 : if (!ab->usedmap)
95 : return -ENOMEM;
96 :
97 77709051 : if (xchk_xattr_want_freemap(sc)) {
98 2154352 : ab->freemap = kvmalloc(bmp_sz, XCHK_GFP_FLAGS);
99 2154348 : if (!ab->freemap)
100 : return -ENOMEM;
101 : }
102 :
103 155418094 : if (xchk_could_repair(sc)) {
104 178489 : ab->name = kvmalloc(XATTR_NAME_MAX + 1, XCHK_GFP_FLAGS);
105 178489 : if (!ab->name)
106 : return -ENOMEM;
107 : }
108 :
109 77709047 : resize_value:
110 77887624 : if (ab->value_sz >= value_size)
111 : return 0;
112 :
113 178844 : if (ab->value) {
114 0 : kvfree(ab->value);
115 0 : ab->value = NULL;
116 0 : ab->value_sz = 0;
117 : }
118 :
119 178844 : new_val = kvmalloc(value_size, XCHK_GFP_FLAGS);
120 178844 : if (!new_val)
121 : return -ENOMEM;
122 :
123 178844 : ab->value = new_val;
124 178844 : ab->value_sz = value_size;
125 178844 : return 0;
126 : }
127 :
128 : /* Set us up to scrub an inode's extended attributes. */
129 : int
130 78254994 : xchk_setup_xattr(
131 : struct xfs_scrub *sc)
132 : {
133 78254994 : int error;
134 :
135 156509988 : if (xchk_could_repair(sc)) {
136 182232 : error = xrep_setup_xattr(sc);
137 182232 : if (error)
138 : return error;
139 : }
140 :
141 : /*
142 : * We failed to get memory while checking attrs, so this time try to
143 : * get all the memory we're ever going to need. Allocate the buffer
144 : * without the inode lock held, which means we can sleep.
145 : */
146 78254994 : if (sc->flags & XCHK_TRY_HARDER) {
147 0 : error = xchk_setup_xattr_buf(sc, XATTR_SIZE_MAX);
148 0 : if (error)
149 : return error;
150 : }
151 :
152 78254994 : return xchk_setup_inode_contents(sc, 0);
153 : }
154 :
155 : /* Extended Attributes */
156 :
157 : /*
158 : * Check that an extended attribute key can be looked up by hash.
159 : *
160 : * We use the extended attribute walk helper to call this function for every
161 : * attribute key in an inode. Once we're here, we load the attribute value to
162 : * see if any errors happen, or if we get more or less data than we expected.
163 : */
164 : static int
165 126928416 : xchk_xattr_actor(
166 : struct xfs_scrub *sc,
167 : struct xfs_inode *ip,
168 : unsigned int attr_flags,
169 : const unsigned char *name,
170 : unsigned int namelen,
171 : const void *value,
172 : unsigned int valuelen,
173 : void *priv)
174 : {
175 253861418 : struct xfs_da_args args = {
176 : .op_flags = XFS_DA_OP_NOTIME,
177 126928416 : .attr_filter = attr_flags & XFS_ATTR_NSP_ONDISK_MASK,
178 126928416 : .geo = sc->mp->m_attr_geo,
179 : .whichfork = XFS_ATTR_FORK,
180 : .dp = ip,
181 : .name = name,
182 : .namelen = namelen,
183 126928416 : .hashval = xfs_da_hashname(name, namelen),
184 126933002 : .trans = sc->tp,
185 : .valuelen = valuelen,
186 126933002 : .owner = ip->i_ino,
187 : };
188 126933002 : struct xchk_xattr_buf *ab;
189 126933002 : int error = 0;
190 :
191 126933002 : ab = sc->buf;
192 :
193 126933002 : if (xchk_should_terminate(sc, &error))
194 0 : return error;
195 :
196 126932882 : if (attr_flags & XFS_ATTR_INCOMPLETE) {
197 : /* Incomplete attr key, just mark the inode for preening. */
198 0 : xchk_ino_set_preen(sc, ip->i_ino);
199 0 : return 0;
200 : }
201 :
202 : /* Only one namespace bit allowed. */
203 253867405 : if (hweight32(attr_flags & XFS_ATTR_NSP_ONDISK_MASK) > 1) {
204 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, args.blkno);
205 0 : return -ECANCELED;
206 : }
207 :
208 : /* Does this name make sense? */
209 126934523 : if (!xfs_attr_namecheck(sc->mp, name, namelen, attr_flags)) {
210 2 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, args.blkno);
211 2 : return -ECANCELED;
212 : }
213 :
214 : /*
215 : * Local and shortform xattr values are stored in the attr leaf block,
216 : * so we don't need to retrieve the value from a remote block to detect
217 : * corruption problems.
218 : */
219 126935148 : if (value)
220 : return 0;
221 :
222 : /*
223 : * Try to allocate enough memory to extract the attr value. If that
224 : * doesn't work, return -EDEADLOCK as a signal to try again with a
225 : * maximally sized buffer.
226 : */
227 488 : error = xchk_setup_xattr_buf(sc, valuelen);
228 488 : if (error == -ENOMEM)
229 0 : error = -EDEADLOCK;
230 488 : if (error)
231 : return error;
232 :
233 488 : args.value = ab->value;
234 :
235 488 : error = xfs_attr_get_ilocked(&args);
236 : /* ENODATA means the hash lookup failed and the attr is bad */
237 488 : if (error == -ENODATA)
238 0 : error = -EFSCORRUPTED;
239 488 : if (!xchk_fblock_process_error(sc, XFS_ATTR_FORK, args.blkno,
240 : &error))
241 0 : return error;
242 488 : if (args.valuelen != valuelen)
243 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, args.blkno);
244 :
245 : return 0;
246 : }
247 :
248 : /*
249 : * Mark a range [start, start+len) in this map. Returns true if the
250 : * region was free, and false if there's a conflict or a problem.
251 : *
252 : * Within a char, the lowest bit of the char represents the byte with
253 : * the smallest address
254 : */
255 : bool
256 426527681 : xchk_xattr_set_map(
257 : struct xfs_scrub *sc,
258 : unsigned long *map,
259 : unsigned int start,
260 : unsigned int len)
261 : {
262 426527681 : unsigned int mapsize = sc->mp->m_attr_geo->blksize;
263 426527681 : bool ret = true;
264 :
265 426527681 : if (start >= mapsize)
266 : return false;
267 426527681 : if (start + len > mapsize) {
268 0 : len = mapsize - start;
269 0 : ret = false;
270 : }
271 :
272 426527681 : if (find_next_bit(map, mapsize, start) < start + len)
273 0 : ret = false;
274 426561215 : bitmap_set(map, start, len);
275 :
276 : return ret;
277 : }
278 :
279 : /*
280 : * Check the leaf freemap from the usage bitmap. Returns false if the
281 : * attr freemap has problems or points to used space.
282 : */
283 : STATIC bool
284 2223985 : xchk_xattr_check_freemap(
285 : struct xfs_scrub *sc,
286 : struct xfs_attr3_icleaf_hdr *leafhdr)
287 : {
288 2223985 : struct xchk_xattr_buf *ab = sc->buf;
289 2223985 : unsigned int mapsize = sc->mp->m_attr_geo->blksize;
290 2223985 : int i;
291 :
292 : /* Construct bitmap of freemap contents. */
293 2223985 : bitmap_zero(ab->freemap, mapsize);
294 11119566 : for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
295 6671601 : if (!xchk_xattr_set_map(sc, ab->freemap,
296 6671618 : leafhdr->freemap[i].base,
297 6671618 : leafhdr->freemap[i].size))
298 : return false;
299 : }
300 :
301 : /* Look for bits that are set in freemap and are marked in use. */
302 2223963 : return !bitmap_intersects(ab->freemap, ab->usedmap, mapsize);
303 : }
304 :
305 : /*
306 : * Check this leaf entry's relations to everything else.
307 : * Returns the number of bytes used for the name/value data.
308 : */
309 : STATIC void
310 41179479 : xchk_xattr_entry(
311 : struct xchk_da_btree *ds,
312 : int level,
313 : char *buf_end,
314 : struct xfs_attr_leafblock *leaf,
315 : struct xfs_attr3_icleaf_hdr *leafhdr,
316 : struct xfs_attr_leaf_entry *ent,
317 : int idx,
318 : unsigned int *usedbytes,
319 : __u32 *last_hashval)
320 : {
321 41179479 : struct xfs_mount *mp = ds->state->mp;
322 41179479 : struct xchk_xattr_buf *ab = ds->sc->buf;
323 41179479 : char *name_end;
324 41179479 : struct xfs_attr_leaf_name_local *lentry;
325 41179479 : struct xfs_attr_leaf_name_remote *rentry;
326 41179479 : unsigned int nameidx;
327 41179479 : unsigned int namesize;
328 :
329 41179479 : if (ent->pad2 != 0)
330 0 : xchk_da_set_corrupt(ds, level);
331 :
332 : /* Hash values in order? */
333 82358958 : if (be32_to_cpu(ent->hashval) < *last_hashval)
334 0 : xchk_da_set_corrupt(ds, level);
335 41179297 : *last_hashval = be32_to_cpu(ent->hashval);
336 :
337 41179297 : nameidx = be16_to_cpu(ent->nameidx);
338 41179297 : if (nameidx < leafhdr->firstused ||
339 41179297 : nameidx >= mp->m_attr_geo->blksize) {
340 1954 : xchk_da_set_corrupt(ds, level);
341 1954 : return;
342 : }
343 :
344 : /* Check the name information. */
345 41177343 : if (ent->flags & XFS_ATTR_LOCAL) {
346 41176855 : lentry = xfs_attr3_leaf_name_local(leaf, idx);
347 41176855 : namesize = xfs_attr_leaf_entsize_local(lentry->namelen,
348 41176855 : be16_to_cpu(lentry->valuelen));
349 41176855 : name_end = (char *)lentry + namesize;
350 41176855 : if (lentry->namelen == 0)
351 0 : xchk_da_set_corrupt(ds, level);
352 : } else {
353 488 : rentry = xfs_attr3_leaf_name_remote(leaf, idx);
354 488 : namesize = xfs_attr_leaf_entsize_remote(rentry->namelen);
355 488 : name_end = (char *)rentry + namesize;
356 488 : if (rentry->namelen == 0 || rentry->valueblk == 0)
357 0 : xchk_da_set_corrupt(ds, level);
358 : }
359 41177343 : if (name_end > buf_end)
360 0 : xchk_da_set_corrupt(ds, level);
361 :
362 41177343 : if (!xchk_xattr_set_map(ds->sc, ab->usedmap, nameidx, namesize))
363 0 : xchk_da_set_corrupt(ds, level);
364 41181302 : if (!(ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
365 41189987 : *usedbytes += namesize;
366 : }
367 :
368 : /* Scrub an attribute leaf. */
369 : STATIC int
370 41203755 : xchk_xattr_block(
371 : struct xchk_da_btree *ds,
372 : int level)
373 : {
374 41203755 : struct xfs_attr3_icleaf_hdr leafhdr;
375 41203755 : struct xfs_mount *mp = ds->state->mp;
376 41203755 : struct xfs_da_state_blk *blk = &ds->state->path.blk[level];
377 41203755 : struct xfs_buf *bp = blk->bp;
378 41203755 : xfs_dablk_t *last_checked = ds->private;
379 41203755 : struct xfs_attr_leafblock *leaf = bp->b_addr;
380 41203755 : struct xfs_attr_leaf_entry *ent;
381 41203755 : struct xfs_attr_leaf_entry *entries;
382 41203755 : struct xchk_xattr_buf *ab = ds->sc->buf;
383 41203755 : char *buf_end;
384 41203755 : size_t off;
385 41203755 : __u32 last_hashval = 0;
386 41203755 : unsigned int usedbytes = 0;
387 41203755 : unsigned int hdrsize;
388 41203755 : int i;
389 :
390 41203755 : if (*last_checked == blk->blkno)
391 : return 0;
392 :
393 2224023 : *last_checked = blk->blkno;
394 2224023 : bitmap_zero(ab->usedmap, mp->m_attr_geo->blksize);
395 :
396 : /* Check all the padding. */
397 2224021 : if (xfs_has_crc(ds->sc->mp)) {
398 2224021 : struct xfs_attr3_leafblock *leaf3 = bp->b_addr;
399 :
400 2224021 : if (leaf3->hdr.pad1 != 0 || leaf3->hdr.pad2 != 0 ||
401 2224023 : leaf3->hdr.info.hdr.pad != 0)
402 1 : xchk_da_set_corrupt(ds, level);
403 : } else {
404 0 : if (leaf->hdr.pad1 != 0 || leaf->hdr.info.pad != 0)
405 0 : xchk_da_set_corrupt(ds, level);
406 : }
407 :
408 : /* Check the leaf header */
409 2224023 : xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
410 2224018 : hdrsize = xfs_attr3_leaf_hdr_size(leaf);
411 :
412 : /*
413 : * Empty xattr leaf blocks mapped at block 0 are probably a byproduct
414 : * of a race between setxattr and a log shutdown. Anywhere else in the
415 : * attr fork is a corruption.
416 : */
417 2224018 : if (leafhdr.count == 0) {
418 0 : if (blk->blkno == 0)
419 0 : xchk_da_set_preen(ds, level);
420 : else
421 0 : xchk_da_set_corrupt(ds, level);
422 : }
423 2224018 : if (leafhdr.usedbytes > mp->m_attr_geo->blksize)
424 0 : xchk_da_set_corrupt(ds, level);
425 2224018 : if (leafhdr.firstused > mp->m_attr_geo->blksize)
426 0 : xchk_da_set_corrupt(ds, level);
427 2224018 : if (leafhdr.firstused < hdrsize)
428 0 : xchk_da_set_corrupt(ds, level);
429 2224018 : if (!xchk_xattr_set_map(ds->sc, ab->usedmap, 0, hdrsize))
430 0 : xchk_da_set_corrupt(ds, level);
431 2224022 : if (leafhdr.holes)
432 1899713 : xchk_da_set_preen(ds, level);
433 :
434 2224023 : if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
435 0 : goto out;
436 :
437 2224023 : entries = xfs_attr3_leaf_entryp(leaf);
438 2224023 : if ((char *)&entries[leafhdr.count] > (char *)leaf + leafhdr.firstused)
439 0 : xchk_da_set_corrupt(ds, level);
440 :
441 2224023 : buf_end = (char *)bp->b_addr + mp->m_attr_geo->blksize;
442 43402016 : for (i = 0, ent = entries; i < leafhdr.count; ent++, i++) {
443 : /* Mark the leaf entry itself. */
444 41178074 : off = (char *)ent - (char *)leaf;
445 41178074 : if (!xchk_xattr_set_map(ds->sc, ab->usedmap, off,
446 : sizeof(xfs_attr_leaf_entry_t))) {
447 0 : xchk_da_set_corrupt(ds, level);
448 0 : goto out;
449 : }
450 :
451 : /* Check the entry and nameval. */
452 41178583 : xchk_xattr_entry(ds, level, buf_end, leaf, &leafhdr,
453 : ent, i, &usedbytes, &last_hashval);
454 :
455 41177993 : if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
456 0 : goto out;
457 : }
458 :
459 2223942 : if (!xchk_xattr_check_freemap(ds->sc, &leafhdr))
460 0 : xchk_da_set_corrupt(ds, level);
461 :
462 2223977 : if (leafhdr.usedbytes != usedbytes)
463 0 : xchk_da_set_corrupt(ds, level);
464 :
465 2223977 : out:
466 : return 0;
467 : }
468 :
469 : /* Scrub a attribute btree record. */
470 : STATIC int
471 41193643 : xchk_xattr_rec(
472 : struct xchk_da_btree *ds,
473 : int level)
474 : {
475 41193643 : struct xfs_mount *mp = ds->state->mp;
476 41193643 : struct xfs_da_state_blk *blk = &ds->state->path.blk[level];
477 41193643 : struct xfs_attr_leaf_name_local *lentry;
478 41193643 : struct xfs_attr_leaf_name_remote *rentry;
479 41193643 : struct xfs_buf *bp;
480 41193643 : struct xfs_attr_leaf_entry *ent;
481 41193643 : xfs_dahash_t calc_hash;
482 41193643 : xfs_dahash_t hash;
483 41193643 : int nameidx;
484 41193643 : int hdrsize;
485 41193643 : unsigned int badflags;
486 41193643 : int error;
487 :
488 41193643 : ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
489 :
490 41193643 : ent = xfs_attr3_leaf_entryp(blk->bp->b_addr) + blk->index;
491 :
492 : /* Check the whole block, if necessary. */
493 41193643 : error = xchk_xattr_block(ds, level);
494 41204058 : if (error)
495 0 : goto out;
496 41204058 : if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
497 0 : goto out;
498 :
499 : /* Check the hash of the entry. */
500 41204058 : error = xchk_da_btree_hash(ds, level, &ent->hashval);
501 41200412 : if (error)
502 0 : goto out;
503 :
504 : /* Find the attr entry's location. */
505 41200412 : bp = blk->bp;
506 41200412 : hdrsize = xfs_attr3_leaf_hdr_size(bp->b_addr);
507 41200412 : nameidx = be16_to_cpu(ent->nameidx);
508 41200412 : if (nameidx < hdrsize || nameidx >= mp->m_attr_geo->blksize) {
509 169 : xchk_da_set_corrupt(ds, level);
510 0 : goto out;
511 : }
512 :
513 : /* Retrieve the entry and check it. */
514 41200408 : hash = be32_to_cpu(ent->hashval);
515 41200408 : badflags = ~(XFS_ATTR_LOCAL | XFS_ATTR_ROOT | XFS_ATTR_SECURE |
516 : XFS_ATTR_INCOMPLETE | XFS_ATTR_PARENT);
517 41200408 : if ((ent->flags & badflags) != 0)
518 0 : xchk_da_set_corrupt(ds, level);
519 41200170 : if (ent->flags & XFS_ATTR_LOCAL) {
520 41199682 : lentry = (struct xfs_attr_leaf_name_local *)
521 41199682 : (((char *)bp->b_addr) + nameidx);
522 41199682 : if (lentry->namelen <= 0) {
523 0 : xchk_da_set_corrupt(ds, level);
524 0 : goto out;
525 : }
526 41199682 : calc_hash = xfs_da_hashname(lentry->nameval, lentry->namelen);
527 : } else {
528 488 : rentry = (struct xfs_attr_leaf_name_remote *)
529 488 : (((char *)bp->b_addr) + nameidx);
530 488 : if (rentry->namelen <= 0) {
531 0 : xchk_da_set_corrupt(ds, level);
532 0 : goto out;
533 : }
534 488 : calc_hash = xfs_da_hashname(rentry->name, rentry->namelen);
535 : }
536 41200024 : if (calc_hash != hash)
537 0 : xchk_da_set_corrupt(ds, level);
538 :
539 41200024 : out:
540 41200024 : return error;
541 : }
542 :
543 : /* Check space usage of shortform attrs. */
544 : STATIC int
545 75553369 : xchk_xattr_check_sf(
546 : struct xfs_scrub *sc)
547 : {
548 75553369 : struct xchk_xattr_buf *ab = sc->buf;
549 75553369 : struct xfs_attr_shortform *sf;
550 75553369 : struct xfs_attr_sf_entry *sfe;
551 75553369 : struct xfs_attr_sf_entry *next;
552 75553369 : struct xfs_ifork *ifp;
553 75553369 : unsigned char *end;
554 75553369 : int i;
555 75553369 : int error = 0;
556 :
557 75553369 : ifp = xfs_ifork_ptr(sc->ip, XFS_ATTR_FORK);
558 :
559 75553369 : bitmap_zero(ab->usedmap, ifp->if_bytes);
560 75554285 : sf = (struct xfs_attr_shortform *)sc->ip->i_af.if_u1.if_data;
561 75554285 : end = (unsigned char *)ifp->if_u1.if_data + ifp->if_bytes;
562 75554285 : xchk_xattr_set_map(sc, ab->usedmap, 0, sizeof(sf->hdr));
563 :
564 75551893 : sfe = &sf->list[0];
565 75551893 : if ((unsigned char *)sfe > end) {
566 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
567 0 : return 0;
568 : }
569 :
570 161296611 : for (i = 0; i < sf->hdr.count; i++) {
571 85742786 : unsigned char *name = sfe->nameval;
572 85742786 : unsigned char *value = &sfe->nameval[sfe->namelen];
573 :
574 85742786 : if (xchk_should_terminate(sc, &error))
575 2 : return error;
576 :
577 85742875 : next = xfs_attr_sf_nextentry(sfe);
578 85742875 : if ((unsigned char *)next > end) {
579 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
580 0 : break;
581 : }
582 :
583 85745386 : if (!xchk_xattr_set_map(sc, ab->usedmap,
584 85742875 : (char *)sfe - (char *)sf,
585 : sizeof(struct xfs_attr_sf_entry))) {
586 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
587 0 : break;
588 : }
589 :
590 85745828 : if (!xchk_xattr_set_map(sc, ab->usedmap,
591 85745386 : (char *)name - (char *)sf,
592 85745386 : sfe->namelen)) {
593 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
594 0 : break;
595 : }
596 :
597 85744718 : if (!xchk_xattr_set_map(sc, ab->usedmap,
598 85745828 : (char *)value - (char *)sf,
599 85745828 : sfe->valuelen)) {
600 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
601 0 : break;
602 : }
603 :
604 85744718 : sfe = next;
605 : }
606 :
607 : return 0;
608 : }
609 :
610 : /* Scrub the extended attribute metadata. */
611 : int
612 77745182 : xchk_xattr(
613 : struct xfs_scrub *sc)
614 : {
615 77745182 : xfs_dablk_t last_checked = -1U;
616 77745182 : int error = 0;
617 :
618 77745182 : if (!xfs_inode_hasattr(sc->ip))
619 : return -ENOENT;
620 :
621 : /* Allocate memory for xattr checking. */
622 77709356 : error = xchk_setup_xattr_buf(sc, 0);
623 77708748 : if (error == -ENOMEM)
624 : return -EDEADLOCK;
625 77708748 : if (error)
626 : return error;
627 :
628 : /* Check the physical structure of the xattr. */
629 77708748 : if (sc->ip->i_af.if_format == XFS_DINODE_FMT_LOCAL)
630 75554396 : error = xchk_xattr_check_sf(sc);
631 : else
632 2154352 : error = xchk_da_btree(sc, XFS_ATTR_FORK, xchk_xattr_rec,
633 : &last_checked);
634 77708091 : if (error)
635 : return error;
636 :
637 77707420 : if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
638 : return 0;
639 :
640 : /*
641 : * Look up every xattr in this file by name and hash.
642 : *
643 : * The VFS only locks i_rwsem when modifying attrs, so keep all
644 : * three locks held because that's the only way to ensure we're
645 : * the only thread poking into the da btree. We traverse the da
646 : * btree while holding a leaf buffer locked for the xattr name
647 : * iteration, which doesn't really follow the usual buffer
648 : * locking order.
649 : */
650 77707908 : error = xchk_xattr_walk(sc, sc->ip, xchk_xattr_actor, NULL, NULL);
651 77708213 : if (!xchk_fblock_process_error(sc, XFS_ATTR_FORK, 0, &error))
652 2 : return error;
653 :
654 : return 0;
655 : }
|