1664 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (c) 2018-2024 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_defer.h"13#include "xfs_btree.h"14#include "xfs_bit.h"15#include "xfs_log_format.h"16#include "xfs_trans.h"17#include "xfs_sb.h"18#include "xfs_inode.h"19#include "xfs_da_format.h"20#include "xfs_da_btree.h"21#include "xfs_dir2.h"22#include "xfs_attr.h"23#include "xfs_attr_leaf.h"24#include "xfs_attr_sf.h"25#include "xfs_attr_remote.h"26#include "xfs_bmap.h"27#include "xfs_bmap_util.h"28#include "xfs_exchmaps.h"29#include "xfs_exchrange.h"30#include "xfs_acl.h"31#include "xfs_parent.h"32#include "scrub/xfs_scrub.h"33#include "scrub/scrub.h"34#include "scrub/common.h"35#include "scrub/trace.h"36#include "scrub/repair.h"37#include "scrub/tempfile.h"38#include "scrub/tempexch.h"39#include "scrub/xfile.h"40#include "scrub/xfarray.h"41#include "scrub/xfblob.h"42#include "scrub/attr.h"43#include "scrub/reap.h"44#include "scrub/attr_repair.h"45 46/*47 * Extended Attribute Repair48 * =========================49 *50 * We repair extended attributes by reading the attr leaf blocks looking for51 * attributes entries that look salvageable (name passes verifiers, value can52 * be retrieved, etc). Each extended attribute worth salvaging is stashed in53 * memory, and the stashed entries are periodically replayed into a temporary54 * file to constrain memory use. Batching the construction of the temporary55 * extended attribute structure in this fashion reduces lock cycling of the56 * file being repaired and the temporary file.57 *58 * When salvaging completes, the remaining stashed attributes are replayed to59 * the temporary file. An atomic file contents exchange is used to commit the60 * new xattr blocks to the file being repaired. This will disrupt attrmulti61 * cursors.62 */63 64struct xrep_xattr_key {65 /* Cookie for retrieval of the xattr name. */66 xfblob_cookie name_cookie;67 68 /* Cookie for retrieval of the xattr value. */69 xfblob_cookie value_cookie;70 71 /* XFS_ATTR_* flags */72 int flags;73 74 /* Length of the value and name. */75 uint32_t valuelen;76 uint16_t namelen;77};78 79/*80 * Stash up to 8 pages of attrs in xattr_records/xattr_blobs before we write81 * them to the temp file.82 */83#define XREP_XATTR_MAX_STASH_BYTES (PAGE_SIZE * 8)84 85struct xrep_xattr {86 struct xfs_scrub *sc;87 88 /* Information for exchanging attr fork mappings at the end. */89 struct xrep_tempexch tx;90 91 /* xattr keys */92 struct xfarray *xattr_records;93 94 /* xattr values */95 struct xfblob *xattr_blobs;96 97 /* Number of attributes that we are salvaging. */98 unsigned long long attrs_found;99 100 /* Can we flush stashed attrs to the tempfile? */101 bool can_flush;102 103 /* Did the live update fail, and hence the repair is now out of date? */104 bool live_update_aborted;105 106 /* Lock protecting parent pointer updates */107 struct mutex lock;108 109 /* Fixed-size array of xrep_xattr_pptr structures. */110 struct xfarray *pptr_recs;111 112 /* Blobs containing parent pointer names. */113 struct xfblob *pptr_names;114 115 /* Hook to capture parent pointer updates. */116 struct xfs_dir_hook dhook;117 118 /* Scratch buffer for capturing parent pointers. */119 struct xfs_da_args pptr_args;120 121 /* Name buffer */122 struct xfs_name xname;123 char namebuf[MAXNAMELEN];124};125 126/* Create a parent pointer in the tempfile. */127#define XREP_XATTR_PPTR_ADD (1)128 129/* Remove a parent pointer from the tempfile. */130#define XREP_XATTR_PPTR_REMOVE (2)131 132/* A stashed parent pointer update. */133struct xrep_xattr_pptr {134 /* Cookie for retrieval of the pptr name. */135 xfblob_cookie name_cookie;136 137 /* Parent pointer record. */138 struct xfs_parent_rec pptr_rec;139 140 /* Length of the pptr name. */141 uint8_t namelen;142 143 /* XREP_XATTR_PPTR_{ADD,REMOVE} */144 uint8_t action;145};146 147/* Set up to recreate the extended attributes. */148int149xrep_setup_xattr(150 struct xfs_scrub *sc)151{152 if (xfs_has_parent(sc->mp))153 xchk_fsgates_enable(sc, XCHK_FSGATES_DIRENTS);154 155 return xrep_tempfile_create(sc, S_IFREG);156}157 158/*159 * Decide if we want to salvage this attribute. We don't bother with160 * incomplete or oversized keys or values. The @value parameter can be null161 * for remote attrs.162 */163STATIC int164xrep_xattr_want_salvage(165 struct xrep_xattr *rx,166 unsigned int attr_flags,167 const void *name,168 int namelen,169 const void *value,170 int valuelen)171{172 if (attr_flags & XFS_ATTR_INCOMPLETE)173 return false;174 if (namelen > XATTR_NAME_MAX || namelen <= 0)175 return false;176 if (!xfs_attr_namecheck(attr_flags, name, namelen))177 return false;178 if (valuelen > XATTR_SIZE_MAX || valuelen < 0)179 return false;180 if (attr_flags & XFS_ATTR_PARENT)181 return xfs_parent_valuecheck(rx->sc->mp, value, valuelen);182 183 return true;184}185 186/* Allocate an in-core record to hold xattrs while we rebuild the xattr data. */187STATIC int188xrep_xattr_salvage_key(189 struct xrep_xattr *rx,190 int flags,191 unsigned char *name,192 int namelen,193 unsigned char *value,194 int valuelen)195{196 struct xrep_xattr_key key = {197 .valuelen = valuelen,198 .flags = flags & XFS_ATTR_NSP_ONDISK_MASK,199 };200 unsigned int i = 0;201 int error = 0;202 203 if (xchk_should_terminate(rx->sc, &error))204 return error;205 206 /*207 * Truncate the name to the first character that would trip namecheck.208 * If we no longer have a name after that, ignore this attribute.209 */210 if (flags & XFS_ATTR_PARENT) {211 key.namelen = namelen;212 213 trace_xrep_xattr_salvage_pptr(rx->sc->ip, flags, name,214 key.namelen, value, valuelen);215 } else {216 while (i < namelen && name[i] != 0)217 i++;218 if (i == 0)219 return 0;220 key.namelen = i;221 222 trace_xrep_xattr_salvage_rec(rx->sc->ip, flags, name,223 key.namelen, valuelen);224 }225 226 error = xfblob_store(rx->xattr_blobs, &key.name_cookie, name,227 key.namelen);228 if (error)229 return error;230 231 error = xfblob_store(rx->xattr_blobs, &key.value_cookie, value,232 key.valuelen);233 if (error)234 return error;235 236 error = xfarray_append(rx->xattr_records, &key);237 if (error)238 return error;239 240 rx->attrs_found++;241 return 0;242}243 244/*245 * Record a shortform extended attribute key & value for later reinsertion246 * into the inode.247 */248STATIC int249xrep_xattr_salvage_sf_attr(250 struct xrep_xattr *rx,251 struct xfs_attr_sf_hdr *hdr,252 struct xfs_attr_sf_entry *sfe)253{254 struct xfs_scrub *sc = rx->sc;255 struct xchk_xattr_buf *ab = sc->buf;256 unsigned char *name = sfe->nameval;257 unsigned char *value = &sfe->nameval[sfe->namelen];258 259 if (!xchk_xattr_set_map(sc, ab->usedmap, (char *)name - (char *)hdr,260 sfe->namelen))261 return 0;262 263 if (!xchk_xattr_set_map(sc, ab->usedmap, (char *)value - (char *)hdr,264 sfe->valuelen))265 return 0;266 267 if (!xrep_xattr_want_salvage(rx, sfe->flags, sfe->nameval,268 sfe->namelen, value, sfe->valuelen))269 return 0;270 271 return xrep_xattr_salvage_key(rx, sfe->flags, sfe->nameval,272 sfe->namelen, value, sfe->valuelen);273}274 275/*276 * Record a local format extended attribute key & value for later reinsertion277 * into the inode.278 */279STATIC int280xrep_xattr_salvage_local_attr(281 struct xrep_xattr *rx,282 struct xfs_attr_leaf_entry *ent,283 unsigned int nameidx,284 const char *buf_end,285 struct xfs_attr_leaf_name_local *lentry)286{287 struct xchk_xattr_buf *ab = rx->sc->buf;288 unsigned char *value;289 unsigned int valuelen;290 unsigned int namesize;291 292 /*293 * Decode the leaf local entry format. If something seems wrong, we294 * junk the attribute.295 */296 value = &lentry->nameval[lentry->namelen];297 valuelen = be16_to_cpu(lentry->valuelen);298 namesize = xfs_attr_leaf_entsize_local(lentry->namelen, valuelen);299 if ((char *)lentry + namesize > buf_end)300 return 0;301 if (!xrep_xattr_want_salvage(rx, ent->flags, lentry->nameval,302 lentry->namelen, value, valuelen))303 return 0;304 if (!xchk_xattr_set_map(rx->sc, ab->usedmap, nameidx, namesize))305 return 0;306 307 /* Try to save this attribute. */308 return xrep_xattr_salvage_key(rx, ent->flags, lentry->nameval,309 lentry->namelen, value, valuelen);310}311 312/*313 * Record a remote format extended attribute key & value for later reinsertion314 * into the inode.315 */316STATIC int317xrep_xattr_salvage_remote_attr(318 struct xrep_xattr *rx,319 struct xfs_attr_leaf_entry *ent,320 unsigned int nameidx,321 const char *buf_end,322 struct xfs_attr_leaf_name_remote *rentry,323 unsigned int ent_idx,324 struct xfs_buf *leaf_bp)325{326 struct xchk_xattr_buf *ab = rx->sc->buf;327 struct xfs_da_args args = {328 .trans = rx->sc->tp,329 .dp = rx->sc->ip,330 .index = ent_idx,331 .geo = rx->sc->mp->m_attr_geo,332 .owner = rx->sc->ip->i_ino,333 .attr_filter = ent->flags & XFS_ATTR_NSP_ONDISK_MASK,334 .namelen = rentry->namelen,335 .name = rentry->name,336 .value = ab->value,337 .valuelen = be32_to_cpu(rentry->valuelen),338 };339 unsigned int namesize;340 int error;341 342 /*343 * Decode the leaf remote entry format. If something seems wrong, we344 * junk the attribute. Note that we should never find a zero-length345 * remote attribute value.346 */347 namesize = xfs_attr_leaf_entsize_remote(rentry->namelen);348 if ((char *)rentry + namesize > buf_end)349 return 0;350 if (args.valuelen == 0 ||351 !xrep_xattr_want_salvage(rx, ent->flags, rentry->name,352 rentry->namelen, NULL, args.valuelen))353 return 0;354 if (!xchk_xattr_set_map(rx->sc, ab->usedmap, nameidx, namesize))355 return 0;356 357 /*358 * Enlarge the buffer (if needed) to hold the value that we're trying359 * to salvage from the old extended attribute data.360 */361 error = xchk_setup_xattr_buf(rx->sc, args.valuelen);362 if (error == -ENOMEM)363 error = -EDEADLOCK;364 if (error)365 return error;366 367 /* Look up the remote value and stash it for reconstruction. */368 error = xfs_attr3_leaf_getvalue(leaf_bp, &args);369 if (error || args.rmtblkno == 0)370 goto err_free;371 372 error = xfs_attr_rmtval_get(&args);373 if (error)374 goto err_free;375 376 /* Try to save this attribute. */377 error = xrep_xattr_salvage_key(rx, ent->flags, rentry->name,378 rentry->namelen, ab->value, args.valuelen);379err_free:380 /* remote value was garbage, junk it */381 if (error == -EFSBADCRC || error == -EFSCORRUPTED)382 error = 0;383 return error;384}385 386/* Extract every xattr key that we can from this attr fork block. */387STATIC int388xrep_xattr_recover_leaf(389 struct xrep_xattr *rx,390 struct xfs_buf *bp)391{392 struct xfs_attr3_icleaf_hdr leafhdr;393 struct xfs_scrub *sc = rx->sc;394 struct xfs_mount *mp = sc->mp;395 struct xfs_attr_leafblock *leaf;396 struct xfs_attr_leaf_name_local *lentry;397 struct xfs_attr_leaf_name_remote *rentry;398 struct xfs_attr_leaf_entry *ent;399 struct xfs_attr_leaf_entry *entries;400 struct xchk_xattr_buf *ab = rx->sc->buf;401 char *buf_end;402 size_t off;403 unsigned int nameidx;404 unsigned int hdrsize;405 int i;406 int error = 0;407 408 bitmap_zero(ab->usedmap, mp->m_attr_geo->blksize);409 410 /* Check the leaf header */411 leaf = bp->b_addr;412 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);413 hdrsize = xfs_attr3_leaf_hdr_size(leaf);414 xchk_xattr_set_map(sc, ab->usedmap, 0, hdrsize);415 entries = xfs_attr3_leaf_entryp(leaf);416 417 buf_end = (char *)bp->b_addr + mp->m_attr_geo->blksize;418 for (i = 0, ent = entries; i < leafhdr.count; ent++, i++) {419 if (xchk_should_terminate(sc, &error))420 return error;421 422 /* Skip key if it conflicts with something else? */423 off = (char *)ent - (char *)leaf;424 if (!xchk_xattr_set_map(sc, ab->usedmap, off,425 sizeof(xfs_attr_leaf_entry_t)))426 continue;427 428 /* Check the name information. */429 nameidx = be16_to_cpu(ent->nameidx);430 if (nameidx < leafhdr.firstused ||431 nameidx >= mp->m_attr_geo->blksize)432 continue;433 434 if (ent->flags & XFS_ATTR_LOCAL) {435 lentry = xfs_attr3_leaf_name_local(leaf, i);436 error = xrep_xattr_salvage_local_attr(rx, ent, nameidx,437 buf_end, lentry);438 } else {439 rentry = xfs_attr3_leaf_name_remote(leaf, i);440 error = xrep_xattr_salvage_remote_attr(rx, ent, nameidx,441 buf_end, rentry, i, bp);442 }443 if (error)444 return error;445 }446 447 return 0;448}449 450/* Try to recover shortform attrs. */451STATIC int452xrep_xattr_recover_sf(453 struct xrep_xattr *rx)454{455 struct xfs_scrub *sc = rx->sc;456 struct xchk_xattr_buf *ab = sc->buf;457 struct xfs_attr_sf_hdr *hdr;458 struct xfs_attr_sf_entry *sfe;459 struct xfs_attr_sf_entry *next;460 struct xfs_ifork *ifp;461 unsigned char *end;462 int i;463 int error = 0;464 465 ifp = xfs_ifork_ptr(rx->sc->ip, XFS_ATTR_FORK);466 hdr = ifp->if_data;467 468 bitmap_zero(ab->usedmap, ifp->if_bytes);469 end = (unsigned char *)ifp->if_data + ifp->if_bytes;470 xchk_xattr_set_map(sc, ab->usedmap, 0, sizeof(*hdr));471 472 sfe = xfs_attr_sf_firstentry(hdr);473 if ((unsigned char *)sfe > end)474 return 0;475 476 for (i = 0; i < hdr->count; i++) {477 if (xchk_should_terminate(sc, &error))478 return error;479 480 next = xfs_attr_sf_nextentry(sfe);481 if ((unsigned char *)next > end)482 break;483 484 if (xchk_xattr_set_map(sc, ab->usedmap,485 (char *)sfe - (char *)hdr,486 sizeof(struct xfs_attr_sf_entry))) {487 /*488 * No conflicts with the sf entry; let's save this489 * attribute.490 */491 error = xrep_xattr_salvage_sf_attr(rx, hdr, sfe);492 if (error)493 return error;494 }495 496 sfe = next;497 }498 499 return 0;500}501 502/*503 * Try to return a buffer of xattr data for a given physical extent.504 *505 * Because the buffer cache get function complains if it finds a buffer506 * matching the block number but not matching the length, we must be careful to507 * look for incore buffers (up to the maximum length of a remote value) that508 * could be hiding anywhere in the physical range. If we find an incore509 * buffer, we can pass that to the caller. Optionally, read a single block and510 * pass that back.511 *512 * Note the subtlety that remote attr value blocks for which there is no incore513 * buffer will be passed to the callback one block at a time. These buffers514 * will not have any ops attached and must be staled to prevent aliasing with515 * multiblock buffers once we drop the ILOCK.516 */517STATIC int518xrep_xattr_find_buf(519 struct xfs_mount *mp,520 xfs_fsblock_t fsbno,521 xfs_extlen_t max_len,522 bool can_read,523 struct xfs_buf **bpp)524{525 struct xrep_bufscan scan = {526 .daddr = XFS_FSB_TO_DADDR(mp, fsbno),527 .max_sectors = xrep_bufscan_max_sectors(mp, max_len),528 .daddr_step = XFS_FSB_TO_BB(mp, 1),529 };530 struct xfs_buf *bp;531 532 while ((bp = xrep_bufscan_advance(mp, &scan)) != NULL) {533 *bpp = bp;534 return 0;535 }536 537 if (!can_read) {538 *bpp = NULL;539 return 0;540 }541 542 return xfs_buf_read(mp->m_ddev_targp, scan.daddr, XFS_FSB_TO_BB(mp, 1),543 XBF_TRYLOCK, bpp, NULL);544}545 546/*547 * Deal with a buffer that we found during our walk of the attr fork.548 *549 * Attribute leaf and node blocks are simple -- they're a single block, so we550 * can walk them one at a time and we never have to worry about discontiguous551 * multiblock buffers like we do for directories.552 *553 * Unfortunately, remote attr blocks add a lot of complexity here. Each disk554 * block is totally self contained, in the sense that the v5 header provides no555 * indication that there could be more data in the next block. The incore556 * buffers can span multiple blocks, though they never cross extent records.557 * However, they don't necessarily start or end on an extent record boundary.558 * Therefore, we need a special buffer find function to walk the buffer cache559 * for us.560 *561 * The caller must hold the ILOCK on the file being repaired. We use562 * XBF_TRYLOCK here to skip any locked buffer on the assumption that we don't563 * own the block and don't want to hang the system on a potentially garbage564 * buffer.565 */566STATIC int567xrep_xattr_recover_block(568 struct xrep_xattr *rx,569 xfs_dablk_t dabno,570 xfs_fsblock_t fsbno,571 xfs_extlen_t max_len,572 xfs_extlen_t *actual_len)573{574 struct xfs_da_blkinfo *info;575 struct xfs_buf *bp;576 int error;577 578 error = xrep_xattr_find_buf(rx->sc->mp, fsbno, max_len, true, &bp);579 if (error)580 return error;581 info = bp->b_addr;582 *actual_len = XFS_BB_TO_FSB(rx->sc->mp, bp->b_length);583 584 trace_xrep_xattr_recover_leafblock(rx->sc->ip, dabno,585 be16_to_cpu(info->magic));586 587 /*588 * If the buffer has the right magic number for an attr leaf block and589 * passes a structure check (we don't care about checksums), salvage590 * as much as we can from the block. */591 if (info->magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC) &&592 xrep_buf_verify_struct(bp, &xfs_attr3_leaf_buf_ops) &&593 xfs_attr3_leaf_header_check(bp, rx->sc->ip->i_ino) == NULL)594 error = xrep_xattr_recover_leaf(rx, bp);595 596 /*597 * If the buffer didn't already have buffer ops set, it was read in by598 * the _find_buf function and could very well be /part/ of a multiblock599 * remote block. Mark it stale so that it doesn't hang around in600 * memory to cause problems.601 */602 if (bp->b_ops == NULL)603 xfs_buf_stale(bp);604 605 xfs_buf_relse(bp);606 return error;607}608 609/* Insert one xattr key/value. */610STATIC int611xrep_xattr_insert_rec(612 struct xrep_xattr *rx,613 const struct xrep_xattr_key *key)614{615 struct xfs_da_args args = {616 .dp = rx->sc->tempip,617 .attr_filter = key->flags,618 .namelen = key->namelen,619 .valuelen = key->valuelen,620 .owner = rx->sc->ip->i_ino,621 .geo = rx->sc->mp->m_attr_geo,622 .whichfork = XFS_ATTR_FORK,623 .op_flags = XFS_DA_OP_OKNOENT,624 };625 struct xchk_xattr_buf *ab = rx->sc->buf;626 int error;627 628 /*629 * Grab pointers to the scrub buffer so that we can use them to insert630 * attrs into the temp file.631 */632 args.name = ab->name;633 args.value = ab->value;634 635 /*636 * The attribute name is stored near the end of the in-core buffer,637 * though we reserve one more byte to ensure null termination.638 */639 ab->name[XATTR_NAME_MAX] = 0;640 641 error = xfblob_load(rx->xattr_blobs, key->name_cookie, ab->name,642 key->namelen);643 if (error)644 return error;645 646 error = xfblob_free(rx->xattr_blobs, key->name_cookie);647 if (error)648 return error;649 650 error = xfblob_load(rx->xattr_blobs, key->value_cookie, args.value,651 key->valuelen);652 if (error)653 return error;654 655 error = xfblob_free(rx->xattr_blobs, key->value_cookie);656 if (error)657 return error;658 659 ab->name[key->namelen] = 0;660 661 if (key->flags & XFS_ATTR_PARENT) {662 trace_xrep_xattr_insert_pptr(rx->sc->tempip, key->flags,663 ab->name, key->namelen, ab->value,664 key->valuelen);665 args.op_flags |= XFS_DA_OP_LOGGED;666 } else {667 trace_xrep_xattr_insert_rec(rx->sc->tempip, key->flags,668 ab->name, key->namelen, key->valuelen);669 }670 671 /*672 * xfs_attr_set creates and commits its own transaction. If the attr673 * already exists, we'll just drop it during the rebuild.674 */675 xfs_attr_sethash(&args);676 error = xfs_attr_set(&args, XFS_ATTRUPDATE_CREATE, false);677 if (error == -EEXIST)678 error = 0;679 680 return error;681}682 683/*684 * Periodically flush salvaged attributes to the temporary file. This is done685 * to reduce the memory requirements of the xattr rebuild because files can686 * contain millions of attributes.687 */688STATIC int689xrep_xattr_flush_stashed(690 struct xrep_xattr *rx)691{692 xfarray_idx_t array_cur;693 int error;694 695 /*696 * Entering this function, the scrub context has a reference to the697 * inode being repaired, the temporary file, and a scrub transaction698 * that we use during xattr salvaging to avoid livelocking if there699 * are cycles in the xattr structures. We hold ILOCK_EXCL on both700 * the inode being repaired, though it is not ijoined to the scrub701 * transaction.702 *703 * To constrain kernel memory use, we occasionally flush salvaged704 * xattrs from the xfarray and xfblob structures into the temporary705 * file in preparation for exchanging the xattr structures at the end.706 * Updating the temporary file requires a transaction, so we commit the707 * scrub transaction and drop the two ILOCKs so that xfs_attr_set can708 * allocate whatever transaction it wants.709 *710 * We still hold IOLOCK_EXCL on the inode being repaired, which711 * prevents anyone from modifying the damaged xattr data while we712 * repair it.713 */714 error = xrep_trans_commit(rx->sc);715 if (error)716 return error;717 xchk_iunlock(rx->sc, XFS_ILOCK_EXCL);718 719 /*720 * Take the IOLOCK of the temporary file while we modify xattrs. This721 * isn't strictly required because the temporary file is never revealed722 * to userspace, but we follow the same locking rules. We still hold723 * sc->ip's IOLOCK.724 */725 error = xrep_tempfile_iolock_polled(rx->sc);726 if (error)727 return error;728 729 /* Add all the salvaged attrs to the temporary file. */730 foreach_xfarray_idx(rx->xattr_records, array_cur) {731 struct xrep_xattr_key key;732 733 error = xfarray_load(rx->xattr_records, array_cur, &key);734 if (error)735 return error;736 737 error = xrep_xattr_insert_rec(rx, &key);738 if (error)739 return error;740 }741 742 /* Empty out both arrays now that we've added the entries. */743 xfarray_truncate(rx->xattr_records);744 xfblob_truncate(rx->xattr_blobs);745 746 xrep_tempfile_iounlock(rx->sc);747 748 /* Recreate the salvage transaction and relock the inode. */749 error = xchk_trans_alloc(rx->sc, 0);750 if (error)751 return error;752 xchk_ilock(rx->sc, XFS_ILOCK_EXCL);753 return 0;754}755 756/* Decide if we've stashed too much xattr data in memory. */757static inline bool758xrep_xattr_want_flush_stashed(759 struct xrep_xattr *rx)760{761 unsigned long long bytes;762 763 if (!rx->can_flush)764 return false;765 766 bytes = xfarray_bytes(rx->xattr_records) +767 xfblob_bytes(rx->xattr_blobs);768 return bytes > XREP_XATTR_MAX_STASH_BYTES;769}770 771/*772 * Did we observe rename changing parent pointer xattrs while we were flushing773 * salvaged attrs?774 */775static inline bool776xrep_xattr_saw_pptr_conflict(777 struct xrep_xattr *rx)778{779 bool ret;780 781 ASSERT(rx->can_flush);782 783 if (!xfs_has_parent(rx->sc->mp))784 return false;785 786 xfs_assert_ilocked(rx->sc->ip, XFS_ILOCK_EXCL);787 788 mutex_lock(&rx->lock);789 ret = xfarray_bytes(rx->pptr_recs) > 0;790 mutex_unlock(&rx->lock);791 792 return ret;793}794 795/*796 * Reset the entire repair state back to initial conditions, now that we've797 * detected a parent pointer update to the attr structure while we were798 * flushing salvaged attrs. See the locking notes in dir_repair.c for more799 * information on why this is all necessary.800 */801STATIC int802xrep_xattr_full_reset(803 struct xrep_xattr *rx)804{805 struct xfs_scrub *sc = rx->sc;806 struct xfs_attr_sf_hdr *hdr;807 struct xfs_ifork *ifp = &sc->tempip->i_af;808 int error;809 810 trace_xrep_xattr_full_reset(sc->ip, sc->tempip);811 812 /* The temporary file's data fork had better not be in btree format. */813 if (sc->tempip->i_df.if_format == XFS_DINODE_FMT_BTREE) {814 ASSERT(0);815 return -EIO;816 }817 818 /*819 * We begin in transaction context with sc->ip ILOCKed but not joined820 * to the transaction. To reset to the initial state, we must hold821 * sc->ip's ILOCK to prevent rename from updating parent pointer822 * information and the tempfile's ILOCK to clear its contents.823 */824 xchk_iunlock(rx->sc, XFS_ILOCK_EXCL);825 xrep_tempfile_ilock_both(sc);826 xfs_trans_ijoin(sc->tp, sc->ip, 0);827 xfs_trans_ijoin(sc->tp, sc->tempip, 0);828 829 /*830 * Free all the blocks of the attr fork of the temp file, and reset831 * it back to local format.832 */833 if (xfs_ifork_has_extents(&sc->tempip->i_af)) {834 error = xrep_reap_ifork(sc, sc->tempip, XFS_ATTR_FORK);835 if (error)836 return error;837 838 ASSERT(ifp->if_bytes == 0);839 ifp->if_format = XFS_DINODE_FMT_LOCAL;840 xfs_idata_realloc(sc->tempip, sizeof(*hdr), XFS_ATTR_FORK);841 }842 843 /* Reinitialize the attr fork to an empty shortform structure. */844 hdr = ifp->if_data;845 memset(hdr, 0, sizeof(*hdr));846 hdr->totsize = cpu_to_be16(sizeof(*hdr));847 xfs_trans_log_inode(sc->tp, sc->tempip, XFS_ILOG_CORE | XFS_ILOG_ADATA);848 849 /*850 * Roll this transaction to commit our reset ondisk. The tempfile851 * should no longer be joined to the transaction, so we drop its ILOCK.852 * This should leave us in transaction context with sc->ip ILOCKed but853 * not joined to the transaction.854 */855 error = xrep_roll_trans(sc);856 if (error)857 return error;858 xrep_tempfile_iunlock(sc);859 860 /*861 * Erase any accumulated parent pointer updates now that we've erased862 * the tempfile's attr fork. We're resetting the entire repair state863 * back to where we were initially, except now we won't flush salvaged864 * xattrs until the very end.865 */866 mutex_lock(&rx->lock);867 xfarray_truncate(rx->pptr_recs);868 xfblob_truncate(rx->pptr_names);869 mutex_unlock(&rx->lock);870 871 rx->can_flush = false;872 rx->attrs_found = 0;873 874 ASSERT(xfarray_bytes(rx->xattr_records) == 0);875 ASSERT(xfblob_bytes(rx->xattr_blobs) == 0);876 return 0;877}878 879/* Extract as many attribute keys and values as we can. */880STATIC int881xrep_xattr_recover(882 struct xrep_xattr *rx)883{884 struct xfs_bmbt_irec got;885 struct xfs_scrub *sc = rx->sc;886 struct xfs_da_geometry *geo = sc->mp->m_attr_geo;887 xfs_fileoff_t offset;888 xfs_extlen_t len;889 xfs_dablk_t dabno;890 int nmap;891 int error;892 893restart:894 /*895 * Iterate each xattr leaf block in the attr fork to scan them for any896 * attributes that we might salvage.897 */898 for (offset = 0;899 offset < XFS_MAX_FILEOFF;900 offset = got.br_startoff + got.br_blockcount) {901 nmap = 1;902 error = xfs_bmapi_read(sc->ip, offset, XFS_MAX_FILEOFF - offset,903 &got, &nmap, XFS_BMAPI_ATTRFORK);904 if (error)905 return error;906 if (nmap != 1)907 return -EFSCORRUPTED;908 if (!xfs_bmap_is_written_extent(&got))909 continue;910 911 for (dabno = round_up(got.br_startoff, geo->fsbcount);912 dabno < got.br_startoff + got.br_blockcount;913 dabno += len) {914 xfs_fileoff_t curr_offset = dabno - got.br_startoff;915 xfs_extlen_t maxlen;916 917 if (xchk_should_terminate(rx->sc, &error))918 return error;919 920 maxlen = min_t(xfs_filblks_t, INT_MAX,921 got.br_blockcount - curr_offset);922 error = xrep_xattr_recover_block(rx, dabno,923 curr_offset + got.br_startblock,924 maxlen, &len);925 if (error)926 return error;927 928 if (xrep_xattr_want_flush_stashed(rx)) {929 error = xrep_xattr_flush_stashed(rx);930 if (error)931 return error;932 933 if (xrep_xattr_saw_pptr_conflict(rx)) {934 error = xrep_xattr_full_reset(rx);935 if (error)936 return error;937 938 goto restart;939 }940 }941 }942 }943 944 return 0;945}946 947/*948 * Reset the extended attribute fork to a state where we can start re-adding949 * the salvaged attributes.950 */951STATIC int952xrep_xattr_fork_remove(953 struct xfs_scrub *sc,954 struct xfs_inode *ip)955{956 struct xfs_attr_sf_hdr *hdr;957 struct xfs_ifork *ifp = xfs_ifork_ptr(ip, XFS_ATTR_FORK);958 959 /*960 * If the data fork is in btree format, we can't change di_forkoff961 * because we could run afoul of the rule that the data fork isn't962 * supposed to be in btree format if there's enough space in the fork963 * that it could have used extents format. Instead, reinitialize the964 * attr fork to have a shortform structure with zero attributes.965 */966 if (ip->i_df.if_format == XFS_DINODE_FMT_BTREE) {967 ifp->if_format = XFS_DINODE_FMT_LOCAL;968 hdr = xfs_idata_realloc(ip, (int)sizeof(*hdr) - ifp->if_bytes,969 XFS_ATTR_FORK);970 hdr->count = 0;971 hdr->totsize = cpu_to_be16(sizeof(*hdr));972 xfs_trans_log_inode(sc->tp, ip,973 XFS_ILOG_CORE | XFS_ILOG_ADATA);974 return 0;975 }976 977 /* If we still have attr fork extents, something's wrong. */978 if (ifp->if_nextents != 0) {979 struct xfs_iext_cursor icur;980 struct xfs_bmbt_irec irec;981 unsigned int i = 0;982 983 xfs_emerg(sc->mp,984 "inode 0x%llx attr fork still has %llu attr extents, format %d?!",985 ip->i_ino, ifp->if_nextents, ifp->if_format);986 for_each_xfs_iext(ifp, &icur, &irec) {987 xfs_err(sc->mp,988 "[%u]: startoff %llu startblock %llu blockcount %llu state %u",989 i++, irec.br_startoff,990 irec.br_startblock, irec.br_blockcount,991 irec.br_state);992 }993 ASSERT(0);994 return -EFSCORRUPTED;995 }996 997 xfs_attr_fork_remove(ip, sc->tp);998 return 0;999}1000 1001/*1002 * Free all the attribute fork blocks of the file being repaired and delete the1003 * fork. The caller must ILOCK the scrub file and join it to the transaction.1004 * This function returns with the inode joined to a clean transaction.1005 */1006int1007xrep_xattr_reset_fork(1008 struct xfs_scrub *sc)1009{1010 int error;1011 1012 trace_xrep_xattr_reset_fork(sc->ip, sc->ip);1013 1014 /* Unmap all the attr blocks. */1015 if (xfs_ifork_has_extents(&sc->ip->i_af)) {1016 error = xrep_reap_ifork(sc, sc->ip, XFS_ATTR_FORK);1017 if (error)1018 return error;1019 }1020 1021 error = xrep_xattr_fork_remove(sc, sc->ip);1022 if (error)1023 return error;1024 1025 return xfs_trans_roll_inode(&sc->tp, sc->ip);1026}1027 1028/*1029 * Free all the attribute fork blocks of the temporary file and delete the attr1030 * fork. The caller must ILOCK the tempfile and join it to the transaction.1031 * This function returns with the inode joined to a clean scrub transaction.1032 */1033int1034xrep_xattr_reset_tempfile_fork(1035 struct xfs_scrub *sc)1036{1037 int error;1038 1039 trace_xrep_xattr_reset_fork(sc->ip, sc->tempip);1040 1041 /*1042 * Wipe out the attr fork of the temp file so that regular inode1043 * inactivation won't trip over the corrupt attr fork.1044 */1045 if (xfs_ifork_has_extents(&sc->tempip->i_af)) {1046 error = xrep_reap_ifork(sc, sc->tempip, XFS_ATTR_FORK);1047 if (error)1048 return error;1049 }1050 1051 return xrep_xattr_fork_remove(sc, sc->tempip);1052}1053 1054/*1055 * Find all the extended attributes for this inode by scraping them out of the1056 * attribute key blocks by hand, and flushing them into the temp file.1057 * When we're done, free the staging memory before exchanging the xattr1058 * structures to reduce memory usage.1059 */1060STATIC int1061xrep_xattr_salvage_attributes(1062 struct xrep_xattr *rx)1063{1064 struct xfs_inode *ip = rx->sc->ip;1065 int error;1066 1067 /* Short format xattrs are easy! */1068 if (rx->sc->ip->i_af.if_format == XFS_DINODE_FMT_LOCAL) {1069 error = xrep_xattr_recover_sf(rx);1070 if (error)1071 return error;1072 1073 return xrep_xattr_flush_stashed(rx);1074 }1075 1076 /*1077 * For non-inline xattr structures, the salvage function scans the1078 * buffer cache looking for potential attr leaf blocks. The scan1079 * requires the ability to lock any buffer found and runs independently1080 * of any transaction <-> buffer item <-> buffer linkage. Therefore,1081 * roll the transaction to ensure there are no buffers joined. We hold1082 * the ILOCK independently of the transaction.1083 */1084 error = xfs_trans_roll(&rx->sc->tp);1085 if (error)1086 return error;1087 1088 error = xfs_iread_extents(rx->sc->tp, ip, XFS_ATTR_FORK);1089 if (error)1090 return error;1091 1092 error = xrep_xattr_recover(rx);1093 if (error)1094 return error;1095 1096 return xrep_xattr_flush_stashed(rx);1097}1098 1099/*1100 * Add this stashed incore parent pointer to the temporary file. The caller1101 * must hold the tempdir's IOLOCK, must not hold any ILOCKs, and must not be in1102 * transaction context.1103 */1104STATIC int1105xrep_xattr_replay_pptr_update(1106 struct xrep_xattr *rx,1107 const struct xfs_name *xname,1108 struct xrep_xattr_pptr *pptr)1109{1110 struct xfs_scrub *sc = rx->sc;1111 int error;1112 1113 switch (pptr->action) {1114 case XREP_XATTR_PPTR_ADD:1115 /* Create parent pointer. */1116 trace_xrep_xattr_replay_parentadd(sc->tempip, xname,1117 &pptr->pptr_rec);1118 1119 error = xfs_parent_set(sc->tempip, sc->ip->i_ino, xname,1120 &pptr->pptr_rec, &rx->pptr_args);1121 ASSERT(error != -EEXIST);1122 return error;1123 case XREP_XATTR_PPTR_REMOVE:1124 /* Remove parent pointer. */1125 trace_xrep_xattr_replay_parentremove(sc->tempip, xname,1126 &pptr->pptr_rec);1127 1128 error = xfs_parent_unset(sc->tempip, sc->ip->i_ino, xname,1129 &pptr->pptr_rec, &rx->pptr_args);1130 ASSERT(error != -ENOATTR);1131 return error;1132 }1133 1134 ASSERT(0);1135 return -EIO;1136}1137 1138/*1139 * Flush stashed parent pointer updates that have been recorded by the scanner.1140 * This is done to reduce the memory requirements of the xattr rebuild, since1141 * files can have a lot of hardlinks and the fs can be busy.1142 *1143 * Caller must not hold transactions or ILOCKs. Caller must hold the tempfile1144 * IOLOCK.1145 */1146STATIC int1147xrep_xattr_replay_pptr_updates(1148 struct xrep_xattr *rx)1149{1150 xfarray_idx_t array_cur;1151 int error;1152 1153 mutex_lock(&rx->lock);1154 foreach_xfarray_idx(rx->pptr_recs, array_cur) {1155 struct xrep_xattr_pptr pptr;1156 1157 error = xfarray_load(rx->pptr_recs, array_cur, &pptr);1158 if (error)1159 goto out_unlock;1160 1161 error = xfblob_loadname(rx->pptr_names, pptr.name_cookie,1162 &rx->xname, pptr.namelen);1163 if (error)1164 goto out_unlock;1165 mutex_unlock(&rx->lock);1166 1167 error = xrep_xattr_replay_pptr_update(rx, &rx->xname, &pptr);1168 if (error)1169 return error;1170 1171 mutex_lock(&rx->lock);1172 }1173 1174 /* Empty out both arrays now that we've added the entries. */1175 xfarray_truncate(rx->pptr_recs);1176 xfblob_truncate(rx->pptr_names);1177 mutex_unlock(&rx->lock);1178 return 0;1179out_unlock:1180 mutex_unlock(&rx->lock);1181 return error;1182}1183 1184/*1185 * Remember that we want to create a parent pointer in the tempfile. These1186 * stashed actions will be replayed later.1187 */1188STATIC int1189xrep_xattr_stash_parentadd(1190 struct xrep_xattr *rx,1191 const struct xfs_name *name,1192 const struct xfs_inode *dp)1193{1194 struct xrep_xattr_pptr pptr = {1195 .action = XREP_XATTR_PPTR_ADD,1196 .namelen = name->len,1197 };1198 int error;1199 1200 trace_xrep_xattr_stash_parentadd(rx->sc->tempip, dp, name);1201 1202 xfs_inode_to_parent_rec(&pptr.pptr_rec, dp);1203 error = xfblob_storename(rx->pptr_names, &pptr.name_cookie, name);1204 if (error)1205 return error;1206 1207 return xfarray_append(rx->pptr_recs, &pptr);1208}1209 1210/*1211 * Remember that we want to remove a parent pointer from the tempfile. These1212 * stashed actions will be replayed later.1213 */1214STATIC int1215xrep_xattr_stash_parentremove(1216 struct xrep_xattr *rx,1217 const struct xfs_name *name,1218 const struct xfs_inode *dp)1219{1220 struct xrep_xattr_pptr pptr = {1221 .action = XREP_XATTR_PPTR_REMOVE,1222 .namelen = name->len,1223 };1224 int error;1225 1226 trace_xrep_xattr_stash_parentremove(rx->sc->tempip, dp, name);1227 1228 xfs_inode_to_parent_rec(&pptr.pptr_rec, dp);1229 error = xfblob_storename(rx->pptr_names, &pptr.name_cookie, name);1230 if (error)1231 return error;1232 1233 return xfarray_append(rx->pptr_recs, &pptr);1234}1235 1236/*1237 * Capture dirent updates being made by other threads. We will have to replay1238 * the parent pointer updates before exchanging attr forks.1239 */1240STATIC int1241xrep_xattr_live_dirent_update(1242 struct notifier_block *nb,1243 unsigned long action,1244 void *data)1245{1246 struct xfs_dir_update_params *p = data;1247 struct xrep_xattr *rx;1248 struct xfs_scrub *sc;1249 int error;1250 1251 rx = container_of(nb, struct xrep_xattr, dhook.dirent_hook.nb);1252 sc = rx->sc;1253 1254 /*1255 * This thread updated a dirent that points to the file that we're1256 * repairing, so stash the update for replay against the temporary1257 * file.1258 */1259 if (p->ip->i_ino != sc->ip->i_ino)1260 return NOTIFY_DONE;1261 1262 mutex_lock(&rx->lock);1263 if (p->delta > 0)1264 error = xrep_xattr_stash_parentadd(rx, p->name, p->dp);1265 else1266 error = xrep_xattr_stash_parentremove(rx, p->name, p->dp);1267 if (error)1268 rx->live_update_aborted = true;1269 mutex_unlock(&rx->lock);1270 return NOTIFY_DONE;1271}1272 1273/*1274 * Prepare both inodes' attribute forks for an exchange. Promote the tempfile1275 * from short format to leaf format, and if the file being repaired has a short1276 * format attr fork, turn it into an empty extent list.1277 */1278STATIC int1279xrep_xattr_swap_prep(1280 struct xfs_scrub *sc,1281 bool temp_local,1282 bool ip_local)1283{1284 int error;1285 1286 /*1287 * If the tempfile's attributes are in shortform format, convert that1288 * to a single leaf extent so that we can use the atomic mapping1289 * exchange.1290 */1291 if (temp_local) {1292 struct xfs_da_args args = {1293 .dp = sc->tempip,1294 .geo = sc->mp->m_attr_geo,1295 .whichfork = XFS_ATTR_FORK,1296 .trans = sc->tp,1297 .total = 1,1298 .owner = sc->ip->i_ino,1299 };1300 1301 error = xfs_attr_shortform_to_leaf(&args);1302 if (error)1303 return error;1304 1305 /*1306 * Roll the deferred log items to get us back to a clean1307 * transaction.1308 */1309 error = xfs_defer_finish(&sc->tp);1310 if (error)1311 return error;1312 }1313 1314 /*1315 * If the file being repaired had a shortform attribute fork, convert1316 * that to an empty extent list in preparation for the atomic mapping1317 * exchange.1318 */1319 if (ip_local) {1320 struct xfs_ifork *ifp;1321 1322 ifp = xfs_ifork_ptr(sc->ip, XFS_ATTR_FORK);1323 1324 xfs_idestroy_fork(ifp);1325 ifp->if_format = XFS_DINODE_FMT_EXTENTS;1326 ifp->if_nextents = 0;1327 ifp->if_bytes = 0;1328 ifp->if_data = NULL;1329 ifp->if_height = 0;1330 1331 xfs_trans_log_inode(sc->tp, sc->ip,1332 XFS_ILOG_CORE | XFS_ILOG_ADATA);1333 }1334 1335 return 0;1336}1337 1338/* Exchange the temporary file's attribute fork with the one being repaired. */1339int1340xrep_xattr_swap(1341 struct xfs_scrub *sc,1342 struct xrep_tempexch *tx)1343{1344 bool ip_local, temp_local;1345 int error = 0;1346 1347 ip_local = sc->ip->i_af.if_format == XFS_DINODE_FMT_LOCAL;1348 temp_local = sc->tempip->i_af.if_format == XFS_DINODE_FMT_LOCAL;1349 1350 /*1351 * If the both files have a local format attr fork and the rebuilt1352 * xattr data would fit in the repaired file's attr fork, just copy1353 * the contents from the tempfile and declare ourselves done.1354 */1355 if (ip_local && temp_local) {1356 int forkoff;1357 int newsize;1358 1359 newsize = xfs_attr_sf_totsize(sc->tempip);1360 forkoff = xfs_attr_shortform_bytesfit(sc->ip, newsize);1361 if (forkoff > 0) {1362 sc->ip->i_forkoff = forkoff;1363 xrep_tempfile_copyout_local(sc, XFS_ATTR_FORK);1364 return 0;1365 }1366 }1367 1368 /* Otherwise, make sure both attr forks are in block-mapping mode. */1369 error = xrep_xattr_swap_prep(sc, temp_local, ip_local);1370 if (error)1371 return error;1372 1373 return xrep_tempexch_contents(sc, tx);1374}1375 1376/*1377 * Finish replaying stashed parent pointer updates, allocate a transaction for1378 * exchanging extent mappings, and take the ILOCKs of both files before we1379 * commit the new extended attribute structure.1380 */1381STATIC int1382xrep_xattr_finalize_tempfile(1383 struct xrep_xattr *rx)1384{1385 struct xfs_scrub *sc = rx->sc;1386 int error;1387 1388 if (!xfs_has_parent(sc->mp))1389 return xrep_tempexch_trans_alloc(sc, XFS_ATTR_FORK, &rx->tx);1390 1391 /*1392 * Repair relies on the ILOCK to quiesce all possible xattr updates.1393 * Replay all queued parent pointer updates into the tempfile before1394 * exchanging the contents, even if that means dropping the ILOCKs and1395 * the transaction.1396 */1397 do {1398 error = xrep_xattr_replay_pptr_updates(rx);1399 if (error)1400 return error;1401 1402 error = xrep_tempexch_trans_alloc(sc, XFS_ATTR_FORK, &rx->tx);1403 if (error)1404 return error;1405 1406 if (xfarray_length(rx->pptr_recs) == 0)1407 break;1408 1409 xchk_trans_cancel(sc);1410 xrep_tempfile_iunlock_both(sc);1411 } while (!xchk_should_terminate(sc, &error));1412 return error;1413}1414 1415/*1416 * Exchange the new extended attribute data (which we created in the tempfile)1417 * with the file being repaired.1418 */1419STATIC int1420xrep_xattr_rebuild_tree(1421 struct xrep_xattr *rx)1422{1423 struct xfs_scrub *sc = rx->sc;1424 int error;1425 1426 /*1427 * If we didn't find any attributes to salvage, repair the file by1428 * zapping its attr fork.1429 */1430 if (rx->attrs_found == 0) {1431 xfs_trans_ijoin(sc->tp, sc->ip, 0);1432 error = xrep_xattr_reset_fork(sc);1433 if (error)1434 return error;1435 1436 goto forget_acls;1437 }1438 1439 trace_xrep_xattr_rebuild_tree(sc->ip, sc->tempip);1440 1441 /*1442 * Commit the repair transaction and drop the ILOCKs so that we can use1443 * the atomic file content exchange helper functions to compute the1444 * correct resource reservations.1445 *1446 * We still hold IOLOCK_EXCL (aka i_rwsem) which will prevent xattr1447 * modifications, but there's nothing to prevent userspace from reading1448 * the attributes until we're ready for the exchange operation. Reads1449 * will return -EIO without shutting down the fs, so we're ok with1450 * that.1451 */1452 error = xrep_trans_commit(sc);1453 if (error)1454 return error;1455 1456 xchk_iunlock(sc, XFS_ILOCK_EXCL);1457 1458 /*1459 * Take the IOLOCK on the temporary file so that we can run xattr1460 * operations with the same locks held as we would for a normal file.1461 * We still hold sc->ip's IOLOCK.1462 */1463 error = xrep_tempfile_iolock_polled(rx->sc);1464 if (error)1465 return error;1466 1467 /*1468 * Allocate transaction, lock inodes, and make sure that we've replayed1469 * all the stashed parent pointer updates to the temp file. After this1470 * point, we're ready to exchange attr fork mappings.1471 */1472 error = xrep_xattr_finalize_tempfile(rx);1473 if (error)1474 return error;1475 1476 /*1477 * Exchange the blocks mapped by the tempfile's attr fork with the file1478 * being repaired. The old attr blocks will then be attached to the1479 * tempfile, so reap its attr fork.1480 */1481 error = xrep_xattr_swap(sc, &rx->tx);1482 if (error)1483 return error;1484 1485 error = xrep_xattr_reset_tempfile_fork(sc);1486 if (error)1487 return error;1488 1489 /*1490 * Roll to get a transaction without any inodes joined to it. Then we1491 * can drop the tempfile's ILOCK and IOLOCK before doing more work on1492 * the scrub target file.1493 */1494 error = xfs_trans_roll(&sc->tp);1495 if (error)1496 return error;1497 1498 xrep_tempfile_iunlock(sc);1499 xrep_tempfile_iounlock(sc);1500 1501forget_acls:1502 /* Invalidate cached ACLs now that we've reloaded all the xattrs. */1503 xfs_forget_acl(VFS_I(sc->ip), SGI_ACL_FILE);1504 xfs_forget_acl(VFS_I(sc->ip), SGI_ACL_DEFAULT);1505 return 0;1506}1507 1508/* Tear down all the incore scan stuff we created. */1509STATIC void1510xrep_xattr_teardown(1511 struct xrep_xattr *rx)1512{1513 if (xfs_has_parent(rx->sc->mp))1514 xfs_dir_hook_del(rx->sc->mp, &rx->dhook);1515 if (rx->pptr_names)1516 xfblob_destroy(rx->pptr_names);1517 if (rx->pptr_recs)1518 xfarray_destroy(rx->pptr_recs);1519 xfblob_destroy(rx->xattr_blobs);1520 xfarray_destroy(rx->xattr_records);1521 mutex_destroy(&rx->lock);1522 kfree(rx);1523}1524 1525/* Set up the filesystem scan so we can regenerate extended attributes. */1526STATIC int1527xrep_xattr_setup_scan(1528 struct xfs_scrub *sc,1529 struct xrep_xattr **rxp)1530{1531 struct xrep_xattr *rx;1532 char *descr;1533 int max_len;1534 int error;1535 1536 rx = kzalloc(sizeof(struct xrep_xattr), XCHK_GFP_FLAGS);1537 if (!rx)1538 return -ENOMEM;1539 rx->sc = sc;1540 rx->can_flush = true;1541 rx->xname.name = rx->namebuf;1542 1543 mutex_init(&rx->lock);1544 1545 /*1546 * Allocate enough memory to handle loading local attr values from the1547 * xfblob data while flushing stashed attrs to the temporary file.1548 * We only realloc the buffer when salvaging remote attr values.1549 */1550 max_len = xfs_attr_leaf_entsize_local_max(sc->mp->m_attr_geo->blksize);1551 error = xchk_setup_xattr_buf(rx->sc, max_len);1552 if (error == -ENOMEM)1553 error = -EDEADLOCK;1554 if (error)1555 goto out_rx;1556 1557 /* Set up some staging for salvaged attribute keys and values */1558 descr = xchk_xfile_ino_descr(sc, "xattr keys");1559 error = xfarray_create(descr, 0, sizeof(struct xrep_xattr_key),1560 &rx->xattr_records);1561 kfree(descr);1562 if (error)1563 goto out_rx;1564 1565 descr = xchk_xfile_ino_descr(sc, "xattr names");1566 error = xfblob_create(descr, &rx->xattr_blobs);1567 kfree(descr);1568 if (error)1569 goto out_keys;1570 1571 if (xfs_has_parent(sc->mp)) {1572 ASSERT(sc->flags & XCHK_FSGATES_DIRENTS);1573 1574 descr = xchk_xfile_ino_descr(sc,1575 "xattr retained parent pointer entries");1576 error = xfarray_create(descr, 0,1577 sizeof(struct xrep_xattr_pptr),1578 &rx->pptr_recs);1579 kfree(descr);1580 if (error)1581 goto out_values;1582 1583 descr = xchk_xfile_ino_descr(sc,1584 "xattr retained parent pointer names");1585 error = xfblob_create(descr, &rx->pptr_names);1586 kfree(descr);1587 if (error)1588 goto out_pprecs;1589 1590 xfs_dir_hook_setup(&rx->dhook, xrep_xattr_live_dirent_update);1591 error = xfs_dir_hook_add(sc->mp, &rx->dhook);1592 if (error)1593 goto out_ppnames;1594 }1595 1596 *rxp = rx;1597 return 0;1598out_ppnames:1599 xfblob_destroy(rx->pptr_names);1600out_pprecs:1601 xfarray_destroy(rx->pptr_recs);1602out_values:1603 xfblob_destroy(rx->xattr_blobs);1604out_keys:1605 xfarray_destroy(rx->xattr_records);1606out_rx:1607 mutex_destroy(&rx->lock);1608 kfree(rx);1609 return error;1610}1611 1612/*1613 * Repair the extended attribute metadata.1614 *1615 * XXX: Remote attribute value buffers encompass the entire (up to 64k) buffer.1616 * The buffer cache in XFS can't handle aliased multiblock buffers, so this1617 * might misbehave if the attr fork is crosslinked with other filesystem1618 * metadata.1619 */1620int1621xrep_xattr(1622 struct xfs_scrub *sc)1623{1624 struct xrep_xattr *rx = NULL;1625 int error;1626 1627 if (!xfs_inode_hasattr(sc->ip))1628 return -ENOENT;1629 1630 /* The rmapbt is required to reap the old attr fork. */1631 if (!xfs_has_rmapbt(sc->mp))1632 return -EOPNOTSUPP;1633 /* We require atomic file exchange range to rebuild anything. */1634 if (!xfs_has_exchange_range(sc->mp))1635 return -EOPNOTSUPP;1636 1637 error = xrep_xattr_setup_scan(sc, &rx);1638 if (error)1639 return error;1640 1641 ASSERT(sc->ilock_flags & XFS_ILOCK_EXCL);1642 1643 error = xrep_xattr_salvage_attributes(rx);1644 if (error)1645 goto out_scan;1646 1647 if (rx->live_update_aborted) {1648 error = -EIO;1649 goto out_scan;1650 }1651 1652 /* Last chance to abort before we start committing fixes. */1653 if (xchk_should_terminate(sc, &error))1654 goto out_scan;1655 1656 error = xrep_xattr_rebuild_tree(rx);1657 if (error)1658 goto out_scan;1659 1660out_scan:1661 xrep_xattr_teardown(rx);1662 return error;1663}1664