[PATCH 3/5] xfs: factor free block index lookup from xfs_dir2_node_addname_int()

Dave Chinner
2018-10-25T07:27:30Z

From: Dave Chinner <dchinner@redhat.com>

Simplify the logic in xfs_dir2_node_addname_int() by factoring out
the free block index lookup code that finds a block with enough free
space for the entry to be added. The code that is moved gets a major
cleanup at the same time, but there is no algorithm change here.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
fs/xfs/libxfs/xfs_dir2_node.c | 195 ++++++++++++++++++----------------
1 file changed, 105 insertions(+), 90 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
index 7c674c55e004..1ecf41e380fb 100644
--- a/fs/xfs/libxfs/xfs_dir2_node.c
+++ b/fs/xfs/libxfs/xfs_dir2_node.c
@@ -1638,7 +1638,7 @@ xfs_dir2_node_add_datablk(
int error;

/* Not allowed to allocate, return failure. */
- if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0)
+ if (args->total == 0)
return -ENOSPC;

/* Allocate and initialize the new data block. */
@@ -1735,43 +1735,29 @@ xfs_dir2_node_add_datablk(
return 0;
}

-/*
- * Add the data entry for a node-format directory name addition.
- * The leaf entry is added in xfs_dir2_leafn_add.
- * We may enter with a freespace block that the lookup found.
- */
-static int /* error */
-xfs_dir2_node_addname_int(
- xfs_da_args_t *args, /* operation arguments */
- xfs_da_state_blk_t *fblk) /* optional freespace block */
+static int
+xfs_dir2_node_find_freeblk(
+ struct xfs_da_args *args,
+ struct xfs_da_state_blk *fblk,
+ xfs_dir2_db_t *dbnop,
+ struct xfs_buf **fbpp,
+ int *findexp,
+ int length)
{
- xfs_dir2_data_hdr_t *hdr; /* data block header */
- xfs_dir2_db_t dbno; /* data block number */
- struct xfs_buf *dbp; /* data block buffer */
- xfs_dir2_data_entry_t *dep; /* data entry pointer */
- xfs_inode_t *dp; /* incore directory inode */
- xfs_dir2_data_unused_t *dup; /* data unused entry pointer */
- int error; /* error return value */
- xfs_dir2_db_t fbno; /* freespace block number */
- struct xfs_buf *fbp; /* freespace buffer */
- int findex; /* freespace entry index */
- xfs_dir2_free_t *free=NULL; /* freespace block structure */
- xfs_dir2_db_t ifbno; /* initial freespace block no */
- xfs_dir2_db_t lastfbno=0; /* highest freespace block no */
- int length; /* length of the new entry */
- int logfree = 0; /* need to log free entry */
- int needlog = 0; /* need to log data header */
- int needscan = 0; /* need to rescan data frees */
- __be16 *tagp; /* data entry tag pointer */
- xfs_trans_t *tp; /* transaction pointer */
- __be16 *bests;
+ struct xfs_inode *dp = args->dp;
+ struct xfs_trans *tp = args->trans;
+ struct xfs_buf *fbp = NULL;
+ int findex;
+ xfs_dir2_db_t lastfbno;
+ xfs_dir2_db_t ifbno = -1;
+ xfs_dir2_db_t dbno = -1;
+ xfs_dir2_db_t fbno = -1;
+ xfs_dir2_free_t *free = NULL;
struct xfs_dir3_icfree_hdr freehdr;
- struct xfs_dir2_data_free *bf;
- xfs_dir2_data_aoff_t aoff;
+ __be16 *bests;
+ xfs_fileoff_t fo;
+ int error;

- dp = args->dp;
- tp = args->trans;
- length = dp->d_ops->data_entsize(args->namelen);
/*
* If we came in with a freespace block that means that lookup
* found an entry with our hash value. This is the freespace
@@ -1779,56 +1765,44 @@ xfs_dir2_node_addname_int(
*/
if (fblk) {
fbp = fblk->bp;
- /*
- * Remember initial freespace block number.
- */
- ifbno = fblk->blkno;
free = fbp->b_addr;
findex = fblk->index;
- bests = dp->d_ops->free_bests_p(free);
- dp->d_ops->free_hdr_from_disk(&freehdr, free);
-
- /*
- * This means the free entry showed that the data block had
- * space for our entry, so we remembered it.
- * Use that data block.
- */
if (findex >= 0) {
+ /* caller already found the freespace for us. */
+ bests = dp->d_ops->free_bests_p(free);
+ dp->d_ops->free_hdr_from_disk(&freehdr, free);
+
ASSERT(findex < freehdr.nvalid);
ASSERT(be16_to_cpu(bests[findex]) != NULLDATAOFF);
ASSERT(be16_to_cpu(bests[findex]) >= length);
dbno = freehdr.firstdb + findex;
- goto found_block;
- } else {
- /*
- * The data block looked at didn't have enough room.
- * We'll start at the beginning of the freespace entries.
- */
- dbno = -1;
- findex = 0;
+ goto out;
}
- } else {
+
/*
- * Didn't come in with a freespace block, so no data block.
+ * The data block looked at didn't have enough room.
+ * We'll start at the beginning of the freespace entries.
*/
- ifbno = dbno = -1;
- fbp = NULL;
- findex = 0;
+ ifbno = fblk->blkno;
+ fbno = ifbno;
}
+ ASSERT(dbno == -1);
+ findex = 0;

/*
- * If we don't have a data block yet, we're going to scan the
- * freespace blocks looking for one. Figure out what the
- * highest freespace block number is.
+ * If we don't have a data block yet, we're going to scan the freespace
+ * blocks looking for one. Figure out what the highest freespace block
+ * number is.
*/
- if (dbno == -1) {
- xfs_fileoff_t fo; /* freespace block number */
+ error = xfs_bmap_last_offset(dp, &fo, XFS_DATA_FORK);
+ if (error)
+ return error;
+ lastfbno = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)fo);
+
+ /* If we haven't get a search start block, set it now */
+ if (fbno == -1)
+ fbno = xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET);

- if ((error = xfs_bmap_last_offset(dp, &fo, XFS_DATA_FORK)))
- return error;
- lastfbno = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)fo);
- fbno = ifbno;
- }
/*
* While we haven't identified a data block, search the freeblock
* data for a good data block. If we find a null freeblock entry,
@@ -1839,17 +1813,10 @@ xfs_dir2_node_addname_int(
* If we don't have a freeblock in hand, get the next one.
*/
if (fbp == NULL) {
- /*
- * Happens the first time through unless lookup gave
- * us a freespace block to start with.
- */
- if (++fbno == 0)
- fbno = xfs_dir2_byte_to_db(args->geo,
- XFS_DIR2_FREE_OFFSET);
/*
* If it's ifbno we already looked at it.
*/
- if (fbno == ifbno)
+ if (++fbno == ifbno)
fbno++;
/*
* If it's off the end we're done.
@@ -1900,6 +1867,62 @@ xfs_dir2_node_addname_int(
}
}
}
+out:
+ *dbnop = dbno;
+ *fbpp = fbp;
+ *findexp = findex;
+ return 0;
+}
+
+
+/*
+ * Add the data entry for a node-format directory name addition.
+ * The leaf entry is added in xfs_dir2_leafn_add.
+ * We may enter with a freespace block that the lookup found.
+ */
+static int /* error */
+xfs_dir2_node_addname_int(
+ xfs_da_args_t *args, /* operation arguments */
+ xfs_da_state_blk_t *fblk) /* optional freespace block */
+{
+ xfs_dir2_data_hdr_t *hdr; /* data block header */
+ xfs_dir2_db_t dbno; /* data block number */
+ struct xfs_buf *dbp; /* data block buffer */
+ xfs_dir2_data_entry_t *dep; /* data entry pointer */
+ xfs_inode_t *dp; /* incore directory inode */
+ xfs_dir2_data_unused_t *dup; /* data unused entry pointer */
+ int error; /* error return value */
+ struct xfs_buf *fbp; /* freespace buffer */
+ int findex; /* freespace entry index */
+ xfs_dir2_free_t *free=NULL; /* freespace block structure */
+ int length; /* length of the new entry */
+ int logfree = 0; /* need to log free entry */
+ int needlog = 0; /* need to log data header */
+ int needscan = 0; /* need to rescan data frees */
+ __be16 *tagp; /* data entry tag pointer */
+ xfs_trans_t *tp; /* transaction pointer */
+ __be16 *bests;
+ struct xfs_dir2_data_free *bf;
+ xfs_dir2_data_aoff_t aoff;
+
+ dp = args->dp;
+ tp = args->trans;
+ length = dp->d_ops->data_entsize(args->namelen);
+
+ error = xfs_dir2_node_find_freeblk(args, fblk, &dbno, &fbp, &findex,
+ length);
+ if (error)
+ return error;
+
+ /*
+ * Now we know if we must allocate blocks, so if we are checking whether
+ * we can insert without allocation then we can return now.
+ */
+ if (args->op_flags & XFS_DA_OP_JUSTCHECK) {
+ if (dbno != -1)
+ return 0;
+ return -ENOSPC;
+ }

/*
* If we don't have a data block, we need to allocate one and make
@@ -1911,29 +1934,21 @@ xfs_dir2_node_addname_int(
if (error)
return error;

- /* setup current free block buffer */
- free = fbp->b_addr;
- bests = dp->d_ops->free_bests_p(free);
-
/* we're going to have to log the free block index later */
logfree = 1;
} else {
-found_block:
- /* If just checking, we succeeded. */
- if (args->op_flags & XFS_DA_OP_JUSTCHECK)
- return 0;
-
/* Read the data block in. */
error = xfs_dir3_data_read(tp, dp,
xfs_dir2_db_to_da(args->geo, dbno),
-1, &dbp);
if (error)
return error;
-
- /* suppress gcc maybe-used-initialised warning */
- bests = dp->d_ops->free_bests_p(free);
}

+ /* setup current free block buffer */
+ free = fbp->b_addr;
+ bests = dp->d_ops->free_bests_p(free);
+
/* setup for data block up now */
hdr = dbp->b_addr;
bf = dp->d_ops->data_bestfree_p(hdr);
--
2.19.1