xfs: use discontiguous xfs_buf support in dabuf wrappers

First step in converting the directory code to use native
discontiguous buffers and replacing the dabuf construct.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Ben Myers <bpm@sgi.com>
This commit is contained in:
Dave Chinner 2012-06-22 18:50:13 +10:00 committed by Ben Myers
parent 372cc85ec6
commit 3605431fb9
2 changed files with 238 additions and 304 deletions

View File

@ -85,7 +85,7 @@ STATIC void xfs_da_node_unbalance(xfs_da_state_t *state,
*/ */
STATIC uint xfs_da_node_lasthash(xfs_dabuf_t *bp, int *count); STATIC uint xfs_da_node_lasthash(xfs_dabuf_t *bp, int *count);
STATIC int xfs_da_node_order(xfs_dabuf_t *node1_bp, xfs_dabuf_t *node2_bp); STATIC int xfs_da_node_order(xfs_dabuf_t *node1_bp, xfs_dabuf_t *node2_bp);
STATIC xfs_dabuf_t *xfs_da_buf_make(int nbuf, xfs_buf_t **bps); STATIC xfs_dabuf_t *xfs_da_buf_make(xfs_buf_t *bp);
STATIC int xfs_da_blk_unlink(xfs_da_state_t *state, STATIC int xfs_da_blk_unlink(xfs_da_state_t *state,
xfs_da_state_blk_t *drop_blk, xfs_da_state_blk_t *drop_blk,
xfs_da_state_blk_t *save_blk); xfs_da_state_blk_t *save_blk);
@ -1967,35 +1967,75 @@ xfs_da_map_covers_blocks(
} }
/* /*
* Make a dabuf. * Convert a struct xfs_bmbt_irec to a struct xfs_buf_map.
* Used for get_buf, read_buf, read_bufr, and reada_buf. *
* For the single map case, it is assumed that the caller has provided a pointer
* to a valid xfs_buf_map. For the multiple map case, this function will
* allocate the xfs_buf_map to hold all the maps and replace the caller's single
* map pointer with the allocated map.
*/ */
STATIC int static int
xfs_da_do_buf( xfs_buf_map_from_irec(
xfs_trans_t *trans, struct xfs_mount *mp,
xfs_inode_t *dp, struct xfs_buf_map **mapp,
xfs_dablk_t bno, unsigned int *nmaps,
xfs_daddr_t *mappedbnop, struct xfs_bmbt_irec *irecs,
xfs_dabuf_t **bpp, unsigned int nirecs)
int whichfork,
int caller)
{ {
xfs_buf_t *bp = NULL; struct xfs_buf_map *map;
xfs_buf_t **bplist; int i;
int error=0;
int i; ASSERT(*nmaps == 1);
xfs_bmbt_irec_t map; ASSERT(nirecs >= 1);
xfs_bmbt_irec_t *mapp;
xfs_daddr_t mappedbno; if (nirecs > 1) {
xfs_mount_t *mp; map = kmem_zalloc(nirecs * sizeof(struct xfs_buf_map), KM_SLEEP);
int nbplist=0; if (!map)
int nfsb; return ENOMEM;
int nmap; *mapp = map;
xfs_dabuf_t *rbp; }
*nmaps = nirecs;
map = *mapp;
for (i = 0; i < *nmaps; i++) {
ASSERT(irecs[i].br_startblock != DELAYSTARTBLOCK &&
irecs[i].br_startblock != HOLESTARTBLOCK);
map[i].bm_bn = XFS_FSB_TO_DADDR(mp, irecs[i].br_startblock);
map[i].bm_len = XFS_FSB_TO_BB(mp, irecs[i].br_blockcount);
}
return 0;
}
/*
* Map the block we are given ready for reading. There are three possible return
* values:
* -1 - will be returned if we land in a hole and mappedbno == -2 so the
* caller knows not to execute a subsequent read.
* 0 - if we mapped the block successfully
* >0 - positive error number if there was an error.
*/
static int
xfs_dabuf_map(
struct xfs_trans *trans,
struct xfs_inode *dp,
xfs_dablk_t bno,
xfs_daddr_t mappedbno,
int whichfork,
struct xfs_buf_map **map,
int *nmaps)
{
struct xfs_mount *mp = dp->i_mount;
int nfsb;
int error = 0;
struct xfs_bmbt_irec irec;
struct xfs_bmbt_irec *irecs = &irec;
int nirecs;
ASSERT(map && *map);
ASSERT(*nmaps == 1);
mp = dp->i_mount;
nfsb = (whichfork == XFS_DATA_FORK) ? mp->m_dirblkfsbs : 1; nfsb = (whichfork == XFS_DATA_FORK) ? mp->m_dirblkfsbs : 1;
mappedbno = *mappedbnop;
/* /*
* Caller doesn't have a mapping. -2 means don't complain * Caller doesn't have a mapping. -2 means don't complain
* if we land in a hole. * if we land in a hole.
@ -2004,112 +2044,152 @@ xfs_da_do_buf(
/* /*
* Optimize the one-block case. * Optimize the one-block case.
*/ */
if (nfsb == 1) if (nfsb != 1)
mapp = &map; irecs = kmem_zalloc(sizeof(irec) * nfsb, KM_SLEEP);
else
mapp = kmem_alloc(sizeof(*mapp) * nfsb, KM_SLEEP);
nmap = nfsb; nirecs = nfsb;
error = xfs_bmapi_read(dp, (xfs_fileoff_t)bno, nfsb, mapp, error = xfs_bmapi_read(dp, (xfs_fileoff_t)bno, nfsb, irecs,
&nmap, xfs_bmapi_aflag(whichfork)); &nirecs, xfs_bmapi_aflag(whichfork));
if (error) if (error)
goto exit0; goto out;
} else { } else {
map.br_startblock = XFS_DADDR_TO_FSB(mp, mappedbno); irecs->br_startblock = XFS_DADDR_TO_FSB(mp, mappedbno);
map.br_startoff = (xfs_fileoff_t)bno; irecs->br_startoff = (xfs_fileoff_t)bno;
map.br_blockcount = nfsb; irecs->br_blockcount = nfsb;
mapp = &map; irecs->br_state = 0;
nmap = 1; nirecs = 1;
} }
if (!xfs_da_map_covers_blocks(nmap, mapp, bno, nfsb)) {
error = mappedbno == -2 ? 0 : XFS_ERROR(EFSCORRUPTED); if (!xfs_da_map_covers_blocks(nirecs, irecs, bno, nfsb)) {
error = mappedbno == -2 ? -1 : XFS_ERROR(EFSCORRUPTED);
if (unlikely(error == EFSCORRUPTED)) { if (unlikely(error == EFSCORRUPTED)) {
if (xfs_error_level >= XFS_ERRLEVEL_LOW) { if (xfs_error_level >= XFS_ERRLEVEL_LOW) {
int i;
xfs_alert(mp, "%s: bno %lld dir: inode %lld", xfs_alert(mp, "%s: bno %lld dir: inode %lld",
__func__, (long long)bno, __func__, (long long)bno,
(long long)dp->i_ino); (long long)dp->i_ino);
for (i = 0; i < nmap; i++) { for (i = 0; i < *nmaps; i++) {
xfs_alert(mp, xfs_alert(mp,
"[%02d] br_startoff %lld br_startblock %lld br_blockcount %lld br_state %d", "[%02d] br_startoff %lld br_startblock %lld br_blockcount %lld br_state %d",
i, i,
(long long)mapp[i].br_startoff, (long long)irecs[i].br_startoff,
(long long)mapp[i].br_startblock, (long long)irecs[i].br_startblock,
(long long)mapp[i].br_blockcount, (long long)irecs[i].br_blockcount,
mapp[i].br_state); irecs[i].br_state);
} }
} }
XFS_ERROR_REPORT("xfs_da_do_buf(1)", XFS_ERROR_REPORT("xfs_da_do_buf(1)",
XFS_ERRLEVEL_LOW, mp); XFS_ERRLEVEL_LOW, mp);
} }
goto exit0; goto out;
} }
if (caller != 3 && nmap > 1) { error = xfs_buf_map_from_irec(mp, map, nmaps, irecs, nirecs);
bplist = kmem_alloc(sizeof(*bplist) * nmap, KM_SLEEP); out:
nbplist = 0; if (irecs != &irec)
} else kmem_free(irecs);
bplist = NULL; return error;
/* }
* Turn the mapping(s) into buffer(s).
*/
for (i = 0; i < nmap; i++) {
int nmapped;
mappedbno = XFS_FSB_TO_DADDR(mp, mapp[i].br_startblock); /*
if (i == 0) * Get a buffer for the dir/attr block.
*mappedbnop = mappedbno; */
nmapped = (int)XFS_FSB_TO_BB(mp, mapp[i].br_blockcount); int
switch (caller) { xfs_da_get_buf(
case 0: struct xfs_trans *trans,
bp = xfs_trans_get_buf(trans, mp->m_ddev_targp, struct xfs_inode *dp,
mappedbno, nmapped, 0); xfs_dablk_t bno,
error = bp ? bp->b_error : XFS_ERROR(EIO); xfs_daddr_t mappedbno,
break; xfs_dabuf_t **bpp,
case 1: int whichfork)
case 2: {
bp = NULL; struct xfs_buf *bp;
error = xfs_trans_read_buf(mp, trans, mp->m_ddev_targp, struct xfs_buf_map map;
mappedbno, nmapped, 0, &bp); struct xfs_buf_map *mapp;
break; int nmap;
case 3: int error;
xfs_buf_readahead(mp->m_ddev_targp, mappedbno, nmapped);
*bpp = NULL;
mapp = &map;
nmap = 1;
error = xfs_dabuf_map(trans, dp, bno, mappedbno, whichfork,
&mapp, &nmap);
if (error) {
/* mapping a hole is not an error, but we don't continue */
if (error == -1)
error = 0; error = 0;
bp = NULL; goto out_free;
break;
}
if (error) {
if (bp)
xfs_trans_brelse(trans, bp);
goto exit1;
}
if (!bp)
continue;
if (caller == 1) {
if (whichfork == XFS_ATTR_FORK)
xfs_buf_set_ref(bp, XFS_ATTR_BTREE_REF);
else
xfs_buf_set_ref(bp, XFS_DIR_BTREE_REF);
}
if (bplist) {
bplist[nbplist++] = bp;
}
} }
/*
* Build a dabuf structure. bp = xfs_trans_get_buf_map(trans, dp->i_mount->m_ddev_targp,
*/ mapp, nmap, 0);
if (bplist) { error = bp ? bp->b_error : XFS_ERROR(EIO);
rbp = xfs_da_buf_make(nbplist, bplist); if (error) {
} else if (bp) xfs_trans_brelse(trans, bp);
rbp = xfs_da_buf_make(1, &bp); goto out_free;
}
*bpp = xfs_da_buf_make(bp);
out_free:
if (mapp != &map)
kmem_free(mapp);
return error;
}
/*
* Get a buffer for the dir/attr block, fill in the contents.
*/
int
xfs_da_read_buf(
struct xfs_trans *trans,
struct xfs_inode *dp,
xfs_dablk_t bno,
xfs_daddr_t mappedbno,
xfs_dabuf_t **bpp,
int whichfork)
{
struct xfs_buf *bp;
struct xfs_buf_map map;
struct xfs_buf_map *mapp;
int nmap;
int error;
*bpp = NULL;
mapp = &map;
nmap = 1;
error = xfs_dabuf_map(trans, dp, bno, mappedbno, whichfork,
&mapp, &nmap);
if (error) {
/* mapping a hole is not an error, but we don't continue */
if (error == -1)
error = 0;
goto out_free;
}
error = xfs_trans_read_buf_map(dp->i_mount, trans,
dp->i_mount->m_ddev_targp,
mapp, nmap, 0, &bp);
if (error)
goto out_free;
if (whichfork == XFS_ATTR_FORK)
xfs_buf_set_ref(bp, XFS_ATTR_BTREE_REF);
else else
rbp = NULL; xfs_buf_set_ref(bp, XFS_DIR_BTREE_REF);
*bpp = xfs_da_buf_make(bp);
/* /*
* For read_buf, check the magic number. * This verification code will be moved to a CRC verification callback
* function so just leave it here unchanged until then.
*/ */
if (caller == 1) { {
xfs_dir2_data_hdr_t *hdr = rbp->data; xfs_dir2_data_hdr_t *hdr = (*bpp)->data;
xfs_dir2_free_t *free = rbp->data; xfs_dir2_free_t *free = (*bpp)->data;
xfs_da_blkinfo_t *info = rbp->data; xfs_da_blkinfo_t *info = (*bpp)->data;
uint magic, magic1; uint magic, magic1;
struct xfs_mount *mp = dp->i_mount;
magic = be16_to_cpu(info->magic); magic = be16_to_cpu(info->magic);
magic1 = be32_to_cpu(hdr->magic); magic1 = be32_to_cpu(hdr->magic);
@ -2123,85 +2203,59 @@ xfs_da_do_buf(
(free->hdr.magic != cpu_to_be32(XFS_DIR2_FREE_MAGIC)), (free->hdr.magic != cpu_to_be32(XFS_DIR2_FREE_MAGIC)),
mp, XFS_ERRTAG_DA_READ_BUF, mp, XFS_ERRTAG_DA_READ_BUF,
XFS_RANDOM_DA_READ_BUF))) { XFS_RANDOM_DA_READ_BUF))) {
trace_xfs_da_btree_corrupt(rbp->bps[0], _RET_IP_); trace_xfs_da_btree_corrupt(bp, _RET_IP_);
XFS_CORRUPTION_ERROR("xfs_da_do_buf(2)", XFS_CORRUPTION_ERROR("xfs_da_do_buf(2)",
XFS_ERRLEVEL_LOW, mp, info); XFS_ERRLEVEL_LOW, mp, info);
error = XFS_ERROR(EFSCORRUPTED); error = XFS_ERROR(EFSCORRUPTED);
xfs_da_brelse(trans, rbp); xfs_da_brelse(trans, *bpp);
nbplist = 0; goto out_free;
goto exit1;
} }
} }
if (bplist) {
kmem_free(bplist); out_free:
}
if (mapp != &map) {
kmem_free(mapp);
}
if (bpp)
*bpp = rbp;
return 0;
exit1:
if (bplist) {
for (i = 0; i < nbplist; i++)
xfs_trans_brelse(trans, bplist[i]);
kmem_free(bplist);
}
exit0:
if (mapp != &map) if (mapp != &map)
kmem_free(mapp); kmem_free(mapp);
if (bpp)
*bpp = NULL;
return error; return error;
} }
/*
* Get a buffer for the dir/attr block.
*/
int
xfs_da_get_buf(
xfs_trans_t *trans,
xfs_inode_t *dp,
xfs_dablk_t bno,
xfs_daddr_t mappedbno,
xfs_dabuf_t **bpp,
int whichfork)
{
return xfs_da_do_buf(trans, dp, bno, &mappedbno, bpp, whichfork, 0);
}
/*
* Get a buffer for the dir/attr block, fill in the contents.
*/
int
xfs_da_read_buf(
xfs_trans_t *trans,
xfs_inode_t *dp,
xfs_dablk_t bno,
xfs_daddr_t mappedbno,
xfs_dabuf_t **bpp,
int whichfork)
{
return xfs_da_do_buf(trans, dp, bno, &mappedbno, bpp, whichfork, 1);
}
/* /*
* Readahead the dir/attr block. * Readahead the dir/attr block.
*/ */
xfs_daddr_t xfs_daddr_t
xfs_da_reada_buf( xfs_da_reada_buf(
xfs_trans_t *trans, struct xfs_trans *trans,
xfs_inode_t *dp, struct xfs_inode *dp,
xfs_dablk_t bno, xfs_dablk_t bno,
int whichfork) int whichfork)
{ {
xfs_daddr_t rval; xfs_daddr_t mappedbno = -1;
struct xfs_buf_map map;
struct xfs_buf_map *mapp;
int nmap;
int error;
rval = -1; mapp = &map;
if (xfs_da_do_buf(trans, dp, bno, &rval, NULL, whichfork, 3)) nmap = 1;
error = xfs_dabuf_map(trans, dp, bno, -1, whichfork,
&mapp, &nmap);
if (error) {
/* mapping a hole is not an error, but we don't continue */
if (error == -1)
error = 0;
goto out_free;
}
mappedbno = mapp[0].bm_bn;
xfs_buf_readahead_map(dp->i_mount->m_ddev_targp, mapp, nmap);
out_free:
if (mapp != &map)
kmem_free(mapp);
if (error)
return -1; return -1;
else return mappedbno;
return rval;
} }
kmem_zone_t *xfs_da_state_zone; /* anchor for state struct zone */ kmem_zone_t *xfs_da_state_zone; /* anchor for state struct zone */
@ -2261,78 +2315,25 @@ xfs_da_state_free(xfs_da_state_t *state)
*/ */
/* ARGSUSED */ /* ARGSUSED */
STATIC xfs_dabuf_t * STATIC xfs_dabuf_t *
xfs_da_buf_make(int nbuf, xfs_buf_t **bps) xfs_da_buf_make(xfs_buf_t *bp)
{ {
xfs_buf_t *bp;
xfs_dabuf_t *dabuf; xfs_dabuf_t *dabuf;
int i;
int off;
if (nbuf == 1) dabuf = kmem_zone_alloc(xfs_dabuf_zone, KM_NOFS);
dabuf = kmem_zone_alloc(xfs_dabuf_zone, KM_NOFS); dabuf->bbcount = bp->b_length;
else dabuf->data = bp->b_addr;
dabuf = kmem_alloc(XFS_DA_BUF_SIZE(nbuf), KM_NOFS); dabuf->bp = bp;
dabuf->dirty = 0;
if (nbuf == 1) {
dabuf->nbuf = 1;
bp = bps[0];
dabuf->bbcount = bp->b_length;
dabuf->data = bp->b_addr;
dabuf->bps[0] = bp;
} else {
dabuf->nbuf = nbuf;
for (i = 0, dabuf->bbcount = 0; i < nbuf; i++) {
dabuf->bps[i] = bp = bps[i];
dabuf->bbcount += bp->b_length;
}
dabuf->data = kmem_alloc(BBTOB(dabuf->bbcount), KM_SLEEP);
for (i = off = 0; i < nbuf; i++, off += BBTOB(bp->b_length)) {
bp = bps[i];
memcpy((char *)dabuf->data + off, bp->b_addr,
BBTOB(bp->b_length));
}
}
return dabuf; return dabuf;
} }
/*
* Un-dirty a dabuf.
*/
STATIC void
xfs_da_buf_clean(xfs_dabuf_t *dabuf)
{
xfs_buf_t *bp;
int i;
int off;
if (dabuf->dirty) {
ASSERT(dabuf->nbuf > 1);
dabuf->dirty = 0;
for (i = off = 0; i < dabuf->nbuf;
i++, off += BBTOB(bp->b_length)) {
bp = dabuf->bps[i];
memcpy(bp->b_addr, dabuf->data + off,
BBTOB(bp->b_length));
}
}
}
/* /*
* Release a dabuf. * Release a dabuf.
*/ */
void void
xfs_da_buf_done(xfs_dabuf_t *dabuf) xfs_da_buf_done(xfs_dabuf_t *dabuf)
{ {
ASSERT(dabuf); ASSERT(dabuf->data && dabuf->bbcount && dabuf->bp);
ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]); kmem_zone_free(xfs_dabuf_zone, dabuf);
if (dabuf->dirty)
xfs_da_buf_clean(dabuf);
if (dabuf->nbuf > 1) {
kmem_free(dabuf->data);
kmem_free(dabuf);
} else {
kmem_zone_free(xfs_dabuf_zone, dabuf);
}
} }
/* /*
@ -2341,41 +2342,9 @@ xfs_da_buf_done(xfs_dabuf_t *dabuf)
void void
xfs_da_log_buf(xfs_trans_t *tp, xfs_dabuf_t *dabuf, uint first, uint last) xfs_da_log_buf(xfs_trans_t *tp, xfs_dabuf_t *dabuf, uint first, uint last)
{ {
xfs_buf_t *bp; ASSERT(dabuf->data && dabuf->bbcount && dabuf->bp);
uint f; ASSERT(dabuf->data == dabuf->bp->b_addr);
int i; xfs_trans_log_buf(tp, dabuf->bp, first, last);
uint l;
int off;
ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]);
if (dabuf->nbuf == 1) {
ASSERT(dabuf->data == dabuf->bps[0]->b_addr);
xfs_trans_log_buf(tp, dabuf->bps[0], first, last);
return;
}
dabuf->dirty = 1;
ASSERT(first <= last);
for (i = off = 0; i < dabuf->nbuf; i++, off += BBTOB(bp->b_length)) {
bp = dabuf->bps[i];
f = off;
l = f + BBTOB(bp->b_length) - 1;
if (f < first)
f = first;
if (l > last)
l = last;
if (f <= l)
xfs_trans_log_buf(tp, bp, f - off, l - off);
/*
* B_DONE is set by xfs_trans_log buf.
* If we don't set it on a new buffer (get not read)
* then if we don't put anything in the buffer it won't
* be set, and at commit it it released into the cache,
* and then a read will fail.
*/
else if (!(XFS_BUF_ISDONE(bp)))
XFS_BUF_DONE(bp);
}
ASSERT(last < off);
} }
/* /*
@ -2386,24 +2355,9 @@ xfs_da_log_buf(xfs_trans_t *tp, xfs_dabuf_t *dabuf, uint first, uint last)
void void
xfs_da_brelse(xfs_trans_t *tp, xfs_dabuf_t *dabuf) xfs_da_brelse(xfs_trans_t *tp, xfs_dabuf_t *dabuf)
{ {
xfs_buf_t *bp; ASSERT(dabuf->data && dabuf->bbcount && dabuf->bp);
xfs_buf_t **bplist; xfs_trans_brelse(tp, dabuf->bp);
int i;
int nbuf;
ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]);
if ((nbuf = dabuf->nbuf) == 1) {
bplist = &bp;
bp = dabuf->bps[0];
} else {
bplist = kmem_alloc(nbuf * sizeof(*bplist), KM_SLEEP);
memcpy(bplist, dabuf->bps, nbuf * sizeof(*bplist));
}
xfs_da_buf_done(dabuf); xfs_da_buf_done(dabuf);
for (i = 0; i < nbuf; i++)
xfs_trans_brelse(tp, bplist[i]);
if (bplist != &bp)
kmem_free(bplist);
} }
/* /*
@ -2412,24 +2366,9 @@ xfs_da_brelse(xfs_trans_t *tp, xfs_dabuf_t *dabuf)
void void
xfs_da_binval(xfs_trans_t *tp, xfs_dabuf_t *dabuf) xfs_da_binval(xfs_trans_t *tp, xfs_dabuf_t *dabuf)
{ {
xfs_buf_t *bp; ASSERT(dabuf->data && dabuf->bbcount && dabuf->bp);
xfs_buf_t **bplist;
int i;
int nbuf;
ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]);
if ((nbuf = dabuf->nbuf) == 1) {
bplist = &bp;
bp = dabuf->bps[0];
} else {
bplist = kmem_alloc(nbuf * sizeof(*bplist), KM_SLEEP);
memcpy(bplist, dabuf->bps, nbuf * sizeof(*bplist));
}
xfs_da_buf_done(dabuf); xfs_da_buf_done(dabuf);
for (i = 0; i < nbuf; i++) xfs_trans_binval(tp, dabuf->bp);
xfs_trans_binval(tp, bplist[i]);
if (bplist != &bp)
kmem_free(bplist);
} }
/* /*
@ -2438,7 +2377,6 @@ xfs_da_binval(xfs_trans_t *tp, xfs_dabuf_t *dabuf)
xfs_daddr_t xfs_daddr_t
xfs_da_blkno(xfs_dabuf_t *dabuf) xfs_da_blkno(xfs_dabuf_t *dabuf)
{ {
ASSERT(dabuf->nbuf);
ASSERT(dabuf->data); ASSERT(dabuf->data);
return XFS_BUF_ADDR(dabuf->bps[0]); return XFS_BUF_ADDR(dabuf->bp);
} }

View File

@ -141,14 +141,10 @@ typedef struct xfs_da_args {
* same place as the b_addr field for the buffer, else to kmem_alloced memory. * same place as the b_addr field for the buffer, else to kmem_alloced memory.
*/ */
typedef struct xfs_dabuf { typedef struct xfs_dabuf {
int nbuf; /* number of buffer pointers present */
short dirty; /* data needs to be copied back */
short bbcount; /* how large is data in bbs */ short bbcount; /* how large is data in bbs */
void *data; /* pointer for buffers' data */ void *data; /* pointer for buffers' data */
struct xfs_buf *bps[1]; /* actually nbuf of these */ struct xfs_buf *bp; /* actually nbuf of these */
} xfs_dabuf_t; } xfs_dabuf_t;
#define XFS_DA_BUF_SIZE(n) \
(sizeof(xfs_dabuf_t) + sizeof(struct xfs_buf *) * ((n) - 1))
/* /*
* Storage for holding state during Btree searches and split/join ops. * Storage for holding state during Btree searches and split/join ops.