Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2025207c authored by Dave Chinner's avatar Dave Chinner Committed by Ben Myers
Browse files

xfs: factor dir2 free block reading



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: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarPhil White <pwhite@sgi.com>
Signed-off-by: default avatarBen Myers <bpm@sgi.com>
parent 82025d7f
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -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;
+140 −78
Original line number Diff line number Diff line
@@ -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.
 */
@@ -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;
@@ -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,
@@ -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;
@@ -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)
		error = xfs_dir2_data_block_free(args, hdr, free,
						 fdb, findex, fbp, longest);
		if (error)
			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);
	}

	xfs_dir2_leafn_check(dp, bp);
	/*
	 * Return indication of whether this leaf block is empty enough
@@ -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)
@@ -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;

@@ -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));
	/*
+2 −0
Original line number Diff line number Diff line
@@ -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);