From: Dave Chinner <david@fromorbit.com>
To: linux-xfs@vger.kernel.org
Cc: xfs@oss.sgi.com
Subject: [PATCH 4/6] xfs: automatically fix up AGFL size issues
Date: Fri, 2 Sep 2016 12:27:35 +1000 [thread overview]
Message-ID: <1472783257-15941-5-git-send-email-david@fromorbit.com> (raw)
In-Reply-To: <1472783257-15941-1-git-send-email-david@fromorbit.com>
From: Dave Chinner <dchinner@redhat.com>
Now that we can safely detect whether we have a screwed up AGFL
size, we need to automatically fix it up. We do this by modifying
the AGFL index and/or count values in the AGF. This will only ever
lead to reducing the size of the AGFL, leaving a free block in the
unused slot to remain there if a problem is corrected. WHile this is
a leak, it should only occur once and it will be corrected the next
time the filesystem is repaired.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
fs/xfs/libxfs/xfs_alloc.c | 105 +++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 99 insertions(+), 6 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index 31a18fe..8deb736 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -2417,10 +2417,7 @@ xfs_agf_verify(
if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) &&
- be32_to_cpu(agf->agf_freeblks) <= be32_to_cpu(agf->agf_length) &&
- be32_to_cpu(agf->agf_flfirst) < agfl_size &&
- be32_to_cpu(agf->agf_fllast) < agfl_size &&
- be32_to_cpu(agf->agf_flcount) <= agfl_size))
+ be32_to_cpu(agf->agf_freeblks) <= be32_to_cpu(agf->agf_length)))
return false;
if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) > XFS_BTREE_MAXLEVELS ||
@@ -2440,10 +2437,18 @@ xfs_agf_verify(
be32_to_cpu(agf->agf_btreeblks) > be32_to_cpu(agf->agf_length))
return false;
- if (!xfs_sb_version_hascrc(&mp->m_sb))
+ /*
+ * AGFL parameters are strict only for non-CRC filesystems now.
+ * See the comment below in the v5 format section for details
+ */
+ if (!xfs_sb_version_hascrc(&mp->m_sb)) {
+ if (!(flfirst < agfl_size && fllast < agfl_size &&
+ flcount <= agfl_size))
+ return false;
return true;
+ }
- /* CRC format checks only from here */
+ /* v5 format checks only from here */
if (!uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid))
return false;
@@ -2575,6 +2580,92 @@ xfs_read_agf(
}
/*
+ * Detect and fixup a screwup in the struct xfs_agfl definition that results in
+ * different free list sizes depending on the compiler padding added to the
+ * xfs_agfl. This will only matter on v5 filesystems that have the freelist
+ * wrapping around the end of the AGFL. The changes fixup changes will be logged
+ * in the first free list modification done to the AGF.
+ */
+static void
+xfs_agf_fixup_freelist_count(
+ struct xfs_mount *mp,
+ struct xfs_perag *pag,
+ struct xfs_agf *agf)
+{
+ int32_t agfl_size = xfs_agfl_size(mp);
+ int32_t active;
+
+ ASSERT(pag->pagf_fllast <= agfl_size);
+ ASSERT(pag->pagf_flfirst <= agfl_size);
+
+ if (!xfs_sb_version_hascrc(&mp->m_sb))
+ return;
+
+ /* if not wrapped or completely within range, nothing to do */
+ if (pag->pagf_fllast < agfl_size &&
+ pag->pagf_flfirst <= pag->pagf_fllast)
+ return;
+
+ /* if last is invalid, pull it back and return */
+ if (pag->pagf_fllast == agfl_size) {
+ xfs_notice(mp, "AGF %d: last index fixup being performed",
+ pag->pag_agno);
+ if (pag->pagf_flcount) {
+ pag->pagf_flcount--;
+ be32_add_cpu(&agf->agf_flcount, -1);
+ be32_add_cpu(&agf->agf_fllast, -1);
+ pag->pagf_fllast--;
+ } else {
+ /* empty free list, move the both pointers back one */
+ ASSERT(pag->pagf_flfirst == pag->pagf_fllast);
+ be32_add_cpu(&agf->agf_fllast, -1);
+ be32_add_cpu(&agf->agf_flfirst, -1);
+ pag->pagf_flfirst--;
+ pag->pagf_fllast--;
+ }
+ return;
+ }
+
+ /* if first is invalid, wrap it, reset count and return */
+ if (pag->pagf_flfirst == agfl_size) {
+ xfs_notice(mp, "AGF %d: first index fixup being performed",
+ pag->pag_agno);
+ ASSERT(pag->pagf_flfirst != pag->pagf_fllast);
+ ASSERT(pag->pagf_flcount);
+ pag->pagf_flcount = pag->pagf_fllast + 1;
+ agf->agf_flcount = cpu_to_be32(pag->pagf_flcount);
+ agf->agf_flfirst = 0;
+ pag->pagf_flfirst = 0;
+ return;
+ }
+
+ /*
+ * Pure wrap, first and last are valid.
+ * flfirst
+ * |
+ * +oo------------------oo+
+ * |
+ * fllast
+ *
+ * We need to determine if the count includes the last slot in the AGFL
+ * which we no longer use. If the flcount does not match the expected
+ * size based on the first/last indexes, we need to fix it up.
+ */
+ active = pag->pagf_fllast - pag->pagf_flfirst + 1;
+ if (active <= 0)
+ active += agfl_size;
+ if (active == pag->pagf_flcount)
+ return;
+
+ /* should only be off by one */
+ ASSERT(active + 1 == pag->pagf_flcount);
+ xfs_notice(mp, "AGF %d: wrapped count fixup being performed",
+ pag->pag_agno);
+ pag->pagf_flcount--;
+ be32_add_cpu(&agf->agf_flcount, -1);
+}
+
+/*
* Read in the allocation group header (free/alloc section).
*/
int /* error */
@@ -2620,6 +2711,8 @@ xfs_alloc_read_agf(
pag->pagb_count = 0;
pag->pagb_tree = RB_ROOT;
pag->pagf_init = 1;
+
+ xfs_agf_fixup_freelist_count(mp, pag, agf);
}
#ifdef DEBUG
else if (!XFS_FORCED_SHUTDOWN(mp)) {
--
2.8.0.rc3
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
next prev parent reply other threads:[~2016-09-02 2:28 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-09-02 2:27 [RFC PATCH 0/6] xfs: sort out the AGFL size mess Dave Chinner
2016-09-02 2:27 ` [PATCH 1/6] xfs: clean up XFS_AGFL_SIZE Dave Chinner
2018-01-03 22:27 ` Darrick J. Wong
2016-09-02 2:27 ` [PATCH 2/6] xfs: shadow agfl indexes in the per-ag structures Dave Chinner
2016-09-02 13:25 ` Eric Sandeen
2016-09-02 23:06 ` Dave Chinner
2016-09-02 2:27 ` [PATCH 3/6] xfs: detect AGFL size mismatches Dave Chinner
2016-09-13 23:39 ` Eric Sandeen
2016-09-14 21:26 ` Dave Chinner
2016-09-28 17:39 ` Eric Sandeen
2016-09-02 2:27 ` Dave Chinner [this message]
2016-09-14 18:20 ` [PATCH 4/6] xfs: automatically fix up AGFL size issues Darrick J. Wong
2016-09-14 21:50 ` Dave Chinner
2016-09-02 2:27 ` [PATCH 5/6] xfs: clean up AGFL index initialisation in growfs Dave Chinner
2016-09-02 2:27 ` [PATCH 6/6] xfs: use per-ag AGFL indexes everywhere Dave Chinner
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=1472783257-15941-5-git-send-email-david@fromorbit.com \
--to=david@fromorbit.com \
--cc=linux-xfs@vger.kernel.org \
--cc=xfs@oss.sgi.com \
/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.