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

Commit 4a29d200 authored by Adrian Hunter's avatar Adrian Hunter Committed by Artem Bityutskiy
Browse files

UBIFS: fix LPT out-of-space bug (again)



The function to traverse and dirty the LPT was still not
dirtying all nodes, with the result that the LPT could
run out of space.

Signed-off-by: default avatarAdrian Hunter <ext-adrian.hunter@nokia.com>
Signed-off-by: default avatarArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
parent 6f7ab6d4
Loading
Loading
Loading
Loading
+32 −12
Original line number Diff line number Diff line
@@ -556,13 +556,15 @@ static int write_cnodes(struct ubifs_info *c)
}

/**
 * next_pnode - find next pnode.
 * next_pnode_to_dirty - find next pnode to dirty.
 * @c: UBIFS file-system description object
 * @pnode: pnode
 *
 * This function returns the next pnode or %NULL if there are no more pnodes.
 * This function returns the next pnode to dirty or %NULL if there are no more
 * pnodes.  Note that pnodes that have never been written (lnum == 0) are
 * skipped.
 */
static struct ubifs_pnode *next_pnode(struct ubifs_info *c,
static struct ubifs_pnode *next_pnode_to_dirty(struct ubifs_info *c,
					       struct ubifs_pnode *pnode)
{
	struct ubifs_nnode *nnode;
@@ -570,9 +572,7 @@ static struct ubifs_pnode *next_pnode(struct ubifs_info *c,

	/* Try to go right */
	nnode = pnode->parent;
	iip = pnode->iip + 1;
	if (iip < UBIFS_LPT_FANOUT) {
		/* We assume here that LEB zero is never an LPT LEB */
	for (iip = pnode->iip + 1; iip < UBIFS_LPT_FANOUT; iip++) {
		if (nnode->nbranch[iip].lnum)
			return ubifs_get_pnode(c, nnode, iip);
	}
@@ -583,8 +583,11 @@ static struct ubifs_pnode *next_pnode(struct ubifs_info *c,
		nnode = nnode->parent;
		if (!nnode)
			return NULL;
		/* We assume here that LEB zero is never an LPT LEB */
	} while (iip >= UBIFS_LPT_FANOUT || !nnode->nbranch[iip].lnum);
		for (; iip < UBIFS_LPT_FANOUT; iip++) {
			if (nnode->nbranch[iip].lnum)
				break;
		}
       } while (iip >= UBIFS_LPT_FANOUT);

	/* Go right */
	nnode = ubifs_get_nnode(c, nnode, iip);
@@ -593,12 +596,29 @@ static struct ubifs_pnode *next_pnode(struct ubifs_info *c,

	/* Go down to level 1 */
	while (nnode->level > 1) {
		nnode = ubifs_get_nnode(c, nnode, 0);
		for (iip = 0; iip < UBIFS_LPT_FANOUT; iip++) {
			if (nnode->nbranch[iip].lnum)
				break;
		}
		if (iip >= UBIFS_LPT_FANOUT) {
			/*
			 * Should not happen, but we need to keep going
			 * if it does.
			 */
			iip = 0;
		}
		nnode = ubifs_get_nnode(c, nnode, iip);
		if (IS_ERR(nnode))
			return (void *)nnode;
	}

	return ubifs_get_pnode(c, nnode, 0);
	for (iip = 0; iip < UBIFS_LPT_FANOUT; iip++)
		if (nnode->nbranch[iip].lnum)
			break;
	if (iip >= UBIFS_LPT_FANOUT)
		/* Should not happen, but we need to keep going if it does */
		iip = 0;
	return ubifs_get_pnode(c, nnode, iip);
}

/**
@@ -688,7 +708,7 @@ static int make_tree_dirty(struct ubifs_info *c)
	pnode = pnode_lookup(c, 0);
	while (pnode) {
		do_make_pnode_dirty(c, pnode);
		pnode = next_pnode(c, pnode);
		pnode = next_pnode_to_dirty(c, pnode);
		if (IS_ERR(pnode))
			return PTR_ERR(pnode);
	}