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 129059354 : xchk_xattr_buf_cleanup(
30 : void *priv)
31 : {
32 129059354 : struct xchk_xattr_buf *ab = priv;
33 :
34 129059354 : kvfree(ab->freemap);
35 128728549 : ab->freemap = NULL;
36 128728549 : kvfree(ab->usedmap);
37 128937677 : ab->usedmap = NULL;
38 128937677 : kvfree(ab->value);
39 129003708 : ab->value = NULL;
40 129003708 : ab->value_sz = 0;
41 129003708 : kvfree(ab->name);
42 129002604 : ab->name = NULL;
43 129002604 : }
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 129003759 : xchk_xattr_want_freemap(
51 : struct xfs_scrub *sc)
52 : {
53 129003759 : struct xfs_ifork *ifp;
54 :
55 129003759 : if (sc->flags & XCHK_TRY_HARDER)
56 : return true;
57 :
58 129003759 : if (!sc->ip)
59 : return true;
60 :
61 129003759 : ifp = xfs_ifork_ptr(sc->ip, XFS_ATTR_FORK);
62 129003759 : if (!ifp)
63 : return false;
64 :
65 129003759 : 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 131213015 : xchk_setup_xattr_buf(
75 : struct xfs_scrub *sc,
76 : size_t value_size)
77 : {
78 131213015 : size_t bmp_sz;
79 131213015 : struct xchk_xattr_buf *ab = sc->buf;
80 131213015 : void *new_val;
81 :
82 131213015 : bmp_sz = sizeof(long) * BITS_TO_LONGS(sc->mp->m_attr_geo->blksize);
83 :
84 131213015 : if (ab)
85 2289978 : goto resize_value;
86 :
87 128939618 : ab = kvzalloc(sizeof(struct xchk_xattr_buf), XCHK_GFP_FLAGS);
88 129050658 : if (!ab)
89 : return -ENOMEM;
90 129050658 : sc->buf = ab;
91 129050658 : sc->buf_cleanup = xchk_xattr_buf_cleanup;
92 :
93 129050658 : ab->usedmap = kvmalloc(bmp_sz, XCHK_GFP_FLAGS);
94 128770112 : if (!ab->usedmap)
95 : return -ENOMEM;
96 :
97 128770112 : if (xchk_xattr_want_freemap(sc)) {
98 2212563 : ab->freemap = kvmalloc(bmp_sz, XCHK_GFP_FLAGS);
99 2224255 : if (!ab->freemap)
100 : return -ENOMEM;
101 : }
102 :
103 257563608 : if (xchk_could_repair(sc)) {
104 2314710 : ab->name = kvmalloc(XATTR_NAME_MAX + 1, XCHK_GFP_FLAGS);
105 2314711 : if (!ab->name)
106 : return -ENOMEM;
107 : }
108 :
109 128781805 : resize_value:
110 131055202 : if (ab->value_sz >= value_size)
111 : return 0;
112 :
113 2301346 : if (ab->value) {
114 0 : kvfree(ab->value);
115 0 : ab->value = NULL;
116 0 : ab->value_sz = 0;
117 : }
118 :
119 2301346 : new_val = kvmalloc(value_size, XCHK_GFP_FLAGS);
120 2301348 : if (!new_val)
121 : return -ENOMEM;
122 :
123 2301348 : ab->value = new_val;
124 2301348 : ab->value_sz = value_size;
125 2301348 : return 0;
126 : }
127 :
128 : /* Set us up to scrub an inode's extended attributes. */
129 : int
130 140239562 : xchk_setup_xattr(
131 : struct xfs_scrub *sc)
132 : {
133 140239562 : int error;
134 :
135 280479124 : if (xchk_could_repair(sc)) {
136 8175080 : error = xrep_setup_xattr(sc);
137 8147007 : 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 134389875 : 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 134389875 : 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 184140095 : 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 368274892 : struct xfs_da_args args = {
176 : .op_flags = XFS_DA_OP_NOTIME,
177 184140095 : .attr_filter = attr_flags & XFS_ATTR_NSP_ONDISK_MASK,
178 184140095 : .geo = sc->mp->m_attr_geo,
179 : .whichfork = XFS_ATTR_FORK,
180 : .dp = ip,
181 : .name = name,
182 : .namelen = namelen,
183 184140095 : .hashval = xfs_da_hashname(name, namelen),
184 184134797 : .trans = sc->tp,
185 : .valuelen = valuelen,
186 184134797 : .owner = ip->i_ino,
187 : };
188 184134797 : struct xchk_xattr_buf *ab;
189 184134797 : int error = 0;
190 :
191 184134797 : ab = sc->buf;
192 :
193 184134797 : if (xchk_should_terminate(sc, &error))
194 0 : return error;
195 :
196 184370601 : 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 184370601 : 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 184370601 : if (!xfs_attr_namecheck(sc->mp, name, namelen, attr_flags)) {
210 11 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, args.blkno);
211 11 : 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 184115514 : 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 1348 : error = xchk_setup_xattr_buf(sc, valuelen);
228 1348 : if (error == -ENOMEM)
229 0 : error = -EDEADLOCK;
230 1348 : if (error)
231 : return error;
232 :
233 1348 : args.value = ab->value;
234 :
235 1348 : error = xfs_attr_get_ilocked(&args);
236 : /* ENODATA means the hash lookup failed and the attr is bad */
237 1348 : if (error == -ENODATA)
238 0 : error = -EFSCORRUPTED;
239 1348 : if (!xchk_fblock_process_error(sc, XFS_ATTR_FORK, args.blkno,
240 : &error))
241 0 : return error;
242 1348 : 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 659476515 : xchk_xattr_set_map(
257 : struct xfs_scrub *sc,
258 : unsigned long *map,
259 : unsigned int start,
260 : unsigned int len)
261 : {
262 659476515 : unsigned int mapsize = sc->mp->m_attr_geo->blksize;
263 659476515 : bool ret = true;
264 :
265 659476515 : if (start >= mapsize)
266 : return false;
267 659476515 : if (start + len > mapsize) {
268 0 : len = mapsize - start;
269 0 : ret = false;
270 : }
271 :
272 659476515 : if (find_next_bit(map, mapsize, start) < start + len)
273 0 : ret = false;
274 659353234 : 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 2438893 : xchk_xattr_check_freemap(
285 : struct xfs_scrub *sc,
286 : struct xfs_attr3_icleaf_hdr *leafhdr)
287 : {
288 2438893 : struct xchk_xattr_buf *ab = sc->buf;
289 2438893 : unsigned int mapsize = sc->mp->m_attr_geo->blksize;
290 2438893 : int i;
291 :
292 : /* Construct bitmap of freemap contents. */
293 2438893 : bitmap_zero(ab->freemap, mapsize);
294 12190496 : for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
295 7312770 : if (!xchk_xattr_set_map(sc, ab->freemap,
296 7314296 : leafhdr->freemap[i].base,
297 7312865 : leafhdr->freemap[i].size))
298 : return false;
299 : }
300 :
301 : /* Look for bits that are set in freemap and are marked in use. */
302 2438738 : 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 42232505 : 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 42232505 : struct xfs_mount *mp = ds->state->mp;
322 42232505 : struct xchk_xattr_buf *ab = ds->sc->buf;
323 42232505 : char *name_end;
324 42232505 : struct xfs_attr_leaf_name_local *lentry;
325 42232505 : struct xfs_attr_leaf_name_remote *rentry;
326 42232505 : unsigned int nameidx;
327 42232505 : unsigned int namesize;
328 :
329 42232505 : if (ent->pad2 != 0)
330 0 : xchk_da_set_corrupt(ds, level);
331 :
332 : /* Hash values in order? */
333 42232505 : if (be32_to_cpu(ent->hashval) < *last_hashval)
334 0 : xchk_da_set_corrupt(ds, level);
335 42232505 : *last_hashval = be32_to_cpu(ent->hashval);
336 :
337 42232505 : nameidx = be16_to_cpu(ent->nameidx);
338 42232505 : if (nameidx < leafhdr->firstused ||
339 42232505 : nameidx >= mp->m_attr_geo->blksize) {
340 0 : xchk_da_set_corrupt(ds, level);
341 0 : return;
342 : }
343 :
344 : /* Check the name information. */
345 42232505 : if (ent->flags & XFS_ATTR_LOCAL) {
346 42231157 : lentry = xfs_attr3_leaf_name_local(leaf, idx);
347 42231157 : namesize = xfs_attr_leaf_entsize_local(lentry->namelen,
348 42231157 : be16_to_cpu(lentry->valuelen));
349 42231157 : name_end = (char *)lentry + namesize;
350 42231157 : if (lentry->namelen == 0)
351 0 : xchk_da_set_corrupt(ds, level);
352 : } else {
353 1348 : rentry = xfs_attr3_leaf_name_remote(leaf, idx);
354 1348 : namesize = xfs_attr_leaf_entsize_remote(rentry->namelen);
355 1348 : name_end = (char *)rentry + namesize;
356 1348 : if (rentry->namelen == 0 || rentry->valueblk == 0)
357 0 : xchk_da_set_corrupt(ds, level);
358 : }
359 42232505 : if (name_end > buf_end)
360 0 : xchk_da_set_corrupt(ds, level);
361 :
362 42232505 : if (!xchk_xattr_set_map(ds->sc, ab->usedmap, nameidx, namesize))
363 0 : xchk_da_set_corrupt(ds, level);
364 42213898 : if (!(ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
365 42235832 : *usedbytes += namesize;
366 : }
367 :
368 : /* Scrub an attribute leaf. */
369 : STATIC int
370 42312047 : xchk_xattr_block(
371 : struct xchk_da_btree *ds,
372 : int level)
373 : {
374 42312047 : struct xfs_attr3_icleaf_hdr leafhdr;
375 42312047 : struct xfs_mount *mp = ds->state->mp;
376 42312047 : struct xfs_da_state_blk *blk = &ds->state->path.blk[level];
377 42310877 : struct xfs_buf *bp = blk->bp;
378 42310877 : xfs_dablk_t *last_checked = ds->private;
379 42310877 : struct xfs_attr_leafblock *leaf = bp->b_addr;
380 42310877 : struct xfs_attr_leaf_entry *ent;
381 42310877 : struct xfs_attr_leaf_entry *entries;
382 42310877 : struct xchk_xattr_buf *ab = ds->sc->buf;
383 42310877 : char *buf_end;
384 42310877 : size_t off;
385 42310877 : __u32 last_hashval = 0;
386 42310877 : unsigned int usedbytes = 0;
387 42310877 : unsigned int hdrsize;
388 42310877 : int i;
389 :
390 42310877 : if (*last_checked == blk->blkno)
391 : return 0;
392 :
393 2415231 : *last_checked = blk->blkno;
394 2415231 : bitmap_zero(ab->usedmap, mp->m_attr_geo->blksize);
395 :
396 : /* Check all the padding. */
397 2426443 : if (xfs_has_crc(ds->sc->mp)) {
398 2426443 : struct xfs_attr3_leafblock *leaf3 = bp->b_addr;
399 :
400 2426443 : if (leaf3->hdr.pad1 != 0 || leaf3->hdr.pad2 != 0 ||
401 2426259 : leaf3->hdr.info.hdr.pad != 0)
402 184 : 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 2426259 : xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
410 2425090 : 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 2425090 : 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 2425090 : if (leafhdr.usedbytes > mp->m_attr_geo->blksize)
424 0 : xchk_da_set_corrupt(ds, level);
425 2425090 : if (leafhdr.firstused > mp->m_attr_geo->blksize)
426 0 : xchk_da_set_corrupt(ds, level);
427 2425090 : if (leafhdr.firstused < hdrsize)
428 0 : xchk_da_set_corrupt(ds, level);
429 2425090 : if (!xchk_xattr_set_map(ds->sc, ab->usedmap, 0, hdrsize))
430 0 : xchk_da_set_corrupt(ds, level);
431 2424349 : if (leafhdr.holes)
432 1964418 : xchk_da_set_preen(ds, level);
433 :
434 2424924 : if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
435 0 : goto out;
436 :
437 2424924 : entries = xfs_attr3_leaf_entryp(leaf);
438 2424924 : if ((char *)&entries[leafhdr.count] > (char *)leaf + leafhdr.firstused)
439 0 : xchk_da_set_corrupt(ds, level);
440 :
441 2424924 : buf_end = (char *)bp->b_addr + mp->m_attr_geo->blksize;
442 44659681 : for (i = 0, ent = entries; i < leafhdr.count; ent++, i++) {
443 : /* Mark the leaf entry itself. */
444 42220300 : off = (char *)ent - (char *)leaf;
445 42220300 : 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 42195252 : xchk_xattr_entry(ds, level, buf_end, leaf, &leafhdr,
453 : ent, i, &usedbytes, &last_hashval);
454 :
455 42234757 : if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
456 0 : goto out;
457 : }
458 :
459 2439381 : if (!xchk_xattr_check_freemap(ds->sc, &leafhdr))
460 0 : xchk_da_set_corrupt(ds, level);
461 :
462 2436446 : if (leafhdr.usedbytes != usedbytes)
463 0 : xchk_da_set_corrupt(ds, level);
464 :
465 2436446 : out:
466 : return 0;
467 : }
468 :
469 : /* Scrub a attribute btree record. */
470 : STATIC int
471 42304531 : xchk_xattr_rec(
472 : struct xchk_da_btree *ds,
473 : int level)
474 : {
475 42304531 : struct xfs_mount *mp = ds->state->mp;
476 42304531 : struct xfs_da_state_blk *blk = &ds->state->path.blk[level];
477 42302371 : struct xfs_attr_leaf_name_local *lentry;
478 42302371 : struct xfs_attr_leaf_name_remote *rentry;
479 42302371 : struct xfs_buf *bp;
480 42302371 : struct xfs_attr_leaf_entry *ent;
481 42302371 : xfs_dahash_t calc_hash;
482 42302371 : xfs_dahash_t hash;
483 42302371 : int nameidx;
484 42302371 : int hdrsize;
485 42302371 : unsigned int badflags;
486 42302371 : int error;
487 :
488 42302371 : ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
489 :
490 42302371 : ent = xfs_attr3_leaf_entryp(blk->bp->b_addr) + blk->index;
491 :
492 : /* Check the whole block, if necessary. */
493 42302371 : error = xchk_xattr_block(ds, level);
494 42329806 : if (error)
495 0 : goto out;
496 42329806 : if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
497 0 : goto out;
498 :
499 : /* Check the hash of the entry. */
500 42329806 : error = xchk_da_btree_hash(ds, level, &ent->hashval);
501 42330558 : if (error)
502 0 : goto out;
503 :
504 : /* Find the attr entry's location. */
505 42330558 : bp = blk->bp;
506 42330558 : hdrsize = xfs_attr3_leaf_hdr_size(bp->b_addr);
507 42330558 : nameidx = be16_to_cpu(ent->nameidx);
508 42330558 : if (nameidx < hdrsize || nameidx >= mp->m_attr_geo->blksize) {
509 0 : xchk_da_set_corrupt(ds, level);
510 0 : goto out;
511 : }
512 :
513 : /* Retrieve the entry and check it. */
514 42330558 : hash = be32_to_cpu(ent->hashval);
515 42330558 : badflags = ~(XFS_ATTR_LOCAL | XFS_ATTR_ROOT | XFS_ATTR_SECURE |
516 : XFS_ATTR_INCOMPLETE | XFS_ATTR_PARENT);
517 42330558 : if ((ent->flags & badflags) != 0)
518 0 : xchk_da_set_corrupt(ds, level);
519 42330558 : if (ent->flags & XFS_ATTR_LOCAL) {
520 42329210 : lentry = (struct xfs_attr_leaf_name_local *)
521 42329210 : (((char *)bp->b_addr) + nameidx);
522 42329210 : if (lentry->namelen <= 0) {
523 0 : xchk_da_set_corrupt(ds, level);
524 0 : goto out;
525 : }
526 42329210 : calc_hash = xfs_da_hashname(lentry->nameval, lentry->namelen);
527 : } else {
528 1348 : rentry = (struct xfs_attr_leaf_name_remote *)
529 1348 : (((char *)bp->b_addr) + nameidx);
530 1348 : if (rentry->namelen <= 0) {
531 0 : xchk_da_set_corrupt(ds, level);
532 0 : goto out;
533 : }
534 1348 : calc_hash = xfs_da_hashname(rentry->name, rentry->namelen);
535 : }
536 42302401 : if (calc_hash != hash)
537 0 : xchk_da_set_corrupt(ds, level);
538 :
539 42302401 : out:
540 42302401 : return error;
541 : }
542 :
543 : /* Check space usage of shortform attrs. */
544 : STATIC int
545 126627034 : xchk_xattr_check_sf(
546 : struct xfs_scrub *sc)
547 : {
548 126627034 : struct xchk_xattr_buf *ab = sc->buf;
549 126627034 : struct xfs_attr_shortform *sf;
550 126627034 : struct xfs_attr_sf_entry *sfe;
551 126627034 : struct xfs_attr_sf_entry *next;
552 126627034 : struct xfs_ifork *ifp;
553 126627034 : unsigned char *end;
554 126627034 : int i;
555 126627034 : int error = 0;
556 :
557 126627034 : ifp = xfs_ifork_ptr(sc->ip, XFS_ATTR_FORK);
558 :
559 126627034 : bitmap_zero(ab->usedmap, ifp->if_bytes);
560 126280935 : sf = (struct xfs_attr_shortform *)sc->ip->i_af.if_u1.if_data;
561 126280935 : end = (unsigned char *)ifp->if_u1.if_data + ifp->if_bytes;
562 126280935 : xchk_xattr_set_map(sc, ab->usedmap, 0, sizeof(sf->hdr));
563 :
564 126259892 : sfe = &sf->list[0];
565 126259892 : if ((unsigned char *)sfe > end) {
566 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
567 0 : return 0;
568 : }
569 :
570 268573793 : for (i = 0; i < sf->hdr.count; i++) {
571 141615007 : unsigned char *name = sfe->nameval;
572 141615007 : unsigned char *value = &sfe->nameval[sfe->namelen];
573 :
574 141615007 : if (xchk_should_terminate(sc, &error))
575 2 : return error;
576 :
577 142195141 : next = xfs_attr_sf_nextentry(sfe);
578 142195141 : if ((unsigned char *)next > end) {
579 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
580 0 : break;
581 : }
582 :
583 142259418 : if (!xchk_xattr_set_map(sc, ab->usedmap,
584 142195141 : (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 142313339 : if (!xchk_xattr_set_map(sc, ab->usedmap,
591 142259418 : (char *)name - (char *)sf,
592 142259418 : sfe->namelen)) {
593 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
594 0 : break;
595 : }
596 :
597 142313901 : if (!xchk_xattr_set_map(sc, ab->usedmap,
598 142313339 : (char *)value - (char *)sf,
599 142313339 : sfe->valuelen)) {
600 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
601 0 : break;
602 : }
603 :
604 142313901 : sfe = next;
605 : }
606 :
607 : return 0;
608 : }
609 :
610 : /* Scrub the extended attribute metadata. */
611 : int
612 133619704 : xchk_xattr(
613 : struct xfs_scrub *sc)
614 : {
615 133619704 : xfs_dablk_t last_checked = -1U;
616 133619704 : int error = 0;
617 :
618 133619704 : if (!xfs_inode_hasattr(sc->ip))
619 : return -ENOENT;
620 :
621 : /* Allocate memory for xattr checking. */
622 128898313 : error = xchk_setup_xattr_buf(sc, 0);
623 128952023 : if (error == -ENOMEM)
624 : return -EDEADLOCK;
625 128952023 : if (error)
626 : return error;
627 :
628 : /* Check the physical structure of the xattr. */
629 128952023 : if (sc->ip->i_af.if_format == XFS_DINODE_FMT_LOCAL)
630 126724987 : error = xchk_xattr_check_sf(sc);
631 : else
632 2227036 : error = xchk_da_btree(sc, XFS_ATTR_FORK, xchk_xattr_rec,
633 : &last_checked);
634 129145641 : if (error)
635 : return error;
636 :
637 129141729 : 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 129141204 : error = xchk_xattr_walk(sc, sc->ip, xchk_xattr_actor, NULL, NULL);
651 128775612 : if (!xchk_fblock_process_error(sc, XFS_ATTR_FORK, 0, &error))
652 11 : return error;
653 :
654 : return 0;
655 : }
|