n = DIV_ROUND_UP(c->pnode_cnt, UBIFS_LPT_FANOUT);
c->nnode_cnt = n; for (i = 1; i < c->lpt_hght; i++) {
n = DIV_ROUND_UP(n, UBIFS_LPT_FANOUT);
c->nnode_cnt += n;
}
/** *ubifs_calc_lpt_geom-calculateandchecksizesfortheLPTarea. *@c:theUBIFSfile-systemdescriptionobject * *Thisfunctionreturns%0onsuccessandanegativeerrorcodeonfailure.
*/ int ubifs_calc_lpt_geom(struct ubifs_info *c)
{ int lebs_needed; longlong sz;
do_calc_lpt_geom(c);
/* Verify that lpt_lebs is big enough */
sz = c->lpt_sz * 2; /* Must have at least 2 times the size */
lebs_needed = div_u64(sz + c->leb_size - 1, c->leb_size); if (lebs_needed > c->lpt_lebs) {
ubifs_err(c, "too few LPT LEBs"); return -EINVAL;
}
/* Verify that ltab fits in a single LEB (since ltab is a single node */ if (c->ltab_sz > c->leb_size) {
ubifs_err(c, "LPT ltab too big"); return -EINVAL;
}
c->check_lpt_free = c->big_lpt; return0;
}
/** *calc_dflt_lpt_geom-calculatedefaultLPTgeometry. *@c:theUBIFSfile-systemdescriptionobject *@main_lebs:numberofmainareaLEBsispassedandreturnedhere *@big_lpt:whethertheLPTareais"big"isreturnedhere * *ThesizeoftheLPTareadependsonparametersthatthemselvesaredependent *onthesizeoftheLPTarea.Thisfunction,successivelyrecalculatestheLPT *areageometryuntiltheparametersandresultantgeometryareconsistent. * *Thisfunctionreturns%0onsuccessandanegativeerrorcodeonfailure.
*/ staticint calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs, int *big_lpt)
{ int i, lebs_needed; longlong sz;
/* Start by assuming the minimum number of LPT LEBs */
c->lpt_lebs = UBIFS_MIN_LPT_LEBS;
c->main_lebs = *main_lebs - c->lpt_lebs; if (c->main_lebs <= 0) return -EINVAL;
/* And assume we will use the small LPT model */
c->big_lpt = 0;
/* Small LPT model must have lpt_sz < leb_size */ if (c->lpt_sz > c->leb_size) { /* Nope, so try again using big LPT model */
c->big_lpt = 1;
do_calc_lpt_geom(c);
}
/* Now check there are enough LPT LEBs */ for (i = 0; i < 64 ; i++) {
sz = c->lpt_sz * 4; /* Allow 4 times the size */
lebs_needed = div_u64(sz + c->leb_size - 1, c->leb_size); if (lebs_needed > c->lpt_lebs) { /* Not enough LPT LEBs so try again with more */
c->lpt_lebs = lebs_needed;
c->main_lebs = *main_lebs - c->lpt_lebs; if (c->main_lebs <= 0) return -EINVAL;
do_calc_lpt_geom(c); continue;
} if (c->ltab_sz > c->leb_size) {
ubifs_err(c, "LPT ltab too big"); return -EINVAL;
}
*main_lebs = c->main_lebs;
*big_lpt = c->big_lpt; return0;
} return -EINVAL;
}
/** *pack_bits-packbitfieldsend-to-end. *@c:UBIFSfile-systemdescriptionobject *@addr:addressatwhichtopack(passedandnextaddressreturned) *@pos:bitpositionatwhichtopack(passedandnextpositionreturned) *@val:valuetopack *@nrbits:numberofbitsofvaluetopack(1-32)
*/ staticvoid pack_bits(conststruct ubifs_info *c, uint8_t **addr, int *pos, uint32_t val, int nrbits)
{
uint8_t *p = *addr; int b = *pos;
pack_bits(c, &addr, &pos, UBIFS_LPT_NNODE, UBIFS_LPT_TYPE_BITS); if (c->big_lpt)
pack_bits(c, &addr, &pos, nnode->num, c->pcnt_bits); for (i = 0; i < UBIFS_LPT_FANOUT; i++) { int lnum = nnode->nbranch[i].lnum;
if (!parent) return1;
shft = (c->lpt_hght - parent->level) * UBIFS_LPT_FANOUT_SHIFT;
num = parent->num ^ (1 << shft);
num |= (UBIFS_LPT_FANOUT + iip) << shft; return num;
}
/** *calc_pnode_num_from_parent-calculatepnodenumber. *@c:UBIFSfile-systemdescriptionobject *@parent:parentnnode *@iip:indexinparent * *Thepnodenumberisanumberthatuniquelyidentifiesapnodeandcanbeused *easilytotraversethetreefromtheroottothatpnode. * *Thisfunctioncalculatesandreturnsthepnodenumberbasedontheparent's *nnodenumberandtheindexinparent.
*/ staticint calc_pnode_num_from_parent(conststruct ubifs_info *c, struct ubifs_nnode *parent, int iip)
{ int i, n = c->lpt_hght - 1, pnum = parent->num, num = 0;
for (i = 0; i < n; i++) {
num <<= UBIFS_LPT_FANOUT_SHIFT;
num |= pnum & (UBIFS_LPT_FANOUT - 1);
pnum >>= UBIFS_LPT_FANOUT_SHIFT;
}
num <<= UBIFS_LPT_FANOUT_SHIFT;
num |= iip; return num;
}
/** *ubifs_create_dflt_lpt-createdefaultLPT. *@c:UBIFSfile-systemdescriptionobject *@main_lebs:numberofmainareaLEBsispassedandreturnedhere *@lpt_first:LEBnumberoffirstLPTLEB *@lpt_lebs:numberofLEBsforLPTispassedandreturnedhere *@big_lpt:usebigLPTmodelispassedandreturnedhere *@hash:hashoftheLPTisreturnedhere * *Thisfunctionreturns%0onsuccessandanegativeerrorcodeonfailure.
*/ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, int *lpt_lebs, int *big_lpt, u8 *hash)
{ int lnum, err = 0, node_sz, iopos, i, j, cnt, len, alen, row; int blnum, boffs, bsz, bcnt; struct ubifs_pnode *pnode = NULL; struct ubifs_nnode *nnode = NULL; void *buf = NULL, *p; struct ubifs_lpt_lprops *ltab = NULL; int *lsave = NULL; struct shash_desc *desc;
/* *Tocalculatetheinternalnodebranches,wekeepinformationabout *thelevelbelow.
*/
blnum = lnum; /* LEB number of level below */
boffs = 0; /* Offset of level below */
bcnt = cnt; /* Number of nodes in level below */
bsz = c->pnode_sz; /* Size of nodes in level below */
/* Add all remaining pnodes */ for (i = 1; i < cnt; i++) { if (len + c->pnode_sz > c->leb_size) {
alen = ALIGN(len, c->min_io_size);
set_ltab(c, lnum, c->leb_size - alen, alen - len);
memset(p, 0xff, alen - len);
err = ubifs_leb_change(c, lnum++, buf, alen); if (err) goto out;
p = buf;
len = 0;
}
ubifs_pack_pnode(c, p, pnode);
err = ubifs_shash_update(c, desc, p, c->pnode_sz); if (err) goto out;
p += c->pnode_sz;
len += c->pnode_sz; /* *pnodesaresimplynumberedlefttorightstartingatzero, *whichmeansthepnodenumbercanbeusedeasilytotraverse *downthetreetothecorrespondingpnode.
*/
pnode->num += 1;
}
row = 0; for (i = UBIFS_LPT_FANOUT; cnt > i; i <<= UBIFS_LPT_FANOUT_SHIFT)
row += 1; /* Add all nnodes, one level at a time */ while (1) { /* Number of internal nodes (nnodes) at next level */
cnt = DIV_ROUND_UP(cnt, UBIFS_LPT_FANOUT); for (i = 0; i < cnt; i++) { if (len + c->nnode_sz > c->leb_size) {
alen = ALIGN(len, c->min_io_size);
set_ltab(c, lnum, c->leb_size - alen,
alen - len);
memset(p, 0xff, alen - len);
err = ubifs_leb_change(c, lnum++, buf, alen); if (err) goto out;
p = buf;
len = 0;
} /* Only 1 nnode at this level, so it is the root */ if (cnt == 1) {
c->lpt_lnum = lnum;
c->lpt_offs = len;
} /* Set branches to the level below */ for (j = 0; j < UBIFS_LPT_FANOUT; j++) { if (bcnt) { if (boffs + bsz > c->leb_size) {
blnum += 1;
boffs = 0;
}
nnode->nbranch[j].lnum = blnum;
nnode->nbranch[j].offs = boffs;
boffs += bsz;
bcnt--;
} else {
nnode->nbranch[j].lnum = 0;
nnode->nbranch[j].offs = 0;
}
}
nnode->num = calc_nnode_num(row, i);
ubifs_pack_nnode(c, p, nnode);
p += c->nnode_sz;
len += c->nnode_sz;
} /* Only 1 nnode at this level, so it is the root */ if (cnt == 1) break; /* Update the information about the level below */
bcnt = cnt;
bsz = c->nnode_sz;
row -= 1;
}
if (*big_lpt) { /* Need to add LPT's save table */ if (len + c->lsave_sz > c->leb_size) {
alen = ALIGN(len, c->min_io_size);
set_ltab(c, lnum, c->leb_size - alen, alen - len);
memset(p, 0xff, alen - len);
err = ubifs_leb_change(c, lnum++, buf, alen); if (err) goto out;
p = buf;
len = 0;
}
c->lsave_lnum = lnum;
c->lsave_offs = len;
for (i = 0; i < c->lsave_cnt && i < *main_lebs; i++)
lsave[i] = c->main_first + i; for (; i < c->lsave_cnt; i++)
lsave[i] = c->main_first;
ubifs_pack_lsave(c, p, lsave);
p += c->lsave_sz;
len += c->lsave_sz;
}
/* Need to add LPT's own LEB properties table */ if (len + c->ltab_sz > c->leb_size) {
alen = ALIGN(len, c->min_io_size);
set_ltab(c, lnum, c->leb_size - alen, alen - len);
memset(p, 0xff, alen - len);
err = ubifs_leb_change(c, lnum++, buf, alen); if (err) goto out;
p = buf;
len = 0;
}
c->ltab_lnum = lnum;
c->ltab_offs = len;
/* Update ltab before packing it */
len += c->ltab_sz;
alen = ALIGN(len, c->min_io_size);
set_ltab(c, lnum, c->leb_size - alen, alen - len);
for (i = 0; i < UBIFS_LPT_FANOUT; i++) { if (!new_pnode->lprops[i].lnum) return;
ubifs_replace_cat(c, &old_pnode->lprops[i],
&new_pnode->lprops[i]);
}
}
/** *ubifs_unpack_nnode-unpackannode. *@c:UBIFSfile-systemdescriptionobject *@buf:buffercontainingpackednnodetounpack *@nnode:nnodestructuretofill * *Thisfunctionreturns%0onsuccessandanegativeerrorcodeonfailure.
*/ int ubifs_unpack_nnode(conststruct ubifs_info *c, void *buf, struct ubifs_nnode *nnode)
{
uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; int i, pos = 0, err;
err = check_lpt_type(c, &addr, &pos, UBIFS_LPT_NNODE); if (err) return err; if (c->big_lpt)
nnode->num = ubifs_unpack_bits(c, &addr, &pos, c->pcnt_bits); for (i = 0; i < UBIFS_LPT_FANOUT; i++) { int lnum;
if (c->big_lpt) { int num = calc_pnode_num_from_parent(c, parent, iip);
if (pnode->num != num) return -EINVAL;
} for (i = 0; i < UBIFS_LPT_FANOUT; i++) { int free = pnode->lprops[i].free; int dirty = pnode->lprops[i].dirty;
if (!test_bit(COW_CNODE, &nnode->flags)) { /* nnode is not being committed */ if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) {
c->dirty_nn_cnt += 1;
ubifs_add_nnode_dirt(c, nnode);
} return nnode;
}
/* nnode is being committed, so copy it */
n = kmemdup(nnode, sizeof(struct ubifs_nnode), GFP_NOFS); if (unlikely(!n)) return ERR_PTR(-ENOMEM);
if (!test_bit(COW_CNODE, &pnode->flags)) { /* pnode is not being committed */ if (!test_and_set_bit(DIRTY_CNODE, &pnode->flags)) {
c->dirty_pn_cnt += 1;
add_pnode_dirt(c, pnode);
} return pnode;
}
/* pnode is being committed, so copy it */
p = kmemdup(pnode, sizeof(struct ubifs_pnode), GFP_NOFS); if (unlikely(!p)) return ERR_PTR(-ENOMEM);
while (cnode) {
nnode = cnode->parent;
nn = (struct ubifs_nnode *)cnode; if (cnode->level > 1) { while (iip < UBIFS_LPT_FANOUT) { if (nn->nbranch[iip].lnum == 0) { /* Go right */
iip++; continue;
}
/* Go down */
iip = 0;
cnode = (struct ubifs_cnode *)nnode; break;
} if (iip < UBIFS_LPT_FANOUT) continue;
} else { struct ubifs_pnode *pnode;
for (i = 0; i < UBIFS_LPT_FANOUT; i++) { if (nn->nbranch[i].lnum == 0) continue;
pnode = ubifs_get_pnode(c, nn, i); if (IS_ERR(pnode)) {
err = PTR_ERR(pnode); goto out;
}
ubifs_pack_pnode(c, buf, pnode);
err = ubifs_shash_update(c, desc, buf,
c->pnode_sz); if (err) goto out;
}
} /* Go up and to the right */
iip = cnode->iip + 1;
cnode = (struct ubifs_cnode *)nnode;
}
/* Loop for each lprops */ while (1) { struct ubifs_lprops *lprops = &pnode->lprops[iip]; int ret, lnum = lprops->lnum;
ret = scan_cb(c, lprops, path[h].in_tree, data); if (ret < 0) {
err = ret; goto out;
} if (ret & LPT_SCAN_ADD) { /* Add all the nodes in path to the tree in memory */ for (h = 1; h < c->lpt_hght; h++) { const size_t sz = sizeof(struct ubifs_nnode); struct ubifs_nnode *parent;
pnode = kmemdup(&path[h].pnode, sz, GFP_NOFS); if (!pnode) {
err = -ENOMEM; goto out;
}
parent = pnode->parent;
parent->nbranch[pnode->iip].pnode = pnode;
path[h].ptr.pnode = pnode;
path[h].in_tree = 1;
update_cats(c, pnode);
c->pnodes_have += 1;
}
err = dbg_check_lpt_nodes(c, (struct ubifs_cnode *)
c->nroot, 0, 0); if (err) goto out;
err = dbg_check_cats(c); if (err) goto out;
} if (ret & LPT_SCAN_STOP) {
err = 0; break;
} /* Get the next lprops */ if (lnum == end_lnum) { /* *Wegottotheendwithoutfindingwhatwewere *lookingfor
*/
err = -ENOSPC; goto out;
} if (lnum + 1 >= c->leb_cnt) { /* Wrap-around to the beginning */
start_lnum = c->main_first; goto again;
} if (iip + 1 < UBIFS_LPT_FANOUT) { /* Next lprops is in the same pnode */
iip += 1; continue;
} /* We need to get the next pnode. Go up until we can go right */
iip = pnode->iip; while (1) {
h -= 1;
ubifs_assert(c, h >= 0);
nnode = path[h].ptr.nnode; if (iip + 1 < UBIFS_LPT_FANOUT) break;
iip = nnode->iip;
} /* Go right */
iip += 1; /* Descend to the pnode */
h += 1; for (; h < c->lpt_hght; h++) {
nnode = scan_get_nnode(c, path + h, nnode, iip); if (IS_ERR(nnode)) {
err = PTR_ERR(nnode); goto out;
}
iip = 0;
}
pnode = scan_get_pnode(c, path + h, nnode, iip); if (IS_ERR(pnode)) {
err = PTR_ERR(pnode); goto out;
}
iip = 0;
}
out:
kfree(path); return err;
}
/** *dbg_chk_pnode-checkapnode. *@c:theUBIFSfile-systemdescriptionobject *@pnode:pnodetocheck *@col:pnodecolumn * *Thisfunctionreturns%0onsuccessandanegativeerrorcodeonfailure.
*/ staticint dbg_chk_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode, int col)
{ int i;
if (pnode->num != col) {
ubifs_err(c, "pnode num %d expected %d parent num %d iip %d",
pnode->num, col, pnode->parent->num, pnode->iip); return -EINVAL;
} for (i = 0; i < UBIFS_LPT_FANOUT; i++) { struct ubifs_lprops *lp, *lprops = &pnode->lprops[i]; int lnum = (pnode->num << UBIFS_LPT_FANOUT_SHIFT) + i +
c->main_first; int found, cat = lprops->flags & LPROPS_CAT_MASK; struct ubifs_lpt_heap *heap; struct list_head *list = NULL;
if (lnum >= c->leb_cnt) continue; if (lprops->lnum != lnum) {
ubifs_err(c, "bad LEB number %d expected %d",
lprops->lnum, lnum); return -EINVAL;
} if (lprops->flags & LPROPS_TAKEN) { if (cat != LPROPS_UNCAT) {
ubifs_err(c, "LEB %d taken but not uncat %d",
lprops->lnum, cat); return -EINVAL;
} continue;
} if (lprops->flags & LPROPS_INDEX) { switch (cat) { case LPROPS_UNCAT: case LPROPS_DIRTY_IDX: case LPROPS_FRDI_IDX: break; default:
ubifs_err(c, "LEB %d index but cat %d",
lprops->lnum, cat); return -EINVAL;
}
} else { switch (cat) { case LPROPS_UNCAT: case LPROPS_DIRTY: case LPROPS_FREE: case LPROPS_EMPTY: case LPROPS_FREEABLE: break; default:
ubifs_err(c, "LEB %d not index but cat %d",
lprops->lnum, cat); return -EINVAL;
}
} switch (cat) { case LPROPS_UNCAT:
list = &c->uncat_list; break; case LPROPS_EMPTY:
list = &c->empty_list; break; case LPROPS_FREEABLE:
list = &c->freeable_list; break; case LPROPS_FRDI_IDX:
list = &c->frdi_idx_list; break;
}
found = 0; switch (cat) { case LPROPS_DIRTY: case LPROPS_DIRTY_IDX: case LPROPS_FREE:
heap = &c->lpt_heap[cat - 1]; if (lprops->hpos < heap->cnt &&
heap->arr[lprops->hpos] == lprops)
found = 1; break; case LPROPS_UNCAT: case LPROPS_EMPTY: case LPROPS_FREEABLE: case LPROPS_FRDI_IDX:
list_for_each_entry(lp, list, list) if (lprops == lp) {
found = 1; break;
} break;
} if (!found) {
ubifs_err(c, "LEB %d cat %d not found in cat heap/list",
lprops->lnum, cat); return -EINVAL;
} switch (cat) { case LPROPS_EMPTY: if (lprops->free != c->leb_size) {
ubifs_err(c, "LEB %d cat %d free %d dirty %d",
lprops->lnum, cat, lprops->free,
lprops->dirty); return -EINVAL;
} break; case LPROPS_FREEABLE: case LPROPS_FRDI_IDX: if (lprops->free + lprops->dirty != c->leb_size) {
ubifs_err(c, "LEB %d cat %d free %d dirty %d",
lprops->lnum, cat, lprops->free,
lprops->dirty); return -EINVAL;
} break;
}
} return0;
}
/** *dbg_check_lpt_nodes-checknnodesandpnodes. *@c:theUBIFSfile-systemdescriptionobject *@cnode:nextcnode(nnodeorpnode)tocheck *@row:rowofcnode(rootiszero) *@col:columnofcnode(leftmostiszero) * *Thisfunctionreturns%0onsuccessandanegativeerrorcodeonfailure.
*/ int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode, int row, int col)
{ struct ubifs_nnode *nnode, *nn; struct ubifs_cnode *cn; int num, iip = 0, err;
if (!dbg_is_chk_lprops(c)) return0;
while (cnode) {
ubifs_assert(c, row >= 0);
nnode = cnode->parent; if (cnode->level) { /* cnode is a nnode */
num = calc_nnode_num(row, col); if (cnode->num != num) {
ubifs_err(c, "nnode num %d expected %d parent num %d iip %d",
cnode->num, num,
(nnode ? nnode->num : 0), cnode->iip); return -EINVAL;
}
nn = (struct ubifs_nnode *)cnode; while (iip < UBIFS_LPT_FANOUT) {
cn = nn->nbranch[iip].cnode; if (cn) { /* Go down */
row += 1;
col <<= UBIFS_LPT_FANOUT_SHIFT;
col += iip;
iip = 0;
cnode = cn; break;
} /* Go right */
iip += 1;
} if (iip < UBIFS_LPT_FANOUT) continue;
} else { struct ubifs_pnode *pnode;
/* cnode is a pnode */
pnode = (struct ubifs_pnode *)cnode;
err = dbg_chk_pnode(c, pnode, col); if (err) return err;
} /* Go up and to the right */
row -= 1;
col >>= UBIFS_LPT_FANOUT_SHIFT;
iip = cnode->iip + 1;
cnode = (struct ubifs_cnode *)nnode;
} return0;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.49 Sekunden
(vorverarbeitet am 2026-09-27)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.