Commit 37183a5f authored by Stephen Lord's avatar Stephen Lord Committed by Christoph Hellwig

XFS: Switch to native endian internal representation for extents

Switch xfs from using a big endian internal representation for
the in memory copy of extents to a host byte order representation.
The internal extents are read in once, then modified seperately
from the on disk ones. Since we search and manipulate the extents
multiple times, it is cheaper to convert them to host byte order
once and then keep them in that format. Worth about 5 to 10%
reduction in cpu time for some loads. Complicated by the fact
that the in memory extents are written out to the log sometimes,
and when expanding extents are used to write out the initial
block of extents.

Modid: 2.5.x-xfs:slinx:129646a
parent 1598e9c3
......@@ -3174,7 +3174,7 @@ xfs_bmap_extents_to_btree(
xfs_btree_cur_t *cur; /* bmap btree cursor */
xfs_bmbt_rec_t *ep; /* extent list pointer */
int error; /* error return value */
xfs_extnum_t i; /* extent list index */
xfs_extnum_t i, cnt; /* extent list index */
xfs_ifork_t *ifp; /* inode fork pointer */
xfs_bmbt_key_t *kp; /* root block key pointer */
xfs_mount_t *mp; /* mount structure */
......@@ -3256,24 +3256,25 @@ xfs_bmap_extents_to_btree(
ablock = XFS_BUF_TO_BMBT_BLOCK(abp);
INT_SET(ablock->bb_magic, ARCH_CONVERT, XFS_BMAP_MAGIC);
INT_ZERO(ablock->bb_level, ARCH_CONVERT);
INT_ZERO(ablock->bb_numrecs, ARCH_CONVERT);
INT_SET(ablock->bb_leftsib, ARCH_CONVERT, NULLDFSBNO);
INT_SET(ablock->bb_rightsib, ARCH_CONVERT, NULLDFSBNO);
arp = XFS_BMAP_REC_IADDR(ablock, 1, cur);
nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
for (ep = ifp->if_u1.if_extents, i = 0; i < nextents; i++, ep++) {
for (ep = ifp->if_u1.if_extents, cnt = i = 0; i < nextents; i++, ep++) {
if (!ISNULLSTARTBLOCK(xfs_bmbt_get_startblock(ep))) {
*arp++ = *ep;
INT_MOD(ablock->bb_numrecs, ARCH_CONVERT, +1);
arp->l0 = INT_GET(ep->l0, ARCH_CONVERT);
arp->l1 = INT_GET(ep->l1, ARCH_CONVERT);
arp++; cnt++;
}
}
INT_SET(ablock->bb_numrecs, ARCH_CONVERT, cnt);
ASSERT(INT_GET(ablock->bb_numrecs, ARCH_CONVERT) == XFS_IFORK_NEXTENTS(ip, whichfork));
/*
* Fill in the root key and pointer.
*/
kp = XFS_BMAP_KEY_IADDR(block, 1, cur);
arp = XFS_BMAP_REC_IADDR(ablock, 1, cur);
INT_SET(kp->br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(arp));
INT_SET(kp->br_startoff, ARCH_CONVERT, xfs_bmbt_disk_get_startoff(arp));
pp = XFS_BMAP_PTR_IADDR(block, 1, cur);
INT_SET(*pp, ARCH_CONVERT, args.fsbno);
/*
......@@ -4332,7 +4333,7 @@ xfs_bmap_read_extents(
#ifdef XFS_BMAP_TRACE
static char fname[] = "xfs_bmap_read_extents";
#endif
xfs_extnum_t i; /* index into the extents list */
xfs_extnum_t i, j; /* index into the extents list */
xfs_ifork_t *ifp; /* fork structure */
int level; /* btree level, for checking */
xfs_mount_t *mp; /* file system mount structure */
......@@ -4389,7 +4390,7 @@ xfs_bmap_read_extents(
* Loop over all leaf nodes. Copy information to the extent list.
*/
for (;;) {
xfs_bmbt_rec_t *frp;
xfs_bmbt_rec_t *frp, *temp;
xfs_fsblock_t nextbno;
xfs_extnum_t num_recs;
......@@ -4417,18 +4418,21 @@ xfs_bmap_read_extents(
*/
frp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt,
block, 1, mp->m_bmap_dmxr[0]);
memcpy(trp, frp, num_recs * sizeof(*frp));
temp = trp;
for (j = 0; j < num_recs; j++, frp++, trp++) {
trp->l0 = INT_GET(frp->l0, ARCH_CONVERT);
trp->l1 = INT_GET(frp->l1, ARCH_CONVERT);
}
if (exntf == XFS_EXTFMT_NOSTATE) {
/*
* Check all attribute bmap btree records and
* any "older" data bmap btree records for a
* set bit in the "extent flag" position.
*/
if (xfs_check_nostate_extents(trp, num_recs)) {
if (xfs_check_nostate_extents(temp, num_recs)) {
goto error0;
}
}
trp += num_recs;
i += num_recs;
xfs_trans_brelse(tp, bp);
bno = nextbno;
......@@ -6257,7 +6261,7 @@ xfs_bmap_count_leaves(
int b;
for ( b = 1; b <= numrecs; b++, frp++)
*count += xfs_bmbt_get_blockcount(frp);
*count += xfs_bmbt_disk_get_blockcount(frp);
return 0;
}
This diff is collapsed.
......@@ -509,6 +509,41 @@ xfs_exntst_t
xfs_bmbt_get_state(
xfs_bmbt_rec_t *r);
#if ARCH_CONVERT != ARCH_NOCONVERT
void
xfs_bmbt_disk_get_all(
xfs_bmbt_rec_t *r,
xfs_bmbt_irec_t *s);
xfs_exntst_t
xfs_bmbt_disk_get_state(
xfs_bmbt_rec_t *r);
xfs_filblks_t
xfs_bmbt_disk_get_blockcount(
xfs_bmbt_rec_t *r);
xfs_fsblock_t
xfs_bmbt_disk_get_startblock(
xfs_bmbt_rec_t *r);
xfs_fileoff_t
xfs_bmbt_disk_get_startoff(
xfs_bmbt_rec_t *r);
#else
#define xfs_bmbt_disk_get_all(r, s) \
xfs_bmbt_get_all(r, s)
#define xfs_bmbt_disk_get_state(r) \
xfs_bmbt_get_state(r)
#define xfs_bmbt_disk_get_blockcount(r) \
xfs_bmbt_get_blockcount(r)
#define xfs_bmbt_disk_get_startblock(r) \
xfs_bmbt_get_blockcount(r)
#define xfs_bmbt_disk_get_startoff(r) \
xfs_bmbt_get_startoff(r)
#endif
int
xfs_bmbt_increment(
struct xfs_btree_cur *,
......@@ -607,6 +642,26 @@ xfs_bmbt_set_state(
xfs_bmbt_rec_t *r,
xfs_exntst_t v);
#if ARCH_CONVERT != ARCH_NOCONVERT
void
xfs_bmbt_disk_set_all(
xfs_bmbt_rec_t *r,
xfs_bmbt_irec_t *s);
void
xfs_bmbt_disk_set_allf(
xfs_bmbt_rec_t *r,
xfs_fileoff_t o,
xfs_fsblock_t b,
xfs_filblks_t c,
xfs_exntst_t v);
#else
#define xfs_bmbt_disk_set_all(r, s) \
xfs_bmbt_set_all(r, s)
#define xfs_bmbt_disk_set_allf(r, 0, b, c, v) \
xfs_bmbt_set_allf(r, 0, b, c, v)
#endif
void
xfs_bmbt_to_bmdr(
xfs_bmbt_block_t *,
......
......@@ -261,9 +261,9 @@ xfs_btree_check_rec(
r1 = ar1;
r2 = ar2;
ASSERT(xfs_bmbt_get_startoff(r1) +
xfs_bmbt_get_blockcount(r1) <=
xfs_bmbt_get_startoff(r2));
ASSERT(xfs_bmbt_disk_get_startoff(r1) +
xfs_bmbt_disk_get_blockcount(r1) <=
xfs_bmbt_disk_get_startoff(r2));
break;
}
case XFS_BTNUM_INO: {
......
......@@ -56,8 +56,9 @@ STATIC int xfs_iformat_btree(xfs_inode_t *, xfs_dinode_t *, int);
*/
STATIC void
xfs_validate_extents(
xfs_bmbt_rec_32_t *ep,
xfs_bmbt_rec_t *ep,
int nrecs,
int disk,
xfs_exntfmt_t fmt)
{
xfs_bmbt_irec_t irec;
......@@ -66,14 +67,17 @@ xfs_validate_extents(
for (i = 0; i < nrecs; i++) {
memcpy(&rec, ep, sizeof(rec));
xfs_bmbt_get_all(&rec, &irec);
if (disk)
xfs_bmbt_disk_get_all(&rec, &irec);
else
xfs_bmbt_get_all(&rec, &irec);
if (fmt == XFS_EXTFMT_NOSTATE)
ASSERT(irec.br_state == XFS_EXT_NORM);
ep++;
}
}
#else /* DEBUG */
#define xfs_validate_extents(ep, nrecs, fmt)
#define xfs_validate_extents(ep, nrecs, disk, fmt)
#endif /* DEBUG */
/*
......@@ -598,9 +602,10 @@ xfs_iformat_extents(
int whichfork)
{
xfs_ifork_t *ifp;
int nex;
int nex, i;
int real_size;
int size;
xfs_bmbt_rec_t *ep, *dp;
ifp = XFS_IFORK_PTR(ip, whichfork);
nex = XFS_DFORK_NEXTENTS_ARCH(dip, whichfork, ARCH_CONVERT);
......@@ -633,10 +638,18 @@ xfs_iformat_extents(
ifp->if_real_bytes = real_size;
if (size) {
xfs_validate_extents(
(xfs_bmbt_rec_32_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT),
nex, XFS_EXTFMT_INODE(ip));
memcpy(ifp->if_u1.if_extents,
XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT), size);
(xfs_bmbt_rec_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT),
nex, 1, XFS_EXTFMT_INODE(ip));
dp = (xfs_bmbt_rec_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT);
ep = ifp->if_u1.if_extents;
#if ARCH_CONVERT != ARCH_NOCONVERT
for (i = 0; i < nex; i++, ep++, dp++) {
ep->l0 = INT_GET(dp->l0, ARCH_CONVERT);
ep->l1 = INT_GET(dp->l1, ARCH_CONVERT);
}
#else
memcpy(ep, dp, size);
#endif
xfs_bmap_trace_exlist("xfs_iformat_extents", ip, nex,
whichfork);
if (whichfork != XFS_DATA_FORK ||
......@@ -979,8 +992,8 @@ xfs_iread_extents(
ifp->if_flags &= ~XFS_IFEXTENTS;
return error;
}
xfs_validate_extents((xfs_bmbt_rec_32_t *)ifp->if_u1.if_extents,
XFS_IFORK_NEXTENTS(ip, whichfork), XFS_EXTFMT_INODE(ip));
xfs_validate_extents((xfs_bmbt_rec_t *)ifp->if_u1.if_extents,
XFS_IFORK_NEXTENTS(ip, whichfork), 0, XFS_EXTFMT_INODE(ip));
return 0;
}
......@@ -2617,11 +2630,11 @@ xfs_iunpin_wait(
int
xfs_iextents_copy(
xfs_inode_t *ip,
xfs_bmbt_rec_32_t *buffer,
xfs_bmbt_rec_t *buffer,
int whichfork)
{
int copied;
xfs_bmbt_rec_32_t *dest_ep;
xfs_bmbt_rec_t *dest_ep;
xfs_bmbt_rec_t *ep;
#ifdef XFS_BMAP_TRACE
static char fname[] = "xfs_iextents_copy";
......@@ -2638,28 +2651,13 @@ xfs_iextents_copy(
nrecs = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
xfs_bmap_trace_exlist(fname, ip, nrecs, whichfork);
ASSERT(nrecs > 0);
if (nrecs == XFS_IFORK_NEXTENTS(ip, whichfork)) {
/*
* There are no delayed allocation extents,
* so just copy everything.
*/
ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork));
ASSERT(ifp->if_bytes ==
(XFS_IFORK_NEXTENTS(ip, whichfork) *
(uint)sizeof(xfs_bmbt_rec_t)));
memcpy(buffer, ifp->if_u1.if_extents, ifp->if_bytes);
xfs_validate_extents(buffer, nrecs, XFS_EXTFMT_INODE(ip));
return ifp->if_bytes;
}
ASSERT(whichfork == XFS_DATA_FORK);
/*
* There are some delayed allocation extents in the
* inode, so copy the extents one at a time and skip
* the delayed ones. There must be at least one
* non-delayed extent.
*/
ASSERT(nrecs > ip->i_d.di_nextents);
ep = ifp->if_u1.if_extents;
dest_ep = buffer;
copied = 0;
......@@ -2673,15 +2671,19 @@ xfs_iextents_copy(
continue;
}
*dest_ep = *(xfs_bmbt_rec_32_t *)ep;
#if ARCH_CONVERT != ARCH_NOCONVERT
/* Translate to on disk format */
dest_ep->l0 = INT_GET(ep->l0, ARCH_CONVERT);
dest_ep->l1 = INT_GET(ep->l1, ARCH_CONVERT);
#else
*dest_ep = *ep;
#endif
dest_ep++;
ep++;
copied++;
}
ASSERT(copied != 0);
ASSERT(copied == ip->i_d.di_nextents);
ASSERT((copied * (uint)sizeof(xfs_bmbt_rec_t)) <= XFS_IFORK_DSIZE(ip));
xfs_validate_extents(buffer, copied, XFS_EXTFMT_INODE(ip));
xfs_validate_extents(buffer, copied, 1, XFS_EXTFMT_INODE(ip));
return (copied * (uint)sizeof(xfs_bmbt_rec_t));
}
......@@ -2754,7 +2756,7 @@ xfs_iflush_fork(
if ((iip->ili_format.ilf_fields & extflag[whichfork]) &&
(ifp->if_bytes > 0)) {
ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0);
(void)xfs_iextents_copy(ip, (xfs_bmbt_rec_32_t *)cp,
(void)xfs_iextents_copy(ip, (xfs_bmbt_rec_t *)cp,
whichfork);
}
break;
......
......@@ -520,7 +520,7 @@ void xfs_iext_realloc(xfs_inode_t *, int, int);
void xfs_iroot_realloc(xfs_inode_t *, int, int);
void xfs_ipin(xfs_inode_t *);
void xfs_iunpin(xfs_inode_t *);
int xfs_iextents_copy(xfs_inode_t *, xfs_bmbt_rec_32_t *, int);
int xfs_iextents_copy(xfs_inode_t *, xfs_bmbt_rec_t *, int);
int xfs_iflush(xfs_inode_t *, uint);
int xfs_iflush_all(struct xfs_mount *, int);
int xfs_ibusy_check(xfs_inode_t *, int);
......
......@@ -214,7 +214,7 @@ xfs_inode_item_format(
xfs_log_iovec_t *vecp;
xfs_inode_t *ip;
size_t data_bytes;
xfs_bmbt_rec_32_t *ext_buffer;
xfs_bmbt_rec_t *ext_buffer;
int nrecs;
xfs_mount_t *mp;
......@@ -314,6 +314,7 @@ xfs_inode_item_format(
nrecs = ip->i_df.if_bytes /
(uint)sizeof(xfs_bmbt_rec_t);
ASSERT(nrecs > 0);
#if ARCH_CONVERT == ARCH_NOCONVERT
if (nrecs == ip->i_d.di_nextents) {
/*
* There are no delayed allocation
......@@ -323,10 +324,14 @@ xfs_inode_item_format(
vecp->i_addr =
(char *)(ip->i_df.if_u1.if_extents);
vecp->i_len = ip->i_df.if_bytes;
} else {
} else
#endif
{
/*
* There are delayed allocation extents
* in the inode. Use xfs_iextents_copy()
* in the inode, or we need to convert
* the extents to on disk format.
* Use xfs_iextents_copy()
* to copy only the real extents into
* a separate buffer. We'll free the
* buffer in the unlock routine.
......@@ -336,7 +341,7 @@ xfs_inode_item_format(
iip->ili_extents_buf = ext_buffer;
vecp->i_addr = (xfs_caddr_t)ext_buffer;
vecp->i_len = xfs_iextents_copy(ip, ext_buffer,
XFS_DATA_FORK);
XFS_DATA_FORK);
}
ASSERT(vecp->i_len <= ip->i_df.if_bytes);
iip->ili_format.ilf_dsize = vecp->i_len;
......@@ -428,6 +433,7 @@ xfs_inode_item_format(
ASSERT(!(iip->ili_format.ilf_fields &
(XFS_ILOG_ADATA | XFS_ILOG_ABROOT)));
if (iip->ili_format.ilf_fields & XFS_ILOG_AEXT) {
ASSERT(!(iip->ili_format.ilf_fields & XFS_ILOG_DEXT));
ASSERT(ip->i_afp->if_bytes > 0);
ASSERT(ip->i_afp->if_u1.if_extents != NULL);
ASSERT(ip->i_d.di_anextents > 0);
......@@ -437,12 +443,25 @@ xfs_inode_item_format(
#endif
ASSERT(nrecs > 0);
ASSERT(nrecs == ip->i_d.di_anextents);
#if ARCH_CONVERT == ARCH_NOCONVERT
/*
* There are not delayed allocation extents
* for attributes, so just point at the array.
*/
vecp->i_addr = (char *)(ip->i_afp->if_u1.if_extents);
vecp->i_len = ip->i_afp->if_bytes;
#else
ASSERT(iip->ili_aextents_buf == NULL);
/*
* Need to endian flip before logging
*/
ext_buffer = kmem_alloc(ip->i_df.if_bytes,
KM_SLEEP);
iip->ili_aextents_buf = ext_buffer;
vecp->i_addr = (xfs_caddr_t)ext_buffer;
vecp->i_len = xfs_iextents_copy(ip, ext_buffer,
XFS_ATTR_FORK);
#endif
iip->ili_format.ilf_asize = vecp->i_len;
vecp++;
nvecs++;
......@@ -630,7 +649,6 @@ xfs_inode_item_unlock(
* If the inode needed a separate buffer with which to log
* its extents, then free it now.
*/
/* FIXME */
if (iip->ili_extents_buf != NULL) {
ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS);
ASSERT(ip->i_d.di_nextents > 0);
......@@ -639,6 +657,14 @@ xfs_inode_item_unlock(
kmem_free(iip->ili_extents_buf, ip->i_df.if_bytes);
iip->ili_extents_buf = NULL;
}
if (iip->ili_aextents_buf != NULL) {
ASSERT(ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS);
ASSERT(ip->i_d.di_anextents > 0);
ASSERT(iip->ili_format.ilf_fields & XFS_ILOG_AEXT);
ASSERT(ip->i_afp->if_bytes > 0);
kmem_free(iip->ili_aextents_buf, ip->i_afp->if_bytes);
iip->ili_aextents_buf = NULL;
}
/*
* Figure out if we should unlock the inode or not.
......
......@@ -141,7 +141,10 @@ typedef struct xfs_inode_log_item {
unsigned short ili_flags; /* misc flags */
unsigned short ili_logged; /* flushed logged data */
unsigned int ili_last_fields; /* fields when flushed */
struct xfs_bmbt_rec_32 *ili_extents_buf; /* array of logged exts */
struct xfs_bmbt_rec_32 *ili_extents_buf; /* array of logged
data exts */
struct xfs_bmbt_rec_32 *ili_aextents_buf; /* array of logged
attr exts */
unsigned int ili_pushbuf_flag; /* one bit used in push_ail */
#ifdef DEBUG
......
......@@ -2364,7 +2364,7 @@ xfs_btbmap(xfs_bmbt_block_t *bt, int bsz)
r = (xfs_bmbt_rec_t *)XFS_BTREE_REC_ADDR(bsz,
xfs_bmbt, bt, i, 0);
xfs_bmbt_get_all((xfs_bmbt_rec_t *)r, &irec);
xfs_bmbt_disk_get_all((xfs_bmbt_rec_t *)r, &irec);
kdb_printf("rec %d startoff %Ld startblock %Lx blockcount %Ld flag %d\n",
i, irec.br_startoff,
(__uint64_t)irec.br_startblock,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment