summaryrefslogtreecommitdiff
path: root/fs/xfs
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2013-04-03 16:11:29 +1100
committerBen Myers <bpm@sgi.com>2013-04-27 13:01:06 -0500
commitd75afeb3d302019527331520a2632b6614425b40 (patch)
tree181dec415cdae00398086764a6229d115114354d /fs/xfs
parentd2e448d5fdebdcda93ed171339a3d864f65c227e (diff)
downloadlinux-stable-d75afeb3d302019527331520a2632b6614425b40.tar.gz
linux-stable-d75afeb3d302019527331520a2632b6614425b40.tar.bz2
linux-stable-d75afeb3d302019527331520a2632b6614425b40.zip
xfs: add buffer types to directory and attribute buffers
Add buffer types to the buffer log items so that log recovery can validate the buffers and calculate CRCs correctly after the buffers are recovered. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Ben Myers <bpm@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_attr_leaf.c9
-rw-r--r--fs/xfs/xfs_attr_remote.h2
-rw-r--r--fs/xfs/xfs_buf_item.h18
-rw-r--r--fs/xfs/xfs_da_btree.c46
-rw-r--r--fs/xfs/xfs_da_btree.h2
-rw-r--r--fs/xfs/xfs_dir2_block.c12
-rw-r--r--fs/xfs/xfs_dir2_data.c8
-rw-r--r--fs/xfs/xfs_dir2_leaf.c26
-rw-r--r--fs/xfs/xfs_dir2_node.c15
-rw-r--r--fs/xfs/xfs_dir2_priv.h2
-rw-r--r--fs/xfs/xfs_log_recover.c254
-rw-r--r--fs/xfs/xfs_trans.h2
-rw-r--r--fs/xfs/xfs_trans_buf.c17
13 files changed, 323 insertions, 90 deletions
diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c
index 287c8089b705..92cda03d1c01 100644
--- a/fs/xfs/xfs_attr_leaf.c
+++ b/fs/xfs/xfs_attr_leaf.c
@@ -271,8 +271,13 @@ xfs_attr3_leaf_read(
xfs_daddr_t mappedbno,
struct xfs_buf **bpp)
{
- return xfs_da_read_buf(tp, dp, bno, mappedbno, bpp,
+ int err;
+
+ err = xfs_da_read_buf(tp, dp, bno, mappedbno, bpp,
XFS_ATTR_FORK, &xfs_attr3_leaf_buf_ops);
+ if (!err && tp)
+ xfs_trans_buf_set_type(tp, *bpp, XFS_BLF_ATTR_LEAF_BUF);
+ return err;
}
/*========================================================================
@@ -1078,6 +1083,7 @@ xfs_attr3_leaf_to_node(
goto out;
/* copy leaf to new buffer, update identifiers */
+ xfs_trans_buf_set_type(args->trans, bp2, XFS_BLF_ATTR_LEAF_BUF);
bp2->b_ops = bp1->b_ops;
memcpy(bp2->b_addr, bp1->b_addr, XFS_LBSIZE(mp));
if (xfs_sb_version_hascrc(&mp->m_sb)) {
@@ -1140,6 +1146,7 @@ xfs_attr3_leaf_create(
if (error)
return error;
bp->b_ops = &xfs_attr3_leaf_buf_ops;
+ xfs_trans_buf_set_type(args->trans, bp, XFS_BLF_ATTR_LEAF_BUF);
leaf = bp->b_addr;
memset(leaf, 0, XFS_LBSIZE(mp));
diff --git a/fs/xfs/xfs_attr_remote.h b/fs/xfs/xfs_attr_remote.h
index 0ca8d9a1fa03..c7cca60a062a 100644
--- a/fs/xfs/xfs_attr_remote.h
+++ b/fs/xfs/xfs_attr_remote.h
@@ -37,6 +37,8 @@ struct xfs_attr3_rmt_hdr {
((bufsize) - (xfs_sb_version_hascrc(&(mp)->m_sb) ? \
sizeof(struct xfs_attr3_rmt_hdr) : 0))
+extern const struct xfs_buf_ops xfs_attr3_rmt_buf_ops;
+
int xfs_attr_rmtval_get(struct xfs_da_args *args);
int xfs_attr_rmtval_set(struct xfs_da_args *args);
int xfs_attr_rmtval_remove(struct xfs_da_args *args);
diff --git a/fs/xfs/xfs_buf_item.h b/fs/xfs/xfs_buf_item.h
index 09cab4ed1065..640adcfa4143 100644
--- a/fs/xfs/xfs_buf_item.h
+++ b/fs/xfs/xfs_buf_item.h
@@ -50,6 +50,14 @@ extern kmem_zone_t *xfs_buf_item_zone;
#define XFS_BLF_AGI_BUF (1<<8)
#define XFS_BLF_DINO_BUF (1<<9)
#define XFS_BLF_SYMLINK_BUF (1<<10)
+#define XFS_BLF_DIR_BLOCK_BUF (1<<11)
+#define XFS_BLF_DIR_DATA_BUF (1<<12)
+#define XFS_BLF_DIR_FREE_BUF (1<<13)
+#define XFS_BLF_DIR_LEAF1_BUF (1<<14)
+#define XFS_BLF_DIR_LEAFN_BUF (1<<15)
+#define XFS_BLF_DA_NODE_BUF (1<<16)
+#define XFS_BLF_ATTR_LEAF_BUF (1<<17)
+#define XFS_BLF_ATTR_RMT_BUF (1<<18)
#define XFS_BLF_TYPE_MASK \
(XFS_BLF_UDQUOT_BUF | \
@@ -60,7 +68,15 @@ extern kmem_zone_t *xfs_buf_item_zone;
XFS_BLF_AGFL_BUF | \
XFS_BLF_AGI_BUF | \
XFS_BLF_DINO_BUF | \
- XFS_BLF_SYMLINK_BUF)
+ XFS_BLF_SYMLINK_BUF | \
+ XFS_BLF_DIR_BLOCK_BUF | \
+ XFS_BLF_DIR_DATA_BUF | \
+ XFS_BLF_DIR_FREE_BUF | \
+ XFS_BLF_DIR_LEAF1_BUF | \
+ XFS_BLF_DIR_LEAFN_BUF | \
+ XFS_BLF_DA_NODE_BUF | \
+ XFS_BLF_ATTR_LEAF_BUF | \
+ XFS_BLF_ATTR_RMT_BUF)
#define XFS_BLF_CHUNK 128
#define XFS_BLF_SHIFT 7
diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c
index 779ecdcdbe02..5aebd9bd44d1 100644
--- a/fs/xfs/xfs_da_btree.c
+++ b/fs/xfs/xfs_da_btree.c
@@ -292,7 +292,6 @@ const struct xfs_buf_ops xfs_da3_node_buf_ops = {
.verify_write = xfs_da3_node_write_verify,
};
-
int
xfs_da3_node_read(
struct xfs_trans *tp,
@@ -302,8 +301,35 @@ xfs_da3_node_read(
struct xfs_buf **bpp,
int which_fork)
{
- return xfs_da_read_buf(tp, dp, bno, mappedbno, bpp,
+ int err;
+
+ err = xfs_da_read_buf(tp, dp, bno, mappedbno, bpp,
which_fork, &xfs_da3_node_buf_ops);
+ if (!err && tp) {
+ struct xfs_da_blkinfo *info = (*bpp)->b_addr;
+ int type;
+
+ switch (be16_to_cpu(info->magic)) {
+ case XFS_DA3_NODE_MAGIC:
+ case XFS_DA_NODE_MAGIC:
+ type = XFS_BLF_DA_NODE_BUF;
+ break;
+ case XFS_ATTR_LEAF_MAGIC:
+ case XFS_ATTR3_LEAF_MAGIC:
+ type = XFS_BLF_ATTR_LEAF_BUF;
+ break;
+ case XFS_DIR2_LEAFN_MAGIC:
+ case XFS_DIR3_LEAFN_MAGIC:
+ type = XFS_BLF_DIR_LEAFN_BUF;
+ break;
+ default:
+ type = 0;
+ ASSERT(0);
+ break;
+ }
+ xfs_trans_buf_set_type(tp, *bpp, type);
+ }
+ return err;
}
/*========================================================================
@@ -334,6 +360,8 @@ xfs_da3_node_create(
error = xfs_da_get_buf(tp, args->dp, blkno, -1, &bp, whichfork);
if (error)
return(error);
+ bp->b_ops = &xfs_da3_node_buf_ops;
+ xfs_trans_buf_set_type(tp, bp, XFS_BLF_DA_NODE_BUF);
node = bp->b_addr;
if (xfs_sb_version_hascrc(&mp->m_sb)) {
@@ -352,7 +380,6 @@ xfs_da3_node_create(
xfs_trans_log_buf(tp, bp,
XFS_DA_LOGRANGE(node, &node->hdr, xfs_da3_node_hdr_size(node)));
- bp->b_ops = &xfs_da3_node_buf_ops;
*bpp = bp;
return(0);
}
@@ -565,6 +592,12 @@ xfs_da3_root_split(
btree = xfs_da3_node_tree_p(oldroot);
size = (int)((char *)&btree[nodehdr.count] - (char *)oldroot);
level = nodehdr.level;
+
+ /*
+ * we are about to copy oldroot to bp, so set up the type
+ * of bp while we know exactly what it will be.
+ */
+ xfs_trans_buf_set_type(tp, bp, XFS_BLF_DA_NODE_BUF);
} else {
struct xfs_dir3_icleaf_hdr leafhdr;
struct xfs_dir2_leaf_entry *ents;
@@ -577,6 +610,12 @@ xfs_da3_root_split(
leafhdr.magic == XFS_DIR3_LEAFN_MAGIC);
size = (int)((char *)&ents[leafhdr.count] - (char *)leaf);
level = 0;
+
+ /*
+ * we are about to copy oldroot to bp, so set up the type
+ * of bp while we know exactly what it will be.
+ */
+ xfs_trans_buf_set_type(tp, bp, XFS_BLF_DIR_LEAFN_BUF);
}
/*
@@ -1092,6 +1131,7 @@ xfs_da3_root_join(
*/
memcpy(root_blk->bp->b_addr, bp->b_addr, state->blocksize);
root_blk->bp->b_ops = bp->b_ops;
+ xfs_trans_buf_copy_type(root_blk->bp, bp);
if (oldroothdr.magic == XFS_DA3_NODE_MAGIC) {
struct xfs_da3_blkinfo *da3 = root_blk->bp->b_addr;
da3->blkno = cpu_to_be64(root_blk->bp->b_bn);
diff --git a/fs/xfs/xfs_da_btree.h b/fs/xfs/xfs_da_btree.h
index 0e8182c5210b..6fb3371c63cf 100644
--- a/fs/xfs/xfs_da_btree.h
+++ b/fs/xfs/xfs_da_btree.h
@@ -301,6 +301,8 @@ int xfs_da3_node_read(struct xfs_trans *tp, struct xfs_inode *dp,
xfs_dablk_t bno, xfs_daddr_t mappedbno,
struct xfs_buf **bpp, int which_fork);
+extern const struct xfs_buf_ops xfs_da3_node_buf_ops;
+
/*
* Utility routines.
*/
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c
index d2e445f92ffb..58816ecdbba5 100644
--- a/fs/xfs/xfs_dir2_block.c
+++ b/fs/xfs/xfs_dir2_block.c
@@ -132,20 +132,26 @@ xfs_dir3_block_read(
struct xfs_buf **bpp)
{
struct xfs_mount *mp = dp->i_mount;
+ int err;
- return xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, bpp,
+ err = xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, bpp,
XFS_DATA_FORK, &xfs_dir3_block_buf_ops);
+ if (!err && tp)
+ xfs_trans_buf_set_type(tp, *bpp, XFS_BLF_DIR_BLOCK_BUF);
+ return err;
}
static void
xfs_dir3_block_init(
struct xfs_mount *mp,
+ struct xfs_trans *tp,
struct xfs_buf *bp,
struct xfs_inode *dp)
{
struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
bp->b_ops = &xfs_dir3_block_buf_ops;
+ xfs_trans_buf_set_type(tp, bp, XFS_BLF_DIR_BLOCK_BUF);
if (xfs_sb_version_hascrc(&mp->m_sb)) {
memset(hdr3, 0, sizeof(*hdr3));
@@ -1080,7 +1086,7 @@ xfs_dir2_leaf_to_block(
/*
* Start converting it to block form.
*/
- xfs_dir3_block_init(mp, dbp, dp);
+ xfs_dir3_block_init(mp, tp, dbp, dp);
needlog = 1;
needscan = 0;
@@ -1209,7 +1215,7 @@ xfs_dir2_sf_to_block(
kmem_free(sfp);
return error;
}
- xfs_dir3_block_init(mp, bp, dp);
+ xfs_dir3_block_init(mp, tp, bp, dp);
hdr = bp->b_addr;
/*
diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c
index 78320df3743f..5e0c711f9af3 100644
--- a/fs/xfs/xfs_dir2_data.c
+++ b/fs/xfs/xfs_dir2_data.c
@@ -301,8 +301,13 @@ xfs_dir3_data_read(
xfs_daddr_t mapped_bno,
struct xfs_buf **bpp)
{
- return xfs_da_read_buf(tp, dp, bno, mapped_bno, bpp,
+ int err;
+
+ err = xfs_da_read_buf(tp, dp, bno, mapped_bno, bpp,
XFS_DATA_FORK, &xfs_dir3_data_buf_ops);
+ if (!err && tp)
+ xfs_trans_buf_set_type(tp, *bpp, XFS_BLF_DIR_DATA_BUF);
+ return err;
}
int
@@ -571,6 +576,7 @@ xfs_dir3_data_init(
if (error)
return error;
bp->b_ops = &xfs_dir3_data_buf_ops;
+ xfs_trans_buf_set_type(tp, bp, XFS_BLF_DIR_DATA_BUF);
/*
* Initialize the header.
diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c
index 7352e41d2aaa..84f4c9cfe95a 100644
--- a/fs/xfs/xfs_dir2_leaf.c
+++ b/fs/xfs/xfs_dir2_leaf.c
@@ -279,7 +279,7 @@ xfs_dir3_leafn_write_verify(
__write_verify(bp, XFS_DIR2_LEAFN_MAGIC);
}
-static const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops = {
+const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops = {
.verify_read = xfs_dir3_leaf1_read_verify,
.verify_write = xfs_dir3_leaf1_write_verify,
};
@@ -297,8 +297,13 @@ xfs_dir3_leaf_read(
xfs_daddr_t mappedbno,
struct xfs_buf **bpp)
{
- return xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp,
+ int err;
+
+ err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp,
XFS_DATA_FORK, &xfs_dir3_leaf1_buf_ops);
+ if (!err && tp)
+ xfs_trans_buf_set_type(tp, *bpp, XFS_BLF_DIR_LEAF1_BUF);
+ return err;
}
int
@@ -309,8 +314,13 @@ xfs_dir3_leafn_read(
xfs_daddr_t mappedbno,
struct xfs_buf **bpp)
{
- return xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp,
+ int err;
+
+ err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp,
XFS_DATA_FORK, &xfs_dir3_leafn_buf_ops);
+ if (!err && tp)
+ xfs_trans_buf_set_type(tp, *bpp, XFS_BLF_DIR_LEAFN_BUF);
+ return err;
}
/*
@@ -319,6 +329,7 @@ xfs_dir3_leafn_read(
static void
xfs_dir3_leaf_init(
struct xfs_mount *mp,
+ struct xfs_trans *tp,
struct xfs_buf *bp,
xfs_ino_t owner,
__uint16_t type)
@@ -353,8 +364,11 @@ xfs_dir3_leaf_init(
ltp = xfs_dir2_leaf_tail_p(mp, leaf);
ltp->bestcount = 0;
bp->b_ops = &xfs_dir3_leaf1_buf_ops;
- } else
+ xfs_trans_buf_set_type(tp, bp, XFS_BLF_DIR_LEAF1_BUF);
+ } else {
bp->b_ops = &xfs_dir3_leafn_buf_ops;
+ xfs_trans_buf_set_type(tp, bp, XFS_BLF_DIR_LEAFN_BUF);
+ }
}
int
@@ -379,7 +393,7 @@ xfs_dir3_leaf_get_buf(
if (error)
return error;
- xfs_dir3_leaf_init(mp, bp, dp->i_ino, magic);
+ xfs_dir3_leaf_init(mp, tp, bp, dp->i_ino, magic);
xfs_dir3_leaf_log_header(tp, bp);
if (magic == XFS_DIR2_LEAF1_MAGIC)
xfs_dir3_leaf_log_tail(tp, bp);
@@ -474,6 +488,7 @@ xfs_dir2_block_to_leaf(
* Fix up the block header, make it a data block.
*/
dbp->b_ops = &xfs_dir3_data_buf_ops;
+ xfs_trans_buf_set_type(tp, dbp, XFS_BLF_DIR_DATA_BUF);
if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC))
hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
else
@@ -2182,6 +2197,7 @@ xfs_dir2_node_to_leaf(
xfs_dir3_leaf_compact(args, &leafhdr, lbp);
lbp->b_ops = &xfs_dir3_leaf1_buf_ops;
+ xfs_trans_buf_set_type(tp, lbp, XFS_BLF_DIR_LEAF1_BUF);
leafhdr.magic = (leafhdr.magic == XFS_DIR2_LEAFN_MAGIC)
? XFS_DIR2_LEAF1_MAGIC
: XFS_DIR3_LEAF1_MAGIC;
diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c
index 122449b33f5e..1806a22d5593 100644
--- a/fs/xfs/xfs_dir2_node.c
+++ b/fs/xfs/xfs_dir2_node.c
@@ -147,7 +147,7 @@ xfs_dir3_free_write_verify(
xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), XFS_DIR3_FREE_CRC_OFF);
}
-static const struct xfs_buf_ops xfs_dir3_free_buf_ops = {
+const struct xfs_buf_ops xfs_dir3_free_buf_ops = {
.verify_read = xfs_dir3_free_read_verify,
.verify_write = xfs_dir3_free_write_verify,
};
@@ -161,8 +161,15 @@ __xfs_dir3_free_read(
xfs_daddr_t mappedbno,
struct xfs_buf **bpp)
{
- return xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp,
+ int err;
+
+ err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp,
XFS_DATA_FORK, &xfs_dir3_free_buf_ops);
+
+ /* try read returns without an error or *bpp if it lands in a hole */
+ if (!err && tp && *bpp)
+ xfs_trans_buf_set_type(tp, *bpp, XFS_BLF_DIR_FREE_BUF);
+ return err;
}
int
@@ -249,6 +256,7 @@ xfs_dir3_free_get_buf(
if (error)
return error;
+ xfs_trans_buf_set_type(tp, bp, XFS_BLF_DIR_FREE_BUF);
bp->b_ops = &xfs_dir3_free_buf_ops;
/*
@@ -396,6 +404,7 @@ xfs_dir2_leaf_to_node(
else
leaf->hdr.info.magic = cpu_to_be16(XFS_DIR3_LEAFN_MAGIC);
lbp->b_ops = &xfs_dir3_leafn_buf_ops;
+ xfs_trans_buf_set_type(tp, lbp, XFS_BLF_DIR_LEAFN_BUF);
xfs_dir3_leaf_log_header(tp, lbp);
xfs_dir3_leaf_check(mp, lbp);
return 0;
@@ -811,6 +820,7 @@ xfs_dir2_leafn_lookup_for_entry(
(char *)curbp->b_addr);
state->extrablk.magic = XFS_DIR2_DATA_MAGIC;
curbp->b_ops = &xfs_dir3_data_buf_ops;
+ xfs_trans_buf_set_type(tp, curbp, XFS_BLF_DIR_DATA_BUF);
if (cmp == XFS_CMP_EXACT)
return XFS_ERROR(EEXIST);
}
@@ -825,6 +835,7 @@ xfs_dir2_leafn_lookup_for_entry(
state->extrablk.blkno = curdb;
state->extrablk.magic = XFS_DIR2_DATA_MAGIC;
curbp->b_ops = &xfs_dir3_data_buf_ops;
+ xfs_trans_buf_set_type(tp, curbp, XFS_BLF_DIR_DATA_BUF);
} else {
/* If the curbp is not the CI match block, drop it */
if (state->extrablk.bp != curbp)
diff --git a/fs/xfs/xfs_dir2_priv.h b/fs/xfs/xfs_dir2_priv.h
index 932565d6ef2a..7cf573c88aad 100644
--- a/fs/xfs/xfs_dir2_priv.h
+++ b/fs/xfs/xfs_dir2_priv.h
@@ -49,6 +49,7 @@ extern int xfs_dir2_leaf_to_block(struct xfs_da_args *args,
#endif
extern const struct xfs_buf_ops xfs_dir3_data_buf_ops;
+extern const struct xfs_buf_ops xfs_dir3_free_buf_ops;
extern int __xfs_dir3_data_check(struct xfs_inode *dp, struct xfs_buf *bp);
extern int xfs_dir3_data_read(struct xfs_trans *tp, struct xfs_inode *dp,
@@ -77,6 +78,7 @@ extern void xfs_dir2_data_use_free(struct xfs_trans *tp, struct xfs_buf *bp,
xfs_dir2_data_aoff_t len, int *needlogp, int *needscanp);
/* xfs_dir2_leaf.c */
+extern const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops;
extern const struct xfs_buf_ops xfs_dir3_leafn_buf_ops;
extern int xfs_dir3_leafn_read(struct xfs_trans *tp, struct xfs_inode *dp,
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index d1292fd1112a..00727bc4a9b0 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -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,19 +1960,169 @@ 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.
*/
int
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 1b04fe59c603..fa78a3f87c6e 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -507,6 +507,8 @@ void xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint);
void xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *);
void xfs_trans_buf_set_type(struct xfs_trans *, struct xfs_buf *,
uint);
+void xfs_trans_buf_copy_type(struct xfs_buf *dst_bp,
+ struct xfs_buf *src_bp);
void xfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int);
void xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint);
void xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint);
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c
index 8a0f6af51206..40871bf607f0 100644
--- a/fs/xfs/xfs_trans_buf.c
+++ b/fs/xfs/xfs_trans_buf.c
@@ -768,6 +768,9 @@ xfs_trans_buf_set_type(
{
struct xfs_buf_log_item *bip = bp->b_fspriv;
+ if (!tp)
+ return;
+
ASSERT(bp->b_transp == tp);
ASSERT(bip != NULL);
ASSERT(atomic_read(&bip->bli_refcount) > 0);
@@ -777,6 +780,20 @@ xfs_trans_buf_set_type(
bip->__bli_format.blf_flags |= type;
}
+void
+xfs_trans_buf_copy_type(
+ struct xfs_buf *dst_bp,
+ struct xfs_buf *src_bp)
+{
+ struct xfs_buf_log_item *sbip = src_bp->b_fspriv;
+ struct xfs_buf_log_item *dbip = dst_bp->b_fspriv;
+ uint type;
+
+ type = sbip->__bli_format.blf_flags & XFS_BLF_TYPE_MASK;
+ dbip->__bli_format.blf_flags &= ~XFS_BLF_TYPE_MASK;
+ dbip->__bli_format.blf_flags |= type;
+}
+
/*
* Similar to xfs_trans_inode_buf(), this marks the buffer as a cluster of
* dquots. However, unlike in inode buffer recovery, dquot buffers get