spi: spi-pxa2xx: Check status register to determine if SSSR_TINT is disabled
[firefly-linux-kernel-4.4.55.git] / fs / xfs / xfs_alloc.c
index 0ad23253e8b1ed1da6c723b44d828fbb7e743350..5673bcfda2f0c8c0151142b52dc5202d7030da63 100644 (file)
@@ -33,7 +33,9 @@
 #include "xfs_alloc.h"
 #include "xfs_extent_busy.h"
 #include "xfs_error.h"
+#include "xfs_cksum.h"
 #include "xfs_trace.h"
+#include "xfs_buf_item.h"
 
 struct workqueue_struct *xfs_alloc_wq;
 
@@ -430,53 +432,84 @@ xfs_alloc_fixup_trees(
        return 0;
 }
 
-static void
+static bool
 xfs_agfl_verify(
        struct xfs_buf  *bp)
 {
-#ifdef WHEN_CRCS_COME_ALONG
-       /*
-        * we cannot actually do any verification of the AGFL because mkfs does
-        * not initialise the AGFL to zero or NULL. Hence the only valid part of
-        * the AGFL is what the AGF says is active. We can't get to the AGF, so
-        * we can't verify just those entries are valid.
-        *
-        * This problem goes away when the CRC format change comes along as that
-        * requires the AGFL to be initialised by mkfs. At that point, we can
-        * verify the blocks in the agfl -active or not- lie within the bounds
-        * of the AG. Until then, just leave this check ifdef'd out.
-        */
        struct xfs_mount *mp = bp->b_target->bt_mount;
        struct xfs_agfl *agfl = XFS_BUF_TO_AGFL(bp);
-       int             agfl_ok = 1;
-
        int             i;
 
+       if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_uuid))
+               return false;
+       if (be32_to_cpu(agfl->agfl_magicnum) != XFS_AGFL_MAGIC)
+               return false;
+       /*
+        * during growfs operations, the perag is not fully initialised,
+        * so we can't use it for any useful checking. growfs ensures we can't
+        * use it by using uncached buffers that don't have the perag attached
+        * so we can detect and avoid this problem.
+        */
+       if (bp->b_pag && be32_to_cpu(agfl->agfl_seqno) != bp->b_pag->pag_agno)
+               return false;
+
        for (i = 0; i < XFS_AGFL_SIZE(mp); i++) {
-               if (be32_to_cpu(agfl->agfl_bno[i]) == NULLAGBLOCK ||
+               if (be32_to_cpu(agfl->agfl_bno[i]) != NULLAGBLOCK &&
                    be32_to_cpu(agfl->agfl_bno[i]) >= mp->m_sb.sb_agblocks)
-                       agfl_ok = 0;
+                       return false;
        }
+       return true;
+}
+
+static void
+xfs_agfl_read_verify(
+       struct xfs_buf  *bp)
+{
+       struct xfs_mount *mp = bp->b_target->bt_mount;
+       int             agfl_ok = 1;
+
+       /*
+        * There is no verification of non-crc AGFLs because mkfs does not
+        * initialise the AGFL to zero or NULL. Hence the only valid part of the
+        * AGFL is what the AGF says is active. We can't get to the AGF, so we
+        * can't verify just those entries are valid.
+        */
+       if (!xfs_sb_version_hascrc(&mp->m_sb))
+               return;
+
+       agfl_ok = xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
+                                  offsetof(struct xfs_agfl, agfl_crc));
+
+       agfl_ok = agfl_ok && xfs_agfl_verify(bp);
 
        if (!agfl_ok) {
-               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, agfl);
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
                xfs_buf_ioerror(bp, EFSCORRUPTED);
        }
-#endif
 }
 
 static void
 xfs_agfl_write_verify(
        struct xfs_buf  *bp)
 {
-       xfs_agfl_verify(bp);
-}
+       struct xfs_mount *mp = bp->b_target->bt_mount;
+       struct xfs_buf_log_item *bip = bp->b_fspriv;
 
-static void
-xfs_agfl_read_verify(
-       struct xfs_buf  *bp)
-{
-       xfs_agfl_verify(bp);
+       /* no verification of non-crc AGFLs */
+       if (!xfs_sb_version_hascrc(&mp->m_sb))
+               return;
+
+       if (!xfs_agfl_verify(bp)) {
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
+               xfs_buf_ioerror(bp, EFSCORRUPTED);
+               return;
+       }
+
+       if (bip)
+               XFS_BUF_TO_AGFL(bp)->agfl_lsn = cpu_to_be64(bip->bli_item.li_lsn);
+
+       xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length),
+                        offsetof(struct xfs_agfl, agfl_crc));
 }
 
 const struct xfs_buf_ops xfs_agfl_buf_ops = {
@@ -842,7 +875,7 @@ xfs_alloc_ag_vextent_near(
         */
        int             dofirst;        /* set to do first algorithm */
 
-       dofirst = random32() & 1;
+       dofirst = prandom_u32() & 1;
 #endif
 
 restart:
@@ -1982,18 +2015,18 @@ xfs_alloc_get_freelist(
        int             btreeblk) /* destination is a AGF btree */
 {
        xfs_agf_t       *agf;   /* a.g. freespace structure */
-       xfs_agfl_t      *agfl;  /* a.g. freelist structure */
        xfs_buf_t       *agflbp;/* buffer for a.g. freelist structure */
        xfs_agblock_t   bno;    /* block number returned */
+       __be32          *agfl_bno;
        int             error;
        int             logflags;
-       xfs_mount_t     *mp;    /* mount structure */
+       xfs_mount_t     *mp = tp->t_mountp;
        xfs_perag_t     *pag;   /* per allocation group data */
 
-       agf = XFS_BUF_TO_AGF(agbp);
        /*
         * Freelist is empty, give up.
         */
+       agf = XFS_BUF_TO_AGF(agbp);
        if (!agf->agf_flcount) {
                *bnop = NULLAGBLOCK;
                return 0;
@@ -2001,15 +2034,17 @@ xfs_alloc_get_freelist(
        /*
         * Read the array of free blocks.
         */
-       mp = tp->t_mountp;
-       if ((error = xfs_alloc_read_agfl(mp, tp,
-                       be32_to_cpu(agf->agf_seqno), &agflbp)))
+       error = xfs_alloc_read_agfl(mp, tp, be32_to_cpu(agf->agf_seqno),
+                                   &agflbp);
+       if (error)
                return error;
-       agfl = XFS_BUF_TO_AGFL(agflbp);
+
+
        /*
         * Get the block number and update the data structures.
         */
-       bno = be32_to_cpu(agfl->agfl_bno[be32_to_cpu(agf->agf_flfirst)]);
+       agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agflbp);
+       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))
@@ -2058,11 +2093,14 @@ xfs_alloc_log_agf(
                offsetof(xfs_agf_t, agf_freeblks),
                offsetof(xfs_agf_t, agf_longest),
                offsetof(xfs_agf_t, agf_btreeblks),
+               offsetof(xfs_agf_t, agf_uuid),
                sizeof(xfs_agf_t)
        };
 
        trace_xfs_agf(tp->t_mountp, XFS_BUF_TO_AGF(bp), fields, _RET_IP_);
 
+       xfs_trans_buf_set_type(tp, bp, XFS_BLFT_AGF_BUF);
+
        xfs_btree_offsets(fields, offsets, XFS_AGF_NUM_BITS, &first, &last);
        xfs_trans_log_buf(tp, bp, (uint)first, (uint)last);
 }
@@ -2099,12 +2137,13 @@ xfs_alloc_put_freelist(
        int                     btreeblk) /* block came from a AGF btree */
 {
        xfs_agf_t               *agf;   /* a.g. freespace structure */
-       xfs_agfl_t              *agfl;  /* a.g. free block array */
        __be32                  *blockp;/* pointer to array entry */
        int                     error;
        int                     logflags;
        xfs_mount_t             *mp;    /* mount structure */
        xfs_perag_t             *pag;   /* per allocation group data */
+       __be32                  *agfl_bno;
+       int                     startoff;
 
        agf = XFS_BUF_TO_AGF(agbp);
        mp = tp->t_mountp;
@@ -2112,7 +2151,6 @@ xfs_alloc_put_freelist(
        if (!agflbp && (error = xfs_alloc_read_agfl(mp, tp,
                        be32_to_cpu(agf->agf_seqno), &agflbp)))
                return error;
-       agfl = XFS_BUF_TO_AGFL(agflbp);
        be32_add_cpu(&agf->agf_fllast, 1);
        if (be32_to_cpu(agf->agf_fllast) == XFS_AGFL_SIZE(mp))
                agf->agf_fllast = 0;
@@ -2133,32 +2171,38 @@ xfs_alloc_put_freelist(
        xfs_alloc_log_agf(tp, agbp, logflags);
 
        ASSERT(be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp));
-       blockp = &agfl->agfl_bno[be32_to_cpu(agf->agf_fllast)];
+
+       agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agflbp);
+       blockp = &agfl_bno[be32_to_cpu(agf->agf_fllast)];
        *blockp = cpu_to_be32(bno);
+       startoff = (char *)blockp - (char *)agflbp->b_addr;
+
        xfs_alloc_log_agf(tp, agbp, logflags);
-       xfs_trans_log_buf(tp, agflbp,
-               (int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl),
-               (int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl +
-                       sizeof(xfs_agblock_t) - 1));
+
+       xfs_trans_buf_set_type(tp, agflbp, XFS_BLFT_AGFL_BUF);
+       xfs_trans_log_buf(tp, agflbp, startoff,
+                         startoff + sizeof(xfs_agblock_t) - 1);
        return 0;
 }
 
-static void
+static bool
 xfs_agf_verify(
+       struct xfs_mount *mp,
        struct xfs_buf  *bp)
  {
-       struct xfs_mount *mp = bp->b_target->bt_mount;
-       struct xfs_agf  *agf;
-       int             agf_ok;
+       struct xfs_agf  *agf = XFS_BUF_TO_AGF(bp);
 
-       agf = XFS_BUF_TO_AGF(bp);
+       if (xfs_sb_version_hascrc(&mp->m_sb) &&
+           !uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_uuid))
+                       return false;
 
-       agf_ok = 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);
+       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)))
+               return false;
 
        /*
         * during growfs operations, the perag is not fully initialised,
@@ -2166,33 +2210,58 @@ xfs_agf_verify(
         * use it by using uncached buffers that don't have the perag attached
         * so we can detect and avoid this problem.
         */
-       if (bp->b_pag)
-               agf_ok = agf_ok && be32_to_cpu(agf->agf_seqno) ==
-                                               bp->b_pag->pag_agno;
+       if (bp->b_pag && be32_to_cpu(agf->agf_seqno) != bp->b_pag->pag_agno)
+               return false;
 
-       if (xfs_sb_version_haslazysbcount(&mp->m_sb))
-               agf_ok = agf_ok && be32_to_cpu(agf->agf_btreeblks) <=
-                                               be32_to_cpu(agf->agf_length);
+       if (xfs_sb_version_haslazysbcount(&mp->m_sb) &&
+           be32_to_cpu(agf->agf_btreeblks) > be32_to_cpu(agf->agf_length))
+               return false;
+
+       return true;;
 
-       if (unlikely(XFS_TEST_ERROR(!agf_ok, mp, XFS_ERRTAG_ALLOC_READ_AGF,
-                       XFS_RANDOM_ALLOC_READ_AGF))) {
-               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, agf);
-               xfs_buf_ioerror(bp, EFSCORRUPTED);
-       }
 }
 
 static void
 xfs_agf_read_verify(
        struct xfs_buf  *bp)
 {
-       xfs_agf_verify(bp);
+       struct xfs_mount *mp = bp->b_target->bt_mount;
+       int             agf_ok = 1;
+
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               agf_ok = xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
+                                         offsetof(struct xfs_agf, agf_crc));
+
+       agf_ok = agf_ok && xfs_agf_verify(mp, bp);
+
+       if (unlikely(XFS_TEST_ERROR(!agf_ok, mp, XFS_ERRTAG_ALLOC_READ_AGF,
+                       XFS_RANDOM_ALLOC_READ_AGF))) {
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
+               xfs_buf_ioerror(bp, EFSCORRUPTED);
+       }
 }
 
 static void
 xfs_agf_write_verify(
        struct xfs_buf  *bp)
 {
-       xfs_agf_verify(bp);
+       struct xfs_mount *mp = bp->b_target->bt_mount;
+       struct xfs_buf_log_item *bip = bp->b_fspriv;
+
+       if (!xfs_agf_verify(mp, bp)) {
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
+               xfs_buf_ioerror(bp, EFSCORRUPTED);
+               return;
+       }
+
+       if (!xfs_sb_version_hascrc(&mp->m_sb))
+               return;
+
+       if (bip)
+               XFS_BUF_TO_AGF(bp)->agf_lsn = cpu_to_be64(bip->bli_item.li_lsn);
+
+       xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length),
+                        offsetof(struct xfs_agf, agf_crc));
 }
 
 const struct xfs_buf_ops xfs_agf_buf_ops = {