From: Dave Chinner <david@fromorbit.com>
To: "Darrick J. Wong" <darrick.wong@oracle.com>
Cc: linux-xfs@vger.kernel.org
Subject: Re: [PATCH 17/21] xfs: repair extended attributes
Date: Fri, 6 Jul 2018 11:03:24 +1000 [thread overview]
Message-ID: <20180706010324.GR2234@dastard> (raw)
In-Reply-To: <152986832301.3155.2967196267590663478.stgit@magnolia>
On Sun, Jun 24, 2018 at 12:25:23PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
>
> If the extended attributes look bad, try to sift through the rubble to
> find whatever keys/values we can, zap the attr tree, and re-add the
> values.
.....
>
> +/*
> + * Extended Attribute Repair
> + * =========================
> + *
> + * We repair extended attributes by reading the attribute fork blocks looking
> + * for keys and values, then truncate the entire attr fork and reinsert all
> + * the attributes. Unfortunately, there's no secondary copy of most extended
> + * attribute data, which means that if we blow up midway through there's
> + * little we can do.
> + */
> +
> +struct xfs_attr_key {
> + struct list_head list;
> + unsigned char *value;
> + int valuelen;
> + int flags;
> + int namelen;
> + unsigned char name[0];
> +};
> +
> +#define XFS_ATTR_KEY_LEN(namelen) (sizeof(struct xfs_attr_key) + (namelen) + 1)
> +
> +struct xfs_repair_xattr {
> + struct list_head *attrlist;
> + struct xfs_scrub_context *sc;
> +};
> +
> +/* Iterate each block in an attr fork extent */
> +#define for_each_xfs_attr_block(mp, irec, dabno) \
> + for ((dabno) = roundup((xfs_dablk_t)(irec)->br_startoff, \
> + (mp)->m_attr_geo->fsbcount); \
> + (dabno) < (irec)->br_startoff + (irec)->br_blockcount; \
> + (dabno) += (mp)->m_attr_geo->fsbcount)
What's the roundup() for? The attribute fsbcount is only ever going
to be 1 (single block), so it's not obvious what this is doing...
> +/*
> + * Record an extended attribute key & value for later reinsertion into the
> + * inode. Use the helpers below, don't call this directly.
> + */
> +STATIC int
> +__xfs_repair_xattr_salvage_attr(
> + struct xfs_repair_xattr *rx,
> + struct xfs_buf *bp,
> + int flags,
> + int idx,
> + unsigned char *name,
> + int namelen,
> + unsigned char *value,
> + int valuelen)
> +{
> + struct xfs_attr_key *key;
> + struct xfs_da_args args;
> + int error = -ENOMEM;
> +
> + /* Ignore incomplete or oversized attributes. */
> + if ((flags & XFS_ATTR_INCOMPLETE) ||
> + namelen > XATTR_NAME_MAX || namelen < 0 ||
> + valuelen > XATTR_SIZE_MAX || valuelen < 0)
> + return 0;
> +
> + /* Store attr key. */
> + key = kmem_alloc(XFS_ATTR_KEY_LEN(namelen), KM_MAYFAIL);
> + if (!key)
> + goto err;
> + INIT_LIST_HEAD(&key->list);
> + key->value = kmem_zalloc_large(valuelen, KM_MAYFAIL);
Why zero this? Also, it looks like valuelen can be zero? Should be
we be allocating a buffer in that case?
> + if (!key->value)
> + goto err_key;
> + key->valuelen = valuelen;
> + key->flags = flags & (ATTR_ROOT | ATTR_SECURE);
> + key->namelen = namelen;
> + key->name[namelen] = 0;
> + memcpy(key->name, name, namelen);
> +
> + /* Caller already had the value, so copy it and exit. */
> + if (value) {
> + memcpy(key->value, value, valuelen);
> + goto out_ok;
memcpy of a zero length buffer into a zero length pointer does what?
> + }
> +
> + /* Otherwise look up the remote value directly. */
It's not at all obvious why we are looking up a remote xattr at this
point in the function.
> + memset(&args, 0, sizeof(args));
> + args.geo = rx->sc->mp->m_attr_geo;
> + args.index = idx;
> + args.namelen = namelen;
> + args.name = key->name;
> + args.valuelen = valuelen;
> + args.value = key->value;
> + args.dp = rx->sc->ip;
> + args.trans = rx->sc->tp;
> + error = xfs_attr3_leaf_getvalue(bp, &args);
> + if (error || args.rmtblkno == 0)
> + goto err_value;
> +
> + error = xfs_attr_rmtval_get(&args);
> + switch (error) {
> + case 0:
> + break;
> + case -EFSBADCRC:
> + case -EFSCORRUPTED:
> + error = 0;
> + /* fall through */
> + default:
> + goto err_value;
So here we can return with error = 0, but no actual extended
attribute. Isn't this a silent failure?
> + }
> +
> +out_ok:
> + list_add_tail(&key->list, rx->attrlist);
> + return 0;
> +
> +err_value:
> + kmem_free(key->value);
> +err_key:
> + kmem_free(key);
> +err:
> + return error;
> +}
> +
> +/*
> + * Record a local format extended attribute key & value for later reinsertion
> + * into the inode.
> + */
> +static inline int
> +xfs_repair_xattr_salvage_local_attr(
> + struct xfs_repair_xattr *rx,
> + int flags,
> + unsigned char *name,
> + int namelen,
> + unsigned char *value,
> + int valuelen)
> +{
> + return __xfs_repair_xattr_salvage_attr(rx, NULL, flags, 0, name,
> + namelen, value, valuelen);
> +}
> +
> +/*
> + * Record a remote format extended attribute key & value for later reinsertion
> + * into the inode.
> + */
> +static inline int
> +xfs_repair_xattr_salvage_remote_attr(
> + struct xfs_repair_xattr *rx,
> + int flags,
> + unsigned char *name,
> + int namelen,
> + struct xfs_buf *leaf_bp,
> + int idx,
> + int valuelen)
> +{
> + return __xfs_repair_xattr_salvage_attr(rx, leaf_bp, flags, idx,
> + name, namelen, NULL, valuelen);
> +}
Oh, this is why __xfs_repair_xattr_salvage_attr() has two completely
separate sets of code in it. Can we factor this differently? i.e a
helper function to do all the validity checking and key allocation,
and then leave the local versus remote attr handling in these
functions?
> +
> +/* Extract every xattr key that we can from this attr fork block. */
> +STATIC int
> +xfs_repair_xattr_recover_leaf(
> + struct xfs_repair_xattr *rx,
> + struct xfs_buf *bp)
> +{
> + struct xfs_attr3_icleaf_hdr leafhdr;
> + struct xfs_scrub_context *sc = rx->sc;
> + struct xfs_mount *mp = sc->mp;
> + struct xfs_attr_leafblock *leaf;
> + unsigned long *usedmap = sc->buf;
> + struct xfs_attr_leaf_name_local *lentry;
> + struct xfs_attr_leaf_name_remote *rentry;
> + struct xfs_attr_leaf_entry *ent;
> + struct xfs_attr_leaf_entry *entries;
> + char *buf_end;
> + char *name;
> + char *name_end;
> + char *value;
> + size_t off;
> + unsigned int nameidx;
> + unsigned int namesize;
> + unsigned int hdrsize;
> + unsigned int namelen;
> + unsigned int valuelen;
> + int i;
> + int error;
Can we scope all these variables inside the blocks that use them?
> +
> + bitmap_zero(usedmap, mp->m_attr_geo->blksize);
> +
> + /* Check the leaf header */
> + leaf = bp->b_addr;
> + xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
> + hdrsize = xfs_attr3_leaf_hdr_size(leaf);
> + xfs_scrub_xattr_set_map(sc, usedmap, 0, hdrsize);
> + entries = xfs_attr3_leaf_entryp(leaf);
> +
> + buf_end = (char *)bp->b_addr + mp->m_attr_geo->blksize;
> + for (i = 0, ent = entries; i < leafhdr.count; ent++, i++) {
> + /* Skip key if it conflicts with something else? */
> + off = (char *)ent - (char *)leaf;
> + if (!xfs_scrub_xattr_set_map(sc, usedmap, off,
> + sizeof(xfs_attr_leaf_entry_t)))
> + continue;
> +
> + /* Check the name information. */
> + nameidx = be16_to_cpu(ent->nameidx);
> + if (nameidx < leafhdr.firstused ||
> + nameidx >= mp->m_attr_geo->blksize)
> + continue;
> +
> + if (ent->flags & XFS_ATTR_LOCAL) {
> + lentry = xfs_attr3_leaf_name_local(leaf, i);
> + namesize = xfs_attr_leaf_entsize_local(lentry->namelen,
> + be16_to_cpu(lentry->valuelen));
> + name_end = (char *)lentry + namesize;
> + if (lentry->namelen == 0)
> + continue;
> + name = lentry->nameval;
> + namelen = lentry->namelen;
> + valuelen = be16_to_cpu(lentry->valuelen);
> + value = &name[namelen];
It seems cumbersome to do a bunch of special local/remote attr
decoding into a set of semi-common variables, only to then pass the
specific local/remote variables back to specific local/remote
processing functions.
i.e. I'd prefer to see the attr decoding done inside the salvage
function so this looks something like:
if (ent->flags & XFS_ATTR_LOCAL) {
lentry = xfs_attr3_leaf_name_local(leaf, i);
error = xfs_repair_xattr_salvage_local_attr(rx,
lentry, ...);
} else {
rentry = xfs_attr3_leaf_name_remote(leaf, i);
error = xfs_repair_xattr_salvage_local_attr(rx,
rentry, ....);
}
......
> +
> +/* Try to recover shortform attrs. */
> +STATIC int
> +xfs_repair_xattr_recover_sf(
> + struct xfs_repair_xattr *rx)
> +{
> + struct xfs_attr_shortform *sf;
> + struct xfs_attr_sf_entry *sfe;
> + struct xfs_attr_sf_entry *next;
> + struct xfs_ifork *ifp;
> + unsigned char *end;
> + int i;
> + int error;
> +
> + ifp = XFS_IFORK_PTR(rx->sc->ip, XFS_ATTR_FORK);
> + sf = (struct xfs_attr_shortform *)rx->sc->ip->i_afp->if_u1.if_data;
sf = (struct xfs_attr_shortform *)ifp->if_u1.if_data;
....
> +/*
> + * Repair the extended attribute metadata.
> + *
> + * XXX: Remote attribute value buffers encompass the entire (up to 64k) buffer
> + * and we can't handle those 100% until the buffer cache learns how to deal
> + * with that.
I'm not sure what this comment means/implies.
Cheers,
Dave.
--
Dave Chinner
david@fromorbit.com
next prev parent reply other threads:[~2018-07-06 1:03 UTC|newest]
Thread overview: 77+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-06-24 19:23 [PATCH v16 00/21] xfs-4.19: online repair support Darrick J. Wong
2018-06-24 19:23 ` [PATCH 01/21] xfs: don't assume a left rmap when allocating a new rmap Darrick J. Wong
2018-06-27 0:54 ` Dave Chinner
2018-06-28 21:11 ` Allison Henderson
2018-06-29 14:39 ` Darrick J. Wong
2018-06-24 19:23 ` [PATCH 02/21] xfs: add helper to decide if an inode has allocated cow blocks Darrick J. Wong
2018-06-27 1:02 ` Dave Chinner
2018-06-28 21:12 ` Allison Henderson
2018-06-24 19:23 ` [PATCH 03/21] xfs: refactor part of xfs_free_eofblocks Darrick J. Wong
2018-06-28 21:13 ` Allison Henderson
2018-06-24 19:23 ` [PATCH 04/21] xfs: repair the AGF and AGFL Darrick J. Wong
2018-06-27 2:19 ` Dave Chinner
2018-06-27 16:44 ` Allison Henderson
2018-06-27 23:37 ` Dave Chinner
2018-06-29 15:14 ` Darrick J. Wong
2018-06-28 17:25 ` Allison Henderson
2018-06-29 15:08 ` Darrick J. Wong
2018-06-28 21:14 ` Allison Henderson
2018-06-28 23:21 ` Dave Chinner
2018-06-29 1:35 ` Allison Henderson
2018-06-29 14:55 ` Darrick J. Wong
2018-06-24 19:24 ` [PATCH 05/21] xfs: repair the AGI Darrick J. Wong
2018-06-27 2:22 ` Dave Chinner
2018-06-28 21:15 ` Allison Henderson
2018-06-24 19:24 ` [PATCH 06/21] xfs: repair free space btrees Darrick J. Wong
2018-06-27 3:21 ` Dave Chinner
2018-07-04 2:15 ` Darrick J. Wong
2018-07-04 2:25 ` Dave Chinner
2018-06-30 17:36 ` Allison Henderson
2018-06-24 19:24 ` [PATCH 07/21] xfs: repair inode btrees Darrick J. Wong
2018-06-28 0:55 ` Dave Chinner
2018-07-04 2:22 ` Darrick J. Wong
2018-06-30 17:36 ` Allison Henderson
2018-06-30 18:30 ` Darrick J. Wong
2018-07-01 0:45 ` Allison Henderson
2018-06-24 19:24 ` [PATCH 08/21] xfs: defer iput on certain inodes while scrub / repair are running Darrick J. Wong
2018-06-28 23:37 ` Dave Chinner
2018-06-29 14:49 ` Darrick J. Wong
2018-06-24 19:24 ` [PATCH 09/21] xfs: finish our set of inode get/put tracepoints for scrub Darrick J. Wong
2018-06-24 19:24 ` [PATCH 10/21] xfs: introduce online scrub freeze Darrick J. Wong
2018-06-24 19:24 ` [PATCH 11/21] xfs: repair the rmapbt Darrick J. Wong
2018-07-03 5:32 ` Dave Chinner
2018-07-03 23:59 ` Darrick J. Wong
2018-07-04 8:44 ` Carlos Maiolino
2018-07-04 18:40 ` Darrick J. Wong
2018-07-04 23:21 ` Dave Chinner
2018-07-05 3:48 ` Darrick J. Wong
2018-07-05 7:03 ` Dave Chinner
2018-07-06 0:47 ` Darrick J. Wong
2018-07-06 1:08 ` Dave Chinner
2018-06-24 19:24 ` [PATCH 12/21] xfs: repair refcount btrees Darrick J. Wong
2018-07-03 5:50 ` Dave Chinner
2018-07-04 2:23 ` Darrick J. Wong
2018-06-24 19:24 ` [PATCH 13/21] xfs: repair inode records Darrick J. Wong
2018-07-03 6:17 ` Dave Chinner
2018-07-04 0:16 ` Darrick J. Wong
2018-07-04 1:03 ` Dave Chinner
2018-07-04 1:30 ` Darrick J. Wong
2018-06-24 19:24 ` [PATCH 14/21] xfs: zap broken inode forks Darrick J. Wong
2018-07-04 2:07 ` Dave Chinner
2018-07-04 3:26 ` Darrick J. Wong
2018-06-24 19:25 ` [PATCH 15/21] xfs: repair inode block maps Darrick J. Wong
2018-07-04 3:00 ` Dave Chinner
2018-07-04 3:41 ` Darrick J. Wong
2018-06-24 19:25 ` [PATCH 16/21] xfs: repair damaged symlinks Darrick J. Wong
2018-07-04 5:45 ` Dave Chinner
2018-07-04 18:45 ` Darrick J. Wong
2018-06-24 19:25 ` [PATCH 17/21] xfs: repair extended attributes Darrick J. Wong
2018-07-06 1:03 ` Dave Chinner [this message]
2018-07-06 3:10 ` Darrick J. Wong
2018-06-24 19:25 ` [PATCH 18/21] xfs: scrub should set preen if attr leaf has holes Darrick J. Wong
2018-06-29 2:52 ` Dave Chinner
2018-06-24 19:25 ` [PATCH 19/21] xfs: repair quotas Darrick J. Wong
2018-07-06 1:50 ` Dave Chinner
2018-07-06 3:16 ` Darrick J. Wong
2018-06-24 19:25 ` [PATCH 20/21] xfs: implement live quotacheck as part of quota repair Darrick J. Wong
2018-06-24 19:25 ` [PATCH 21/21] xfs: add online scrub/repair for superblock counters Darrick J. Wong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180706010324.GR2234@dastard \
--to=david@fromorbit.com \
--cc=darrick.wong@oracle.com \
--cc=linux-xfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.