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 165681505 : xchk_xattr_buf_cleanup(
30 : void *priv)
31 : {
32 165681505 : struct xchk_xattr_buf *ab = priv;
33 :
34 165681505 : kvfree(ab->freemap);
35 165368693 : ab->freemap = NULL;
36 165368693 : kvfree(ab->usedmap);
37 165588736 : ab->usedmap = NULL;
38 165588736 : kvfree(ab->value);
39 165612649 : ab->value = NULL;
40 165612649 : ab->value_sz = 0;
41 165612649 : kvfree(ab->name);
42 165660215 : ab->name = NULL;
43 165660215 : }
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 165560957 : xchk_xattr_want_freemap(
51 : struct xfs_scrub *sc)
52 : {
53 165560957 : struct xfs_ifork *ifp;
54 :
55 165560957 : if (sc->flags & XCHK_TRY_HARDER)
56 : return true;
57 :
58 165560957 : if (!sc->ip)
59 : return true;
60 :
61 165560957 : ifp = xfs_ifork_ptr(sc->ip, XFS_ATTR_FORK);
62 165560957 : if (!ifp)
63 : return false;
64 :
65 165560957 : 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 167411639 : xchk_setup_xattr_buf(
75 : struct xfs_scrub *sc,
76 : size_t value_size)
77 : {
78 167411639 : size_t bmp_sz;
79 167411639 : struct xchk_xattr_buf *ab = sc->buf;
80 167411639 : void *new_val;
81 :
82 167411639 : bmp_sz = sizeof(long) * BITS_TO_LONGS(sc->mp->m_attr_geo->blksize);
83 :
84 167411639 : if (ab)
85 2144478 : goto resize_value;
86 :
87 165364859 : ab = kvzalloc(sizeof(struct xchk_xattr_buf), XCHK_GFP_FLAGS);
88 165569131 : if (!ab)
89 : return -ENOMEM;
90 165569131 : sc->buf = ab;
91 165569131 : sc->buf_cleanup = xchk_xattr_buf_cleanup;
92 :
93 165569131 : ab->usedmap = kvmalloc(bmp_sz, XCHK_GFP_FLAGS);
94 165664479 : if (!ab->usedmap)
95 : return -ENOMEM;
96 :
97 165664479 : if (xchk_xattr_want_freemap(sc)) {
98 1456564 : ab->freemap = kvmalloc(bmp_sz, XCHK_GFP_FLAGS);
99 1458054 : if (!ab->freemap)
100 : return -ENOMEM;
101 : }
102 :
103 331331938 : if (xchk_could_repair(sc)) {
104 8157272 : ab->name = kvmalloc(XATTR_NAME_MAX + 1, XCHK_GFP_FLAGS);
105 8157273 : if (!ab->name)
106 : return -ENOMEM;
107 : }
108 :
109 165665970 : resize_value:
110 167712750 : if (ab->value_sz >= value_size)
111 : return 0;
112 :
113 2183334 : if (ab->value) {
114 0 : kvfree(ab->value);
115 0 : ab->value = NULL;
116 0 : ab->value_sz = 0;
117 : }
118 :
119 2183334 : new_val = kvmalloc(value_size, XCHK_GFP_FLAGS);
120 2183335 : if (!new_val)
121 : return -ENOMEM;
122 :
123 2183335 : ab->value = new_val;
124 2183335 : ab->value_sz = value_size;
125 2183335 : return 0;
126 : }
127 :
128 : /* Set us up to scrub an inode's extended attributes. */
129 : int
130 177305094 : xchk_setup_xattr(
131 : struct xfs_scrub *sc)
132 : {
133 177305094 : int error;
134 :
135 354610188 : if (xchk_could_repair(sc)) {
136 14024748 : error = xrep_setup_xattr(sc);
137 13931626 : 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 171473596 : 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 171473596 : 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 208021072 : 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 415867116 : struct xfs_da_args args = {
176 : .op_flags = XFS_DA_OP_NOTIME,
177 208021072 : .attr_filter = attr_flags & XFS_ATTR_NSP_ONDISK_MASK,
178 208021072 : .geo = sc->mp->m_attr_geo,
179 : .whichfork = XFS_ATTR_FORK,
180 : .dp = ip,
181 : .name = name,
182 : .namelen = namelen,
183 208021072 : .hashval = xfs_da_hashname(name, namelen),
184 207846044 : .trans = sc->tp,
185 : .valuelen = valuelen,
186 207846044 : .owner = ip->i_ino,
187 : };
188 207846044 : struct xchk_xattr_buf *ab;
189 207846044 : int error = 0;
190 :
191 207846044 : ab = sc->buf;
192 :
193 207846044 : if (xchk_should_terminate(sc, &error))
194 0 : return error;
195 :
196 208043109 : 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 208043109 : 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 208043109 : 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 207952259 : 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 932 : error = xchk_setup_xattr_buf(sc, valuelen);
228 932 : if (error == -ENOMEM)
229 0 : error = -EDEADLOCK;
230 932 : if (error)
231 : return error;
232 :
233 932 : args.value = ab->value;
234 :
235 932 : error = xfs_attr_get_ilocked(&args);
236 : /* ENODATA means the hash lookup failed and the attr is bad */
237 932 : if (error == -ENODATA)
238 0 : error = -EFSCORRUPTED;
239 932 : if (!xchk_fblock_process_error(sc, XFS_ATTR_FORK, args.blkno,
240 : &error))
241 0 : return error;
242 932 : 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 778885022 : xchk_xattr_set_map(
257 : struct xfs_scrub *sc,
258 : unsigned long *map,
259 : unsigned int start,
260 : unsigned int len)
261 : {
262 778885022 : unsigned int mapsize = sc->mp->m_attr_geo->blksize;
263 778885022 : bool ret = true;
264 :
265 778885022 : if (start >= mapsize)
266 : return false;
267 778885022 : if (start + len > mapsize) {
268 0 : len = mapsize - start;
269 0 : ret = false;
270 : }
271 :
272 778885022 : if (find_next_bit(map, mapsize, start) < start + len)
273 0 : ret = false;
274 778924214 : 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 1641619 : xchk_xattr_check_freemap(
285 : struct xfs_scrub *sc,
286 : struct xfs_attr3_icleaf_hdr *leafhdr)
287 : {
288 1641619 : struct xchk_xattr_buf *ab = sc->buf;
289 1641619 : unsigned int mapsize = sc->mp->m_attr_geo->blksize;
290 1641619 : int i;
291 :
292 : /* Construct bitmap of freemap contents. */
293 1641619 : bitmap_zero(ab->freemap, mapsize);
294 8206201 : for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
295 4922795 : if (!xchk_xattr_set_map(sc, ab->freemap,
296 4922917 : leafhdr->freemap[i].base,
297 4922960 : leafhdr->freemap[i].size))
298 : return false;
299 : }
300 :
301 : /* Look for bits that are set in freemap and are marked in use. */
302 1641622 : 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 26407360 : 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 26407360 : struct xfs_mount *mp = ds->state->mp;
322 26407360 : struct xchk_xattr_buf *ab = ds->sc->buf;
323 26407360 : char *name_end;
324 26407360 : struct xfs_attr_leaf_name_local *lentry;
325 26407360 : struct xfs_attr_leaf_name_remote *rentry;
326 26407360 : unsigned int nameidx;
327 26407360 : unsigned int namesize;
328 :
329 26407360 : if (ent->pad2 != 0)
330 0 : xchk_da_set_corrupt(ds, level);
331 :
332 : /* Hash values in order? */
333 26407360 : if (be32_to_cpu(ent->hashval) < *last_hashval)
334 0 : xchk_da_set_corrupt(ds, level);
335 26407360 : *last_hashval = be32_to_cpu(ent->hashval);
336 :
337 26407360 : nameidx = be16_to_cpu(ent->nameidx);
338 26407360 : if (nameidx < leafhdr->firstused ||
339 26407360 : 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 26407360 : if (ent->flags & XFS_ATTR_LOCAL) {
346 26406428 : lentry = xfs_attr3_leaf_name_local(leaf, idx);
347 26406428 : namesize = xfs_attr_leaf_entsize_local(lentry->namelen,
348 26406428 : be16_to_cpu(lentry->valuelen));
349 26406428 : name_end = (char *)lentry + namesize;
350 26406428 : if (lentry->namelen == 0)
351 0 : xchk_da_set_corrupt(ds, level);
352 : } else {
353 932 : rentry = xfs_attr3_leaf_name_remote(leaf, idx);
354 932 : namesize = xfs_attr_leaf_entsize_remote(rentry->namelen);
355 932 : name_end = (char *)rentry + namesize;
356 932 : if (rentry->namelen == 0 || rentry->valueblk == 0)
357 0 : xchk_da_set_corrupt(ds, level);
358 : }
359 26407360 : if (name_end > buf_end)
360 0 : xchk_da_set_corrupt(ds, level);
361 :
362 26407360 : if (!xchk_xattr_set_map(ds->sc, ab->usedmap, nameidx, namesize))
363 0 : xchk_da_set_corrupt(ds, level);
364 26403509 : if (!(ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
365 26409051 : *usedbytes += namesize;
366 : }
367 :
368 : /* Scrub an attribute leaf. */
369 : STATIC int
370 26479677 : xchk_xattr_block(
371 : struct xchk_da_btree *ds,
372 : int level)
373 : {
374 26479677 : struct xfs_attr3_icleaf_hdr leafhdr;
375 26479677 : struct xfs_mount *mp = ds->state->mp;
376 26479677 : struct xfs_da_state_blk *blk = &ds->state->path.blk[level];
377 26477078 : struct xfs_buf *bp = blk->bp;
378 26477078 : xfs_dablk_t *last_checked = ds->private;
379 26477078 : struct xfs_attr_leafblock *leaf = bp->b_addr;
380 26477078 : struct xfs_attr_leaf_entry *ent;
381 26477078 : struct xfs_attr_leaf_entry *entries;
382 26477078 : struct xchk_xattr_buf *ab = ds->sc->buf;
383 26477078 : char *buf_end;
384 26477078 : size_t off;
385 26477078 : __u32 last_hashval = 0;
386 26477078 : unsigned int usedbytes = 0;
387 26477078 : unsigned int hdrsize;
388 26477078 : int i;
389 :
390 26477078 : if (*last_checked == blk->blkno)
391 : return 0;
392 :
393 1626196 : *last_checked = blk->blkno;
394 1626196 : bitmap_zero(ab->usedmap, mp->m_attr_geo->blksize);
395 :
396 : /* Check all the padding. */
397 1637023 : if (xfs_has_crc(ds->sc->mp)) {
398 1637023 : struct xfs_attr3_leafblock *leaf3 = bp->b_addr;
399 :
400 1637023 : if (leaf3->hdr.pad1 != 0 || leaf3->hdr.pad2 != 0 ||
401 1636085 : leaf3->hdr.info.hdr.pad != 0)
402 938 : 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 1636085 : xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
410 1632124 : 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 1632124 : 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 1632124 : if (leafhdr.usedbytes > mp->m_attr_geo->blksize)
424 0 : xchk_da_set_corrupt(ds, level);
425 1632124 : if (leafhdr.firstused > mp->m_attr_geo->blksize)
426 0 : xchk_da_set_corrupt(ds, level);
427 1632124 : if (leafhdr.firstused < hdrsize)
428 0 : xchk_da_set_corrupt(ds, level);
429 1632124 : if (!xchk_xattr_set_map(ds->sc, ab->usedmap, 0, hdrsize))
430 0 : xchk_da_set_corrupt(ds, level);
431 1630783 : if (leafhdr.holes)
432 1256580 : xchk_da_set_preen(ds, level);
433 :
434 1629194 : if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
435 0 : goto out;
436 :
437 1629194 : entries = xfs_attr3_leaf_entryp(leaf);
438 1629194 : if ((char *)&entries[leafhdr.count] > (char *)leaf + leafhdr.firstused)
439 0 : xchk_da_set_corrupt(ds, level);
440 :
441 1629194 : buf_end = (char *)bp->b_addr + mp->m_attr_geo->blksize;
442 28042692 : for (i = 0, ent = entries; i < leafhdr.count; ent++, i++) {
443 : /* Mark the leaf entry itself. */
444 26400882 : off = (char *)ent - (char *)leaf;
445 26400882 : 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 26391927 : xchk_xattr_entry(ds, level, buf_end, leaf, &leafhdr,
453 : ent, i, &usedbytes, &last_hashval);
454 :
455 26413498 : if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
456 0 : goto out;
457 : }
458 :
459 1641810 : if (!xchk_xattr_check_freemap(ds->sc, &leafhdr))
460 0 : xchk_da_set_corrupt(ds, level);
461 :
462 1640713 : if (leafhdr.usedbytes != usedbytes)
463 0 : xchk_da_set_corrupt(ds, level);
464 :
465 1640713 : out:
466 : return 0;
467 : }
468 :
469 : /* Scrub a attribute btree record. */
470 : STATIC int
471 26474022 : xchk_xattr_rec(
472 : struct xchk_da_btree *ds,
473 : int level)
474 : {
475 26474022 : struct xfs_mount *mp = ds->state->mp;
476 26474022 : struct xfs_da_state_blk *blk = &ds->state->path.blk[level];
477 26471240 : struct xfs_attr_leaf_name_local *lentry;
478 26471240 : struct xfs_attr_leaf_name_remote *rentry;
479 26471240 : struct xfs_buf *bp;
480 26471240 : struct xfs_attr_leaf_entry *ent;
481 26471240 : xfs_dahash_t calc_hash;
482 26471240 : xfs_dahash_t hash;
483 26471240 : int nameidx;
484 26471240 : int hdrsize;
485 26471240 : unsigned int badflags;
486 26471240 : int error;
487 :
488 26471240 : ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
489 :
490 26471240 : ent = xfs_attr3_leaf_entryp(blk->bp->b_addr) + blk->index;
491 :
492 : /* Check the whole block, if necessary. */
493 26471240 : error = xchk_xattr_block(ds, level);
494 26485807 : if (error)
495 0 : goto out;
496 26485807 : if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
497 0 : goto out;
498 :
499 : /* Check the hash of the entry. */
500 26485807 : error = xchk_da_btree_hash(ds, level, &ent->hashval);
501 26484372 : if (error)
502 0 : goto out;
503 :
504 : /* Find the attr entry's location. */
505 26484372 : bp = blk->bp;
506 26484372 : hdrsize = xfs_attr3_leaf_hdr_size(bp->b_addr);
507 26484372 : nameidx = be16_to_cpu(ent->nameidx);
508 26484372 : 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 26484372 : hash = be32_to_cpu(ent->hashval);
515 26484372 : badflags = ~(XFS_ATTR_LOCAL | XFS_ATTR_ROOT | XFS_ATTR_SECURE |
516 : XFS_ATTR_INCOMPLETE | XFS_ATTR_PARENT);
517 26484372 : if ((ent->flags & badflags) != 0)
518 0 : xchk_da_set_corrupt(ds, level);
519 26484372 : if (ent->flags & XFS_ATTR_LOCAL) {
520 26483440 : lentry = (struct xfs_attr_leaf_name_local *)
521 26483440 : (((char *)bp->b_addr) + nameidx);
522 26483440 : if (lentry->namelen <= 0) {
523 0 : xchk_da_set_corrupt(ds, level);
524 0 : goto out;
525 : }
526 26483440 : calc_hash = xfs_da_hashname(lentry->nameval, lentry->namelen);
527 : } else {
528 932 : rentry = (struct xfs_attr_leaf_name_remote *)
529 932 : (((char *)bp->b_addr) + nameidx);
530 932 : if (rentry->namelen <= 0) {
531 0 : xchk_da_set_corrupt(ds, level);
532 0 : goto out;
533 : }
534 932 : calc_hash = xfs_da_hashname(rentry->name, rentry->namelen);
535 : }
536 26468138 : if (calc_hash != hash)
537 0 : xchk_da_set_corrupt(ds, level);
538 :
539 26468138 : out:
540 26468138 : return error;
541 : }
542 :
543 : /* Check space usage of shortform attrs. */
544 : STATIC int
545 163949082 : xchk_xattr_check_sf(
546 : struct xfs_scrub *sc)
547 : {
548 163949082 : struct xchk_xattr_buf *ab = sc->buf;
549 163949082 : struct xfs_attr_shortform *sf;
550 163949082 : struct xfs_attr_sf_entry *sfe;
551 163949082 : struct xfs_attr_sf_entry *next;
552 163949082 : struct xfs_ifork *ifp;
553 163949082 : unsigned char *end;
554 163949082 : int i;
555 163949082 : int error = 0;
556 :
557 163949082 : ifp = xfs_ifork_ptr(sc->ip, XFS_ATTR_FORK);
558 :
559 163949082 : bitmap_zero(ab->usedmap, ifp->if_bytes);
560 163458905 : sf = (struct xfs_attr_shortform *)sc->ip->i_af.if_u1.if_data;
561 163458905 : end = (unsigned char *)ifp->if_u1.if_data + ifp->if_bytes;
562 163458905 : xchk_xattr_set_map(sc, ab->usedmap, 0, sizeof(sf->hdr));
563 :
564 163283263 : sfe = &sf->list[0];
565 163283263 : if ((unsigned char *)sfe > end) {
566 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
567 0 : return 0;
568 : }
569 :
570 345213388 : for (i = 0; i < sf->hdr.count; i++) {
571 180935500 : unsigned char *name = sfe->nameval;
572 180935500 : unsigned char *value = &sfe->nameval[sfe->namelen];
573 :
574 180935500 : if (xchk_should_terminate(sc, &error))
575 7 : return error;
576 :
577 181891212 : next = xfs_attr_sf_nextentry(sfe);
578 181891212 : if ((unsigned char *)next > end) {
579 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
580 0 : break;
581 : }
582 :
583 182005496 : if (!xchk_xattr_set_map(sc, ab->usedmap,
584 181891212 : (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 182114090 : if (!xchk_xattr_set_map(sc, ab->usedmap,
591 182005496 : (char *)name - (char *)sf,
592 182005496 : sfe->namelen)) {
593 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
594 0 : break;
595 : }
596 :
597 181930125 : if (!xchk_xattr_set_map(sc, ab->usedmap,
598 182114090 : (char *)value - (char *)sf,
599 182114090 : sfe->valuelen)) {
600 0 : xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
601 0 : break;
602 : }
603 :
604 181930125 : sfe = next;
605 : }
606 :
607 : return 0;
608 : }
609 :
610 : /* Scrub the extended attribute metadata. */
611 : int
612 170553350 : xchk_xattr(
613 : struct xfs_scrub *sc)
614 : {
615 170553350 : xfs_dablk_t last_checked = -1U;
616 170553350 : int error = 0;
617 :
618 170553350 : if (!xfs_inode_hasattr(sc->ip))
619 : return -ENOENT;
620 :
621 : /* Allocate memory for xattr checking. */
622 165150554 : error = xchk_setup_xattr_buf(sc, 0);
623 165282608 : if (error == -ENOMEM)
624 : return -EDEADLOCK;
625 165282608 : if (error)
626 : return error;
627 :
628 : /* Check the physical structure of the xattr. */
629 165282608 : if (sc->ip->i_af.if_format == XFS_DINODE_FMT_LOCAL)
630 163825236 : error = xchk_xattr_check_sf(sc);
631 : else
632 1457372 : error = xchk_da_btree(sc, XFS_ATTR_FORK, xchk_xattr_rec,
633 : &last_checked);
634 165740223 : if (error)
635 : return error;
636 :
637 165707325 : 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 165702267 : error = xchk_xattr_walk(sc, sc->ip, xchk_xattr_actor, NULL, NULL);
651 165394394 : if (!xchk_fblock_process_error(sc, XFS_ATTR_FORK, 0, &error))
652 11 : return error;
653 :
654 : return 0;
655 : }
|