Skip to content
Snippets Groups Projects
Commit 20f7e9f3 authored by Dave Chinner's avatar Dave Chinner Committed by Ben Myers
Browse files

xfs: factor dir2 block read operations


In preparation for verifying dir2 block format buffers, factor
the read operations out of the block operations (lookup, addname,
getdents) and some of the additional logic to make it easier to
understand an dmodify the code.

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 4bb20a83
Branches
Tags
No related merge requests found
...@@ -56,172 +56,253 @@ xfs_dir_startup(void) ...@@ -56,172 +56,253 @@ xfs_dir_startup(void)
xfs_dir_hash_dotdot = xfs_da_hashname((unsigned char *)"..", 2); xfs_dir_hash_dotdot = xfs_da_hashname((unsigned char *)"..", 2);
} }
/* static int
* Add an entry to a block directory. xfs_dir2_block_read(
*/ struct xfs_trans *tp,
int /* error */ struct xfs_inode *dp,
xfs_dir2_block_addname( struct xfs_buf **bpp)
xfs_da_args_t *args) /* directory op arguments */
{ {
xfs_dir2_data_free_t *bf; /* bestfree table in block */ struct xfs_mount *mp = dp->i_mount;
xfs_dir2_data_hdr_t *hdr; /* block header */
xfs_dir2_leaf_entry_t *blp; /* block leaf entries */
struct xfs_buf *bp; /* buffer for block */
xfs_dir2_block_tail_t *btp; /* block tail */
int compact; /* need to compact leaf ents */
xfs_dir2_data_entry_t *dep; /* block data entry */
xfs_inode_t *dp; /* directory inode */
xfs_dir2_data_unused_t *dup; /* block unused entry */
int error; /* error return value */
xfs_dir2_data_unused_t *enddup=NULL; /* unused at end of data */
xfs_dahash_t hash; /* hash value of found entry */
int high; /* high index for binary srch */
int highstale; /* high stale index */
int lfloghigh=0; /* last final leaf to log */
int lfloglow=0; /* first final leaf to log */
int len; /* length of the new entry */
int low; /* low index for binary srch */
int lowstale; /* low stale index */
int mid=0; /* midpoint for binary srch */
xfs_mount_t *mp; /* filesystem mount point */
int needlog; /* need to log header */
int needscan; /* need to rescan freespace */
__be16 *tagp; /* pointer to tag value */
xfs_trans_t *tp; /* transaction structure */
trace_xfs_dir2_block_addname(args); return xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, bpp,
XFS_DATA_FORK, NULL);
}
static void
xfs_dir2_block_need_space(
struct xfs_dir2_data_hdr *hdr,
struct xfs_dir2_block_tail *btp,
struct xfs_dir2_leaf_entry *blp,
__be16 **tagpp,
struct xfs_dir2_data_unused **dupp,
struct xfs_dir2_data_unused **enddupp,
int *compact,
int len)
{
struct xfs_dir2_data_free *bf;
__be16 *tagp = NULL;
struct xfs_dir2_data_unused *dup = NULL;
struct xfs_dir2_data_unused *enddup = NULL;
*compact = 0;
bf = hdr->bestfree;
dp = args->dp;
tp = args->trans;
mp = dp->i_mount;
/* /*
* Read the (one and only) directory block into dabuf bp. * If there are stale entries we'll use one for the leaf.
*/ */
error = xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &bp, if (btp->stale) {
XFS_DATA_FORK, NULL); if (be16_to_cpu(bf[0].length) >= len) {
if (error)
return error;
ASSERT(bp != NULL);
hdr = bp->b_addr;
/* /*
* Check the magic number, corrupted if wrong. * The biggest entry enough to avoid compaction.
*/ */
if (unlikely(hdr->magic != cpu_to_be32(XFS_DIR2_BLOCK_MAGIC))) { dup = (xfs_dir2_data_unused_t *)
XFS_CORRUPTION_ERROR("xfs_dir2_block_addname", ((char *)hdr + be16_to_cpu(bf[0].offset));
XFS_ERRLEVEL_LOW, mp, hdr); goto out;
xfs_trans_brelse(tp, bp);
return XFS_ERROR(EFSCORRUPTED);
} }
len = xfs_dir2_data_entsize(args->namelen);
/* /*
* Set up pointers to parts of the block. * Will need to compact to make this work.
* Tag just before the first leaf entry.
*/ */
bf = hdr->bestfree; *compact = 1;
btp = xfs_dir2_block_tail_p(mp, hdr); tagp = (__be16 *)blp - 1;
blp = xfs_dir2_block_leaf_p(btp);
/* Data object just before the first leaf entry. */
dup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp));
/* /*
* No stale entries? Need space for entry and new leaf. * If it's not free then the data will go where the
* leaf data starts now, if it works at all.
*/ */
if (!btp->stale) { if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
if (be16_to_cpu(dup->length) + (be32_to_cpu(btp->stale) - 1) *
(uint)sizeof(*blp) < len)
dup = NULL;
} else if ((be32_to_cpu(btp->stale) - 1) * (uint)sizeof(*blp) < len)
dup = NULL;
else
dup = (xfs_dir2_data_unused_t *)blp;
goto out;
}
/* /*
* no stale entries, so just use free space.
* Tag just before the first leaf entry. * Tag just before the first leaf entry.
*/ */
tagp = (__be16 *)blp - 1; tagp = (__be16 *)blp - 1;
/*
* Data object just before the first leaf entry. /* Data object just before the first leaf entry. */
*/
enddup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp)); enddup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp));
/* /*
* If it's not free then can't do this add without cleaning up: * If it's not free then can't do this add without cleaning up:
* the space before the first leaf entry needs to be free so it * the space before the first leaf entry needs to be free so it
* can be expanded to hold the pointer to the new entry. * can be expanded to hold the pointer to the new entry.
*/ */
if (be16_to_cpu(enddup->freetag) != XFS_DIR2_DATA_FREE_TAG) if (be16_to_cpu(enddup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
dup = enddup = NULL;
/* /*
* Check out the biggest freespace and see if it's the same one. * Check out the biggest freespace and see if it's the same one.
*/ */
else {
dup = (xfs_dir2_data_unused_t *) dup = (xfs_dir2_data_unused_t *)
((char *)hdr + be16_to_cpu(bf[0].offset)); ((char *)hdr + be16_to_cpu(bf[0].offset));
if (dup == enddup) { if (dup != enddup) {
/* /*
* It is the biggest freespace, is it too small * Not the same free entry, just check its length.
* to hold the new leaf too? */
if (be16_to_cpu(dup->length) < len)
dup = NULL;
goto out;
}
/*
* It is the biggest freespace, can it hold the leaf too?
*/ */
if (be16_to_cpu(dup->length) < len + (uint)sizeof(*blp)) { if (be16_to_cpu(dup->length) < len + (uint)sizeof(*blp)) {
/* /*
* Yes, we use the second-largest * Yes, use the second-largest entry instead if it works.
* entry instead if it works.
*/ */
if (be16_to_cpu(bf[1].length) >= len) if (be16_to_cpu(bf[1].length) >= len)
dup = (xfs_dir2_data_unused_t *) dup = (xfs_dir2_data_unused_t *)
((char *)hdr + ((char *)hdr + be16_to_cpu(bf[1].offset));
be16_to_cpu(bf[1].offset));
else else
dup = NULL; dup = NULL;
} }
} else { }
out:
*tagpp = tagp;
*dupp = dup;
*enddupp = enddup;
}
/* /*
* Not the same free entry, * compact the leaf entries.
* just check its length. * Leave the highest-numbered stale entry stale.
* XXX should be the one closest to mid but mid is not yet computed.
*/ */
if (be16_to_cpu(dup->length) < len) { static void
dup = NULL; xfs_dir2_block_compact(
} struct xfs_trans *tp,
struct xfs_buf *bp,
struct xfs_dir2_data_hdr *hdr,
struct xfs_dir2_block_tail *btp,
struct xfs_dir2_leaf_entry *blp,
int *needlog,
int *lfloghigh,
int *lfloglow)
{
int fromidx; /* source leaf index */
int toidx; /* target leaf index */
int needscan = 0;
int highstale; /* high stale index */
fromidx = toidx = be32_to_cpu(btp->count) - 1;
highstale = *lfloghigh = -1;
for (; fromidx >= 0; fromidx--) {
if (blp[fromidx].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) {
if (highstale == -1)
highstale = toidx;
else {
if (*lfloghigh == -1)
*lfloghigh = toidx;
continue;
} }
} }
compact = 0; if (fromidx < toidx)
blp[toidx] = blp[fromidx];
toidx--;
} }
*lfloglow = toidx + 1 - (be32_to_cpu(btp->stale) - 1);
*lfloghigh -= be32_to_cpu(btp->stale) - 1;
be32_add_cpu(&btp->count, -(be32_to_cpu(btp->stale) - 1));
xfs_dir2_data_make_free(tp, bp,
(xfs_dir2_data_aoff_t)((char *)blp - (char *)hdr),
(xfs_dir2_data_aoff_t)((be32_to_cpu(btp->stale) - 1) * sizeof(*blp)),
needlog, &needscan);
blp += be32_to_cpu(btp->stale) - 1;
btp->stale = cpu_to_be32(1);
/* /*
* If there are stale entries we'll use one for the leaf. * If we now need to rebuild the bestfree map, do so.
* Is the biggest entry enough to avoid compaction? * This needs to happen before the next call to use_free.
*/ */
else if (be16_to_cpu(bf[0].length) >= len) { if (needscan)
dup = (xfs_dir2_data_unused_t *) xfs_dir2_data_freescan(tp->t_mountp, hdr, needlog);
((char *)hdr + be16_to_cpu(bf[0].offset));
compact = 0;
} }
/* /*
* Will need to compact to make this work. * Add an entry to a block directory.
*/
else {
/*
* Tag just before the first leaf entry.
*/ */
tagp = (__be16 *)blp - 1; int /* error */
xfs_dir2_block_addname(
xfs_da_args_t *args) /* directory op arguments */
{
xfs_dir2_data_hdr_t *hdr; /* block header */
xfs_dir2_leaf_entry_t *blp; /* block leaf entries */
struct xfs_buf *bp; /* buffer for block */
xfs_dir2_block_tail_t *btp; /* block tail */
int compact; /* need to compact leaf ents */
xfs_dir2_data_entry_t *dep; /* block data entry */
xfs_inode_t *dp; /* directory inode */
xfs_dir2_data_unused_t *dup; /* block unused entry */
int error; /* error return value */
xfs_dir2_data_unused_t *enddup=NULL; /* unused at end of data */
xfs_dahash_t hash; /* hash value of found entry */
int high; /* high index for binary srch */
int highstale; /* high stale index */
int lfloghigh=0; /* last final leaf to log */
int lfloglow=0; /* first final leaf to log */
int len; /* length of the new entry */
int low; /* low index for binary srch */
int lowstale; /* low stale index */
int mid=0; /* midpoint for binary srch */
xfs_mount_t *mp; /* filesystem mount point */
int needlog; /* need to log header */
int needscan; /* need to rescan freespace */
__be16 *tagp; /* pointer to tag value */
xfs_trans_t *tp; /* transaction structure */
trace_xfs_dir2_block_addname(args);
dp = args->dp;
tp = args->trans;
mp = dp->i_mount;
/* Read the (one and only) directory block into bp. */
error = xfs_dir2_block_read(tp, dp, &bp);
if (error)
return error;
len = xfs_dir2_data_entsize(args->namelen);
/* /*
* Data object just before the first leaf entry. * Set up pointers to parts of the block.
*/ */
dup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp)); hdr = bp->b_addr;
btp = xfs_dir2_block_tail_p(mp, hdr);
blp = xfs_dir2_block_leaf_p(btp);
/* /*
* If it's not free then the data will go where the * Find out if we can reuse stale entries or whether we need extra
* leaf data starts now, if it works at all. * space for entry and new leaf.
*/ */
if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { xfs_dir2_block_need_space(hdr, btp, blp, &tagp, &dup,
if (be16_to_cpu(dup->length) + (be32_to_cpu(btp->stale) - 1) * &enddup, &compact, len);
(uint)sizeof(*blp) < len)
dup = NULL;
} else if ((be32_to_cpu(btp->stale) - 1) * (uint)sizeof(*blp) < len)
dup = NULL;
else
dup = (xfs_dir2_data_unused_t *)blp;
compact = 1;
}
/* /*
* If this isn't a real add, we're done with the buffer. * Done everything we need for a space check now.
*/ */
if (args->op_flags & XFS_DA_OP_JUSTCHECK) if (args->op_flags & XFS_DA_OP_JUSTCHECK) {
xfs_trans_brelse(tp, bp); xfs_trans_brelse(tp, bp);
if (!dup)
return XFS_ERROR(ENOSPC);
return 0;
}
/* /*
* If we don't have space for the new entry & leaf ... * If we don't have space for the new entry & leaf ...
*/ */
if (!dup) { if (!dup) {
/* /* Don't have a space reservation: return no-space. */
* Not trying to actually do anything, or don't have if (args->total == 0)
* a space reservation: return no-space.
*/
if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0)
return XFS_ERROR(ENOSPC); return XFS_ERROR(ENOSPC);
/* /*
* Convert to the next larger format. * Convert to the next larger format.
...@@ -232,65 +313,24 @@ xfs_dir2_block_addname( ...@@ -232,65 +313,24 @@ xfs_dir2_block_addname(
return error; return error;
return xfs_dir2_leaf_addname(args); return xfs_dir2_leaf_addname(args);
} }
/*
* Just checking, and it would work, so say so.
*/
if (args->op_flags & XFS_DA_OP_JUSTCHECK)
return 0;
needlog = needscan = 0; needlog = needscan = 0;
/*
* If need to compact the leaf entries, do it now.
* Leave the highest-numbered stale entry stale.
* XXX should be the one closest to mid but mid is not yet computed.
*/
if (compact) {
int fromidx; /* source leaf index */
int toidx; /* target leaf index */
for (fromidx = toidx = be32_to_cpu(btp->count) - 1,
highstale = lfloghigh = -1;
fromidx >= 0;
fromidx--) {
if (blp[fromidx].address ==
cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) {
if (highstale == -1)
highstale = toidx;
else {
if (lfloghigh == -1)
lfloghigh = toidx;
continue;
}
}
if (fromidx < toidx)
blp[toidx] = blp[fromidx];
toidx--;
}
lfloglow = toidx + 1 - (be32_to_cpu(btp->stale) - 1);
lfloghigh -= be32_to_cpu(btp->stale) - 1;
be32_add_cpu(&btp->count, -(be32_to_cpu(btp->stale) - 1));
xfs_dir2_data_make_free(tp, bp,
(xfs_dir2_data_aoff_t)((char *)blp - (char *)hdr),
(xfs_dir2_data_aoff_t)((be32_to_cpu(btp->stale) - 1) * sizeof(*blp)),
&needlog, &needscan);
blp += be32_to_cpu(btp->stale) - 1;
btp->stale = cpu_to_be32(1);
/* /*
* If we now need to rebuild the bestfree map, do so. * If need to compact the leaf entries, do it now.
* This needs to happen before the next call to use_free.
*/ */
if (needscan) { if (compact)
xfs_dir2_data_freescan(mp, hdr, &needlog); xfs_dir2_block_compact(tp, bp, hdr, btp, blp, &needlog,
needscan = 0; &lfloghigh, &lfloglow);
} else if (btp->stale) {
}
/* /*
* Set leaf logging boundaries to impossible state. * Set leaf logging boundaries to impossible state.
* For the no-stale case they're set explicitly. * For the no-stale case they're set explicitly.
*/ */
else if (btp->stale) {
lfloglow = be32_to_cpu(btp->count); lfloglow = be32_to_cpu(btp->count);
lfloghigh = -1; lfloghigh = -1;
} }
/* /*
* Find the slot that's first lower than our hash value, -1 if none. * Find the slot that's first lower than our hash value, -1 if none.
*/ */
...@@ -450,18 +490,13 @@ xfs_dir2_block_getdents( ...@@ -450,18 +490,13 @@ xfs_dir2_block_getdents(
/* /*
* If the block number in the offset is out of range, we're done. * If the block number in the offset is out of range, we're done.
*/ */
if (xfs_dir2_dataptr_to_db(mp, *offset) > mp->m_dirdatablk) { if (xfs_dir2_dataptr_to_db(mp, *offset) > mp->m_dirdatablk)
return 0; return 0;
}
/* error = xfs_dir2_block_read(NULL, dp, &bp);
* Can't read the block, give up, else get dabuf in bp.
*/
error = xfs_da_read_buf(NULL, dp, mp->m_dirdatablk, -1,
&bp, XFS_DATA_FORK, NULL);
if (error) if (error)
return error; return error;
ASSERT(bp != NULL);
/* /*
* Extract the byte offset we start at from the seek pointer. * Extract the byte offset we start at from the seek pointer.
* We'll skip entries before this. * We'll skip entries before this.
...@@ -637,14 +672,11 @@ xfs_dir2_block_lookup_int( ...@@ -637,14 +672,11 @@ xfs_dir2_block_lookup_int(
dp = args->dp; dp = args->dp;
tp = args->trans; tp = args->trans;
mp = dp->i_mount; mp = dp->i_mount;
/*
* Read the buffer, return error if we can't get it. error = xfs_dir2_block_read(tp, dp, &bp);
*/
error = xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &bp,
XFS_DATA_FORK, NULL);
if (error) if (error)
return error; return error;
ASSERT(bp != NULL);
hdr = bp->b_addr; hdr = bp->b_addr;
xfs_dir2_data_check(dp, bp); xfs_dir2_data_check(dp, bp);
btp = xfs_dir2_block_tail_p(mp, hdr); btp = xfs_dir2_block_tail_p(mp, hdr);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment