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

Commit 4254b0bb authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Felix Blyakher
Browse files

xfs: untangle xfs_dialloc



Clarify the control flow in xfs_dialloc.  Factor out a helper to go to the
next node from the current one and improve the control flow by expanding
composite if statements and using gotos.

The xfs_ialloc_next_rec helper is borrowed from Dave Chinners dynamic
allocation policy patches.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarAlex Elder <aelder@sgi.com>
Signed-off-by: default avatarFelix Blyakher <felixb@sgi.com>
parent 0b48db80
Loading
Loading
Loading
Loading
+138 −153
Original line number Diff line number Diff line
@@ -589,6 +589,37 @@ xfs_ialloc_ag_select(
	}
}

/*
 * Try to retrieve the next record to the left/right from the current one.
 */
STATIC int
xfs_ialloc_next_rec(
	struct xfs_btree_cur	*cur,
	xfs_inobt_rec_incore_t	*rec,
	int			*done,
	int			left)
{
	int                     error;
	int			i;

	if (left)
		error = xfs_btree_decrement(cur, 0, &i);
	else
		error = xfs_btree_increment(cur, 0, &i);

	if (error)
		return error;
	*done = !i;
	if (i) {
		error = xfs_inobt_get_rec(cur, rec, &i);
		if (error)
			return error;
		XFS_WANT_CORRUPTED_RETURN(i == 1);
	}

	return 0;
}


/*
 * Visible inode allocation functions.
@@ -644,8 +675,8 @@ xfs_dialloc(
	int		j;		/* result code */
	xfs_mount_t	*mp;		/* file system mount structure */
	int		offset;		/* index of inode in chunk */
	xfs_agino_t	pagino;		/* parent's a.g. relative inode # */
	xfs_agnumber_t	pagno;		/* parent's allocation group number */
	xfs_agino_t	pagino;		/* parent's AG relative inode # */
	xfs_agnumber_t	pagno;		/* parent's AG number */
	xfs_inobt_rec_incore_t rec;	/* inode allocation record */
	xfs_agnumber_t	tagno;		/* testing allocation group number */
	xfs_btree_cur_t	*tcur;		/* temp cursor */
@@ -781,173 +812,125 @@ xfs_dialloc(
		goto error0;

	/*
	 * If in the same a.g. as the parent, try to get near the parent.
	 * If in the same AG as the parent, try to get near the parent.
	 */
	if (pagno == agno) {
		if ((error = xfs_inobt_lookup_le(cur, pagino, 0, 0, &i)))
			goto error0;
		if (i != 0 &&
		    (error = xfs_inobt_get_rec(cur, &rec, &j)) == 0 &&
		    j == 1 &&
		    rec.ir_freecount > 0) {
			/*
			 * Found a free inode in the same chunk
			 * as parent, done.
			 */
		}
		/*
		 * In the same a.g. as parent, but parent's chunk is full.
		 */
		else {
		int		doneleft;	/* done, to the left */
		int		doneright;	/* done, to the right */

		error = xfs_inobt_lookup_le(cur, pagino, 0, 0, &i);
		if (error)
			goto error0;
			ASSERT(i == 1);
			ASSERT(j == 1);
			/*
			 * Duplicate the cursor, search left & right
			 * simultaneously.
			 */
			if ((error = xfs_btree_dup_cursor(cur, &tcur)))
		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);

		error = xfs_inobt_get_rec(cur, &rec, &j);
		if (error)
			goto error0;
		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);

		if (rec.ir_freecount > 0) {
			/*
			 * Search left with tcur, back up 1 record.
			 * Found a free inode in the same chunk
			 * as the parent, done.
			 */
			if ((error = xfs_btree_decrement(tcur, 0, &i)))
				goto error1;
			doneleft = !i;
			if (!doneleft) {
				error = xfs_inobt_get_rec(tcur, &trec, &i);
				if (error)
					goto error1;
				XFS_WANT_CORRUPTED_GOTO(i == 1, error1);
			goto alloc_inode;
		}


		/*
			 * Search right with cur, go forward 1 record.
		 * In the same AG as parent, but parent's chunk is full.
		 */
			if ((error = xfs_btree_increment(cur, 0, &i)))

		/* duplicate the cursor, search left & right simultaneously */
		error = xfs_btree_dup_cursor(cur, &tcur);
		if (error)
			goto error0;

		/* search left with tcur, back up 1 record */
		error = xfs_ialloc_next_rec(tcur, &trec, &doneleft, 1);
		if (error)
			goto error1;
			doneright = !i;
			if (!doneright) {
				error = xfs_inobt_get_rec(cur, &rec, &i);

		/* search right with cur, go forward 1 record. */
		error = xfs_ialloc_next_rec(cur, &rec, &doneright, 0);
		if (error)
			goto error1;
				XFS_WANT_CORRUPTED_GOTO(i == 1, error1);
			}

		/*
			 * Loop until we find the closest inode chunk
			 * with a free one.
		 * Loop until we find an inode chunk with a free inode.
		 */
		while (!doneleft || !doneright) {
				int	useleft;  /* using left inode
						     chunk this time */
			int	useleft;  /* using left inode chunk this time */

				/*
				 * Figure out which block is closer,
				 * if both are valid.
				 */
				if (!doneleft && !doneright)
					useleft =
						pagino -
						(trec.ir_startino +
						 XFS_INODES_PER_CHUNK - 1) <
			/* figure out the closer block if both are valid. */
			if (!doneleft && !doneright) {
				useleft = pagino -
				 (trec.ir_startino + XFS_INODES_PER_CHUNK - 1) <
				  rec.ir_startino - pagino;
				else
			} else {
				useleft = !doneleft;
				/*
				 * If checking the left, does it have
				 * free inodes?
				 */
			}

			/* free inodes to the left? */
			if (useleft && trec.ir_freecount) {
					/*
					 * Yes, set it up as the chunk to use.
					 */
				rec = trec;
					xfs_btree_del_cursor(cur,
						XFS_BTREE_NOERROR);
				xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
				cur = tcur;
					break;
				goto alloc_inode;
			}
				/*
				 * If checking the right, does it have
				 * free inodes?
				 */

			/* free inodes to the right? */
			if (!useleft && rec.ir_freecount) {
					/*
					 * Yes, it's already set up.
					 */
					xfs_btree_del_cursor(tcur,
						XFS_BTREE_NOERROR);
					break;
				xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
				goto alloc_inode;
			}
				/*
				 * If used the left, get another one
				 * further left.
				 */

			/* get next record to check */
			if (useleft) {
					if ((error = xfs_btree_decrement(tcur, 0,
							&i)))
						goto error1;
					doneleft = !i;
					if (!doneleft) {
						error = xfs_inobt_get_rec(
							    tcur, &trec, &i);
						if (error)
							goto error1;
						XFS_WANT_CORRUPTED_GOTO(i == 1,
							error1);
					}
				error = xfs_ialloc_next_rec(tcur, &trec,
								 &doneleft, 1);
			} else {
				error = xfs_ialloc_next_rec(cur, &rec,
								 &doneright, 0);
			}
				/*
				 * If used the right, get another one
				 * further right.
				 */
				else {
					if ((error = xfs_btree_increment(cur, 0,
							&i)))
						goto error1;
					doneright = !i;
					if (!doneright) {
						error = xfs_inobt_get_rec(
							    cur, &rec, &i);
			if (error)
				goto error1;
						XFS_WANT_CORRUPTED_GOTO(i == 1,
							error1);
					}
				}
		}
		ASSERT(!doneleft || !doneright);
	}
	}

	/*
	 * In a different a.g. from the parent.
	 * In a different AG from the parent.
	 * See if the most recently allocated block has any free.
	 */
	else if (be32_to_cpu(agi->agi_newino) != NULLAGINO) {
		if ((error = xfs_inobt_lookup_eq(cur,
				be32_to_cpu(agi->agi_newino), 0, 0, &i)))
		error = xfs_inobt_lookup_eq(cur, be32_to_cpu(agi->agi_newino),
					    0, 0, &i);
		if (error)
			goto error0;

		if (i == 1) {
			error = xfs_inobt_get_rec(cur, &rec, &j);
			if (error)
				goto error0;
		if (i == 1 &&
		    (error = xfs_inobt_get_rec(cur, &rec, &j)) == 0 &&
		    j == 1 &&
		    rec.ir_freecount > 0) {

			if (j == 1 && rec.ir_freecount > 0) {
				/*
			 * The last chunk allocated in the group still has
			 * a free inode.
				 * The last chunk allocated in the group
				 * still has a free inode.
				 */
				goto alloc_inode;
			}
		}

		/*
		 * None left in the last group, search the whole a.g.
		 * None left in the last group, search the whole AG
		 */
		else {
		error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i);
		if (error)
			goto error0;
			if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i)))
				goto error0;
			ASSERT(i == 1);
		XFS_WANT_CORRUPTED_GOTO(i == 1, error0);

		for (;;) {
			error = xfs_inobt_get_rec(cur, &rec, &i);
			if (error)
@@ -955,12 +938,14 @@ xfs_dialloc(
			XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
			if (rec.ir_freecount > 0)
				break;
				if ((error = xfs_btree_increment(cur, 0, &i)))
			error = xfs_btree_increment(cur, 0, &i);
			if (error)
				goto error0;
			XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
		}
	}
	}

alloc_inode:
	offset = xfs_ialloc_find_free(&rec.ir_free);
	ASSERT(offset >= 0);
	ASSERT(offset < XFS_INODES_PER_CHUNK);