|
@@ -45,7 +45,14 @@
|
|
|
#include "xfs_cksum.h"
|
|
|
#include "xfs_trace.h"
|
|
|
#include "xfs_icache.h"
|
|
|
+
|
|
|
+/* Need all the magic numbers and buffer ops structures from these headers */
|
|
|
#include "xfs_symlink.h"
|
|
|
+#include "xfs_da_btree.h"
|
|
|
+#include "xfs_dir2_format.h"
|
|
|
+#include "xfs_dir2_priv.h"
|
|
|
+#include "xfs_attr_leaf.h"
|
|
|
+#include "xfs_attr_remote.h"
|
|
|
|
|
|
STATIC int
|
|
|
xlog_find_zeroed(
|
|
@@ -1860,81 +1867,30 @@ xlog_recover_do_inode_buffer(
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Perform a 'normal' buffer recovery. Each logged region of the
|
|
|
- * buffer should be copied over the corresponding region in the
|
|
|
- * given buffer. The bitmap in the buf log format structure indicates
|
|
|
- * where to place the logged data.
|
|
|
+ * Validate the recovered buffer is of the correct type and attach the
|
|
|
+ * appropriate buffer operations to them for writeback. Magic numbers are in a
|
|
|
+ * few places:
|
|
|
+ * the first 16 bits of the buffer (inode buffer, dquot buffer),
|
|
|
+ * the first 32 bits of the buffer (most blocks),
|
|
|
+ * inside a struct xfs_da_blkinfo at the start of the buffer.
|
|
|
*/
|
|
|
-STATIC void
|
|
|
-xlog_recover_do_reg_buffer(
|
|
|
+static void
|
|
|
+xlog_recovery_validate_buf_type(
|
|
|
struct xfs_mount *mp,
|
|
|
- xlog_recover_item_t *item,
|
|
|
struct xfs_buf *bp,
|
|
|
xfs_buf_log_format_t *buf_f)
|
|
|
{
|
|
|
- int i;
|
|
|
- int bit;
|
|
|
- int nbits;
|
|
|
- int error;
|
|
|
-
|
|
|
- trace_xfs_log_recover_buf_reg_buf(mp->m_log, buf_f);
|
|
|
-
|
|
|
- bit = 0;
|
|
|
- i = 1; /* 0 is the buf format structure */
|
|
|
- while (1) {
|
|
|
- bit = xfs_next_bit(buf_f->blf_data_map,
|
|
|
- buf_f->blf_map_size, bit);
|
|
|
- if (bit == -1)
|
|
|
- break;
|
|
|
- nbits = xfs_contig_bits(buf_f->blf_data_map,
|
|
|
- buf_f->blf_map_size, bit);
|
|
|
- ASSERT(nbits > 0);
|
|
|
- ASSERT(item->ri_buf[i].i_addr != NULL);
|
|
|
- ASSERT(item->ri_buf[i].i_len % XFS_BLF_CHUNK == 0);
|
|
|
- ASSERT(BBTOB(bp->b_io_length) >=
|
|
|
- ((uint)bit << XFS_BLF_SHIFT) + (nbits << XFS_BLF_SHIFT));
|
|
|
-
|
|
|
- /*
|
|
|
- * Do a sanity check if this is a dquot buffer. Just checking
|
|
|
- * the first dquot in the buffer should do. XXXThis is
|
|
|
- * probably a good thing to do for other buf types also.
|
|
|
- */
|
|
|
- error = 0;
|
|
|
- if (buf_f->blf_flags &
|
|
|
- (XFS_BLF_UDQUOT_BUF|XFS_BLF_PDQUOT_BUF|XFS_BLF_GDQUOT_BUF)) {
|
|
|
- if (item->ri_buf[i].i_addr == NULL) {
|
|
|
- xfs_alert(mp,
|
|
|
- "XFS: NULL dquot in %s.", __func__);
|
|
|
- goto next;
|
|
|
- }
|
|
|
- if (item->ri_buf[i].i_len < sizeof(xfs_disk_dquot_t)) {
|
|
|
- xfs_alert(mp,
|
|
|
- "XFS: dquot too small (%d) in %s.",
|
|
|
- item->ri_buf[i].i_len, __func__);
|
|
|
- goto next;
|
|
|
- }
|
|
|
- error = xfs_qm_dqcheck(mp, item->ri_buf[i].i_addr,
|
|
|
- -1, 0, XFS_QMOPT_DOWARN,
|
|
|
- "dquot_buf_recover");
|
|
|
- if (error)
|
|
|
- goto next;
|
|
|
- }
|
|
|
-
|
|
|
- memcpy(xfs_buf_offset(bp,
|
|
|
- (uint)bit << XFS_BLF_SHIFT), /* dest */
|
|
|
- item->ri_buf[i].i_addr, /* source */
|
|
|
- nbits<<XFS_BLF_SHIFT); /* length */
|
|
|
- next:
|
|
|
- i++;
|
|
|
- bit += nbits;
|
|
|
- }
|
|
|
-
|
|
|
- /* Shouldn't be any more regions */
|
|
|
- ASSERT(i == item->ri_total);
|
|
|
-
|
|
|
+ struct xfs_da_blkinfo *info = bp->b_addr;
|
|
|
+ __uint32_t magic32;
|
|
|
+ __uint16_t magic16;
|
|
|
+ __uint16_t magicda;
|
|
|
+
|
|
|
+ magic32 = be32_to_cpu(*(__be32 *)bp->b_addr);
|
|
|
+ magic16 = be16_to_cpu(*(__be16*)bp->b_addr);
|
|
|
+ magicda = be16_to_cpu(info->magic);
|
|
|
switch (buf_f->blf_flags & XFS_BLF_TYPE_MASK) {
|
|
|
case XFS_BLF_BTREE_BUF:
|
|
|
- switch (be32_to_cpu(*(__be32 *)bp->b_addr)) {
|
|
|
+ switch (magic32) {
|
|
|
case XFS_ABTB_CRC_MAGIC:
|
|
|
case XFS_ABTC_CRC_MAGIC:
|
|
|
case XFS_ABTB_MAGIC:
|
|
@@ -1956,7 +1912,7 @@ xlog_recover_do_reg_buffer(
|
|
|
}
|
|
|
break;
|
|
|
case XFS_BLF_AGF_BUF:
|
|
|
- if (*(__be32 *)bp->b_addr != cpu_to_be32(XFS_AGF_MAGIC)) {
|
|
|
+ if (magic32 != XFS_AGF_MAGIC) {
|
|
|
xfs_warn(mp, "Bad AGF block magic!");
|
|
|
ASSERT(0);
|
|
|
break;
|
|
@@ -1966,7 +1922,7 @@ xlog_recover_do_reg_buffer(
|
|
|
case XFS_BLF_AGFL_BUF:
|
|
|
if (!xfs_sb_version_hascrc(&mp->m_sb))
|
|
|
break;
|
|
|
- if (*(__be32 *)bp->b_addr != cpu_to_be32(XFS_AGFL_MAGIC)) {
|
|
|
+ if (magic32 != XFS_AGFL_MAGIC) {
|
|
|
xfs_warn(mp, "Bad AGFL block magic!");
|
|
|
ASSERT(0);
|
|
|
break;
|
|
@@ -1974,7 +1930,7 @@ xlog_recover_do_reg_buffer(
|
|
|
bp->b_ops = &xfs_agfl_buf_ops;
|
|
|
break;
|
|
|
case XFS_BLF_AGI_BUF:
|
|
|
- if (*(__be32 *)bp->b_addr != cpu_to_be32(XFS_AGI_MAGIC)) {
|
|
|
+ if (magic32 != XFS_AGI_MAGIC) {
|
|
|
xfs_warn(mp, "Bad AGI block magic!");
|
|
|
ASSERT(0);
|
|
|
break;
|
|
@@ -1984,7 +1940,7 @@ xlog_recover_do_reg_buffer(
|
|
|
case XFS_BLF_UDQUOT_BUF:
|
|
|
case XFS_BLF_PDQUOT_BUF:
|
|
|
case XFS_BLF_GDQUOT_BUF:
|
|
|
- if (*(__be16 *)bp->b_addr != cpu_to_be16(XFS_DQUOT_MAGIC)) {
|
|
|
+ if (magic16 != XFS_DQUOT_MAGIC) {
|
|
|
xfs_warn(mp, "Bad DQUOT block magic!");
|
|
|
ASSERT(0);
|
|
|
break;
|
|
@@ -1996,7 +1952,7 @@ xlog_recover_do_reg_buffer(
|
|
|
* we get here with inode allocation buffers, not buffers that
|
|
|
* track unlinked list changes.
|
|
|
*/
|
|
|
- if (*(__be16 *)bp->b_addr != cpu_to_be16(XFS_DINODE_MAGIC)) {
|
|
|
+ if (magic16 != XFS_DINODE_MAGIC) {
|
|
|
xfs_warn(mp, "Bad INODE block magic!");
|
|
|
ASSERT(0);
|
|
|
break;
|
|
@@ -2004,18 +1960,168 @@ xlog_recover_do_reg_buffer(
|
|
|
bp->b_ops = &xfs_inode_buf_ops;
|
|
|
break;
|
|
|
case XFS_BLF_SYMLINK_BUF:
|
|
|
- if (*(__be32 *)bp->b_addr != cpu_to_be32(XFS_SYMLINK_MAGIC)) {
|
|
|
+ if (magic32 != XFS_SYMLINK_MAGIC) {
|
|
|
xfs_warn(mp, "Bad symlink block magic!");
|
|
|
ASSERT(0);
|
|
|
break;
|
|
|
}
|
|
|
bp->b_ops = &xfs_symlink_buf_ops;
|
|
|
break;
|
|
|
+ case XFS_BLF_DIR_BLOCK_BUF:
|
|
|
+ if (magic32 != XFS_DIR2_BLOCK_MAGIC &&
|
|
|
+ magic32 != XFS_DIR3_BLOCK_MAGIC) {
|
|
|
+ xfs_warn(mp, "Bad dir block magic!");
|
|
|
+ ASSERT(0);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ bp->b_ops = &xfs_dir3_block_buf_ops;
|
|
|
+ break;
|
|
|
+ case XFS_BLF_DIR_DATA_BUF:
|
|
|
+ if (magic32 != XFS_DIR2_DATA_MAGIC &&
|
|
|
+ magic32 != XFS_DIR3_DATA_MAGIC) {
|
|
|
+ xfs_warn(mp, "Bad dir data magic!");
|
|
|
+ ASSERT(0);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ bp->b_ops = &xfs_dir3_data_buf_ops;
|
|
|
+ break;
|
|
|
+ case XFS_BLF_DIR_FREE_BUF:
|
|
|
+ if (magic32 != XFS_DIR2_FREE_MAGIC &&
|
|
|
+ magic32 != XFS_DIR3_FREE_MAGIC) {
|
|
|
+ xfs_warn(mp, "Bad dir3 free magic!");
|
|
|
+ ASSERT(0);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ bp->b_ops = &xfs_dir3_free_buf_ops;
|
|
|
+ break;
|
|
|
+ case XFS_BLF_DIR_LEAF1_BUF:
|
|
|
+ if (magicda != XFS_DIR2_LEAF1_MAGIC &&
|
|
|
+ magicda != XFS_DIR3_LEAF1_MAGIC) {
|
|
|
+ xfs_warn(mp, "Bad dir leaf1 magic!");
|
|
|
+ ASSERT(0);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ bp->b_ops = &xfs_dir3_leaf1_buf_ops;
|
|
|
+ break;
|
|
|
+ case XFS_BLF_DIR_LEAFN_BUF:
|
|
|
+ if (magicda != XFS_DIR2_LEAFN_MAGIC &&
|
|
|
+ magicda != XFS_DIR3_LEAFN_MAGIC) {
|
|
|
+ xfs_warn(mp, "Bad dir leafn magic!");
|
|
|
+ ASSERT(0);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ bp->b_ops = &xfs_dir3_leafn_buf_ops;
|
|
|
+ break;
|
|
|
+ case XFS_BLF_DA_NODE_BUF:
|
|
|
+ if (magicda != XFS_DA_NODE_MAGIC &&
|
|
|
+ magicda != XFS_DA3_NODE_MAGIC) {
|
|
|
+ xfs_warn(mp, "Bad da node magic!");
|
|
|
+ ASSERT(0);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ bp->b_ops = &xfs_da3_node_buf_ops;
|
|
|
+ break;
|
|
|
+ case XFS_BLF_ATTR_LEAF_BUF:
|
|
|
+ if (magicda != XFS_ATTR_LEAF_MAGIC &&
|
|
|
+ magicda != XFS_ATTR3_LEAF_MAGIC) {
|
|
|
+ xfs_warn(mp, "Bad attr leaf magic!");
|
|
|
+ ASSERT(0);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ bp->b_ops = &xfs_attr3_leaf_buf_ops;
|
|
|
+ break;
|
|
|
+ case XFS_BLF_ATTR_RMT_BUF:
|
|
|
+ if (!xfs_sb_version_hascrc(&mp->m_sb))
|
|
|
+ break;
|
|
|
+ if (magicda != XFS_ATTR3_RMT_MAGIC) {
|
|
|
+ xfs_warn(mp, "Bad attr remote magic!");
|
|
|
+ ASSERT(0);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ bp->b_ops = &xfs_attr3_rmt_buf_ops;
|
|
|
+ break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Perform a 'normal' buffer recovery. Each logged region of the
|
|
|
+ * buffer should be copied over the corresponding region in the
|
|
|
+ * given buffer. The bitmap in the buf log format structure indicates
|
|
|
+ * where to place the logged data.
|
|
|
+ */
|
|
|
+STATIC void
|
|
|
+xlog_recover_do_reg_buffer(
|
|
|
+ struct xfs_mount *mp,
|
|
|
+ xlog_recover_item_t *item,
|
|
|
+ struct xfs_buf *bp,
|
|
|
+ xfs_buf_log_format_t *buf_f)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ int bit;
|
|
|
+ int nbits;
|
|
|
+ int error;
|
|
|
+
|
|
|
+ trace_xfs_log_recover_buf_reg_buf(mp->m_log, buf_f);
|
|
|
+
|
|
|
+ bit = 0;
|
|
|
+ i = 1; /* 0 is the buf format structure */
|
|
|
+ while (1) {
|
|
|
+ bit = xfs_next_bit(buf_f->blf_data_map,
|
|
|
+ buf_f->blf_map_size, bit);
|
|
|
+ if (bit == -1)
|
|
|
+ break;
|
|
|
+ nbits = xfs_contig_bits(buf_f->blf_data_map,
|
|
|
+ buf_f->blf_map_size, bit);
|
|
|
+ ASSERT(nbits > 0);
|
|
|
+ ASSERT(item->ri_buf[i].i_addr != NULL);
|
|
|
+ ASSERT(item->ri_buf[i].i_len % XFS_BLF_CHUNK == 0);
|
|
|
+ ASSERT(BBTOB(bp->b_io_length) >=
|
|
|
+ ((uint)bit << XFS_BLF_SHIFT) + (nbits << XFS_BLF_SHIFT));
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Do a sanity check if this is a dquot buffer. Just checking
|
|
|
+ * the first dquot in the buffer should do. XXXThis is
|
|
|
+ * probably a good thing to do for other buf types also.
|
|
|
+ */
|
|
|
+ error = 0;
|
|
|
+ if (buf_f->blf_flags &
|
|
|
+ (XFS_BLF_UDQUOT_BUF|XFS_BLF_PDQUOT_BUF|XFS_BLF_GDQUOT_BUF)) {
|
|
|
+ if (item->ri_buf[i].i_addr == NULL) {
|
|
|
+ xfs_alert(mp,
|
|
|
+ "XFS: NULL dquot in %s.", __func__);
|
|
|
+ goto next;
|
|
|
+ }
|
|
|
+ if (item->ri_buf[i].i_len < sizeof(xfs_disk_dquot_t)) {
|
|
|
+ xfs_alert(mp,
|
|
|
+ "XFS: dquot too small (%d) in %s.",
|
|
|
+ item->ri_buf[i].i_len, __func__);
|
|
|
+ goto next;
|
|
|
+ }
|
|
|
+ error = xfs_qm_dqcheck(mp, item->ri_buf[i].i_addr,
|
|
|
+ -1, 0, XFS_QMOPT_DOWARN,
|
|
|
+ "dquot_buf_recover");
|
|
|
+ if (error)
|
|
|
+ goto next;
|
|
|
+ }
|
|
|
+
|
|
|
+ memcpy(xfs_buf_offset(bp,
|
|
|
+ (uint)bit << XFS_BLF_SHIFT), /* dest */
|
|
|
+ item->ri_buf[i].i_addr, /* source */
|
|
|
+ nbits<<XFS_BLF_SHIFT); /* length */
|
|
|
+ next:
|
|
|
+ i++;
|
|
|
+ bit += nbits;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Shouldn't be any more regions */
|
|
|
+ ASSERT(i == item->ri_total);
|
|
|
+
|
|
|
+ xlog_recovery_validate_buf_type(mp, bp, buf_f);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Do some primitive error checking on ondisk dquot data structures.
|
|
|
*/
|