Skip to content

Commit

Permalink
xfs: factor dir2 free block reading
Browse files Browse the repository at this point in the history
Also factor out the updating of the free block when removing entries
from leaf blocks, and add a verifier callback for reads.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Phil White <pwhite@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
  • Loading branch information
Dave Chinner authored and Ben Myers committed Nov 16, 2012
1 parent 82025d7 commit 2025207
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 80 deletions.
3 changes: 1 addition & 2 deletions fs/xfs/xfs_dir2_leaf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1863,8 +1863,7 @@ xfs_dir2_node_to_leaf(
/*
* Read the freespace block.
*/
error = xfs_da_read_buf(tp, dp, mp->m_dirfreeblk, -1, &fbp,
XFS_DATA_FORK, NULL);
error = xfs_dir2_free_read(tp, dp, mp->m_dirfreeblk, &fbp);
if (error)
return error;
free = fbp->b_addr;
Expand Down
218 changes: 140 additions & 78 deletions fs/xfs/xfs_dir2_node.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,57 @@ static int xfs_dir2_leafn_remove(xfs_da_args_t *args, struct xfs_buf *bp,
static int xfs_dir2_node_addname_int(xfs_da_args_t *args,
xfs_da_state_blk_t *fblk);

static void
xfs_dir2_free_verify(
struct xfs_buf *bp)
{
struct xfs_mount *mp = bp->b_target->bt_mount;
struct xfs_dir2_free_hdr *hdr = bp->b_addr;
int block_ok = 0;

block_ok = hdr->magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC);
if (!block_ok) {
XFS_CORRUPTION_ERROR("xfs_dir2_free_verify magic",
XFS_ERRLEVEL_LOW, mp, hdr);
xfs_buf_ioerror(bp, EFSCORRUPTED);
}

bp->b_iodone = NULL;
xfs_buf_ioend(bp, 0);
}

static int
__xfs_dir2_free_read(
struct xfs_trans *tp,
struct xfs_inode *dp,
xfs_dablk_t fbno,
xfs_daddr_t mappedbno,
struct xfs_buf **bpp)
{
return xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp,
XFS_DATA_FORK, xfs_dir2_free_verify);
}

int
xfs_dir2_free_read(
struct xfs_trans *tp,
struct xfs_inode *dp,
xfs_dablk_t fbno,
struct xfs_buf **bpp)
{
return __xfs_dir2_free_read(tp, dp, fbno, -1, bpp);
}

static int
xfs_dir2_free_try_read(
struct xfs_trans *tp,
struct xfs_inode *dp,
xfs_dablk_t fbno,
struct xfs_buf **bpp)
{
return __xfs_dir2_free_read(tp, dp, fbno, -2, bpp);
}

/*
* Log entries from a freespace block.
*/
Expand Down Expand Up @@ -394,12 +445,10 @@ xfs_dir2_leafn_lookup_for_addname(
*/
if (curbp)
xfs_trans_brelse(tp, curbp);
/*
* Read the free block.
*/
error = xfs_da_read_buf(tp, dp,

error = xfs_dir2_free_read(tp, dp,
xfs_dir2_db_to_da(mp, newfdb),
-1, &curbp, XFS_DATA_FORK, NULL);
&curbp);
if (error)
return error;
free = curbp->b_addr;
Expand Down Expand Up @@ -825,6 +874,77 @@ xfs_dir2_leafn_rebalance(
}
}

static int
xfs_dir2_data_block_free(
xfs_da_args_t *args,
struct xfs_dir2_data_hdr *hdr,
struct xfs_dir2_free *free,
xfs_dir2_db_t fdb,
int findex,
struct xfs_buf *fbp,
int longest)
{
struct xfs_trans *tp = args->trans;
int logfree = 0;

if (!hdr) {
/* One less used entry in the free table. */
be32_add_cpu(&free->hdr.nused, -1);
xfs_dir2_free_log_header(tp, fbp);

/*
* If this was the last entry in the table, we can trim the
* table size back. There might be other entries at the end
* referring to non-existent data blocks, get those too.
*/
if (findex == be32_to_cpu(free->hdr.nvalid) - 1) {
int i; /* free entry index */

for (i = findex - 1; i >= 0; i--) {
if (free->bests[i] != cpu_to_be16(NULLDATAOFF))
break;
}
free->hdr.nvalid = cpu_to_be32(i + 1);
logfree = 0;
} else {
/* Not the last entry, just punch it out. */
free->bests[findex] = cpu_to_be16(NULLDATAOFF);
logfree = 1;
}
/*
* If there are no useful entries left in the block,
* get rid of the block if we can.
*/
if (!free->hdr.nused) {
int error;

error = xfs_dir2_shrink_inode(args, fdb, fbp);
if (error == 0) {
fbp = NULL;
logfree = 0;
} else if (error != ENOSPC || args->total != 0)
return error;
/*
* It's possible to get ENOSPC if there is no
* space reservation. In this case some one
* else will eventually get rid of this block.
*/
}
} else {
/*
* Data block is not empty, just set the free entry to the new
* value.
*/
free->bests[findex] = cpu_to_be16(longest);
logfree = 1;
}

/* Log the free entry that changed, unless we got rid of it. */
if (logfree)
xfs_dir2_free_log_bests(tp, fbp, findex, findex);
return 0;
}

/*
* Remove an entry from a node directory.
* This removes the leaf entry and the data entry,
Expand Down Expand Up @@ -908,15 +1028,14 @@ xfs_dir2_leafn_remove(
xfs_dir2_db_t fdb; /* freeblock block number */
int findex; /* index in freeblock entries */
xfs_dir2_free_t *free; /* freeblock structure */
int logfree; /* need to log free entry */

/*
* Convert the data block number to a free block,
* read in the free block.
*/
fdb = xfs_dir2_db_to_fdb(mp, db);
error = xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, fdb),
-1, &fbp, XFS_DATA_FORK, NULL);
error = xfs_dir2_free_read(tp, dp, xfs_dir2_db_to_da(mp, fdb),
&fbp);
if (error)
return error;
free = fbp->b_addr;
Expand Down Expand Up @@ -954,68 +1073,12 @@ xfs_dir2_leafn_remove(
* If we got rid of the data block, we can eliminate that entry
* in the free block.
*/
if (hdr == NULL) {
/*
* One less used entry in the free table.
*/
be32_add_cpu(&free->hdr.nused, -1);
xfs_dir2_free_log_header(tp, fbp);
/*
* If this was the last entry in the table, we can
* trim the table size back. There might be other
* entries at the end referring to non-existent
* data blocks, get those too.
*/
if (findex == be32_to_cpu(free->hdr.nvalid) - 1) {
int i; /* free entry index */

for (i = findex - 1;
i >= 0 &&
free->bests[i] == cpu_to_be16(NULLDATAOFF);
i--)
continue;
free->hdr.nvalid = cpu_to_be32(i + 1);
logfree = 0;
}
/*
* Not the last entry, just punch it out.
*/
else {
free->bests[findex] = cpu_to_be16(NULLDATAOFF);
logfree = 1;
}
/*
* If there are no useful entries left in the block,
* get rid of the block if we can.
*/
if (!free->hdr.nused) {
error = xfs_dir2_shrink_inode(args, fdb, fbp);
if (error == 0) {
fbp = NULL;
logfree = 0;
} else if (error != ENOSPC || args->total != 0)
return error;
/*
* It's possible to get ENOSPC if there is no
* space reservation. In this case some one
* else will eventually get rid of this block.
*/
}
}
/*
* Data block is not empty, just set the free entry to
* the new value.
*/
else {
free->bests[findex] = cpu_to_be16(longest);
logfree = 1;
}
/*
* Log the free entry that changed, unless we got rid of it.
*/
if (logfree)
xfs_dir2_free_log_bests(tp, fbp, findex, findex);
error = xfs_dir2_data_block_free(args, hdr, free,
fdb, findex, fbp, longest);
if (error)
return error;
}

xfs_dir2_leafn_check(dp, bp);
/*
* Return indication of whether this leaf block is empty enough
Expand Down Expand Up @@ -1453,9 +1516,9 @@ xfs_dir2_node_addname_int(
* This should be really rare, so there's no reason
* to avoid it.
*/
error = xfs_da_read_buf(tp, dp,
xfs_dir2_db_to_da(mp, fbno), -2,
&fbp, XFS_DATA_FORK, NULL);
error = xfs_dir2_free_try_read(tp, dp,
xfs_dir2_db_to_da(mp, fbno),
&fbp);
if (error)
return error;
if (!fbp)
Expand Down Expand Up @@ -1518,8 +1581,9 @@ xfs_dir2_node_addname_int(
* that was just allocated.
*/
fbno = xfs_dir2_db_to_fdb(mp, dbno);
error = xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, fbno), -2,
&fbp, XFS_DATA_FORK, NULL);
error = xfs_dir2_free_try_read(tp, dp,
xfs_dir2_db_to_da(mp, fbno),
&fbp);
if (error)
return error;

Expand Down Expand Up @@ -1915,17 +1979,15 @@ xfs_dir2_node_trim_free(
/*
* Read the freespace block.
*/
error = xfs_da_read_buf(tp, dp, (xfs_dablk_t)fo, -2, &bp,
XFS_DATA_FORK, NULL);
error = xfs_dir2_free_try_read(tp, dp, fo, &bp);
if (error)
return error;
/*
* There can be holes in freespace. If fo is a hole, there's
* nothing to do.
*/
if (bp == NULL) {
if (!bp)
return 0;
}
free = bp->b_addr;
ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC));
/*
Expand Down
2 changes: 2 additions & 0 deletions fs/xfs/xfs_dir2_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ extern int xfs_dir2_node_removename(struct xfs_da_args *args);
extern int xfs_dir2_node_replace(struct xfs_da_args *args);
extern int xfs_dir2_node_trim_free(struct xfs_da_args *args, xfs_fileoff_t fo,
int *rvalp);
extern int xfs_dir2_free_read(struct xfs_trans *tp, struct xfs_inode *dp,
xfs_dablk_t fbno, struct xfs_buf **bpp);

/* xfs_dir2_sf.c */
extern xfs_ino_t xfs_dir2_sf_get_parent_ino(struct xfs_dir2_sf_hdr *sfp);
Expand Down

0 comments on commit 2025207

Please sign in to comment.