--- /dev/null
+From a78ee256c325ecfaec13cafc41b315bd4e1dd518 Mon Sep 17 00:00:00 2001
+From: Dave Chinner <dchinner@redhat.com>
+Date: Tue, 6 Mar 2018 17:08:32 -0800
+Subject: xfs: convert XFS_AGFL_SIZE to a helper function
+
+From: Dave Chinner <dchinner@redhat.com>
+
+commit a78ee256c325ecfaec13cafc41b315bd4e1dd518 upstream.
+
+The AGFL size calculation is about to get more complex, so lets turn
+the macro into a function first and remove the macro.
+
+Signed-off-by: Dave Chinner <dchinner@redhat.com>
+[darrick: forward port to newer kernel, simplify the helper]
+Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
+Reviewed-by: Brian Foster <bfoster@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/xfs/libxfs/xfs_alloc.c | 31 ++++++++++++++++++++++++-------
+ fs/xfs/libxfs/xfs_alloc.h | 2 ++
+ fs/xfs/libxfs/xfs_format.h | 13 +------------
+ fs/xfs/scrub/agheader.c | 6 +++---
+ fs/xfs/xfs_fsops.c | 2 +-
+ 5 files changed, 31 insertions(+), 23 deletions(-)
+
+--- a/fs/xfs/libxfs/xfs_alloc.c
++++ b/fs/xfs/libxfs/xfs_alloc.c
+@@ -53,6 +53,23 @@ STATIC int xfs_alloc_ag_vextent_size(xfs
+ STATIC int xfs_alloc_ag_vextent_small(xfs_alloc_arg_t *,
+ xfs_btree_cur_t *, xfs_agblock_t *, xfs_extlen_t *, int *);
+
++/*
++ * Size of the AGFL. For CRC-enabled filesystes we steal a couple of slots in
++ * the beginning of the block for a proper header with the location information
++ * and CRC.
++ */
++unsigned int
++xfs_agfl_size(
++ struct xfs_mount *mp)
++{
++ unsigned int size = mp->m_sb.sb_sectsize;
++
++ if (xfs_sb_version_hascrc(&mp->m_sb))
++ size -= sizeof(struct xfs_agfl);
++
++ return size / sizeof(xfs_agblock_t);
++}
++
+ unsigned int
+ xfs_refc_block(
+ struct xfs_mount *mp)
+@@ -550,7 +567,7 @@ xfs_agfl_verify(
+ if (bp->b_pag && be32_to_cpu(agfl->agfl_seqno) != bp->b_pag->pag_agno)
+ return __this_address;
+
+- for (i = 0; i < XFS_AGFL_SIZE(mp); i++) {
++ for (i = 0; i < xfs_agfl_size(mp); i++) {
+ if (be32_to_cpu(agfl->agfl_bno[i]) != NULLAGBLOCK &&
+ be32_to_cpu(agfl->agfl_bno[i]) >= mp->m_sb.sb_agblocks)
+ return __this_address;
+@@ -2266,7 +2283,7 @@ xfs_alloc_get_freelist(
+ bno = be32_to_cpu(agfl_bno[be32_to_cpu(agf->agf_flfirst)]);
+ be32_add_cpu(&agf->agf_flfirst, 1);
+ xfs_trans_brelse(tp, agflbp);
+- if (be32_to_cpu(agf->agf_flfirst) == XFS_AGFL_SIZE(mp))
++ if (be32_to_cpu(agf->agf_flfirst) == xfs_agfl_size(mp))
+ agf->agf_flfirst = 0;
+
+ pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno));
+@@ -2377,7 +2394,7 @@ xfs_alloc_put_freelist(
+ be32_to_cpu(agf->agf_seqno), &agflbp)))
+ return error;
+ be32_add_cpu(&agf->agf_fllast, 1);
+- if (be32_to_cpu(agf->agf_fllast) == XFS_AGFL_SIZE(mp))
++ if (be32_to_cpu(agf->agf_fllast) == xfs_agfl_size(mp))
+ agf->agf_fllast = 0;
+
+ pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno));
+@@ -2395,7 +2412,7 @@ xfs_alloc_put_freelist(
+
+ xfs_alloc_log_agf(tp, agbp, logflags);
+
+- ASSERT(be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp));
++ ASSERT(be32_to_cpu(agf->agf_flcount) <= xfs_agfl_size(mp));
+
+ agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agflbp);
+ blockp = &agfl_bno[be32_to_cpu(agf->agf_fllast)];
+@@ -2428,9 +2445,9 @@ 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) < XFS_AGFL_SIZE(mp) &&
+- be32_to_cpu(agf->agf_fllast) < XFS_AGFL_SIZE(mp) &&
+- be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp)))
++ be32_to_cpu(agf->agf_flfirst) < xfs_agfl_size(mp) &&
++ be32_to_cpu(agf->agf_fllast) < xfs_agfl_size(mp) &&
++ be32_to_cpu(agf->agf_flcount) <= xfs_agfl_size(mp)))
+ return __this_address;
+
+ if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) < 1 ||
+--- a/fs/xfs/libxfs/xfs_alloc.h
++++ b/fs/xfs/libxfs/xfs_alloc.h
+@@ -26,6 +26,8 @@ struct xfs_trans;
+
+ extern struct workqueue_struct *xfs_alloc_wq;
+
++unsigned int xfs_agfl_size(struct xfs_mount *mp);
++
+ /*
+ * Freespace allocation types. Argument to xfs_alloc_[v]extent.
+ */
+--- a/fs/xfs/libxfs/xfs_format.h
++++ b/fs/xfs/libxfs/xfs_format.h
+@@ -803,24 +803,13 @@ typedef struct xfs_agi {
+ &(XFS_BUF_TO_AGFL(bp)->agfl_bno[0]) : \
+ (__be32 *)(bp)->b_addr)
+
+-/*
+- * Size of the AGFL. For CRC-enabled filesystes we steal a couple of
+- * slots in the beginning of the block for a proper header with the
+- * location information and CRC.
+- */
+-#define XFS_AGFL_SIZE(mp) \
+- (((mp)->m_sb.sb_sectsize - \
+- (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \
+- sizeof(struct xfs_agfl) : 0)) / \
+- sizeof(xfs_agblock_t))
+-
+ typedef struct xfs_agfl {
+ __be32 agfl_magicnum;
+ __be32 agfl_seqno;
+ uuid_t agfl_uuid;
+ __be64 agfl_lsn;
+ __be32 agfl_crc;
+- __be32 agfl_bno[]; /* actually XFS_AGFL_SIZE(mp) */
++ __be32 agfl_bno[]; /* actually xfs_agfl_size(mp) */
+ } __attribute__((packed)) xfs_agfl_t;
+
+ #define XFS_AGFL_CRC_OFF offsetof(struct xfs_agfl, agfl_crc)
+--- a/fs/xfs/scrub/agheader.c
++++ b/fs/xfs/scrub/agheader.c
+@@ -80,7 +80,7 @@ xfs_scrub_walk_agfl(
+ }
+
+ /* first to the end */
+- for (i = flfirst; i < XFS_AGFL_SIZE(mp); i++) {
++ for (i = flfirst; i < xfs_agfl_size(mp); i++) {
+ error = fn(sc, be32_to_cpu(agfl_bno[i]), priv);
+ if (error)
+ return error;
+@@ -664,7 +664,7 @@ xfs_scrub_agf(
+ if (agfl_last > agfl_first)
+ fl_count = agfl_last - agfl_first + 1;
+ else
+- fl_count = XFS_AGFL_SIZE(mp) - agfl_first + agfl_last + 1;
++ fl_count = xfs_agfl_size(mp) - agfl_first + agfl_last + 1;
+ if (agfl_count != 0 && fl_count != agfl_count)
+ xfs_scrub_block_set_corrupt(sc, sc->sa.agf_bp);
+
+@@ -791,7 +791,7 @@ xfs_scrub_agfl(
+ /* Allocate buffer to ensure uniqueness of AGFL entries. */
+ agf = XFS_BUF_TO_AGF(sc->sa.agf_bp);
+ agflcount = be32_to_cpu(agf->agf_flcount);
+- if (agflcount > XFS_AGFL_SIZE(sc->mp)) {
++ if (agflcount > xfs_agfl_size(sc->mp)) {
+ xfs_scrub_block_set_corrupt(sc, sc->sa.agf_bp);
+ goto out;
+ }
+--- a/fs/xfs/xfs_fsops.c
++++ b/fs/xfs/xfs_fsops.c
+@@ -217,7 +217,7 @@ xfs_growfs_data_private(
+ }
+
+ agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, bp);
+- for (bucket = 0; bucket < XFS_AGFL_SIZE(mp); bucket++)
++ for (bucket = 0; bucket < xfs_agfl_size(mp); bucket++)
+ agfl_bno[bucket] = cpu_to_be32(NULLAGBLOCK);
+
+ error = xfs_bwrite(bp);
--- /dev/null
+From a27ba2607e60312554cbcd43fc660b2c7f29dc9c Mon Sep 17 00:00:00 2001
+From: Brian Foster <bfoster@redhat.com>
+Date: Thu, 15 Mar 2018 10:51:58 -0700
+Subject: xfs: detect agfl count corruption and reset agfl
+
+From: Brian Foster <bfoster@redhat.com>
+
+commit a27ba2607e60312554cbcd43fc660b2c7f29dc9c upstream.
+
+The struct xfs_agfl v5 header was originally introduced with
+unexpected padding that caused the AGFL to operate with one less
+slot than intended. The header has since been packed, but the fix
+left an incompatibility for users who upgrade from an old kernel
+with the unpacked header to a newer kernel with the packed header
+while the AGFL happens to wrap around the end. The newer kernel
+recognizes one extra slot at the physical end of the AGFL that the
+previous kernel did not. The new kernel will eventually attempt to
+allocate a block from that slot, which contains invalid data, and
+cause a crash.
+
+This condition can be detected by comparing the active range of the
+AGFL to the count. While this detects a padding mismatch, it can
+also trigger false positives for unrelated flcount corruption. Since
+we cannot distinguish a size mismatch due to padding from unrelated
+corruption, we can't trust the AGFL enough to simply repopulate the
+empty slot.
+
+Instead, avoid unnecessarily complex detection logic and and use a
+solution that can handle any form of flcount corruption that slips
+through read verifiers: distrust the entire AGFL and reset it to an
+empty state. Any valid blocks within the AGFL are intentionally
+leaked. This requires xfs_repair to rectify (which was already
+necessary based on the state the AGFL was found in). The reset
+mitigates the side effect of the padding mismatch problem from a
+filesystem crash to a free space accounting inconsistency. The
+generic approach also means that this patch can be safely backported
+to kernels with or without a packed struct xfs_agfl.
+
+Check the AGF for an invalid freelist count on initial read from
+disk. If detected, set a flag on the xfs_perag to indicate that a
+reset is required before the AGFL can be used. In the first
+transaction that attempts to use a flagged AGFL, reset it to empty,
+warn the user about the inconsistency and allow the freelist fixup
+code to repopulate the AGFL with new blocks. The xfs_perag flag is
+cleared to eliminate the need for repeated checks on each block
+allocation operation.
+
+This allows kernels that include the packing fix commit 96f859d52bcb
+("libxfs: pack the agfl header structure so XFS_AGFL_SIZE is correct")
+to handle older unpacked AGFL formats without a filesystem crash.
+
+Suggested-by: Dave Chinner <david@fromorbit.com>
+Signed-off-by: Brian Foster <bfoster@redhat.com>
+Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
+Reviewed-by Dave Chiluk <chiluk+linuxxfs@indeed.com>
+Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/xfs/libxfs/xfs_alloc.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++
+ fs/xfs/xfs_mount.h | 1
+ fs/xfs/xfs_trace.h | 9 +++-
+ 3 files changed, 103 insertions(+), 1 deletion(-)
+
+--- a/fs/xfs/libxfs/xfs_alloc.c
++++ b/fs/xfs/libxfs/xfs_alloc.c
+@@ -2071,6 +2071,93 @@ xfs_alloc_space_available(
+ }
+
+ /*
++ * Check the agfl fields of the agf for inconsistency or corruption. The purpose
++ * is to detect an agfl header padding mismatch between current and early v5
++ * kernels. This problem manifests as a 1-slot size difference between the
++ * on-disk flcount and the active [first, last] range of a wrapped agfl. This
++ * may also catch variants of agfl count corruption unrelated to padding. Either
++ * way, we'll reset the agfl and warn the user.
++ *
++ * Return true if a reset is required before the agfl can be used, false
++ * otherwise.
++ */
++static bool
++xfs_agfl_needs_reset(
++ struct xfs_mount *mp,
++ struct xfs_agf *agf)
++{
++ uint32_t f = be32_to_cpu(agf->agf_flfirst);
++ uint32_t l = be32_to_cpu(agf->agf_fllast);
++ uint32_t c = be32_to_cpu(agf->agf_flcount);
++ int agfl_size = xfs_agfl_size(mp);
++ int active;
++
++ /* no agfl header on v4 supers */
++ if (!xfs_sb_version_hascrc(&mp->m_sb))
++ return false;
++
++ /*
++ * The agf read verifier catches severe corruption of these fields.
++ * Repeat some sanity checks to cover a packed -> unpacked mismatch if
++ * the verifier allows it.
++ */
++ if (f >= agfl_size || l >= agfl_size)
++ return true;
++ if (c > agfl_size)
++ return true;
++
++ /*
++ * Check consistency between the on-disk count and the active range. An
++ * agfl padding mismatch manifests as an inconsistent flcount.
++ */
++ if (c && l >= f)
++ active = l - f + 1;
++ else if (c)
++ active = agfl_size - f + l + 1;
++ else
++ active = 0;
++
++ return active != c;
++}
++
++/*
++ * Reset the agfl to an empty state. Ignore/drop any existing blocks since the
++ * agfl content cannot be trusted. Warn the user that a repair is required to
++ * recover leaked blocks.
++ *
++ * The purpose of this mechanism is to handle filesystems affected by the agfl
++ * header padding mismatch problem. A reset keeps the filesystem online with a
++ * relatively minor free space accounting inconsistency rather than suffer the
++ * inevitable crash from use of an invalid agfl block.
++ */
++static void
++xfs_agfl_reset(
++ struct xfs_trans *tp,
++ struct xfs_buf *agbp,
++ struct xfs_perag *pag)
++{
++ struct xfs_mount *mp = tp->t_mountp;
++ struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp);
++
++ ASSERT(pag->pagf_agflreset);
++ trace_xfs_agfl_reset(mp, agf, 0, _RET_IP_);
++
++ xfs_warn(mp,
++ "WARNING: Reset corrupted AGFL on AG %u. %d blocks leaked. "
++ "Please unmount and run xfs_repair.",
++ pag->pag_agno, pag->pagf_flcount);
++
++ agf->agf_flfirst = 0;
++ agf->agf_fllast = cpu_to_be32(xfs_agfl_size(mp) - 1);
++ agf->agf_flcount = 0;
++ xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLFIRST | XFS_AGF_FLLAST |
++ XFS_AGF_FLCOUNT);
++
++ pag->pagf_flcount = 0;
++ pag->pagf_agflreset = false;
++}
++
++/*
+ * Decide whether to use this allocation group for this allocation.
+ * If so, fix up the btree freelist's size.
+ */
+@@ -2131,6 +2218,10 @@ xfs_alloc_fix_freelist(
+ }
+ }
+
++ /* reset a padding mismatched agfl before final free space check */
++ if (pag->pagf_agflreset)
++ xfs_agfl_reset(tp, agbp, pag);
++
+ /* If there isn't enough total space or single-extent, reject it. */
+ need = xfs_alloc_min_freelist(mp, pag);
+ if (!xfs_alloc_space_available(args, need, flags))
+@@ -2287,6 +2378,7 @@ xfs_alloc_get_freelist(
+ agf->agf_flfirst = 0;
+
+ pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno));
++ ASSERT(!pag->pagf_agflreset);
+ be32_add_cpu(&agf->agf_flcount, -1);
+ xfs_trans_agflist_delta(tp, -1);
+ pag->pagf_flcount--;
+@@ -2398,6 +2490,7 @@ xfs_alloc_put_freelist(
+ agf->agf_fllast = 0;
+
+ pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno));
++ ASSERT(!pag->pagf_agflreset);
+ be32_add_cpu(&agf->agf_flcount, 1);
+ xfs_trans_agflist_delta(tp, 1);
+ pag->pagf_flcount++;
+@@ -2605,6 +2698,7 @@ xfs_alloc_read_agf(
+ pag->pagb_count = 0;
+ pag->pagb_tree = RB_ROOT;
+ pag->pagf_init = 1;
++ pag->pagf_agflreset = xfs_agfl_needs_reset(mp, agf);
+ }
+ #ifdef DEBUG
+ else if (!XFS_FORCED_SHUTDOWN(mp)) {
+--- a/fs/xfs/xfs_mount.h
++++ b/fs/xfs/xfs_mount.h
+@@ -353,6 +353,7 @@ typedef struct xfs_perag {
+ char pagi_inodeok; /* The agi is ok for inodes */
+ uint8_t pagf_levels[XFS_BTNUM_AGF];
+ /* # of levels in bno & cnt btree */
++ bool pagf_agflreset; /* agfl requires reset before use */
+ uint32_t pagf_flcount; /* count of blocks in freelist */
+ xfs_extlen_t pagf_freeblks; /* total free blocks */
+ xfs_extlen_t pagf_longest; /* longest free space */
+--- a/fs/xfs/xfs_trace.h
++++ b/fs/xfs/xfs_trace.h
+@@ -1477,7 +1477,7 @@ TRACE_EVENT(xfs_extent_busy_trim,
+ __entry->tlen)
+ );
+
+-TRACE_EVENT(xfs_agf,
++DECLARE_EVENT_CLASS(xfs_agf_class,
+ TP_PROTO(struct xfs_mount *mp, struct xfs_agf *agf, int flags,
+ unsigned long caller_ip),
+ TP_ARGS(mp, agf, flags, caller_ip),
+@@ -1533,6 +1533,13 @@ TRACE_EVENT(xfs_agf,
+ __entry->longest,
+ (void *)__entry->caller_ip)
+ );
++#define DEFINE_AGF_EVENT(name) \
++DEFINE_EVENT(xfs_agf_class, name, \
++ TP_PROTO(struct xfs_mount *mp, struct xfs_agf *agf, int flags, \
++ unsigned long caller_ip), \
++ TP_ARGS(mp, agf, flags, caller_ip))
++DEFINE_AGF_EVENT(xfs_agf);
++DEFINE_AGF_EVENT(xfs_agfl_reset);
+
+ TRACE_EVENT(xfs_free_extent,
+ TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t agbno,