]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/xfs/xfs_log_recover.c
Merge tag 'arm-soc/for-5.5/devicetree-part2' of https://github.com/Broadcom/stblinux...
[linux.git] / fs / xfs / xfs_log_recover.c
index c1a514ffff55507e2986568868b7df915f3b00f8..99ec3fba45485a1aff9c665be127d102dced6a26 100644 (file)
@@ -103,10 +103,9 @@ xlog_alloc_buffer(
         * Pass log block 0 since we don't have an addr yet, buffer will be
         * verified on read.
         */
-       if (!xlog_verify_bno(log, 0, nbblks)) {
+       if (XFS_IS_CORRUPT(log->l_mp, !xlog_verify_bno(log, 0, nbblks))) {
                xfs_warn(log->l_mp, "Invalid block length (0x%x) for buffer",
                        nbblks);
-               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp);
                return NULL;
        }
 
@@ -152,11 +151,10 @@ xlog_do_io(
 {
        int                     error;
 
-       if (!xlog_verify_bno(log, blk_no, nbblks)) {
+       if (XFS_IS_CORRUPT(log->l_mp, !xlog_verify_bno(log, blk_no, nbblks))) {
                xfs_warn(log->l_mp,
                         "Invalid log block/length (0x%llx, 0x%x) for buffer",
                         blk_no, nbblks);
-               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp);
                return -EFSCORRUPTED;
        }
 
@@ -244,19 +242,17 @@ xlog_header_check_recover(
         * (XLOG_FMT_UNKNOWN). This stops us from trying to recover
         * a dirty log created in IRIX.
         */
-       if (unlikely(head->h_fmt != cpu_to_be32(XLOG_FMT))) {
+       if (XFS_IS_CORRUPT(mp, head->h_fmt != cpu_to_be32(XLOG_FMT))) {
                xfs_warn(mp,
        "dirty log written in incompatible format - can't recover");
                xlog_header_check_dump(mp, head);
-               XFS_ERROR_REPORT("xlog_header_check_recover(1)",
-                                XFS_ERRLEVEL_HIGH, mp);
                return -EFSCORRUPTED;
-       } else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) {
+       }
+       if (XFS_IS_CORRUPT(mp, !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 -EFSCORRUPTED;
        }
        return 0;
@@ -279,11 +275,10 @@ xlog_header_check_mount(
                 * by IRIX and continue.
                 */
                xfs_warn(mp, "null uuid in log - IRIX style log");
-       } else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) {
+       } else if (XFS_IS_CORRUPT(mp, !uuid_equal(&mp->m_sb.sb_uuid,
+                                                 &head->h_fs_uuid))) {
                xfs_warn(mp, "log has mismatched uuid - can't recover");
                xlog_header_check_dump(mp, head);
-               XFS_ERROR_REPORT("xlog_header_check_mount",
-                                XFS_ERRLEVEL_HIGH, mp);
                return -EFSCORRUPTED;
        }
        return 0;
@@ -471,7 +466,7 @@ xlog_find_verify_log_record(
                        xfs_warn(log->l_mp,
                "Log inconsistent (didn't find previous header)");
                        ASSERT(0);
-                       error = -EIO;
+                       error = -EFSCORRUPTED;
                        goto out;
                }
 
@@ -1347,10 +1342,11 @@ xlog_find_tail(
        error = xlog_rseek_logrec_hdr(log, *head_blk, *head_blk, 1, buffer,
                                      &rhead_blk, &rhead, &wrapped);
        if (error < 0)
-               return error;
+               goto done;
        if (!error) {
                xfs_warn(log->l_mp, "%s: couldn't find sync record", __func__);
-               return -EIO;
+               error = -EFSCORRUPTED;
+               goto done;
        }
        *tail_blk = BLOCK_LSN(be64_to_cpu(rhead->h_tail_lsn));
 
@@ -1699,11 +1695,10 @@ xlog_clear_stale_blocks(
                 * the distance from the beginning of the log to the
                 * tail.
                 */
-               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);
+               if (XFS_IS_CORRUPT(log->l_mp,
+                                  head_block < tail_block ||
+                                  head_block >= log->l_logBBsize))
                        return -EFSCORRUPTED;
-               }
                tail_distance = tail_block + (log->l_logBBsize - head_block);
        } else {
                /*
@@ -1711,11 +1706,10 @@ xlog_clear_stale_blocks(
                 * so the distance from the head to the tail is just
                 * the tail block minus the head block.
                 */
-               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);
+               if (XFS_IS_CORRUPT(log->l_mp,
+                                  head_block >= tail_block ||
+                                  head_cycle != tail_cycle + 1))
                        return -EFSCORRUPTED;
-               }
                tail_distance = tail_block - head_block;
        }
 
@@ -2135,13 +2129,11 @@ xlog_recover_do_inode_buffer(
                 */
                logged_nextp = item->ri_buf[item_index].i_addr +
                                next_unlinked_offset - reg_buf_offset;
-               if (unlikely(*logged_nextp == 0)) {
+               if (XFS_IS_CORRUPT(mp, *logged_nextp == 0)) {
                        xfs_alert(mp,
                "Bad inode buffer log record (ptr = "PTR_FMT", bp = "PTR_FMT"). "
                "Trying to replay bad (0) inode di_next_unlinked field.",
                                item, bp);
-                       XFS_ERROR_REPORT("xlog_recover_do_inode_buf",
-                                        XFS_ERRLEVEL_LOW, mp);
                        return -EFSCORRUPTED;
                }
 
@@ -2576,6 +2568,7 @@ xlog_recover_do_reg_buffer(
        int                     bit;
        int                     nbits;
        xfs_failaddr_t          fa;
+       const size_t            size_disk_dquot = sizeof(struct xfs_disk_dquot);
 
        trace_xfs_log_recover_buf_reg_buf(mp->m_log, buf_f);
 
@@ -2618,7 +2611,7 @@ xlog_recover_do_reg_buffer(
                                        "XFS: NULL dquot in %s.", __func__);
                                goto next;
                        }
-                       if (item->ri_buf[i].i_len < sizeof(xfs_disk_dquot_t)) {
+                       if (item->ri_buf[i].i_len < size_disk_dquot) {
                                xfs_alert(mp,
                                        "XFS: dquot too small (%d) in %s.",
                                        item->ri_buf[i].i_len, __func__);
@@ -2969,22 +2962,18 @@ xlog_recover_inode_pass2(
         * Make sure the place we're flushing out to really looks
         * like an inode!
         */
-       if (unlikely(!xfs_verify_magic16(bp, dip->di_magic))) {
+       if (XFS_IS_CORRUPT(mp, !xfs_verify_magic16(bp, dip->di_magic))) {
                xfs_alert(mp,
        "%s: Bad inode magic number, dip = "PTR_FMT", dino bp = "PTR_FMT", ino = %Ld",
                        __func__, dip, bp, in_f->ilf_ino);
-               XFS_ERROR_REPORT("xlog_recover_inode_pass2(1)",
-                                XFS_ERRLEVEL_LOW, mp);
                error = -EFSCORRUPTED;
                goto out_release;
        }
        ldip = item->ri_buf[1].i_addr;
-       if (unlikely(ldip->di_magic != XFS_DINODE_MAGIC)) {
+       if (XFS_IS_CORRUPT(mp, ldip->di_magic != XFS_DINODE_MAGIC)) {
                xfs_alert(mp,
                        "%s: Bad inode log record, rec ptr "PTR_FMT", ino %Ld",
                        __func__, item, in_f->ilf_ino);
-               XFS_ERROR_REPORT("xlog_recover_inode_pass2(2)",
-                                XFS_ERRLEVEL_LOW, mp);
                error = -EFSCORRUPTED;
                goto out_release;
        }
@@ -3166,7 +3155,7 @@ xlog_recover_inode_pass2(
                default:
                        xfs_warn(log->l_mp, "%s: Invalid flag", __func__);
                        ASSERT(0);
-                       error = -EIO;
+                       error = -EFSCORRUPTED;
                        goto out_release;
                }
        }
@@ -3247,12 +3236,12 @@ xlog_recover_dquot_pass2(
        recddq = item->ri_buf[1].i_addr;
        if (recddq == NULL) {
                xfs_alert(log->l_mp, "NULL dquot in %s.", __func__);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
-       if (item->ri_buf[1].i_len < sizeof(xfs_disk_dquot_t)) {
+       if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot)) {
                xfs_alert(log->l_mp, "dquot too small (%d) in %s.",
                        item->ri_buf[1].i_len, __func__);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 
        /*
@@ -3279,7 +3268,7 @@ xlog_recover_dquot_pass2(
        if (fa) {
                xfs_alert(mp, "corrupt dquot ID 0x%x in log at %pS",
                                dq_f->qlf_id, fa);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
        ASSERT(dq_f->qlf_len == 1);
 
@@ -3537,6 +3526,7 @@ xfs_cui_copy_format(
                memcpy(dst_cui_fmt, src_cui_fmt, len);
                return 0;
        }
+       XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
        return -EFSCORRUPTED;
 }
 
@@ -3601,8 +3591,10 @@ xlog_recover_cud_pass2(
        struct xfs_ail                  *ailp = log->l_ailp;
 
        cud_formatp = item->ri_buf[0].i_addr;
-       if (item->ri_buf[0].i_len != sizeof(struct xfs_cud_log_format))
+       if (item->ri_buf[0].i_len != sizeof(struct xfs_cud_log_format)) {
+               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp);
                return -EFSCORRUPTED;
+       }
        cui_id = cud_formatp->cud_cui_id;
 
        /*
@@ -3654,6 +3646,7 @@ xfs_bui_copy_format(
                memcpy(dst_bui_fmt, src_bui_fmt, len);
                return 0;
        }
+       XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
        return -EFSCORRUPTED;
 }
 
@@ -3677,8 +3670,10 @@ xlog_recover_bui_pass2(
 
        bui_formatp = item->ri_buf[0].i_addr;
 
-       if (bui_formatp->bui_nextents != XFS_BUI_MAX_FAST_EXTENTS)
+       if (bui_formatp->bui_nextents != XFS_BUI_MAX_FAST_EXTENTS) {
+               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp);
                return -EFSCORRUPTED;
+       }
        buip = xfs_bui_init(mp);
        error = xfs_bui_copy_format(&item->ri_buf[0], &buip->bui_format);
        if (error) {
@@ -3720,8 +3715,10 @@ xlog_recover_bud_pass2(
        struct xfs_ail                  *ailp = log->l_ailp;
 
        bud_formatp = item->ri_buf[0].i_addr;
-       if (item->ri_buf[0].i_len != sizeof(struct xfs_bud_log_format))
+       if (item->ri_buf[0].i_len != sizeof(struct xfs_bud_log_format)) {
+               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp);
                return -EFSCORRUPTED;
+       }
        bui_id = bud_formatp->bud_bui_id;
 
        /*
@@ -4018,7 +4015,7 @@ xlog_recover_commit_pass1(
                xfs_warn(log->l_mp, "%s: invalid item type (%d)",
                        __func__, ITEM_TYPE(item));
                ASSERT(0);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 }
 
@@ -4066,7 +4063,7 @@ xlog_recover_commit_pass2(
                xfs_warn(log->l_mp, "%s: invalid item type (%d)",
                        __func__, ITEM_TYPE(item));
                ASSERT(0);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 }
 
@@ -4187,7 +4184,7 @@ xlog_recover_add_to_cont_trans(
                ASSERT(len <= sizeof(struct xfs_trans_header));
                if (len > sizeof(struct xfs_trans_header)) {
                        xfs_warn(log->l_mp, "%s: bad header length", __func__);
-                       return -EIO;
+                       return -EFSCORRUPTED;
                }
 
                xlog_recover_add_item(&trans->r_itemq);
@@ -4243,13 +4240,13 @@ xlog_recover_add_to_trans(
                        xfs_warn(log->l_mp, "%s: bad header magic number",
                                __func__);
                        ASSERT(0);
-                       return -EIO;
+                       return -EFSCORRUPTED;
                }
 
                if (len > sizeof(struct xfs_trans_header)) {
                        xfs_warn(log->l_mp, "%s: bad header length", __func__);
                        ASSERT(0);
-                       return -EIO;
+                       return -EFSCORRUPTED;
                }
 
                /*
@@ -4285,7 +4282,7 @@ xlog_recover_add_to_trans(
                                  in_f->ilf_size);
                        ASSERT(0);
                        kmem_free(ptr);
-                       return -EIO;
+                       return -EFSCORRUPTED;
                }
 
                item->ri_total = in_f->ilf_size;
@@ -4293,7 +4290,16 @@ xlog_recover_add_to_trans(
                        kmem_zalloc(item->ri_total * sizeof(xfs_log_iovec_t),
                                    0);
        }
-       ASSERT(item->ri_total > item->ri_cnt);
+
+       if (item->ri_total <= item->ri_cnt) {
+               xfs_warn(log->l_mp,
+       "log item region count (%d) overflowed size (%d)",
+                               item->ri_cnt, item->ri_total);
+               ASSERT(0);
+               kmem_free(ptr);
+               return -EFSCORRUPTED;
+       }
+
        /* Description region is ri_buf[0] */
        item->ri_buf[item->ri_cnt].i_addr = ptr;
        item->ri_buf[item->ri_cnt].i_len  = len;
@@ -4380,7 +4386,7 @@ xlog_recovery_process_trans(
        default:
                xfs_warn(log->l_mp, "%s: bad flag 0x%x", __func__, flags);
                ASSERT(0);
-               error = -EIO;
+               error = -EFSCORRUPTED;
                break;
        }
        if (error || freeit)
@@ -4460,7 +4466,7 @@ xlog_recover_process_ophdr(
                xfs_warn(log->l_mp, "%s: bad clientid 0x%x",
                        __func__, ohead->oh_clientid);
                ASSERT(0);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 
        /*
@@ -4470,7 +4476,7 @@ xlog_recover_process_ophdr(
        if (dp + len > end) {
                xfs_warn(log->l_mp, "%s: bad length 0x%x", __func__, len);
                WARN_ON(1);
-               return -EIO;
+               return -EFSCORRUPTED;
        }
 
        trans = xlog_recover_ophdr_to_trans(rhash, rhead, ohead);
@@ -5172,8 +5178,10 @@ xlog_recover_process(
                 * If the filesystem is CRC enabled, this mismatch becomes a
                 * fatal log corruption failure.
                 */
-               if (xfs_sb_version_hascrc(&log->l_mp->m_sb))
+               if (xfs_sb_version_hascrc(&log->l_mp->m_sb)) {
+                       XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp);
                        return -EFSCORRUPTED;
+               }
        }
 
        xlog_unpack_data(rhead, dp, log);
@@ -5190,31 +5198,25 @@ xlog_valid_rec_header(
 {
        int                     hlen;
 
-       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);
+       if (XFS_IS_CORRUPT(log->l_mp,
+                          rhead->h_magicno != cpu_to_be32(XLOG_HEADER_MAGIC_NUM)))
                return -EFSCORRUPTED;
-       }
-       if (unlikely(
-           (!rhead->h_version ||
-           (be32_to_cpu(rhead->h_version) & (~XLOG_VERSION_OKBITS))))) {
+       if (XFS_IS_CORRUPT(log->l_mp,
+                          (!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 -EIO;
+               return -EFSCORRUPTED;
        }
 
        /* LR body must have data or it wouldn't have been written */
        hlen = be32_to_cpu(rhead->h_len);
-       if (unlikely( hlen <= 0 || hlen > INT_MAX )) {
-               XFS_ERROR_REPORT("xlog_valid_rec_header(2)",
-                               XFS_ERRLEVEL_LOW, log->l_mp);
+       if (XFS_IS_CORRUPT(log->l_mp, hlen <= 0 || hlen > INT_MAX))
                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);
+       if (XFS_IS_CORRUPT(log->l_mp,
+                          blkno > log->l_logBBsize || blkno > INT_MAX))
                return -EFSCORRUPTED;
-       }
        return 0;
 }
 
@@ -5296,8 +5298,12 @@ xlog_do_recovery_pass(
                "invalid iclog size (%d bytes), using lsunit (%d bytes)",
                                         h_size, log->l_mp->m_logbsize);
                                h_size = log->l_mp->m_logbsize;
-                       } else
-                               return -EFSCORRUPTED;
+                       } else {
+                               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW,
+                                               log->l_mp);
+                               error = -EFSCORRUPTED;
+                               goto bread_err1;
+                       }
                }
 
                if ((be32_to_cpu(rhead->h_version) & XLOG_VERSION_2) &&