Merge tag 'tiny/kconfig-for-3.17' of https://git.kernel.org/pub/scm/linux/kernel...
[firefly-linux-kernel-4.4.55.git] / fs / xfs / xfs_log_recover.c
index 981af0f6504b1e5b5e171ea3ea207e8759913b2c..1fd5787add9924d7ac726329f2ee88c13a90422d 100644 (file)
@@ -179,7 +179,7 @@ xlog_bread_noalign(
                xfs_warn(log->l_mp, "Invalid block length (0x%x) for buffer",
                        nbblks);
                XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp);
-               return EFSCORRUPTED;
+               return -EFSCORRUPTED;
        }
 
        blk_no = round_down(blk_no, log->l_sectBBsize);
@@ -194,7 +194,7 @@ xlog_bread_noalign(
        bp->b_error = 0;
 
        if (XFS_FORCED_SHUTDOWN(log->l_mp))
-               return XFS_ERROR(EIO);
+               return -EIO;
 
        xfs_buf_iorequest(bp);
        error = xfs_buf_iowait(bp);
@@ -268,7 +268,7 @@ xlog_bwrite(
                xfs_warn(log->l_mp, "Invalid block length (0x%x) for buffer",
                        nbblks);
                XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp);
-               return EFSCORRUPTED;
+               return -EFSCORRUPTED;
        }
 
        blk_no = round_down(blk_no, log->l_sectBBsize);
@@ -330,14 +330,14 @@ xlog_header_check_recover(
                xlog_header_check_dump(mp, head);
                XFS_ERROR_REPORT("xlog_header_check_recover(1)",
                                 XFS_ERRLEVEL_HIGH, mp);
-               return XFS_ERROR(EFSCORRUPTED);
+               return -EFSCORRUPTED;
        } else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) {
                xfs_warn(mp,
        "dirty log entry has mismatched uuid - can't recover");
                xlog_header_check_dump(mp, head);
                XFS_ERROR_REPORT("xlog_header_check_recover(2)",
                                 XFS_ERRLEVEL_HIGH, mp);
-               return XFS_ERROR(EFSCORRUPTED);
+               return -EFSCORRUPTED;
        }
        return 0;
 }
@@ -364,7 +364,7 @@ xlog_header_check_mount(
                xlog_header_check_dump(mp, head);
                XFS_ERROR_REPORT("xlog_header_check_mount",
                                 XFS_ERRLEVEL_HIGH, mp);
-               return XFS_ERROR(EFSCORRUPTED);
+               return -EFSCORRUPTED;
        }
        return 0;
 }
@@ -462,7 +462,7 @@ xlog_find_verify_cycle(
        while (!(bp = xlog_get_bp(log, bufblks))) {
                bufblks >>= 1;
                if (bufblks < log->l_sectBBsize)
-                       return ENOMEM;
+                       return -ENOMEM;
        }
 
        for (i = start_blk; i < start_blk + nbblks; i += bufblks) {
@@ -524,7 +524,7 @@ xlog_find_verify_log_record(
 
        if (!(bp = xlog_get_bp(log, num_blks))) {
                if (!(bp = xlog_get_bp(log, 1)))
-                       return ENOMEM;
+                       return -ENOMEM;
                smallmem = 1;
        } else {
                error = xlog_bread(log, start_blk, num_blks, bp, &offset);
@@ -539,7 +539,7 @@ xlog_find_verify_log_record(
                        xfs_warn(log->l_mp,
                "Log inconsistent (didn't find previous header)");
                        ASSERT(0);
-                       error = XFS_ERROR(EIO);
+                       error = -EIO;
                        goto out;
                }
 
@@ -564,7 +564,7 @@ xlog_find_verify_log_record(
         * will be called again for the end of the physical log.
         */
        if (i == -1) {
-               error = -1;
+               error = 1;
                goto out;
        }
 
@@ -628,7 +628,12 @@ xlog_find_head(
        int             error, log_bbnum = log->l_logBBsize;
 
        /* Is the end of the log device zeroed? */
-       if ((error = xlog_find_zeroed(log, &first_blk)) == -1) {
+       error = xlog_find_zeroed(log, &first_blk);
+       if (error < 0) {
+               xfs_warn(log->l_mp, "empty log check failed");
+               return error;
+       }
+       if (error == 1) {
                *return_head_blk = first_blk;
 
                /* Is the whole lot zeroed? */
@@ -641,15 +646,12 @@ xlog_find_head(
                }
 
                return 0;
-       } else if (error) {
-               xfs_warn(log->l_mp, "empty log check failed");
-               return error;
        }
 
        first_blk = 0;                  /* get cycle # of 1st block */
        bp = xlog_get_bp(log, 1);
        if (!bp)
-               return ENOMEM;
+               return -ENOMEM;
 
        error = xlog_bread(log, 0, 1, bp, &offset);
        if (error)
@@ -818,29 +820,29 @@ validate_head:
                start_blk = head_blk - num_scan_bblks; /* don't read head_blk */
 
                /* start ptr at last block ptr before head_blk */
-               if ((error = xlog_find_verify_log_record(log, start_blk,
-                                                       &head_blk, 0)) == -1) {
-                       error = XFS_ERROR(EIO);
-                       goto bp_err;
-               } else if (error)
+               error = xlog_find_verify_log_record(log, start_blk, &head_blk, 0);
+               if (error == 1)
+                       error = -EIO;
+               if (error)
                        goto bp_err;
        } else {
                start_blk = 0;
                ASSERT(head_blk <= INT_MAX);
-               if ((error = xlog_find_verify_log_record(log, start_blk,
-                                                       &head_blk, 0)) == -1) {
+               error = xlog_find_verify_log_record(log, start_blk, &head_blk, 0);
+               if (error < 0)
+                       goto bp_err;
+               if (error == 1) {
                        /* We hit the beginning of the log during our search */
                        start_blk = log_bbnum - (num_scan_bblks - head_blk);
                        new_blk = log_bbnum;
                        ASSERT(start_blk <= INT_MAX &&
                                (xfs_daddr_t) log_bbnum-start_blk >= 0);
                        ASSERT(head_blk <= INT_MAX);
-                       if ((error = xlog_find_verify_log_record(log,
-                                                       start_blk, &new_blk,
-                                                       (int)head_blk)) == -1) {
-                               error = XFS_ERROR(EIO);
-                               goto bp_err;
-                       } else if (error)
+                       error = xlog_find_verify_log_record(log, start_blk,
+                                                       &new_blk, (int)head_blk);
+                       if (error == 1)
+                               error = -EIO;
+                       if (error)
                                goto bp_err;
                        if (new_blk != log_bbnum)
                                head_blk = new_blk;
@@ -911,7 +913,7 @@ xlog_find_tail(
 
        bp = xlog_get_bp(log, 1);
        if (!bp)
-               return ENOMEM;
+               return -ENOMEM;
        if (*head_blk == 0) {                           /* special case */
                error = xlog_bread(log, 0, 1, bp, &offset);
                if (error)
@@ -961,7 +963,7 @@ xlog_find_tail(
                xfs_warn(log->l_mp, "%s: couldn't find sync record", __func__);
                xlog_put_bp(bp);
                ASSERT(0);
-               return XFS_ERROR(EIO);
+               return -EIO;
        }
 
        /* find blk_no of tail of log */
@@ -1092,8 +1094,8 @@ done:
  *
  * Return:
  *     0  => the log is completely written to
- *     -1 => use *blk_no as the first block of the log
- *     >0 => error has occurred
+ *     1 => use *blk_no as the first block of the log
+ *     <0 => error has occurred
  */
 STATIC int
 xlog_find_zeroed(
@@ -1112,7 +1114,7 @@ xlog_find_zeroed(
        /* check totally zeroed log */
        bp = xlog_get_bp(log, 1);
        if (!bp)
-               return ENOMEM;
+               return -ENOMEM;
        error = xlog_bread(log, 0, 1, bp, &offset);
        if (error)
                goto bp_err;
@@ -1121,7 +1123,7 @@ xlog_find_zeroed(
        if (first_cycle == 0) {         /* completely zeroed log */
                *blk_no = 0;
                xlog_put_bp(bp);
-               return -1;
+               return 1;
        }
 
        /* check partially zeroed log */
@@ -1141,7 +1143,7 @@ xlog_find_zeroed(
                 */
                xfs_warn(log->l_mp,
                        "Log inconsistent or not a log (last==0, first!=1)");
-               error = XFS_ERROR(EINVAL);
+               error = -EINVAL;
                goto bp_err;
        }
 
@@ -1179,19 +1181,18 @@ xlog_find_zeroed(
         * Potentially backup over partial log record write.  We don't need
         * to search the end of the log because we know it is zero.
         */
-       if ((error = xlog_find_verify_log_record(log, start_blk,
-                               &last_blk, 0)) == -1) {
-           error = XFS_ERROR(EIO);
-           goto bp_err;
-       } else if (error)
-           goto bp_err;
+       error = xlog_find_verify_log_record(log, start_blk, &last_blk, 0);
+       if (error == 1)
+               error = -EIO;
+       if (error)
+               goto bp_err;
 
        *blk_no = last_blk;
 bp_err:
        xlog_put_bp(bp);
        if (error)
                return error;
-       return -1;
+       return 1;
 }
 
 /*
@@ -1251,7 +1252,7 @@ xlog_write_log_records(
        while (!(bp = xlog_get_bp(log, bufblks))) {
                bufblks >>= 1;
                if (bufblks < sectbb)
-                       return ENOMEM;
+                       return -ENOMEM;
        }
 
        /* We may need to do a read at the start to fill in part of
@@ -1354,7 +1355,7 @@ xlog_clear_stale_blocks(
                if (unlikely(head_block < tail_block || head_block >= log->l_logBBsize)) {
                        XFS_ERROR_REPORT("xlog_clear_stale_blocks(1)",
                                         XFS_ERRLEVEL_LOW, log->l_mp);
-                       return XFS_ERROR(EFSCORRUPTED);
+                       return -EFSCORRUPTED;
                }
                tail_distance = tail_block + (log->l_logBBsize - head_block);
        } else {
@@ -1366,7 +1367,7 @@ xlog_clear_stale_blocks(
                if (unlikely(head_block >= tail_block || head_cycle != (tail_cycle + 1))){
                        XFS_ERROR_REPORT("xlog_clear_stale_blocks(2)",
                                         XFS_ERRLEVEL_LOW, log->l_mp);
-                       return XFS_ERROR(EFSCORRUPTED);
+                       return -EFSCORRUPTED;
                }
                tail_distance = tail_block - head_block;
        }
@@ -1551,7 +1552,7 @@ xlog_recover_add_to_trans(
                        xfs_warn(log->l_mp, "%s: bad header magic number",
                                __func__);
                        ASSERT(0);
-                       return XFS_ERROR(EIO);
+                       return -EIO;
                }
                if (len == sizeof(xfs_trans_header_t))
                        xlog_recover_add_item(&trans->r_itemq);
@@ -1581,7 +1582,7 @@ xlog_recover_add_to_trans(
                                  in_f->ilf_size);
                        ASSERT(0);
                        kmem_free(ptr);
-                       return XFS_ERROR(EIO);
+                       return -EIO;
                }
 
                item->ri_total = in_f->ilf_size;
@@ -1702,7 +1703,7 @@ xlog_recover_reorder_trans(
                         */
                        if (!list_empty(&sort_list))
                                list_splice_init(&sort_list, &trans->r_itemq);
-                       error = XFS_ERROR(EIO);
+                       error = -EIO;
                        goto out;
                }
        }
@@ -1943,7 +1944,7 @@ xlog_recover_do_inode_buffer(
                                item, bp);
                        XFS_ERROR_REPORT("xlog_recover_do_inode_buf",
                                         XFS_ERRLEVEL_LOW, mp);
-                       return XFS_ERROR(EFSCORRUPTED);
+                       return -EFSCORRUPTED;
                }
 
                buffer_nextp = (xfs_agino_t *)xfs_buf_offset(bp,
@@ -2125,6 +2126,17 @@ xlog_recover_validate_buf_type(
        __uint16_t              magic16;
        __uint16_t              magicda;
 
+       /*
+        * We can only do post recovery validation on items on CRC enabled
+        * fielsystems as we need to know when the buffer was written to be able
+        * to determine if we should have replayed the item. If we replay old
+        * metadata over a newer buffer, then it will enter a temporarily
+        * inconsistent state resulting in verification failures. Hence for now
+        * just avoid the verification stage for non-crc filesystems
+        */
+       if (!xfs_sb_version_hascrc(&mp->m_sb))
+               return;
+
        magic32 = be32_to_cpu(*(__be32 *)bp->b_addr);
        magic16 = be16_to_cpu(*(__be16*)bp->b_addr);
        magicda = be16_to_cpu(info->magic);
@@ -2162,8 +2174,6 @@ xlog_recover_validate_buf_type(
                bp->b_ops = &xfs_agf_buf_ops;
                break;
        case XFS_BLFT_AGFL_BUF:
-               if (!xfs_sb_version_hascrc(&mp->m_sb))
-                       break;
                if (magic32 != XFS_AGFL_MAGIC) {
                        xfs_warn(mp, "Bad AGFL block magic!");
                        ASSERT(0);
@@ -2196,10 +2206,6 @@ xlog_recover_validate_buf_type(
 #endif
                break;
        case XFS_BLFT_DINO_BUF:
-               /*
-                * we get here with inode allocation buffers, not buffers that
-                * track unlinked list changes.
-                */
                if (magic16 != XFS_DINODE_MAGIC) {
                        xfs_warn(mp, "Bad INODE block magic!");
                        ASSERT(0);
@@ -2279,8 +2285,6 @@ xlog_recover_validate_buf_type(
                bp->b_ops = &xfs_attr3_leaf_buf_ops;
                break;
        case XFS_BLFT_ATTR_RMT_BUF:
-               if (!xfs_sb_version_hascrc(&mp->m_sb))
-                       break;
                if (magic32 != XFS_ATTR3_RMT_MAGIC) {
                        xfs_warn(mp, "Bad attr remote magic!");
                        ASSERT(0);
@@ -2387,16 +2391,7 @@ xlog_recover_do_reg_buffer(
        /* Shouldn't be any more regions */
        ASSERT(i == item->ri_total);
 
-       /*
-        * We can only do post recovery validation on items on CRC enabled
-        * fielsystems as we need to know when the buffer was written to be able
-        * to determine if we should have replayed the item. If we replay old
-        * metadata over a newer buffer, then it will enter a temporarily
-        * inconsistent state resulting in verification failures. Hence for now
-        * just avoid the verification stage for non-crc filesystems
-        */
-       if (xfs_sb_version_hascrc(&mp->m_sb))
-               xlog_recover_validate_buf_type(mp, bp, buf_f);
+       xlog_recover_validate_buf_type(mp, bp, buf_f);
 }
 
 /*
@@ -2404,8 +2399,11 @@ xlog_recover_do_reg_buffer(
  * Simple algorithm: if we have found a QUOTAOFF log item of the same type
  * (ie. USR or GRP), then just toss this buffer away; don't recover it.
  * Else, treat it as a regular buffer and do recovery.
+ *
+ * Return false if the buffer was tossed and true if we recovered the buffer to
+ * indicate to the caller if the buffer needs writing.
  */
-STATIC void
+STATIC bool
 xlog_recover_do_dquot_buffer(
        struct xfs_mount                *mp,
        struct xlog                     *log,
@@ -2420,9 +2418,8 @@ xlog_recover_do_dquot_buffer(
        /*
         * Filesystems are required to send in quota flags at mount time.
         */
-       if (mp->m_qflags == 0) {
-               return;
-       }
+       if (!mp->m_qflags)
+               return false;
 
        type = 0;
        if (buf_f->blf_flags & XFS_BLF_UDQUOT_BUF)
@@ -2435,9 +2432,10 @@ xlog_recover_do_dquot_buffer(
         * This type of quotas was turned off, so ignore this buffer
         */
        if (log->l_quotaoffs_flag & type)
-               return;
+               return false;
 
        xlog_recover_do_reg_buffer(mp, item, bp, buf_f);
+       return true;
 }
 
 /*
@@ -2496,7 +2494,7 @@ xlog_recover_buffer_pass2(
        bp = xfs_buf_read(mp->m_ddev_targp, buf_f->blf_blkno, buf_f->blf_len,
                          buf_flags, NULL);
        if (!bp)
-               return XFS_ERROR(ENOMEM);
+               return -ENOMEM;
        error = bp->b_error;
        if (error) {
                xfs_buf_ioerror_alert(bp, "xlog_recover_do..(read#1)");
@@ -2504,23 +2502,44 @@ xlog_recover_buffer_pass2(
        }
 
        /*
-        * recover the buffer only if we get an LSN from it and it's less than
+        * Recover the buffer only if we get an LSN from it and it's less than
         * the lsn of the transaction we are replaying.
+        *
+        * Note that we have to be extremely careful of readahead here.
+        * Readahead does not attach verfiers to the buffers so if we don't
+        * actually do any replay after readahead because of the LSN we found
+        * in the buffer if more recent than that current transaction then we
+        * need to attach the verifier directly. Failure to do so can lead to
+        * future recovery actions (e.g. EFI and unlinked list recovery) can
+        * operate on the buffers and they won't get the verifier attached. This
+        * can lead to blocks on disk having the correct content but a stale
+        * CRC.
+        *
+        * It is safe to assume these clean buffers are currently up to date.
+        * If the buffer is dirtied by a later transaction being replayed, then
+        * the verifier will be reset to match whatever recover turns that
+        * buffer into.
         */
        lsn = xlog_recover_get_buf_lsn(mp, bp);
-       if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0)
+       if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) {
+               xlog_recover_validate_buf_type(mp, bp, buf_f);
                goto out_release;
+       }
 
        if (buf_f->blf_flags & XFS_BLF_INODE_BUF) {
                error = xlog_recover_do_inode_buffer(mp, item, bp, buf_f);
+               if (error)
+                       goto out_release;
        } else if (buf_f->blf_flags &
                  (XFS_BLF_UDQUOT_BUF|XFS_BLF_PDQUOT_BUF|XFS_BLF_GDQUOT_BUF)) {
-               xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f);
+               bool    dirty;
+
+               dirty = xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f);
+               if (!dirty)
+                       goto out_release;
        } else {
                xlog_recover_do_reg_buffer(mp, item, bp, buf_f);
        }
-       if (error)
-               goto out_release;
 
        /*
         * Perform delayed write on the buffer.  Asynchronous writes will be
@@ -2598,7 +2617,7 @@ xfs_recover_inode_owner_change(
 
        ip = xfs_inode_alloc(mp, in_f->ilf_ino);
        if (!ip)
-               return ENOMEM;
+               return -ENOMEM;
 
        /* instantiate the inode */
        xfs_dinode_from_disk(&ip->i_d, dip);
@@ -2676,7 +2695,7 @@ xlog_recover_inode_pass2(
        bp = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len, 0,
                          &xfs_inode_buf_ops);
        if (!bp) {
-               error = ENOMEM;
+               error = -ENOMEM;
                goto error;
        }
        error = bp->b_error;
@@ -2697,7 +2716,7 @@ xlog_recover_inode_pass2(
                        __func__, dip, bp, in_f->ilf_ino);
                XFS_ERROR_REPORT("xlog_recover_inode_pass2(1)",
                                 XFS_ERRLEVEL_LOW, mp);
-               error = EFSCORRUPTED;
+               error = -EFSCORRUPTED;
                goto out_release;
        }
        dicp = item->ri_buf[1].i_addr;
@@ -2707,7 +2726,7 @@ xlog_recover_inode_pass2(
                        __func__, item, in_f->ilf_ino);
                XFS_ERROR_REPORT("xlog_recover_inode_pass2(2)",
                                 XFS_ERRLEVEL_LOW, mp);
-               error = EFSCORRUPTED;
+               error = -EFSCORRUPTED;
                goto out_release;
        }
 
@@ -2764,7 +2783,7 @@ xlog_recover_inode_pass2(
                "%s: Bad regular inode log record, rec ptr 0x%p, "
                "ino ptr = 0x%p, ino bp = 0x%p, ino %Ld",
                                __func__, item, dip, bp, in_f->ilf_ino);
-                       error = EFSCORRUPTED;
+                       error = -EFSCORRUPTED;
                        goto out_release;
                }
        } else if (unlikely(S_ISDIR(dicp->di_mode))) {
@@ -2777,7 +2796,7 @@ xlog_recover_inode_pass2(
                "%s: Bad dir inode log record, rec ptr 0x%p, "
                "ino ptr = 0x%p, ino bp = 0x%p, ino %Ld",
                                __func__, item, dip, bp, in_f->ilf_ino);
-                       error = EFSCORRUPTED;
+                       error = -EFSCORRUPTED;
                        goto out_release;
                }
        }
@@ -2790,7 +2809,7 @@ xlog_recover_inode_pass2(
                        __func__, item, dip, bp, in_f->ilf_ino,
                        dicp->di_nextents + dicp->di_anextents,
                        dicp->di_nblocks);
-               error = EFSCORRUPTED;
+               error = -EFSCORRUPTED;
                goto out_release;
        }
        if (unlikely(dicp->di_forkoff > mp->m_sb.sb_inodesize)) {
@@ -2800,7 +2819,7 @@ xlog_recover_inode_pass2(
        "%s: Bad inode log record, rec ptr 0x%p, dino ptr 0x%p, "
        "dino bp 0x%p, ino %Ld, forkoff 0x%x", __func__,
                        item, dip, bp, in_f->ilf_ino, dicp->di_forkoff);
-               error = EFSCORRUPTED;
+               error = -EFSCORRUPTED;
                goto out_release;
        }
        isize = xfs_icdinode_size(dicp->di_version);
@@ -2810,7 +2829,7 @@ xlog_recover_inode_pass2(
                xfs_alert(mp,
                        "%s: Bad inode log record length %d, rec ptr 0x%p",
                        __func__, item->ri_buf[1].i_len, item);
-               error = EFSCORRUPTED;
+               error = -EFSCORRUPTED;
                goto out_release;
        }
 
@@ -2898,7 +2917,7 @@ xlog_recover_inode_pass2(
                default:
                        xfs_warn(log->l_mp, "%s: Invalid flag", __func__);
                        ASSERT(0);
-                       error = EIO;
+                       error = -EIO;
                        goto out_release;
                }
        }
@@ -2919,7 +2938,7 @@ out_release:
 error:
        if (need_free)
                kmem_free(in_f);
-       return XFS_ERROR(error);
+       return error;
 }
 
 /*
@@ -2946,7 +2965,7 @@ xlog_recover_quotaoff_pass1(
        if (qoff_f->qf_flags & XFS_GQUOTA_ACCT)
                log->l_quotaoffs_flag |= XFS_DQ_GROUP;
 
-       return (0);
+       return 0;
 }
 
 /*
@@ -2971,17 +2990,17 @@ xlog_recover_dquot_pass2(
         * Filesystems are required to send in quota flags at mount time.
         */
        if (mp->m_qflags == 0)
-               return (0);
+               return 0;
 
        recddq = item->ri_buf[1].i_addr;
        if (recddq == NULL) {
                xfs_alert(log->l_mp, "NULL dquot in %s.", __func__);
-               return XFS_ERROR(EIO);
+               return -EIO;
        }
        if (item->ri_buf[1].i_len < sizeof(xfs_disk_dquot_t)) {
                xfs_alert(log->l_mp, "dquot too small (%d) in %s.",
                        item->ri_buf[1].i_len, __func__);
-               return XFS_ERROR(EIO);
+               return -EIO;
        }
 
        /*
@@ -2990,7 +3009,7 @@ xlog_recover_dquot_pass2(
        type = recddq->d_flags & (XFS_DQ_USER | XFS_DQ_PROJ | XFS_DQ_GROUP);
        ASSERT(type);
        if (log->l_quotaoffs_flag & type)
-               return (0);
+               return 0;
 
        /*
         * At this point we know that quota was _not_ turned off.
@@ -3007,30 +3026,25 @@ xlog_recover_dquot_pass2(
        error = xfs_dqcheck(mp, recddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN,
                           "xlog_recover_dquot_pass2 (log copy)");
        if (error)
-               return XFS_ERROR(EIO);
+               return -EIO;
        ASSERT(dq_f->qlf_len == 1);
 
+       /*
+        * At this point we are assuming that the dquots have been allocated
+        * and hence the buffer has valid dquots stamped in it. It should,
+        * therefore, pass verifier validation. If the dquot is bad, then the
+        * we'll return an error here, so we don't need to specifically check
+        * the dquot in the buffer after the verifier has run.
+        */
        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,
-                                  NULL);
+                                  &xfs_dquot_buf_ops);
        if (error)
                return error;
 
        ASSERT(bp);
        ddq = (xfs_disk_dquot_t *)xfs_buf_offset(bp, dq_f->qlf_boffset);
 
-       /*
-        * At least the magic num portion should be on disk because this
-        * was among a chunk of dquots created earlier, and we did some
-        * minimal initialization then.
-        */
-       error = xfs_dqcheck(mp, ddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN,
-                          "xlog_recover_dquot_pass2");
-       if (error) {
-               xfs_buf_relse(bp);
-               return XFS_ERROR(EIO);
-       }
-
        /*
         * If the dquot has an LSN in it, recover the dquot only if it's less
         * than the lsn of the transaction we are replaying.
@@ -3178,38 +3192,38 @@ xlog_recover_do_icreate_pass2(
        icl = (struct xfs_icreate_log *)item->ri_buf[0].i_addr;
        if (icl->icl_type != XFS_LI_ICREATE) {
                xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad type");
-               return EINVAL;
+               return -EINVAL;
        }
 
        if (icl->icl_size != 1) {
                xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad icl size");
-               return EINVAL;
+               return -EINVAL;
        }
 
        agno = be32_to_cpu(icl->icl_ag);
        if (agno >= mp->m_sb.sb_agcount) {
                xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad agno");
-               return EINVAL;
+               return -EINVAL;
        }
        agbno = be32_to_cpu(icl->icl_agbno);
        if (!agbno || agbno == NULLAGBLOCK || agbno >= mp->m_sb.sb_agblocks) {
                xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad agbno");
-               return EINVAL;
+               return -EINVAL;
        }
        isize = be32_to_cpu(icl->icl_isize);
        if (isize != mp->m_sb.sb_inodesize) {
                xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad isize");
-               return EINVAL;
+               return -EINVAL;
        }
        count = be32_to_cpu(icl->icl_count);
        if (!count) {
                xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad count");
-               return EINVAL;
+               return -EINVAL;
        }
        length = be32_to_cpu(icl->icl_length);
        if (!length || length >= mp->m_sb.sb_agblocks) {
                xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad length");
-               return EINVAL;
+               return -EINVAL;
        }
 
        /* existing allocation is fixed value */
@@ -3218,7 +3232,7 @@ xlog_recover_do_icreate_pass2(
        if (count != mp->m_ialloc_inos ||
             length != mp->m_ialloc_blks) {
                xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad count 2");
-               return EINVAL;
+               return -EINVAL;
        }
 
        /*
@@ -3389,7 +3403,7 @@ xlog_recover_commit_pass1(
                xfs_warn(log->l_mp, "%s: invalid item type (%d)",
                        __func__, ITEM_TYPE(item));
                ASSERT(0);
-               return XFS_ERROR(EIO);
+               return -EIO;
        }
 }
 
@@ -3425,7 +3439,7 @@ xlog_recover_commit_pass2(
                xfs_warn(log->l_mp, "%s: invalid item type (%d)",
                        __func__, ITEM_TYPE(item));
                ASSERT(0);
-               return XFS_ERROR(EIO);
+               return -EIO;
        }
 }
 
@@ -3560,7 +3574,7 @@ xlog_recover_process_data(
 
        /* check the log format matches our own - else we can't recover */
        if (xlog_header_check_recover(log->l_mp, rhead))
-               return (XFS_ERROR(EIO));
+               return -EIO;
 
        while ((dp < lp) && num_logops) {
                ASSERT(dp + sizeof(xlog_op_header_t) <= lp);
@@ -3571,7 +3585,7 @@ xlog_recover_process_data(
                        xfs_warn(log->l_mp, "%s: bad clientid 0x%x",
                                        __func__, ohead->oh_clientid);
                        ASSERT(0);
-                       return (XFS_ERROR(EIO));
+                       return -EIO;
                }
                tid = be32_to_cpu(ohead->oh_tid);
                hash = XLOG_RHASH(tid);
@@ -3585,7 +3599,7 @@ xlog_recover_process_data(
                                xfs_warn(log->l_mp, "%s: bad length 0x%x",
                                        __func__, be32_to_cpu(ohead->oh_len));
                                WARN_ON(1);
-                               return (XFS_ERROR(EIO));
+                               return -EIO;
                        }
                        flags = ohead->oh_flags & ~XLOG_END_TRANS;
                        if (flags & XLOG_WAS_CONT_TRANS)
@@ -3607,7 +3621,7 @@ xlog_recover_process_data(
                                xfs_warn(log->l_mp, "%s: bad transaction",
                                        __func__);
                                ASSERT(0);
-                               error = XFS_ERROR(EIO);
+                               error = -EIO;
                                break;
                        case 0:
                        case XLOG_CONTINUE_TRANS:
@@ -3618,7 +3632,7 @@ xlog_recover_process_data(
                                xfs_warn(log->l_mp, "%s: bad flag 0x%x",
                                        __func__, flags);
                                ASSERT(0);
-                               error = XFS_ERROR(EIO);
+                               error = -EIO;
                                break;
                        }
                        if (error) {
@@ -3669,7 +3683,7 @@ xlog_recover_process_efi(
                         */
                        set_bit(XFS_EFI_RECOVERED, &efip->efi_flags);
                        xfs_efi_release(efip, efip->efi_format.efi_nextents);
-                       return XFS_ERROR(EIO);
+                       return -EIO;
                }
        }
 
@@ -3969,7 +3983,7 @@ xlog_unpack_data_crc(
                 * CRC protection by punting an error back up the stack.
                 */
                if (xfs_sb_version_hascrc(&log->l_mp->m_sb))
-                       return EFSCORRUPTED;
+                       return -EFSCORRUPTED;
        }
 
        return 0;
@@ -4018,14 +4032,14 @@ xlog_valid_rec_header(
        if (unlikely(rhead->h_magicno != cpu_to_be32(XLOG_HEADER_MAGIC_NUM))) {
                XFS_ERROR_REPORT("xlog_valid_rec_header(1)",
                                XFS_ERRLEVEL_LOW, log->l_mp);
-               return XFS_ERROR(EFSCORRUPTED);
+               return -EFSCORRUPTED;
        }
        if (unlikely(
            (!rhead->h_version ||
            (be32_to_cpu(rhead->h_version) & (~XLOG_VERSION_OKBITS))))) {
                xfs_warn(log->l_mp, "%s: unrecognised log version (%d).",
                        __func__, be32_to_cpu(rhead->h_version));
-               return XFS_ERROR(EIO);
+               return -EIO;
        }
 
        /* LR body must have data or it wouldn't have been written */
@@ -4033,12 +4047,12 @@ xlog_valid_rec_header(
        if (unlikely( hlen <= 0 || hlen > INT_MAX )) {
                XFS_ERROR_REPORT("xlog_valid_rec_header(2)",
                                XFS_ERRLEVEL_LOW, log->l_mp);
-               return XFS_ERROR(EFSCORRUPTED);
+               return -EFSCORRUPTED;
        }
        if (unlikely( blkno > log->l_logBBsize || blkno > INT_MAX )) {
                XFS_ERROR_REPORT("xlog_valid_rec_header(3)",
                                XFS_ERRLEVEL_LOW, log->l_mp);
-               return XFS_ERROR(EFSCORRUPTED);
+               return -EFSCORRUPTED;
        }
        return 0;
 }
@@ -4081,7 +4095,7 @@ xlog_do_recovery_pass(
                 */
                hbp = xlog_get_bp(log, 1);
                if (!hbp)
-                       return ENOMEM;
+                       return -ENOMEM;
 
                error = xlog_bread(log, tail_blk, 1, hbp, &offset);
                if (error)
@@ -4110,11 +4124,11 @@ xlog_do_recovery_pass(
        }
 
        if (!hbp)
-               return ENOMEM;
+               return -ENOMEM;
        dbp = xlog_get_bp(log, BTOBB(h_size));
        if (!dbp) {
                xlog_put_bp(hbp);
-               return ENOMEM;
+               return -ENOMEM;
        }
 
        memset(rhash, 0, sizeof(rhash));
@@ -4388,7 +4402,7 @@ xlog_do_recover(
         * If IO errors happened during recovery, bail out.
         */
        if (XFS_FORCED_SHUTDOWN(log->l_mp)) {
-               return (EIO);
+               return -EIO;
        }
 
        /*
@@ -4415,7 +4429,7 @@ xlog_do_recover(
 
        if (XFS_FORCED_SHUTDOWN(log->l_mp)) {
                xfs_buf_relse(bp);
-               return XFS_ERROR(EIO);
+               return -EIO;
        }
 
        xfs_buf_iorequest(bp);
@@ -4492,7 +4506,7 @@ xlog_recover(
 "Please recover the log on a kernel that supports the unknown features.",
                                (log->l_mp->m_sb.sb_features_log_incompat &
                                        XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN));
-                       return EINVAL;
+                       return -EINVAL;
                }
 
                xfs_notice(log->l_mp, "Starting recovery (logdev: %s)",