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