aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2013-08-26 00:13:30 -0400
committerBen Myers <bpm@sgi.com>2013-08-30 10:48:59 -0400
commit37804376121de1a25fb582bdd8970f139c4d9685 (patch)
treed475f98cdb8fc0548a7e14f8eb480a58c855a1b3
parent0f0d334595105d982ea22ae1d5947723e462344f (diff)
XFS: Assertion failed: first <= last && last < BBTOB(bp->b_length), file: fs/xfs/xfs_trans_buf.c, line: 568
The calculation doesn't take into account the size of the dir v3 header, so overestimates the hash entries in a node. This causes directory buffer overruns when splitting and merging nodes. Signed-off-by: Dave Chinner <dchinner@redhat.com> Tested-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Mark Tinguely <tinguely@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
-rw-r--r--fs/xfs/xfs_da_btree.h11
-rw-r--r--fs/xfs/xfs_dir2.c16
2 files changed, 19 insertions, 8 deletions
diff --git a/fs/xfs/xfs_da_btree.h b/fs/xfs/xfs_da_btree.h
index 8cdc77b2e58d..b1f267995dea 100644
--- a/fs/xfs/xfs_da_btree.h
+++ b/fs/xfs/xfs_da_btree.h
@@ -133,12 +133,19 @@ extern void xfs_da3_node_hdr_to_disk(struct xfs_da_intnode *to,
133 struct xfs_da3_icnode_hdr *from); 133 struct xfs_da3_icnode_hdr *from);
134 134
135static inline int 135static inline int
136xfs_da3_node_hdr_size(struct xfs_da_intnode *dap) 136__xfs_da3_node_hdr_size(bool v3)
137{ 137{
138 if (dap->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC)) 138 if (v3)
139 return sizeof(struct xfs_da3_node_hdr); 139 return sizeof(struct xfs_da3_node_hdr);
140 return sizeof(struct xfs_da_node_hdr); 140 return sizeof(struct xfs_da_node_hdr);
141} 141}
142static inline int
143xfs_da3_node_hdr_size(struct xfs_da_intnode *dap)
144{
145 bool v3 = dap->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC);
146
147 return __xfs_da3_node_hdr_size(v3);
148}
142 149
143static inline struct xfs_da_node_entry * 150static inline struct xfs_da_node_entry *
144xfs_da3_node_tree_p(struct xfs_da_intnode *dap) 151xfs_da3_node_tree_p(struct xfs_da_intnode *dap)
diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c
index d3ff96c321f9..edf203ab50af 100644
--- a/fs/xfs/xfs_dir2.c
+++ b/fs/xfs/xfs_dir2.c
@@ -90,6 +90,9 @@ void
90xfs_dir_mount( 90xfs_dir_mount(
91 xfs_mount_t *mp) 91 xfs_mount_t *mp)
92{ 92{
93 int nodehdr_size;
94
95
93 ASSERT(xfs_sb_version_hasdirv2(&mp->m_sb)); 96 ASSERT(xfs_sb_version_hasdirv2(&mp->m_sb));
94 ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <= 97 ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <=
95 XFS_MAX_BLOCKSIZE); 98 XFS_MAX_BLOCKSIZE);
@@ -98,12 +101,13 @@ xfs_dir_mount(
98 mp->m_dirdatablk = xfs_dir2_db_to_da(mp, XFS_DIR2_DATA_FIRSTDB(mp)); 101 mp->m_dirdatablk = xfs_dir2_db_to_da(mp, XFS_DIR2_DATA_FIRSTDB(mp));
99 mp->m_dirleafblk = xfs_dir2_db_to_da(mp, XFS_DIR2_LEAF_FIRSTDB(mp)); 102 mp->m_dirleafblk = xfs_dir2_db_to_da(mp, XFS_DIR2_LEAF_FIRSTDB(mp));
100 mp->m_dirfreeblk = xfs_dir2_db_to_da(mp, XFS_DIR2_FREE_FIRSTDB(mp)); 103 mp->m_dirfreeblk = xfs_dir2_db_to_da(mp, XFS_DIR2_FREE_FIRSTDB(mp));
101 mp->m_attr_node_ents = 104
102 (mp->m_sb.sb_blocksize - (uint)sizeof(xfs_da_node_hdr_t)) / 105 nodehdr_size = __xfs_da3_node_hdr_size(xfs_sb_version_hascrc(&mp->m_sb));
103 (uint)sizeof(xfs_da_node_entry_t); 106 mp->m_attr_node_ents = (mp->m_sb.sb_blocksize - nodehdr_size) /
104 mp->m_dir_node_ents = 107 (uint)sizeof(xfs_da_node_entry_t);
105 (mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) / 108 mp->m_dir_node_ents = (mp->m_dirblksize - nodehdr_size) /
106 (uint)sizeof(xfs_da_node_entry_t); 109 (uint)sizeof(xfs_da_node_entry_t);
110
107 mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100; 111 mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100;
108 if (xfs_sb_version_hasasciici(&mp->m_sb)) 112 if (xfs_sb_version_hasasciici(&mp->m_sb))
109 mp->m_dirnameops = &xfs_ascii_ci_nameops; 113 mp->m_dirnameops = &xfs_ascii_ci_nameops;