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: Adrian Hunter <ext-adrian.hunter@nokia.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
This commit is contained in:
Adrian Hunter 2009-01-27 15:22:54 +02:00 committed by Artem Bityutskiy
parent 6f7ab6d458
commit 4a29d2005b

View File

@ -556,23 +556,23 @@ no_space:
}
/**
* 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,
struct ubifs_pnode *pnode)
static struct ubifs_pnode *next_pnode_to_dirty(struct ubifs_info *c,
struct ubifs_pnode *pnode)
{
struct ubifs_nnode *nnode;
int iip;
/* 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);
}