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