.. | .. |
---|
9 | 9 | #include "xfs_format.h" |
---|
10 | 10 | #include "xfs_trans_resv.h" |
---|
11 | 11 | #include "xfs_mount.h" |
---|
12 | | -#include "xfs_defer.h" |
---|
13 | | -#include "xfs_btree.h" |
---|
14 | | -#include "xfs_bit.h" |
---|
15 | 12 | #include "xfs_log_format.h" |
---|
16 | | -#include "xfs_trans.h" |
---|
17 | | -#include "xfs_sb.h" |
---|
18 | 13 | #include "xfs_inode.h" |
---|
19 | 14 | #include "xfs_da_format.h" |
---|
20 | 15 | #include "xfs_da_btree.h" |
---|
21 | | -#include "xfs_dir2.h" |
---|
22 | 16 | #include "xfs_attr.h" |
---|
23 | 17 | #include "xfs_attr_leaf.h" |
---|
24 | | -#include "scrub/xfs_scrub.h" |
---|
25 | 18 | #include "scrub/scrub.h" |
---|
26 | 19 | #include "scrub/common.h" |
---|
27 | 20 | #include "scrub/dabtree.h" |
---|
28 | | -#include "scrub/trace.h" |
---|
| 21 | +#include "scrub/attr.h" |
---|
29 | 22 | |
---|
30 | | -#include <linux/posix_acl_xattr.h> |
---|
31 | | -#include <linux/xattr.h> |
---|
| 23 | +/* |
---|
| 24 | + * Allocate enough memory to hold an attr value and attr block bitmaps, |
---|
| 25 | + * reallocating the buffer if necessary. Buffer contents are not preserved |
---|
| 26 | + * across a reallocation. |
---|
| 27 | + */ |
---|
| 28 | +int |
---|
| 29 | +xchk_setup_xattr_buf( |
---|
| 30 | + struct xfs_scrub *sc, |
---|
| 31 | + size_t value_size, |
---|
| 32 | + xfs_km_flags_t flags) |
---|
| 33 | +{ |
---|
| 34 | + size_t sz; |
---|
| 35 | + struct xchk_xattr_buf *ab = sc->buf; |
---|
| 36 | + |
---|
| 37 | + /* |
---|
| 38 | + * We need enough space to read an xattr value from the file or enough |
---|
| 39 | + * space to hold three copies of the xattr free space bitmap. We don't |
---|
| 40 | + * need the buffer space for both purposes at the same time. |
---|
| 41 | + */ |
---|
| 42 | + sz = 3 * sizeof(long) * BITS_TO_LONGS(sc->mp->m_attr_geo->blksize); |
---|
| 43 | + sz = max_t(size_t, sz, value_size); |
---|
| 44 | + |
---|
| 45 | + /* |
---|
| 46 | + * If there's already a buffer, figure out if we need to reallocate it |
---|
| 47 | + * to accommodate a larger size. |
---|
| 48 | + */ |
---|
| 49 | + if (ab) { |
---|
| 50 | + if (sz <= ab->sz) |
---|
| 51 | + return 0; |
---|
| 52 | + kmem_free(ab); |
---|
| 53 | + sc->buf = NULL; |
---|
| 54 | + } |
---|
| 55 | + |
---|
| 56 | + /* |
---|
| 57 | + * Don't zero the buffer upon allocation to avoid runtime overhead. |
---|
| 58 | + * All users must be careful never to read uninitialized contents. |
---|
| 59 | + */ |
---|
| 60 | + ab = kmem_alloc_large(sizeof(*ab) + sz, flags); |
---|
| 61 | + if (!ab) |
---|
| 62 | + return -ENOMEM; |
---|
| 63 | + |
---|
| 64 | + ab->sz = sz; |
---|
| 65 | + sc->buf = ab; |
---|
| 66 | + return 0; |
---|
| 67 | +} |
---|
32 | 68 | |
---|
33 | 69 | /* Set us up to scrub an inode's extended attributes. */ |
---|
34 | 70 | int |
---|
.. | .. |
---|
36 | 72 | struct xfs_scrub *sc, |
---|
37 | 73 | struct xfs_inode *ip) |
---|
38 | 74 | { |
---|
39 | | - size_t sz; |
---|
| 75 | + int error; |
---|
40 | 76 | |
---|
41 | 77 | /* |
---|
42 | | - * Allocate the buffer without the inode lock held. We need enough |
---|
43 | | - * space to read every xattr value in the file or enough space to |
---|
44 | | - * hold three copies of the xattr free space bitmap. (Not both at |
---|
45 | | - * the same time.) |
---|
| 78 | + * We failed to get memory while checking attrs, so this time try to |
---|
| 79 | + * get all the memory we're ever going to need. Allocate the buffer |
---|
| 80 | + * without the inode lock held, which means we can sleep. |
---|
46 | 81 | */ |
---|
47 | | - sz = max_t(size_t, XATTR_SIZE_MAX, 3 * sizeof(long) * |
---|
48 | | - BITS_TO_LONGS(sc->mp->m_attr_geo->blksize)); |
---|
49 | | - sc->buf = kmem_zalloc_large(sz, KM_SLEEP); |
---|
50 | | - if (!sc->buf) |
---|
51 | | - return -ENOMEM; |
---|
| 82 | + if (sc->flags & XCHK_TRY_HARDER) { |
---|
| 83 | + error = xchk_setup_xattr_buf(sc, XATTR_SIZE_MAX, 0); |
---|
| 84 | + if (error) |
---|
| 85 | + return error; |
---|
| 86 | + } |
---|
52 | 87 | |
---|
53 | 88 | return xchk_setup_inode_contents(sc, ip, 0); |
---|
54 | 89 | } |
---|
.. | .. |
---|
63 | 98 | /* |
---|
64 | 99 | * Check that an extended attribute key can be looked up by hash. |
---|
65 | 100 | * |
---|
66 | | - * We use the XFS attribute list iterator (i.e. xfs_attr_list_int_ilocked) |
---|
| 101 | + * We use the XFS attribute list iterator (i.e. xfs_attr_list_ilocked) |
---|
67 | 102 | * to call this function for every attribute key in an inode. Once |
---|
68 | 103 | * we're here, we load the attribute value to see if any errors happen, |
---|
69 | 104 | * or if we get more or less data than we expected. |
---|
.. | .. |
---|
82 | 117 | |
---|
83 | 118 | sx = container_of(context, struct xchk_xattr, context); |
---|
84 | 119 | |
---|
| 120 | + if (xchk_should_terminate(sx->sc, &error)) { |
---|
| 121 | + context->seen_enough = error; |
---|
| 122 | + return; |
---|
| 123 | + } |
---|
| 124 | + |
---|
85 | 125 | if (flags & XFS_ATTR_INCOMPLETE) { |
---|
86 | 126 | /* Incomplete attr key, just mark the inode for preening. */ |
---|
87 | 127 | xchk_ino_set_preen(sx->sc, context->dp->i_ino); |
---|
88 | 128 | return; |
---|
89 | 129 | } |
---|
90 | 130 | |
---|
91 | | - args.flags = ATTR_KERNOTIME; |
---|
92 | | - if (flags & XFS_ATTR_ROOT) |
---|
93 | | - args.flags |= ATTR_ROOT; |
---|
94 | | - else if (flags & XFS_ATTR_SECURE) |
---|
95 | | - args.flags |= ATTR_SECURE; |
---|
| 131 | + /* Does this name make sense? */ |
---|
| 132 | + if (!xfs_attr_namecheck(name, namelen)) { |
---|
| 133 | + xchk_fblock_set_corrupt(sx->sc, XFS_ATTR_FORK, args.blkno); |
---|
| 134 | + return; |
---|
| 135 | + } |
---|
| 136 | + |
---|
| 137 | + /* |
---|
| 138 | + * Try to allocate enough memory to extrat the attr value. If that |
---|
| 139 | + * doesn't work, we overload the seen_enough variable to convey |
---|
| 140 | + * the error message back to the main scrub function. |
---|
| 141 | + */ |
---|
| 142 | + error = xchk_setup_xattr_buf(sx->sc, valuelen, KM_MAYFAIL); |
---|
| 143 | + if (error == -ENOMEM) |
---|
| 144 | + error = -EDEADLOCK; |
---|
| 145 | + if (error) { |
---|
| 146 | + context->seen_enough = error; |
---|
| 147 | + return; |
---|
| 148 | + } |
---|
| 149 | + |
---|
| 150 | + args.op_flags = XFS_DA_OP_NOTIME; |
---|
| 151 | + args.attr_filter = flags & XFS_ATTR_NSP_ONDISK_MASK; |
---|
96 | 152 | args.geo = context->dp->i_mount->m_attr_geo; |
---|
97 | 153 | args.whichfork = XFS_ATTR_FORK; |
---|
98 | 154 | args.dp = context->dp; |
---|
.. | .. |
---|
100 | 156 | args.namelen = namelen; |
---|
101 | 157 | args.hashval = xfs_da_hashname(args.name, args.namelen); |
---|
102 | 158 | args.trans = context->tp; |
---|
103 | | - args.value = sx->sc->buf; |
---|
104 | | - args.valuelen = XATTR_SIZE_MAX; |
---|
| 159 | + args.value = xchk_xattr_valuebuf(sx->sc); |
---|
| 160 | + args.valuelen = valuelen; |
---|
105 | 161 | |
---|
106 | | - error = xfs_attr_get_ilocked(context->dp, &args); |
---|
107 | | - if (error == -EEXIST) |
---|
108 | | - error = 0; |
---|
| 162 | + error = xfs_attr_get_ilocked(&args); |
---|
| 163 | + /* ENODATA means the hash lookup failed and the attr is bad */ |
---|
| 164 | + if (error == -ENODATA) |
---|
| 165 | + error = -EFSCORRUPTED; |
---|
109 | 166 | if (!xchk_fblock_process_error(sx->sc, XFS_ATTR_FORK, args.blkno, |
---|
110 | 167 | &error)) |
---|
111 | 168 | goto fail_xref; |
---|
.. | .. |
---|
159 | 216 | unsigned long *map, |
---|
160 | 217 | struct xfs_attr3_icleaf_hdr *leafhdr) |
---|
161 | 218 | { |
---|
162 | | - unsigned long *freemap; |
---|
163 | | - unsigned long *dstmap; |
---|
| 219 | + unsigned long *freemap = xchk_xattr_freemap(sc); |
---|
| 220 | + unsigned long *dstmap = xchk_xattr_dstmap(sc); |
---|
164 | 221 | unsigned int mapsize = sc->mp->m_attr_geo->blksize; |
---|
165 | 222 | int i; |
---|
166 | 223 | |
---|
167 | 224 | /* Construct bitmap of freemap contents. */ |
---|
168 | | - freemap = (unsigned long *)sc->buf + BITS_TO_LONGS(mapsize); |
---|
169 | 225 | bitmap_zero(freemap, mapsize); |
---|
170 | 226 | for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { |
---|
171 | 227 | if (!xchk_xattr_set_map(sc, freemap, |
---|
.. | .. |
---|
175 | 231 | } |
---|
176 | 232 | |
---|
177 | 233 | /* Look for bits that are set in freemap and are marked in use. */ |
---|
178 | | - dstmap = freemap + BITS_TO_LONGS(mapsize); |
---|
179 | 234 | return bitmap_and(dstmap, freemap, map, mapsize) == 0; |
---|
180 | 235 | } |
---|
181 | 236 | |
---|
.. | .. |
---|
190 | 245 | char *buf_end, |
---|
191 | 246 | struct xfs_attr_leafblock *leaf, |
---|
192 | 247 | struct xfs_attr3_icleaf_hdr *leafhdr, |
---|
193 | | - unsigned long *usedmap, |
---|
194 | 248 | struct xfs_attr_leaf_entry *ent, |
---|
195 | 249 | int idx, |
---|
196 | 250 | unsigned int *usedbytes, |
---|
197 | 251 | __u32 *last_hashval) |
---|
198 | 252 | { |
---|
199 | 253 | struct xfs_mount *mp = ds->state->mp; |
---|
| 254 | + unsigned long *usedmap = xchk_xattr_usedmap(ds->sc); |
---|
200 | 255 | char *name_end; |
---|
201 | 256 | struct xfs_attr_leaf_name_local *lentry; |
---|
202 | 257 | struct xfs_attr_leaf_name_remote *rentry; |
---|
.. | .. |
---|
256 | 311 | struct xfs_attr_leafblock *leaf = bp->b_addr; |
---|
257 | 312 | struct xfs_attr_leaf_entry *ent; |
---|
258 | 313 | struct xfs_attr_leaf_entry *entries; |
---|
259 | | - unsigned long *usedmap = ds->sc->buf; |
---|
| 314 | + unsigned long *usedmap; |
---|
260 | 315 | char *buf_end; |
---|
261 | 316 | size_t off; |
---|
262 | 317 | __u32 last_hashval = 0; |
---|
263 | 318 | unsigned int usedbytes = 0; |
---|
264 | 319 | unsigned int hdrsize; |
---|
265 | 320 | int i; |
---|
| 321 | + int error; |
---|
266 | 322 | |
---|
267 | 323 | if (*last_checked == blk->blkno) |
---|
268 | 324 | return 0; |
---|
| 325 | + |
---|
| 326 | + /* Allocate memory for block usage checking. */ |
---|
| 327 | + error = xchk_setup_xattr_buf(ds->sc, 0, KM_MAYFAIL); |
---|
| 328 | + if (error == -ENOMEM) |
---|
| 329 | + return -EDEADLOCK; |
---|
| 330 | + if (error) |
---|
| 331 | + return error; |
---|
| 332 | + usedmap = xchk_xattr_usedmap(ds->sc); |
---|
| 333 | + |
---|
269 | 334 | *last_checked = blk->blkno; |
---|
270 | 335 | bitmap_zero(usedmap, mp->m_attr_geo->blksize); |
---|
271 | 336 | |
---|
.. | .. |
---|
313 | 378 | |
---|
314 | 379 | /* Check the entry and nameval. */ |
---|
315 | 380 | xchk_xattr_entry(ds, level, buf_end, leaf, &leafhdr, |
---|
316 | | - usedmap, ent, i, &usedbytes, &last_hashval); |
---|
| 381 | + ent, i, &usedbytes, &last_hashval); |
---|
317 | 382 | |
---|
318 | 383 | if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) |
---|
319 | 384 | goto out; |
---|
.. | .. |
---|
333 | 398 | STATIC int |
---|
334 | 399 | xchk_xattr_rec( |
---|
335 | 400 | struct xchk_da_btree *ds, |
---|
336 | | - int level, |
---|
337 | | - void *rec) |
---|
| 401 | + int level) |
---|
338 | 402 | { |
---|
339 | 403 | struct xfs_mount *mp = ds->state->mp; |
---|
340 | | - struct xfs_attr_leaf_entry *ent = rec; |
---|
341 | | - struct xfs_da_state_blk *blk; |
---|
| 404 | + struct xfs_da_state_blk *blk = &ds->state->path.blk[level]; |
---|
342 | 405 | struct xfs_attr_leaf_name_local *lentry; |
---|
343 | 406 | struct xfs_attr_leaf_name_remote *rentry; |
---|
344 | 407 | struct xfs_buf *bp; |
---|
| 408 | + struct xfs_attr_leaf_entry *ent; |
---|
345 | 409 | xfs_dahash_t calc_hash; |
---|
346 | 410 | xfs_dahash_t hash; |
---|
347 | 411 | int nameidx; |
---|
.. | .. |
---|
349 | 413 | unsigned int badflags; |
---|
350 | 414 | int error; |
---|
351 | 415 | |
---|
352 | | - blk = &ds->state->path.blk[level]; |
---|
| 416 | + ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); |
---|
| 417 | + |
---|
| 418 | + ent = xfs_attr3_leaf_entryp(blk->bp->b_addr) + blk->index; |
---|
353 | 419 | |
---|
354 | 420 | /* Check the whole block, if necessary. */ |
---|
355 | 421 | error = xchk_xattr_block(ds, level); |
---|
.. | .. |
---|
408 | 474 | struct xfs_scrub *sc) |
---|
409 | 475 | { |
---|
410 | 476 | struct xchk_xattr sx; |
---|
411 | | - struct attrlist_cursor_kern cursor = { 0 }; |
---|
412 | 477 | xfs_dablk_t last_checked = -1U; |
---|
413 | 478 | int error = 0; |
---|
414 | 479 | |
---|
.. | .. |
---|
427 | 492 | |
---|
428 | 493 | /* Check that every attr key can also be looked up by hash. */ |
---|
429 | 494 | sx.context.dp = sc->ip; |
---|
430 | | - sx.context.cursor = &cursor; |
---|
431 | 495 | sx.context.resynch = 1; |
---|
432 | 496 | sx.context.put_listent = xchk_xattr_listent; |
---|
433 | 497 | sx.context.tp = sc->tp; |
---|
434 | | - sx.context.flags = ATTR_INCOMPLETE; |
---|
| 498 | + sx.context.allow_incomplete = true; |
---|
435 | 499 | sx.sc = sc; |
---|
436 | 500 | |
---|
437 | 501 | /* |
---|
.. | .. |
---|
450 | 514 | * iteration, which doesn't really follow the usual buffer |
---|
451 | 515 | * locking order. |
---|
452 | 516 | */ |
---|
453 | | - error = xfs_attr_list_int_ilocked(&sx.context); |
---|
| 517 | + error = xfs_attr_list_ilocked(&sx.context); |
---|
454 | 518 | if (!xchk_fblock_process_error(sc, XFS_ATTR_FORK, 0, &error)) |
---|
455 | 519 | goto out; |
---|
| 520 | + |
---|
| 521 | + /* Did our listent function try to return any errors? */ |
---|
| 522 | + if (sx.context.seen_enough < 0) |
---|
| 523 | + error = sx.context.seen_enough; |
---|
456 | 524 | out: |
---|
457 | 525 | return error; |
---|
458 | 526 | } |
---|