]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/xfs/xfs_log_recover.c
Merge tag 'sound-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
[karo-tx-linux.git] / fs / xfs / xfs_log_recover.c
index d308749fabf126a5b318c5d55f0e58e5589ef14f..96fcbb85ff835d0223e292125f501482626bc60c 100644 (file)
@@ -41,7 +41,9 @@
 #include "xfs_trans_priv.h"
 #include "xfs_quota.h"
 #include "xfs_utils.h"
+#include "xfs_cksum.h"
 #include "xfs_trace.h"
+#include "xfs_icache.h"
 
 STATIC int
 xlog_find_zeroed(
@@ -2143,7 +2145,7 @@ xlog_recover_buffer_pass2(
                buf_flags |= XBF_UNMAPPED;
 
        bp = xfs_buf_read(mp->m_ddev_targp, buf_f->blf_blkno, buf_f->blf_len,
-                         buf_flags);
+                         buf_flags, NULL);
        if (!bp)
                return XFS_ERROR(ENOMEM);
        error = bp->b_error;
@@ -2236,7 +2238,8 @@ xlog_recover_inode_pass2(
        }
        trace_xfs_log_recover_inode_recover(log, in_f);
 
-       bp = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len, 0);
+       bp = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len, 0,
+                         NULL);
        if (!bp) {
                error = ENOMEM;
                goto error;
@@ -2547,7 +2550,8 @@ xlog_recover_dquot_pass2(
        ASSERT(dq_f->qlf_len == 1);
 
        error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dq_f->qlf_blkno,
-                                  XFS_FSB_TO_BB(mp, dq_f->qlf_len), 0, &bp);
+                                  XFS_FSB_TO_BB(mp, dq_f->qlf_len), 0, &bp,
+                                  NULL);
        if (error)
                return error;
 
@@ -3213,80 +3217,58 @@ xlog_recover_process_iunlinks(
        mp->m_dmevmask = mp_dmevmask;
 }
 
-
-#ifdef DEBUG
-STATIC void
-xlog_pack_data_checksum(
-       struct xlog             *log,
-       struct xlog_in_core     *iclog,
-       int                     size)
-{
-       int             i;
-       __be32          *up;
-       uint            chksum = 0;
-
-       up = (__be32 *)iclog->ic_datap;
-       /* divide length by 4 to get # words */
-       for (i = 0; i < (size >> 2); i++) {
-               chksum ^= be32_to_cpu(*up);
-               up++;
-       }
-       iclog->ic_header.h_chksum = cpu_to_be32(chksum);
-}
-#else
-#define xlog_pack_data_checksum(log, iclog, size)
-#endif
-
 /*
- * Stamp cycle number in every block
+ * Upack the log buffer data and crc check it. If the check fails, issue a
+ * warning if and only if the CRC in the header is non-zero. This makes the
+ * check an advisory warning, and the zero CRC check will prevent failure
+ * warnings from being emitted when upgrading the kernel from one that does not
+ * add CRCs by default.
+ *
+ * When filesystems are CRC enabled, this CRC mismatch becomes a fatal log
+ * corruption failure
  */
-void
-xlog_pack_data(
-       struct xlog             *log,
-       struct xlog_in_core     *iclog,
-       int                     roundoff)
+STATIC int
+xlog_unpack_data_crc(
+       struct xlog_rec_header  *rhead,
+       xfs_caddr_t             dp,
+       struct xlog             *log)
 {
-       int                     i, j, k;
-       int                     size = iclog->ic_offset + roundoff;
-       __be32                  cycle_lsn;
-       xfs_caddr_t             dp;
-
-       xlog_pack_data_checksum(log, iclog, size);
-
-       cycle_lsn = CYCLE_LSN_DISK(iclog->ic_header.h_lsn);
-
-       dp = iclog->ic_datap;
-       for (i = 0; i < BTOBB(size) &&
-               i < (XLOG_HEADER_CYCLE_SIZE / BBSIZE); i++) {
-               iclog->ic_header.h_cycle_data[i] = *(__be32 *)dp;
-               *(__be32 *)dp = cycle_lsn;
-               dp += BBSIZE;
-       }
-
-       if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) {
-               xlog_in_core_2_t *xhdr = iclog->ic_data;
-
-               for ( ; i < BTOBB(size); i++) {
-                       j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE);
-                       k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE);
-                       xhdr[j].hic_xheader.xh_cycle_data[k] = *(__be32 *)dp;
-                       *(__be32 *)dp = cycle_lsn;
-                       dp += BBSIZE;
+       __le32                  crc;
+
+       crc = xlog_cksum(log, rhead, dp, be32_to_cpu(rhead->h_len));
+       if (crc != rhead->h_crc) {
+               if (rhead->h_crc || xfs_sb_version_hascrc(&log->l_mp->m_sb)) {
+                       xfs_alert(log->l_mp,
+               "log record CRC mismatch: found 0x%x, expected 0x%x.\n",
+                                       le32_to_cpu(rhead->h_crc),
+                                       le32_to_cpu(crc));
+                       xfs_hex_dump(dp, 32);
                }
 
-               for (i = 1; i < log->l_iclog_heads; i++) {
-                       xhdr[i].hic_xheader.xh_cycle = cycle_lsn;
-               }
+               /*
+                * If we've detected a log record corruption, then we can't
+                * recover past this point. Abort recovery if we are enforcing
+                * CRC protection by punting an error back up the stack.
+                */
+               if (xfs_sb_version_hascrc(&log->l_mp->m_sb))
+                       return EFSCORRUPTED;
        }
+
+       return 0;
 }
 
-STATIC void
+STATIC int
 xlog_unpack_data(
        struct xlog_rec_header  *rhead,
        xfs_caddr_t             dp,
        struct xlog             *log)
 {
        int                     i, j, k;
+       int                     error;
+
+       error = xlog_unpack_data_crc(rhead, dp, log);
+       if (error)
+               return error;
 
        for (i = 0; i < BTOBB(be32_to_cpu(rhead->h_len)) &&
                  i < (XLOG_HEADER_CYCLE_SIZE / BBSIZE); i++) {
@@ -3303,6 +3285,8 @@ xlog_unpack_data(
                        dp += BBSIZE;
                }
        }
+
+       return 0;
 }
 
 STATIC int
@@ -3434,9 +3418,13 @@ xlog_do_recovery_pass(
                        if (error)
                                goto bread_err2;
 
-                       xlog_unpack_data(rhead, offset, log);
-                       if ((error = xlog_recover_process_data(log,
-                                               rhash, rhead, offset, pass)))
+                       error = xlog_unpack_data(rhead, offset, log);
+                       if (error)
+                               goto bread_err2;
+
+                       error = xlog_recover_process_data(log,
+                                               rhash, rhead, offset, pass);
+                       if (error)
                                goto bread_err2;
                        blk_no += bblks + hblks;
                }
@@ -3546,9 +3534,14 @@ xlog_do_recovery_pass(
                                if (error)
                                        goto bread_err2;
                        }
-                       xlog_unpack_data(rhead, offset, log);
-                       if ((error = xlog_recover_process_data(log, rhash,
-                                                       rhead, offset, pass)))
+
+                       error = xlog_unpack_data(rhead, offset, log);
+                       if (error)
+                               goto bread_err2;
+
+                       error = xlog_recover_process_data(log, rhash,
+                                                       rhead, offset, pass);
+                       if (error)
                                goto bread_err2;
                        blk_no += bblks;
                }
@@ -3573,9 +3566,13 @@ xlog_do_recovery_pass(
                        if (error)
                                goto bread_err2;
 
-                       xlog_unpack_data(rhead, offset, log);
-                       if ((error = xlog_recover_process_data(log, rhash,
-                                                       rhead, offset, pass)))
+                       error = xlog_unpack_data(rhead, offset, log);
+                       if (error)
+                               goto bread_err2;
+
+                       error = xlog_recover_process_data(log, rhash,
+                                                       rhead, offset, pass);
+                       if (error)
                                goto bread_err2;
                        blk_no += bblks + hblks;
                }
@@ -3689,13 +3686,14 @@ xlog_do_recover(
 
        /*
         * Now that we've finished replaying all buffer and inode
-        * updates, re-read in the superblock.
+        * updates, re-read in the superblock and reverify it.
         */
        bp = xfs_getsb(log->l_mp, 0);
        XFS_BUF_UNDONE(bp);
        ASSERT(!(XFS_BUF_ISWRITE(bp)));
        XFS_BUF_READ(bp);
        XFS_BUF_UNASYNC(bp);
+       bp->b_ops = &xfs_sb_buf_ops;
        xfsbdstrat(log->l_mp, bp);
        error = xfs_buf_iowait(bp);
        if (error) {
@@ -3707,7 +3705,7 @@ xlog_do_recover(
 
        /* Convert superblock from on-disk format */
        sbp = &log->l_mp->m_sb;
-       xfs_sb_from_disk(log->l_mp, XFS_BUF_TO_SBP(bp));
+       xfs_sb_from_disk(sbp, XFS_BUF_TO_SBP(bp));
        ASSERT(sbp->sb_magicnum == XFS_SB_MAGIC);
        ASSERT(xfs_sb_good_version(sbp));
        xfs_buf_relse(bp);