Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 61fe135c authored by Dave Chinner's avatar Dave Chinner Committed by Ben Myers
Browse files

xfs: buffer type overruns blf_flags field



The buffer type passed to log recvoery in the buffer log item
overruns the blf_flags field. I had assumed that flags field was a
32 bit value, and it turns out it is a unisgned short. Therefore
having 19 flags doesn't really work.

Convert the buffer type field to numeric value, and use the top 5
bits of the flags field for it. We currently have 17 types of
buffers, so using 5 bits gives us plenty of room for expansion in
future....

Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarBen Myers <bpm@sgi.com>
Signed-off-by: default avatarBen Myers <bpm@sgi.com>
parent d75afeb3
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -2099,7 +2099,7 @@ xfs_alloc_log_agf(

	trace_xfs_agf(tp->t_mountp, XFS_BUF_TO_AGF(bp), fields, _RET_IP_);

	xfs_trans_buf_set_type(tp, bp, XFS_BLF_AGF_BUF);
	xfs_trans_buf_set_type(tp, bp, XFS_BLFT_AGF_BUF);

	xfs_btree_offsets(fields, offsets, XFS_AGF_NUM_BITS, &first, &last);
	xfs_trans_log_buf(tp, bp, (uint)first, (uint)last);
@@ -2179,7 +2179,7 @@ xfs_alloc_put_freelist(

	xfs_alloc_log_agf(tp, agbp, logflags);

	xfs_trans_buf_set_type(tp, agflbp, XFS_BLF_AGFL_BUF);
	xfs_trans_buf_set_type(tp, agflbp, XFS_BLFT_AGFL_BUF);
	xfs_trans_log_buf(tp, agflbp, startoff,
			  startoff + sizeof(xfs_agblock_t) - 1);
	return 0;
+3 −3
Original line number Diff line number Diff line
@@ -276,7 +276,7 @@ xfs_attr3_leaf_read(
	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);
		xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_ATTR_LEAF_BUF);
	return err;
}

@@ -1083,7 +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);
	xfs_trans_buf_set_type(args->trans, bp2, XFS_BLFT_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)) {
@@ -1146,7 +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);
	xfs_trans_buf_set_type(args->trans, bp, XFS_BLFT_ATTR_LEAF_BUF);
	leaf = bp->b_addr;
	memset(leaf, 0, XFS_LBSIZE(mp));

+1 −1
Original line number Diff line number Diff line
@@ -1338,7 +1338,7 @@ xfs_bmap_local_to_extents_init_fn(
	ASSERT(0);
	bp->b_ops = &xfs_bmbt_buf_ops;
	memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
	xfs_trans_buf_set_type(tp, bp, XFS_BLF_BTREE_BUF);
	xfs_trans_buf_set_type(tp, bp, XFS_BLFT_BTREE_BUF);
}

/*
+4 −4
Original line number Diff line number Diff line
@@ -1282,7 +1282,7 @@ xfs_btree_log_keys(
	XFS_BTREE_TRACE_ARGBII(cur, bp, first, last);

	if (bp) {
		xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLF_BTREE_BUF);
		xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF);
		xfs_trans_log_buf(cur->bc_tp, bp,
				  xfs_btree_key_offset(cur, first),
				  xfs_btree_key_offset(cur, last + 1) - 1);
@@ -1307,7 +1307,7 @@ xfs_btree_log_recs(
	XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
	XFS_BTREE_TRACE_ARGBII(cur, bp, first, last);

	xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLF_BTREE_BUF);
	xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF);
	xfs_trans_log_buf(cur->bc_tp, bp,
			  xfs_btree_rec_offset(cur, first),
			  xfs_btree_rec_offset(cur, last + 1) - 1);
@@ -1332,7 +1332,7 @@ xfs_btree_log_ptrs(
		struct xfs_btree_block	*block = XFS_BUF_TO_BLOCK(bp);
		int			level = xfs_btree_get_level(block);

		xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLF_BTREE_BUF);
		xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF);
		xfs_trans_log_buf(cur->bc_tp, bp,
				xfs_btree_ptr_offset(cur, first, level),
				xfs_btree_ptr_offset(cur, last + 1, level) - 1);
@@ -1407,7 +1407,7 @@ xfs_btree_log_block(
				  (cur->bc_flags & XFS_BTREE_LONG_PTRS) ?
					loffsets : soffsets,
				  nbits, &first, &last);
		xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLF_BTREE_BUF);
		xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF);
		xfs_trans_log_buf(cur->bc_tp, bp, first, last);
	} else {
		xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip,
+53 −39
Original line number Diff line number Diff line
@@ -39,45 +39,6 @@ extern kmem_zone_t *xfs_buf_item_zone;
#define XFS_BLF_PDQUOT_BUF	(1<<3)
#define	XFS_BLF_GDQUOT_BUF	(1<<4)

/*
 * all buffers now need flags to tell recovery where the magic number
 * is so that it can verify and calculate the CRCs on the buffer correctly
 * once the changes have been replayed into the buffer.
 */
#define XFS_BLF_BTREE_BUF	(1<<5)
#define XFS_BLF_AGF_BUF		(1<<6)
#define XFS_BLF_AGFL_BUF	(1<<7)
#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 | \
		 XFS_BLF_PDQUOT_BUF | \
		 XFS_BLF_GDQUOT_BUF | \
		 XFS_BLF_BTREE_BUF | \
		 XFS_BLF_AGF_BUF | \
		 XFS_BLF_AGFL_BUF | \
		 XFS_BLF_AGI_BUF | \
		 XFS_BLF_DINO_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
#define	BIT_TO_WORD_SHIFT	5
@@ -100,6 +61,55 @@ typedef struct xfs_buf_log_format {
	unsigned int	blf_data_map[XFS_BLF_DATAMAP_SIZE]; /* dirty bitmap */
} xfs_buf_log_format_t;

/*
 * All buffers now need to tell recovery where the magic number
 * is so that it can verify and calculate the CRCs on the buffer correctly
 * once the changes have been replayed into the buffer.
 *
 * The type value is held in the upper 5 bits of the blf_flags field, which is
 * an unsigned 16 bit field. Hence we need to shift it 11 bits up and down.
 */
#define XFS_BLFT_BITS	5
#define XFS_BLFT_SHIFT	11
#define XFS_BLFT_MASK	(((1 << XFS_BLFT_BITS) - 1) << XFS_BLFT_SHIFT)

enum xfs_blft {
	XFS_BLFT_UNKNOWN_BUF = 0,
	XFS_BLFT_UDQUOT_BUF,
	XFS_BLFT_PDQUOT_BUF,
	XFS_BLFT_GDQUOT_BUF,
	XFS_BLFT_BTREE_BUF,
	XFS_BLFT_AGF_BUF,
	XFS_BLFT_AGFL_BUF,
	XFS_BLFT_AGI_BUF,
	XFS_BLFT_DINO_BUF,
	XFS_BLFT_SYMLINK_BUF,
	XFS_BLFT_DIR_BLOCK_BUF,
	XFS_BLFT_DIR_DATA_BUF,
	XFS_BLFT_DIR_FREE_BUF,
	XFS_BLFT_DIR_LEAF1_BUF,
	XFS_BLFT_DIR_LEAFN_BUF,
	XFS_BLFT_DA_NODE_BUF,
	XFS_BLFT_ATTR_LEAF_BUF,
	XFS_BLFT_ATTR_RMT_BUF,
	XFS_BLFT_SB_BUF,
	XFS_BLFT_MAX_BUF = (1 << XFS_BLFT_BITS),
};

static inline void
xfs_blft_to_flags(struct xfs_buf_log_format *blf, enum xfs_blft type)
{
	ASSERT(type > XFS_BLFT_UNKNOWN_BUF && type < XFS_BLFT_MAX_BUF);
	blf->blf_flags &= ~XFS_BLFT_MASK;
	blf->blf_flags |= ((type << XFS_BLFT_SHIFT) & XFS_BLFT_MASK);
}

static inline __uint16_t
xfs_blft_from_flags(struct xfs_buf_log_format *blf)
{
	return (blf->blf_flags & XFS_BLFT_MASK) >> XFS_BLFT_SHIFT;
}

/*
 * buf log item flags
 */
@@ -153,6 +163,10 @@ void xfs_buf_attach_iodone(struct xfs_buf *,
void	xfs_buf_iodone_callbacks(struct xfs_buf *);
void	xfs_buf_iodone(struct xfs_buf *, struct xfs_log_item *);

void	xfs_trans_buf_set_type(struct xfs_trans *, struct xfs_buf *,
			       enum xfs_blft);
void	xfs_trans_buf_copy_type(struct xfs_buf *dst_bp, struct xfs_buf *src_bp);

#endif	/* __KERNEL__ */

#endif	/* __XFS_BUF_ITEM_H__ */
Loading