xref: /kernel/linux/linux-6.6/fs/ubifs/lpt.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * This file is part of UBIFS.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2006-2008 Nokia Corporation.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Authors: Adrian Hunter
862306a36Sopenharmony_ci *          Artem Bityutskiy (Битюцкий Артём)
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/*
1262306a36Sopenharmony_ci * This file implements the LEB properties tree (LPT) area. The LPT area
1362306a36Sopenharmony_ci * contains the LEB properties tree, a table of LPT area eraseblocks (ltab), and
1462306a36Sopenharmony_ci * (for the "big" model) a table of saved LEB numbers (lsave). The LPT area sits
1562306a36Sopenharmony_ci * between the log and the orphan area.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * The LPT area is like a miniature self-contained file system. It is required
1862306a36Sopenharmony_ci * that it never runs out of space, is fast to access and update, and scales
1962306a36Sopenharmony_ci * logarithmically. The LEB properties tree is implemented as a wandering tree
2062306a36Sopenharmony_ci * much like the TNC, and the LPT area has its own garbage collection.
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * The LPT has two slightly different forms called the "small model" and the
2362306a36Sopenharmony_ci * "big model". The small model is used when the entire LEB properties table
2462306a36Sopenharmony_ci * can be written into a single eraseblock. In that case, garbage collection
2562306a36Sopenharmony_ci * consists of just writing the whole table, which therefore makes all other
2662306a36Sopenharmony_ci * eraseblocks reusable. In the case of the big model, dirty eraseblocks are
2762306a36Sopenharmony_ci * selected for garbage collection, which consists of marking the clean nodes in
2862306a36Sopenharmony_ci * that LEB as dirty, and then only the dirty nodes are written out. Also, in
2962306a36Sopenharmony_ci * the case of the big model, a table of LEB numbers is saved so that the entire
3062306a36Sopenharmony_ci * LPT does not to be scanned looking for empty eraseblocks when UBIFS is first
3162306a36Sopenharmony_ci * mounted.
3262306a36Sopenharmony_ci */
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include "ubifs.h"
3562306a36Sopenharmony_ci#include <linux/crc16.h>
3662306a36Sopenharmony_ci#include <linux/math64.h>
3762306a36Sopenharmony_ci#include <linux/slab.h>
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/**
4062306a36Sopenharmony_ci * do_calc_lpt_geom - calculate sizes for the LPT area.
4162306a36Sopenharmony_ci * @c: the UBIFS file-system description object
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci * Calculate the sizes of LPT bit fields, nodes, and tree, based on the
4462306a36Sopenharmony_ci * properties of the flash and whether LPT is "big" (c->big_lpt).
4562306a36Sopenharmony_ci */
4662306a36Sopenharmony_cistatic void do_calc_lpt_geom(struct ubifs_info *c)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	int i, n, bits, per_leb_wastage, max_pnode_cnt;
4962306a36Sopenharmony_ci	long long sz, tot_wastage;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	n = c->main_lebs + c->max_leb_cnt - c->leb_cnt;
5262306a36Sopenharmony_ci	max_pnode_cnt = DIV_ROUND_UP(n, UBIFS_LPT_FANOUT);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	c->lpt_hght = 1;
5562306a36Sopenharmony_ci	n = UBIFS_LPT_FANOUT;
5662306a36Sopenharmony_ci	while (n < max_pnode_cnt) {
5762306a36Sopenharmony_ci		c->lpt_hght += 1;
5862306a36Sopenharmony_ci		n <<= UBIFS_LPT_FANOUT_SHIFT;
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	c->pnode_cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	n = DIV_ROUND_UP(c->pnode_cnt, UBIFS_LPT_FANOUT);
6462306a36Sopenharmony_ci	c->nnode_cnt = n;
6562306a36Sopenharmony_ci	for (i = 1; i < c->lpt_hght; i++) {
6662306a36Sopenharmony_ci		n = DIV_ROUND_UP(n, UBIFS_LPT_FANOUT);
6762306a36Sopenharmony_ci		c->nnode_cnt += n;
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	c->space_bits = fls(c->leb_size) - 3;
7162306a36Sopenharmony_ci	c->lpt_lnum_bits = fls(c->lpt_lebs);
7262306a36Sopenharmony_ci	c->lpt_offs_bits = fls(c->leb_size - 1);
7362306a36Sopenharmony_ci	c->lpt_spc_bits = fls(c->leb_size);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	n = DIV_ROUND_UP(c->max_leb_cnt, UBIFS_LPT_FANOUT);
7662306a36Sopenharmony_ci	c->pcnt_bits = fls(n - 1);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	c->lnum_bits = fls(c->max_leb_cnt - 1);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
8162306a36Sopenharmony_ci	       (c->big_lpt ? c->pcnt_bits : 0) +
8262306a36Sopenharmony_ci	       (c->space_bits * 2 + 1) * UBIFS_LPT_FANOUT;
8362306a36Sopenharmony_ci	c->pnode_sz = (bits + 7) / 8;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
8662306a36Sopenharmony_ci	       (c->big_lpt ? c->pcnt_bits : 0) +
8762306a36Sopenharmony_ci	       (c->lpt_lnum_bits + c->lpt_offs_bits) * UBIFS_LPT_FANOUT;
8862306a36Sopenharmony_ci	c->nnode_sz = (bits + 7) / 8;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
9162306a36Sopenharmony_ci	       c->lpt_lebs * c->lpt_spc_bits * 2;
9262306a36Sopenharmony_ci	c->ltab_sz = (bits + 7) / 8;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
9562306a36Sopenharmony_ci	       c->lnum_bits * c->lsave_cnt;
9662306a36Sopenharmony_ci	c->lsave_sz = (bits + 7) / 8;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	/* Calculate the minimum LPT size */
9962306a36Sopenharmony_ci	c->lpt_sz = (long long)c->pnode_cnt * c->pnode_sz;
10062306a36Sopenharmony_ci	c->lpt_sz += (long long)c->nnode_cnt * c->nnode_sz;
10162306a36Sopenharmony_ci	c->lpt_sz += c->ltab_sz;
10262306a36Sopenharmony_ci	if (c->big_lpt)
10362306a36Sopenharmony_ci		c->lpt_sz += c->lsave_sz;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	/* Add wastage */
10662306a36Sopenharmony_ci	sz = c->lpt_sz;
10762306a36Sopenharmony_ci	per_leb_wastage = max_t(int, c->pnode_sz, c->nnode_sz);
10862306a36Sopenharmony_ci	sz += per_leb_wastage;
10962306a36Sopenharmony_ci	tot_wastage = per_leb_wastage;
11062306a36Sopenharmony_ci	while (sz > c->leb_size) {
11162306a36Sopenharmony_ci		sz += per_leb_wastage;
11262306a36Sopenharmony_ci		sz -= c->leb_size;
11362306a36Sopenharmony_ci		tot_wastage += per_leb_wastage;
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci	tot_wastage += ALIGN(sz, c->min_io_size) - sz;
11662306a36Sopenharmony_ci	c->lpt_sz += tot_wastage;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci/**
12062306a36Sopenharmony_ci * ubifs_calc_lpt_geom - calculate and check sizes for the LPT area.
12162306a36Sopenharmony_ci * @c: the UBIFS file-system description object
12262306a36Sopenharmony_ci *
12362306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
12462306a36Sopenharmony_ci */
12562306a36Sopenharmony_ciint ubifs_calc_lpt_geom(struct ubifs_info *c)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	int lebs_needed;
12862306a36Sopenharmony_ci	long long sz;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	do_calc_lpt_geom(c);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/* Verify that lpt_lebs is big enough */
13362306a36Sopenharmony_ci	sz = c->lpt_sz * 2; /* Must have at least 2 times the size */
13462306a36Sopenharmony_ci	lebs_needed = div_u64(sz + c->leb_size - 1, c->leb_size);
13562306a36Sopenharmony_ci	if (lebs_needed > c->lpt_lebs) {
13662306a36Sopenharmony_ci		ubifs_err(c, "too few LPT LEBs");
13762306a36Sopenharmony_ci		return -EINVAL;
13862306a36Sopenharmony_ci	}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	/* Verify that ltab fits in a single LEB (since ltab is a single node */
14162306a36Sopenharmony_ci	if (c->ltab_sz > c->leb_size) {
14262306a36Sopenharmony_ci		ubifs_err(c, "LPT ltab too big");
14362306a36Sopenharmony_ci		return -EINVAL;
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	c->check_lpt_free = c->big_lpt;
14762306a36Sopenharmony_ci	return 0;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/**
15162306a36Sopenharmony_ci * calc_dflt_lpt_geom - calculate default LPT geometry.
15262306a36Sopenharmony_ci * @c: the UBIFS file-system description object
15362306a36Sopenharmony_ci * @main_lebs: number of main area LEBs is passed and returned here
15462306a36Sopenharmony_ci * @big_lpt: whether the LPT area is "big" is returned here
15562306a36Sopenharmony_ci *
15662306a36Sopenharmony_ci * The size of the LPT area depends on parameters that themselves are dependent
15762306a36Sopenharmony_ci * on the size of the LPT area. This function, successively recalculates the LPT
15862306a36Sopenharmony_ci * area geometry until the parameters and resultant geometry are consistent.
15962306a36Sopenharmony_ci *
16062306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
16162306a36Sopenharmony_ci */
16262306a36Sopenharmony_cistatic int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs,
16362306a36Sopenharmony_ci			      int *big_lpt)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	int i, lebs_needed;
16662306a36Sopenharmony_ci	long long sz;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	/* Start by assuming the minimum number of LPT LEBs */
16962306a36Sopenharmony_ci	c->lpt_lebs = UBIFS_MIN_LPT_LEBS;
17062306a36Sopenharmony_ci	c->main_lebs = *main_lebs - c->lpt_lebs;
17162306a36Sopenharmony_ci	if (c->main_lebs <= 0)
17262306a36Sopenharmony_ci		return -EINVAL;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	/* And assume we will use the small LPT model */
17562306a36Sopenharmony_ci	c->big_lpt = 0;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	/*
17862306a36Sopenharmony_ci	 * Calculate the geometry based on assumptions above and then see if it
17962306a36Sopenharmony_ci	 * makes sense
18062306a36Sopenharmony_ci	 */
18162306a36Sopenharmony_ci	do_calc_lpt_geom(c);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/* Small LPT model must have lpt_sz < leb_size */
18462306a36Sopenharmony_ci	if (c->lpt_sz > c->leb_size) {
18562306a36Sopenharmony_ci		/* Nope, so try again using big LPT model */
18662306a36Sopenharmony_ci		c->big_lpt = 1;
18762306a36Sopenharmony_ci		do_calc_lpt_geom(c);
18862306a36Sopenharmony_ci	}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	/* Now check there are enough LPT LEBs */
19162306a36Sopenharmony_ci	for (i = 0; i < 64 ; i++) {
19262306a36Sopenharmony_ci		sz = c->lpt_sz * 4; /* Allow 4 times the size */
19362306a36Sopenharmony_ci		lebs_needed = div_u64(sz + c->leb_size - 1, c->leb_size);
19462306a36Sopenharmony_ci		if (lebs_needed > c->lpt_lebs) {
19562306a36Sopenharmony_ci			/* Not enough LPT LEBs so try again with more */
19662306a36Sopenharmony_ci			c->lpt_lebs = lebs_needed;
19762306a36Sopenharmony_ci			c->main_lebs = *main_lebs - c->lpt_lebs;
19862306a36Sopenharmony_ci			if (c->main_lebs <= 0)
19962306a36Sopenharmony_ci				return -EINVAL;
20062306a36Sopenharmony_ci			do_calc_lpt_geom(c);
20162306a36Sopenharmony_ci			continue;
20262306a36Sopenharmony_ci		}
20362306a36Sopenharmony_ci		if (c->ltab_sz > c->leb_size) {
20462306a36Sopenharmony_ci			ubifs_err(c, "LPT ltab too big");
20562306a36Sopenharmony_ci			return -EINVAL;
20662306a36Sopenharmony_ci		}
20762306a36Sopenharmony_ci		*main_lebs = c->main_lebs;
20862306a36Sopenharmony_ci		*big_lpt = c->big_lpt;
20962306a36Sopenharmony_ci		return 0;
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci	return -EINVAL;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci/**
21562306a36Sopenharmony_ci * pack_bits - pack bit fields end-to-end.
21662306a36Sopenharmony_ci * @c: UBIFS file-system description object
21762306a36Sopenharmony_ci * @addr: address at which to pack (passed and next address returned)
21862306a36Sopenharmony_ci * @pos: bit position at which to pack (passed and next position returned)
21962306a36Sopenharmony_ci * @val: value to pack
22062306a36Sopenharmony_ci * @nrbits: number of bits of value to pack (1-32)
22162306a36Sopenharmony_ci */
22262306a36Sopenharmony_cistatic void pack_bits(const struct ubifs_info *c, uint8_t **addr, int *pos, uint32_t val, int nrbits)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	uint8_t *p = *addr;
22562306a36Sopenharmony_ci	int b = *pos;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	ubifs_assert(c, nrbits > 0);
22862306a36Sopenharmony_ci	ubifs_assert(c, nrbits <= 32);
22962306a36Sopenharmony_ci	ubifs_assert(c, *pos >= 0);
23062306a36Sopenharmony_ci	ubifs_assert(c, *pos < 8);
23162306a36Sopenharmony_ci	ubifs_assert(c, (val >> nrbits) == 0 || nrbits == 32);
23262306a36Sopenharmony_ci	if (b) {
23362306a36Sopenharmony_ci		*p |= ((uint8_t)val) << b;
23462306a36Sopenharmony_ci		nrbits += b;
23562306a36Sopenharmony_ci		if (nrbits > 8) {
23662306a36Sopenharmony_ci			*++p = (uint8_t)(val >>= (8 - b));
23762306a36Sopenharmony_ci			if (nrbits > 16) {
23862306a36Sopenharmony_ci				*++p = (uint8_t)(val >>= 8);
23962306a36Sopenharmony_ci				if (nrbits > 24) {
24062306a36Sopenharmony_ci					*++p = (uint8_t)(val >>= 8);
24162306a36Sopenharmony_ci					if (nrbits > 32)
24262306a36Sopenharmony_ci						*++p = (uint8_t)(val >>= 8);
24362306a36Sopenharmony_ci				}
24462306a36Sopenharmony_ci			}
24562306a36Sopenharmony_ci		}
24662306a36Sopenharmony_ci	} else {
24762306a36Sopenharmony_ci		*p = (uint8_t)val;
24862306a36Sopenharmony_ci		if (nrbits > 8) {
24962306a36Sopenharmony_ci			*++p = (uint8_t)(val >>= 8);
25062306a36Sopenharmony_ci			if (nrbits > 16) {
25162306a36Sopenharmony_ci				*++p = (uint8_t)(val >>= 8);
25262306a36Sopenharmony_ci				if (nrbits > 24)
25362306a36Sopenharmony_ci					*++p = (uint8_t)(val >>= 8);
25462306a36Sopenharmony_ci			}
25562306a36Sopenharmony_ci		}
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci	b = nrbits & 7;
25862306a36Sopenharmony_ci	if (b == 0)
25962306a36Sopenharmony_ci		p++;
26062306a36Sopenharmony_ci	*addr = p;
26162306a36Sopenharmony_ci	*pos = b;
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci/**
26562306a36Sopenharmony_ci * ubifs_unpack_bits - unpack bit fields.
26662306a36Sopenharmony_ci * @c: UBIFS file-system description object
26762306a36Sopenharmony_ci * @addr: address at which to unpack (passed and next address returned)
26862306a36Sopenharmony_ci * @pos: bit position at which to unpack (passed and next position returned)
26962306a36Sopenharmony_ci * @nrbits: number of bits of value to unpack (1-32)
27062306a36Sopenharmony_ci *
27162306a36Sopenharmony_ci * This functions returns the value unpacked.
27262306a36Sopenharmony_ci */
27362306a36Sopenharmony_ciuint32_t ubifs_unpack_bits(const struct ubifs_info *c, uint8_t **addr, int *pos, int nrbits)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	const int k = 32 - nrbits;
27662306a36Sopenharmony_ci	uint8_t *p = *addr;
27762306a36Sopenharmony_ci	int b = *pos;
27862306a36Sopenharmony_ci	uint32_t val;
27962306a36Sopenharmony_ci	const int bytes = (nrbits + b + 7) >> 3;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	ubifs_assert(c, nrbits > 0);
28262306a36Sopenharmony_ci	ubifs_assert(c, nrbits <= 32);
28362306a36Sopenharmony_ci	ubifs_assert(c, *pos >= 0);
28462306a36Sopenharmony_ci	ubifs_assert(c, *pos < 8);
28562306a36Sopenharmony_ci	if (b) {
28662306a36Sopenharmony_ci		switch (bytes) {
28762306a36Sopenharmony_ci		case 2:
28862306a36Sopenharmony_ci			val = p[1];
28962306a36Sopenharmony_ci			break;
29062306a36Sopenharmony_ci		case 3:
29162306a36Sopenharmony_ci			val = p[1] | ((uint32_t)p[2] << 8);
29262306a36Sopenharmony_ci			break;
29362306a36Sopenharmony_ci		case 4:
29462306a36Sopenharmony_ci			val = p[1] | ((uint32_t)p[2] << 8) |
29562306a36Sopenharmony_ci				     ((uint32_t)p[3] << 16);
29662306a36Sopenharmony_ci			break;
29762306a36Sopenharmony_ci		case 5:
29862306a36Sopenharmony_ci			val = p[1] | ((uint32_t)p[2] << 8) |
29962306a36Sopenharmony_ci				     ((uint32_t)p[3] << 16) |
30062306a36Sopenharmony_ci				     ((uint32_t)p[4] << 24);
30162306a36Sopenharmony_ci		}
30262306a36Sopenharmony_ci		val <<= (8 - b);
30362306a36Sopenharmony_ci		val |= *p >> b;
30462306a36Sopenharmony_ci		nrbits += b;
30562306a36Sopenharmony_ci	} else {
30662306a36Sopenharmony_ci		switch (bytes) {
30762306a36Sopenharmony_ci		case 1:
30862306a36Sopenharmony_ci			val = p[0];
30962306a36Sopenharmony_ci			break;
31062306a36Sopenharmony_ci		case 2:
31162306a36Sopenharmony_ci			val = p[0] | ((uint32_t)p[1] << 8);
31262306a36Sopenharmony_ci			break;
31362306a36Sopenharmony_ci		case 3:
31462306a36Sopenharmony_ci			val = p[0] | ((uint32_t)p[1] << 8) |
31562306a36Sopenharmony_ci				     ((uint32_t)p[2] << 16);
31662306a36Sopenharmony_ci			break;
31762306a36Sopenharmony_ci		case 4:
31862306a36Sopenharmony_ci			val = p[0] | ((uint32_t)p[1] << 8) |
31962306a36Sopenharmony_ci				     ((uint32_t)p[2] << 16) |
32062306a36Sopenharmony_ci				     ((uint32_t)p[3] << 24);
32162306a36Sopenharmony_ci			break;
32262306a36Sopenharmony_ci		}
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci	val <<= k;
32562306a36Sopenharmony_ci	val >>= k;
32662306a36Sopenharmony_ci	b = nrbits & 7;
32762306a36Sopenharmony_ci	p += nrbits >> 3;
32862306a36Sopenharmony_ci	*addr = p;
32962306a36Sopenharmony_ci	*pos = b;
33062306a36Sopenharmony_ci	ubifs_assert(c, (val >> nrbits) == 0 || nrbits - b == 32);
33162306a36Sopenharmony_ci	return val;
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci/**
33562306a36Sopenharmony_ci * ubifs_pack_pnode - pack all the bit fields of a pnode.
33662306a36Sopenharmony_ci * @c: UBIFS file-system description object
33762306a36Sopenharmony_ci * @buf: buffer into which to pack
33862306a36Sopenharmony_ci * @pnode: pnode to pack
33962306a36Sopenharmony_ci */
34062306a36Sopenharmony_civoid ubifs_pack_pnode(struct ubifs_info *c, void *buf,
34162306a36Sopenharmony_ci		      struct ubifs_pnode *pnode)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
34462306a36Sopenharmony_ci	int i, pos = 0;
34562306a36Sopenharmony_ci	uint16_t crc;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	pack_bits(c, &addr, &pos, UBIFS_LPT_PNODE, UBIFS_LPT_TYPE_BITS);
34862306a36Sopenharmony_ci	if (c->big_lpt)
34962306a36Sopenharmony_ci		pack_bits(c, &addr, &pos, pnode->num, c->pcnt_bits);
35062306a36Sopenharmony_ci	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
35162306a36Sopenharmony_ci		pack_bits(c, &addr, &pos, pnode->lprops[i].free >> 3,
35262306a36Sopenharmony_ci			  c->space_bits);
35362306a36Sopenharmony_ci		pack_bits(c, &addr, &pos, pnode->lprops[i].dirty >> 3,
35462306a36Sopenharmony_ci			  c->space_bits);
35562306a36Sopenharmony_ci		if (pnode->lprops[i].flags & LPROPS_INDEX)
35662306a36Sopenharmony_ci			pack_bits(c, &addr, &pos, 1, 1);
35762306a36Sopenharmony_ci		else
35862306a36Sopenharmony_ci			pack_bits(c, &addr, &pos, 0, 1);
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci	crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
36162306a36Sopenharmony_ci		    c->pnode_sz - UBIFS_LPT_CRC_BYTES);
36262306a36Sopenharmony_ci	addr = buf;
36362306a36Sopenharmony_ci	pos = 0;
36462306a36Sopenharmony_ci	pack_bits(c, &addr, &pos, crc, UBIFS_LPT_CRC_BITS);
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci/**
36862306a36Sopenharmony_ci * ubifs_pack_nnode - pack all the bit fields of a nnode.
36962306a36Sopenharmony_ci * @c: UBIFS file-system description object
37062306a36Sopenharmony_ci * @buf: buffer into which to pack
37162306a36Sopenharmony_ci * @nnode: nnode to pack
37262306a36Sopenharmony_ci */
37362306a36Sopenharmony_civoid ubifs_pack_nnode(struct ubifs_info *c, void *buf,
37462306a36Sopenharmony_ci		      struct ubifs_nnode *nnode)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
37762306a36Sopenharmony_ci	int i, pos = 0;
37862306a36Sopenharmony_ci	uint16_t crc;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	pack_bits(c, &addr, &pos, UBIFS_LPT_NNODE, UBIFS_LPT_TYPE_BITS);
38162306a36Sopenharmony_ci	if (c->big_lpt)
38262306a36Sopenharmony_ci		pack_bits(c, &addr, &pos, nnode->num, c->pcnt_bits);
38362306a36Sopenharmony_ci	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
38462306a36Sopenharmony_ci		int lnum = nnode->nbranch[i].lnum;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci		if (lnum == 0)
38762306a36Sopenharmony_ci			lnum = c->lpt_last + 1;
38862306a36Sopenharmony_ci		pack_bits(c, &addr, &pos, lnum - c->lpt_first, c->lpt_lnum_bits);
38962306a36Sopenharmony_ci		pack_bits(c, &addr, &pos, nnode->nbranch[i].offs,
39062306a36Sopenharmony_ci			  c->lpt_offs_bits);
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci	crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
39362306a36Sopenharmony_ci		    c->nnode_sz - UBIFS_LPT_CRC_BYTES);
39462306a36Sopenharmony_ci	addr = buf;
39562306a36Sopenharmony_ci	pos = 0;
39662306a36Sopenharmony_ci	pack_bits(c, &addr, &pos, crc, UBIFS_LPT_CRC_BITS);
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci/**
40062306a36Sopenharmony_ci * ubifs_pack_ltab - pack the LPT's own lprops table.
40162306a36Sopenharmony_ci * @c: UBIFS file-system description object
40262306a36Sopenharmony_ci * @buf: buffer into which to pack
40362306a36Sopenharmony_ci * @ltab: LPT's own lprops table to pack
40462306a36Sopenharmony_ci */
40562306a36Sopenharmony_civoid ubifs_pack_ltab(struct ubifs_info *c, void *buf,
40662306a36Sopenharmony_ci		     struct ubifs_lpt_lprops *ltab)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
40962306a36Sopenharmony_ci	int i, pos = 0;
41062306a36Sopenharmony_ci	uint16_t crc;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	pack_bits(c, &addr, &pos, UBIFS_LPT_LTAB, UBIFS_LPT_TYPE_BITS);
41362306a36Sopenharmony_ci	for (i = 0; i < c->lpt_lebs; i++) {
41462306a36Sopenharmony_ci		pack_bits(c, &addr, &pos, ltab[i].free, c->lpt_spc_bits);
41562306a36Sopenharmony_ci		pack_bits(c, &addr, &pos, ltab[i].dirty, c->lpt_spc_bits);
41662306a36Sopenharmony_ci	}
41762306a36Sopenharmony_ci	crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
41862306a36Sopenharmony_ci		    c->ltab_sz - UBIFS_LPT_CRC_BYTES);
41962306a36Sopenharmony_ci	addr = buf;
42062306a36Sopenharmony_ci	pos = 0;
42162306a36Sopenharmony_ci	pack_bits(c, &addr, &pos, crc, UBIFS_LPT_CRC_BITS);
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci/**
42562306a36Sopenharmony_ci * ubifs_pack_lsave - pack the LPT's save table.
42662306a36Sopenharmony_ci * @c: UBIFS file-system description object
42762306a36Sopenharmony_ci * @buf: buffer into which to pack
42862306a36Sopenharmony_ci * @lsave: LPT's save table to pack
42962306a36Sopenharmony_ci */
43062306a36Sopenharmony_civoid ubifs_pack_lsave(struct ubifs_info *c, void *buf, int *lsave)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
43362306a36Sopenharmony_ci	int i, pos = 0;
43462306a36Sopenharmony_ci	uint16_t crc;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	pack_bits(c, &addr, &pos, UBIFS_LPT_LSAVE, UBIFS_LPT_TYPE_BITS);
43762306a36Sopenharmony_ci	for (i = 0; i < c->lsave_cnt; i++)
43862306a36Sopenharmony_ci		pack_bits(c, &addr, &pos, lsave[i], c->lnum_bits);
43962306a36Sopenharmony_ci	crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
44062306a36Sopenharmony_ci		    c->lsave_sz - UBIFS_LPT_CRC_BYTES);
44162306a36Sopenharmony_ci	addr = buf;
44262306a36Sopenharmony_ci	pos = 0;
44362306a36Sopenharmony_ci	pack_bits(c, &addr, &pos, crc, UBIFS_LPT_CRC_BITS);
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci/**
44762306a36Sopenharmony_ci * ubifs_add_lpt_dirt - add dirty space to LPT LEB properties.
44862306a36Sopenharmony_ci * @c: UBIFS file-system description object
44962306a36Sopenharmony_ci * @lnum: LEB number to which to add dirty space
45062306a36Sopenharmony_ci * @dirty: amount of dirty space to add
45162306a36Sopenharmony_ci */
45262306a36Sopenharmony_civoid ubifs_add_lpt_dirt(struct ubifs_info *c, int lnum, int dirty)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	if (!dirty || !lnum)
45562306a36Sopenharmony_ci		return;
45662306a36Sopenharmony_ci	dbg_lp("LEB %d add %d to %d",
45762306a36Sopenharmony_ci	       lnum, dirty, c->ltab[lnum - c->lpt_first].dirty);
45862306a36Sopenharmony_ci	ubifs_assert(c, lnum >= c->lpt_first && lnum <= c->lpt_last);
45962306a36Sopenharmony_ci	c->ltab[lnum - c->lpt_first].dirty += dirty;
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci/**
46362306a36Sopenharmony_ci * set_ltab - set LPT LEB properties.
46462306a36Sopenharmony_ci * @c: UBIFS file-system description object
46562306a36Sopenharmony_ci * @lnum: LEB number
46662306a36Sopenharmony_ci * @free: amount of free space
46762306a36Sopenharmony_ci * @dirty: amount of dirty space
46862306a36Sopenharmony_ci */
46962306a36Sopenharmony_cistatic void set_ltab(struct ubifs_info *c, int lnum, int free, int dirty)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	dbg_lp("LEB %d free %d dirty %d to %d %d",
47262306a36Sopenharmony_ci	       lnum, c->ltab[lnum - c->lpt_first].free,
47362306a36Sopenharmony_ci	       c->ltab[lnum - c->lpt_first].dirty, free, dirty);
47462306a36Sopenharmony_ci	ubifs_assert(c, lnum >= c->lpt_first && lnum <= c->lpt_last);
47562306a36Sopenharmony_ci	c->ltab[lnum - c->lpt_first].free = free;
47662306a36Sopenharmony_ci	c->ltab[lnum - c->lpt_first].dirty = dirty;
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci/**
48062306a36Sopenharmony_ci * ubifs_add_nnode_dirt - add dirty space to LPT LEB properties.
48162306a36Sopenharmony_ci * @c: UBIFS file-system description object
48262306a36Sopenharmony_ci * @nnode: nnode for which to add dirt
48362306a36Sopenharmony_ci */
48462306a36Sopenharmony_civoid ubifs_add_nnode_dirt(struct ubifs_info *c, struct ubifs_nnode *nnode)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	struct ubifs_nnode *np = nnode->parent;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	if (np)
48962306a36Sopenharmony_ci		ubifs_add_lpt_dirt(c, np->nbranch[nnode->iip].lnum,
49062306a36Sopenharmony_ci				   c->nnode_sz);
49162306a36Sopenharmony_ci	else {
49262306a36Sopenharmony_ci		ubifs_add_lpt_dirt(c, c->lpt_lnum, c->nnode_sz);
49362306a36Sopenharmony_ci		if (!(c->lpt_drty_flgs & LTAB_DIRTY)) {
49462306a36Sopenharmony_ci			c->lpt_drty_flgs |= LTAB_DIRTY;
49562306a36Sopenharmony_ci			ubifs_add_lpt_dirt(c, c->ltab_lnum, c->ltab_sz);
49662306a36Sopenharmony_ci		}
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci/**
50162306a36Sopenharmony_ci * add_pnode_dirt - add dirty space to LPT LEB properties.
50262306a36Sopenharmony_ci * @c: UBIFS file-system description object
50362306a36Sopenharmony_ci * @pnode: pnode for which to add dirt
50462306a36Sopenharmony_ci */
50562306a36Sopenharmony_cistatic void add_pnode_dirt(struct ubifs_info *c, struct ubifs_pnode *pnode)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	ubifs_add_lpt_dirt(c, pnode->parent->nbranch[pnode->iip].lnum,
50862306a36Sopenharmony_ci			   c->pnode_sz);
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci/**
51262306a36Sopenharmony_ci * calc_nnode_num - calculate nnode number.
51362306a36Sopenharmony_ci * @row: the row in the tree (root is zero)
51462306a36Sopenharmony_ci * @col: the column in the row (leftmost is zero)
51562306a36Sopenharmony_ci *
51662306a36Sopenharmony_ci * The nnode number is a number that uniquely identifies a nnode and can be used
51762306a36Sopenharmony_ci * easily to traverse the tree from the root to that nnode.
51862306a36Sopenharmony_ci *
51962306a36Sopenharmony_ci * This function calculates and returns the nnode number for the nnode at @row
52062306a36Sopenharmony_ci * and @col.
52162306a36Sopenharmony_ci */
52262306a36Sopenharmony_cistatic int calc_nnode_num(int row, int col)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	int num, bits;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	num = 1;
52762306a36Sopenharmony_ci	while (row--) {
52862306a36Sopenharmony_ci		bits = (col & (UBIFS_LPT_FANOUT - 1));
52962306a36Sopenharmony_ci		col >>= UBIFS_LPT_FANOUT_SHIFT;
53062306a36Sopenharmony_ci		num <<= UBIFS_LPT_FANOUT_SHIFT;
53162306a36Sopenharmony_ci		num |= bits;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci	return num;
53462306a36Sopenharmony_ci}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci/**
53762306a36Sopenharmony_ci * calc_nnode_num_from_parent - calculate nnode number.
53862306a36Sopenharmony_ci * @c: UBIFS file-system description object
53962306a36Sopenharmony_ci * @parent: parent nnode
54062306a36Sopenharmony_ci * @iip: index in parent
54162306a36Sopenharmony_ci *
54262306a36Sopenharmony_ci * The nnode number is a number that uniquely identifies a nnode and can be used
54362306a36Sopenharmony_ci * easily to traverse the tree from the root to that nnode.
54462306a36Sopenharmony_ci *
54562306a36Sopenharmony_ci * This function calculates and returns the nnode number based on the parent's
54662306a36Sopenharmony_ci * nnode number and the index in parent.
54762306a36Sopenharmony_ci */
54862306a36Sopenharmony_cistatic int calc_nnode_num_from_parent(const struct ubifs_info *c,
54962306a36Sopenharmony_ci				      struct ubifs_nnode *parent, int iip)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	int num, shft;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	if (!parent)
55462306a36Sopenharmony_ci		return 1;
55562306a36Sopenharmony_ci	shft = (c->lpt_hght - parent->level) * UBIFS_LPT_FANOUT_SHIFT;
55662306a36Sopenharmony_ci	num = parent->num ^ (1 << shft);
55762306a36Sopenharmony_ci	num |= (UBIFS_LPT_FANOUT + iip) << shft;
55862306a36Sopenharmony_ci	return num;
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci/**
56262306a36Sopenharmony_ci * calc_pnode_num_from_parent - calculate pnode number.
56362306a36Sopenharmony_ci * @c: UBIFS file-system description object
56462306a36Sopenharmony_ci * @parent: parent nnode
56562306a36Sopenharmony_ci * @iip: index in parent
56662306a36Sopenharmony_ci *
56762306a36Sopenharmony_ci * The pnode number is a number that uniquely identifies a pnode and can be used
56862306a36Sopenharmony_ci * easily to traverse the tree from the root to that pnode.
56962306a36Sopenharmony_ci *
57062306a36Sopenharmony_ci * This function calculates and returns the pnode number based on the parent's
57162306a36Sopenharmony_ci * nnode number and the index in parent.
57262306a36Sopenharmony_ci */
57362306a36Sopenharmony_cistatic int calc_pnode_num_from_parent(const struct ubifs_info *c,
57462306a36Sopenharmony_ci				      struct ubifs_nnode *parent, int iip)
57562306a36Sopenharmony_ci{
57662306a36Sopenharmony_ci	int i, n = c->lpt_hght - 1, pnum = parent->num, num = 0;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	for (i = 0; i < n; i++) {
57962306a36Sopenharmony_ci		num <<= UBIFS_LPT_FANOUT_SHIFT;
58062306a36Sopenharmony_ci		num |= pnum & (UBIFS_LPT_FANOUT - 1);
58162306a36Sopenharmony_ci		pnum >>= UBIFS_LPT_FANOUT_SHIFT;
58262306a36Sopenharmony_ci	}
58362306a36Sopenharmony_ci	num <<= UBIFS_LPT_FANOUT_SHIFT;
58462306a36Sopenharmony_ci	num |= iip;
58562306a36Sopenharmony_ci	return num;
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci/**
58962306a36Sopenharmony_ci * ubifs_create_dflt_lpt - create default LPT.
59062306a36Sopenharmony_ci * @c: UBIFS file-system description object
59162306a36Sopenharmony_ci * @main_lebs: number of main area LEBs is passed and returned here
59262306a36Sopenharmony_ci * @lpt_first: LEB number of first LPT LEB
59362306a36Sopenharmony_ci * @lpt_lebs: number of LEBs for LPT is passed and returned here
59462306a36Sopenharmony_ci * @big_lpt: use big LPT model is passed and returned here
59562306a36Sopenharmony_ci * @hash: hash of the LPT is returned here
59662306a36Sopenharmony_ci *
59762306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
59862306a36Sopenharmony_ci */
59962306a36Sopenharmony_ciint ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
60062306a36Sopenharmony_ci			  int *lpt_lebs, int *big_lpt, u8 *hash)
60162306a36Sopenharmony_ci{
60262306a36Sopenharmony_ci	int lnum, err = 0, node_sz, iopos, i, j, cnt, len, alen, row;
60362306a36Sopenharmony_ci	int blnum, boffs, bsz, bcnt;
60462306a36Sopenharmony_ci	struct ubifs_pnode *pnode = NULL;
60562306a36Sopenharmony_ci	struct ubifs_nnode *nnode = NULL;
60662306a36Sopenharmony_ci	void *buf = NULL, *p;
60762306a36Sopenharmony_ci	struct ubifs_lpt_lprops *ltab = NULL;
60862306a36Sopenharmony_ci	int *lsave = NULL;
60962306a36Sopenharmony_ci	struct shash_desc *desc;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	err = calc_dflt_lpt_geom(c, main_lebs, big_lpt);
61262306a36Sopenharmony_ci	if (err)
61362306a36Sopenharmony_ci		return err;
61462306a36Sopenharmony_ci	*lpt_lebs = c->lpt_lebs;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	/* Needed by 'ubifs_pack_nnode()' and 'set_ltab()' */
61762306a36Sopenharmony_ci	c->lpt_first = lpt_first;
61862306a36Sopenharmony_ci	/* Needed by 'set_ltab()' */
61962306a36Sopenharmony_ci	c->lpt_last = lpt_first + c->lpt_lebs - 1;
62062306a36Sopenharmony_ci	/* Needed by 'ubifs_pack_lsave()' */
62162306a36Sopenharmony_ci	c->main_first = c->leb_cnt - *main_lebs;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	desc = ubifs_hash_get_desc(c);
62462306a36Sopenharmony_ci	if (IS_ERR(desc))
62562306a36Sopenharmony_ci		return PTR_ERR(desc);
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	lsave = kmalloc_array(c->lsave_cnt, sizeof(int), GFP_KERNEL);
62862306a36Sopenharmony_ci	pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_KERNEL);
62962306a36Sopenharmony_ci	nnode = kzalloc(sizeof(struct ubifs_nnode), GFP_KERNEL);
63062306a36Sopenharmony_ci	buf = vmalloc(c->leb_size);
63162306a36Sopenharmony_ci	ltab = vmalloc(array_size(sizeof(struct ubifs_lpt_lprops),
63262306a36Sopenharmony_ci				  c->lpt_lebs));
63362306a36Sopenharmony_ci	if (!pnode || !nnode || !buf || !ltab || !lsave) {
63462306a36Sopenharmony_ci		err = -ENOMEM;
63562306a36Sopenharmony_ci		goto out;
63662306a36Sopenharmony_ci	}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	ubifs_assert(c, !c->ltab);
63962306a36Sopenharmony_ci	c->ltab = ltab; /* Needed by set_ltab */
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	/* Initialize LPT's own lprops */
64262306a36Sopenharmony_ci	for (i = 0; i < c->lpt_lebs; i++) {
64362306a36Sopenharmony_ci		ltab[i].free = c->leb_size;
64462306a36Sopenharmony_ci		ltab[i].dirty = 0;
64562306a36Sopenharmony_ci		ltab[i].tgc = 0;
64662306a36Sopenharmony_ci		ltab[i].cmt = 0;
64762306a36Sopenharmony_ci	}
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	lnum = lpt_first;
65062306a36Sopenharmony_ci	p = buf;
65162306a36Sopenharmony_ci	/* Number of leaf nodes (pnodes) */
65262306a36Sopenharmony_ci	cnt = c->pnode_cnt;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	/*
65562306a36Sopenharmony_ci	 * The first pnode contains the LEB properties for the LEBs that contain
65662306a36Sopenharmony_ci	 * the root inode node and the root index node of the index tree.
65762306a36Sopenharmony_ci	 */
65862306a36Sopenharmony_ci	node_sz = ALIGN(ubifs_idx_node_sz(c, 1), 8);
65962306a36Sopenharmony_ci	iopos = ALIGN(node_sz, c->min_io_size);
66062306a36Sopenharmony_ci	pnode->lprops[0].free = c->leb_size - iopos;
66162306a36Sopenharmony_ci	pnode->lprops[0].dirty = iopos - node_sz;
66262306a36Sopenharmony_ci	pnode->lprops[0].flags = LPROPS_INDEX;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	node_sz = UBIFS_INO_NODE_SZ;
66562306a36Sopenharmony_ci	iopos = ALIGN(node_sz, c->min_io_size);
66662306a36Sopenharmony_ci	pnode->lprops[1].free = c->leb_size - iopos;
66762306a36Sopenharmony_ci	pnode->lprops[1].dirty = iopos - node_sz;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	for (i = 2; i < UBIFS_LPT_FANOUT; i++)
67062306a36Sopenharmony_ci		pnode->lprops[i].free = c->leb_size;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	/* Add first pnode */
67362306a36Sopenharmony_ci	ubifs_pack_pnode(c, p, pnode);
67462306a36Sopenharmony_ci	err = ubifs_shash_update(c, desc, p, c->pnode_sz);
67562306a36Sopenharmony_ci	if (err)
67662306a36Sopenharmony_ci		goto out;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	p += c->pnode_sz;
67962306a36Sopenharmony_ci	len = c->pnode_sz;
68062306a36Sopenharmony_ci	pnode->num += 1;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	/* Reset pnode values for remaining pnodes */
68362306a36Sopenharmony_ci	pnode->lprops[0].free = c->leb_size;
68462306a36Sopenharmony_ci	pnode->lprops[0].dirty = 0;
68562306a36Sopenharmony_ci	pnode->lprops[0].flags = 0;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	pnode->lprops[1].free = c->leb_size;
68862306a36Sopenharmony_ci	pnode->lprops[1].dirty = 0;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	/*
69162306a36Sopenharmony_ci	 * To calculate the internal node branches, we keep information about
69262306a36Sopenharmony_ci	 * the level below.
69362306a36Sopenharmony_ci	 */
69462306a36Sopenharmony_ci	blnum = lnum; /* LEB number of level below */
69562306a36Sopenharmony_ci	boffs = 0; /* Offset of level below */
69662306a36Sopenharmony_ci	bcnt = cnt; /* Number of nodes in level below */
69762306a36Sopenharmony_ci	bsz = c->pnode_sz; /* Size of nodes in level below */
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	/* Add all remaining pnodes */
70062306a36Sopenharmony_ci	for (i = 1; i < cnt; i++) {
70162306a36Sopenharmony_ci		if (len + c->pnode_sz > c->leb_size) {
70262306a36Sopenharmony_ci			alen = ALIGN(len, c->min_io_size);
70362306a36Sopenharmony_ci			set_ltab(c, lnum, c->leb_size - alen, alen - len);
70462306a36Sopenharmony_ci			memset(p, 0xff, alen - len);
70562306a36Sopenharmony_ci			err = ubifs_leb_change(c, lnum++, buf, alen);
70662306a36Sopenharmony_ci			if (err)
70762306a36Sopenharmony_ci				goto out;
70862306a36Sopenharmony_ci			p = buf;
70962306a36Sopenharmony_ci			len = 0;
71062306a36Sopenharmony_ci		}
71162306a36Sopenharmony_ci		ubifs_pack_pnode(c, p, pnode);
71262306a36Sopenharmony_ci		err = ubifs_shash_update(c, desc, p, c->pnode_sz);
71362306a36Sopenharmony_ci		if (err)
71462306a36Sopenharmony_ci			goto out;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci		p += c->pnode_sz;
71762306a36Sopenharmony_ci		len += c->pnode_sz;
71862306a36Sopenharmony_ci		/*
71962306a36Sopenharmony_ci		 * pnodes are simply numbered left to right starting at zero,
72062306a36Sopenharmony_ci		 * which means the pnode number can be used easily to traverse
72162306a36Sopenharmony_ci		 * down the tree to the corresponding pnode.
72262306a36Sopenharmony_ci		 */
72362306a36Sopenharmony_ci		pnode->num += 1;
72462306a36Sopenharmony_ci	}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	row = 0;
72762306a36Sopenharmony_ci	for (i = UBIFS_LPT_FANOUT; cnt > i; i <<= UBIFS_LPT_FANOUT_SHIFT)
72862306a36Sopenharmony_ci		row += 1;
72962306a36Sopenharmony_ci	/* Add all nnodes, one level at a time */
73062306a36Sopenharmony_ci	while (1) {
73162306a36Sopenharmony_ci		/* Number of internal nodes (nnodes) at next level */
73262306a36Sopenharmony_ci		cnt = DIV_ROUND_UP(cnt, UBIFS_LPT_FANOUT);
73362306a36Sopenharmony_ci		for (i = 0; i < cnt; i++) {
73462306a36Sopenharmony_ci			if (len + c->nnode_sz > c->leb_size) {
73562306a36Sopenharmony_ci				alen = ALIGN(len, c->min_io_size);
73662306a36Sopenharmony_ci				set_ltab(c, lnum, c->leb_size - alen,
73762306a36Sopenharmony_ci					    alen - len);
73862306a36Sopenharmony_ci				memset(p, 0xff, alen - len);
73962306a36Sopenharmony_ci				err = ubifs_leb_change(c, lnum++, buf, alen);
74062306a36Sopenharmony_ci				if (err)
74162306a36Sopenharmony_ci					goto out;
74262306a36Sopenharmony_ci				p = buf;
74362306a36Sopenharmony_ci				len = 0;
74462306a36Sopenharmony_ci			}
74562306a36Sopenharmony_ci			/* Only 1 nnode at this level, so it is the root */
74662306a36Sopenharmony_ci			if (cnt == 1) {
74762306a36Sopenharmony_ci				c->lpt_lnum = lnum;
74862306a36Sopenharmony_ci				c->lpt_offs = len;
74962306a36Sopenharmony_ci			}
75062306a36Sopenharmony_ci			/* Set branches to the level below */
75162306a36Sopenharmony_ci			for (j = 0; j < UBIFS_LPT_FANOUT; j++) {
75262306a36Sopenharmony_ci				if (bcnt) {
75362306a36Sopenharmony_ci					if (boffs + bsz > c->leb_size) {
75462306a36Sopenharmony_ci						blnum += 1;
75562306a36Sopenharmony_ci						boffs = 0;
75662306a36Sopenharmony_ci					}
75762306a36Sopenharmony_ci					nnode->nbranch[j].lnum = blnum;
75862306a36Sopenharmony_ci					nnode->nbranch[j].offs = boffs;
75962306a36Sopenharmony_ci					boffs += bsz;
76062306a36Sopenharmony_ci					bcnt--;
76162306a36Sopenharmony_ci				} else {
76262306a36Sopenharmony_ci					nnode->nbranch[j].lnum = 0;
76362306a36Sopenharmony_ci					nnode->nbranch[j].offs = 0;
76462306a36Sopenharmony_ci				}
76562306a36Sopenharmony_ci			}
76662306a36Sopenharmony_ci			nnode->num = calc_nnode_num(row, i);
76762306a36Sopenharmony_ci			ubifs_pack_nnode(c, p, nnode);
76862306a36Sopenharmony_ci			p += c->nnode_sz;
76962306a36Sopenharmony_ci			len += c->nnode_sz;
77062306a36Sopenharmony_ci		}
77162306a36Sopenharmony_ci		/* Only 1 nnode at this level, so it is the root */
77262306a36Sopenharmony_ci		if (cnt == 1)
77362306a36Sopenharmony_ci			break;
77462306a36Sopenharmony_ci		/* Update the information about the level below */
77562306a36Sopenharmony_ci		bcnt = cnt;
77662306a36Sopenharmony_ci		bsz = c->nnode_sz;
77762306a36Sopenharmony_ci		row -= 1;
77862306a36Sopenharmony_ci	}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	if (*big_lpt) {
78162306a36Sopenharmony_ci		/* Need to add LPT's save table */
78262306a36Sopenharmony_ci		if (len + c->lsave_sz > c->leb_size) {
78362306a36Sopenharmony_ci			alen = ALIGN(len, c->min_io_size);
78462306a36Sopenharmony_ci			set_ltab(c, lnum, c->leb_size - alen, alen - len);
78562306a36Sopenharmony_ci			memset(p, 0xff, alen - len);
78662306a36Sopenharmony_ci			err = ubifs_leb_change(c, lnum++, buf, alen);
78762306a36Sopenharmony_ci			if (err)
78862306a36Sopenharmony_ci				goto out;
78962306a36Sopenharmony_ci			p = buf;
79062306a36Sopenharmony_ci			len = 0;
79162306a36Sopenharmony_ci		}
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci		c->lsave_lnum = lnum;
79462306a36Sopenharmony_ci		c->lsave_offs = len;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci		for (i = 0; i < c->lsave_cnt && i < *main_lebs; i++)
79762306a36Sopenharmony_ci			lsave[i] = c->main_first + i;
79862306a36Sopenharmony_ci		for (; i < c->lsave_cnt; i++)
79962306a36Sopenharmony_ci			lsave[i] = c->main_first;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci		ubifs_pack_lsave(c, p, lsave);
80262306a36Sopenharmony_ci		p += c->lsave_sz;
80362306a36Sopenharmony_ci		len += c->lsave_sz;
80462306a36Sopenharmony_ci	}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	/* Need to add LPT's own LEB properties table */
80762306a36Sopenharmony_ci	if (len + c->ltab_sz > c->leb_size) {
80862306a36Sopenharmony_ci		alen = ALIGN(len, c->min_io_size);
80962306a36Sopenharmony_ci		set_ltab(c, lnum, c->leb_size - alen, alen - len);
81062306a36Sopenharmony_ci		memset(p, 0xff, alen - len);
81162306a36Sopenharmony_ci		err = ubifs_leb_change(c, lnum++, buf, alen);
81262306a36Sopenharmony_ci		if (err)
81362306a36Sopenharmony_ci			goto out;
81462306a36Sopenharmony_ci		p = buf;
81562306a36Sopenharmony_ci		len = 0;
81662306a36Sopenharmony_ci	}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	c->ltab_lnum = lnum;
81962306a36Sopenharmony_ci	c->ltab_offs = len;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	/* Update ltab before packing it */
82262306a36Sopenharmony_ci	len += c->ltab_sz;
82362306a36Sopenharmony_ci	alen = ALIGN(len, c->min_io_size);
82462306a36Sopenharmony_ci	set_ltab(c, lnum, c->leb_size - alen, alen - len);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	ubifs_pack_ltab(c, p, ltab);
82762306a36Sopenharmony_ci	p += c->ltab_sz;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	/* Write remaining buffer */
83062306a36Sopenharmony_ci	memset(p, 0xff, alen - len);
83162306a36Sopenharmony_ci	err = ubifs_leb_change(c, lnum, buf, alen);
83262306a36Sopenharmony_ci	if (err)
83362306a36Sopenharmony_ci		goto out;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	err = ubifs_shash_final(c, desc, hash);
83662306a36Sopenharmony_ci	if (err)
83762306a36Sopenharmony_ci		goto out;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	c->nhead_lnum = lnum;
84062306a36Sopenharmony_ci	c->nhead_offs = ALIGN(len, c->min_io_size);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	dbg_lp("space_bits %d", c->space_bits);
84362306a36Sopenharmony_ci	dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits);
84462306a36Sopenharmony_ci	dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits);
84562306a36Sopenharmony_ci	dbg_lp("lpt_spc_bits %d", c->lpt_spc_bits);
84662306a36Sopenharmony_ci	dbg_lp("pcnt_bits %d", c->pcnt_bits);
84762306a36Sopenharmony_ci	dbg_lp("lnum_bits %d", c->lnum_bits);
84862306a36Sopenharmony_ci	dbg_lp("pnode_sz %d", c->pnode_sz);
84962306a36Sopenharmony_ci	dbg_lp("nnode_sz %d", c->nnode_sz);
85062306a36Sopenharmony_ci	dbg_lp("ltab_sz %d", c->ltab_sz);
85162306a36Sopenharmony_ci	dbg_lp("lsave_sz %d", c->lsave_sz);
85262306a36Sopenharmony_ci	dbg_lp("lsave_cnt %d", c->lsave_cnt);
85362306a36Sopenharmony_ci	dbg_lp("lpt_hght %d", c->lpt_hght);
85462306a36Sopenharmony_ci	dbg_lp("big_lpt %u", c->big_lpt);
85562306a36Sopenharmony_ci	dbg_lp("LPT root is at %d:%d", c->lpt_lnum, c->lpt_offs);
85662306a36Sopenharmony_ci	dbg_lp("LPT head is at %d:%d", c->nhead_lnum, c->nhead_offs);
85762306a36Sopenharmony_ci	dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs);
85862306a36Sopenharmony_ci	if (c->big_lpt)
85962306a36Sopenharmony_ci		dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs);
86062306a36Sopenharmony_ciout:
86162306a36Sopenharmony_ci	c->ltab = NULL;
86262306a36Sopenharmony_ci	kfree(desc);
86362306a36Sopenharmony_ci	kfree(lsave);
86462306a36Sopenharmony_ci	vfree(ltab);
86562306a36Sopenharmony_ci	vfree(buf);
86662306a36Sopenharmony_ci	kfree(nnode);
86762306a36Sopenharmony_ci	kfree(pnode);
86862306a36Sopenharmony_ci	return err;
86962306a36Sopenharmony_ci}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci/**
87262306a36Sopenharmony_ci * update_cats - add LEB properties of a pnode to LEB category lists and heaps.
87362306a36Sopenharmony_ci * @c: UBIFS file-system description object
87462306a36Sopenharmony_ci * @pnode: pnode
87562306a36Sopenharmony_ci *
87662306a36Sopenharmony_ci * When a pnode is loaded into memory, the LEB properties it contains are added,
87762306a36Sopenharmony_ci * by this function, to the LEB category lists and heaps.
87862306a36Sopenharmony_ci */
87962306a36Sopenharmony_cistatic void update_cats(struct ubifs_info *c, struct ubifs_pnode *pnode)
88062306a36Sopenharmony_ci{
88162306a36Sopenharmony_ci	int i;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
88462306a36Sopenharmony_ci		int cat = pnode->lprops[i].flags & LPROPS_CAT_MASK;
88562306a36Sopenharmony_ci		int lnum = pnode->lprops[i].lnum;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci		if (!lnum)
88862306a36Sopenharmony_ci			return;
88962306a36Sopenharmony_ci		ubifs_add_to_cat(c, &pnode->lprops[i], cat);
89062306a36Sopenharmony_ci	}
89162306a36Sopenharmony_ci}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci/**
89462306a36Sopenharmony_ci * replace_cats - add LEB properties of a pnode to LEB category lists and heaps.
89562306a36Sopenharmony_ci * @c: UBIFS file-system description object
89662306a36Sopenharmony_ci * @old_pnode: pnode copied
89762306a36Sopenharmony_ci * @new_pnode: pnode copy
89862306a36Sopenharmony_ci *
89962306a36Sopenharmony_ci * During commit it is sometimes necessary to copy a pnode
90062306a36Sopenharmony_ci * (see dirty_cow_pnode).  When that happens, references in
90162306a36Sopenharmony_ci * category lists and heaps must be replaced.  This function does that.
90262306a36Sopenharmony_ci */
90362306a36Sopenharmony_cistatic void replace_cats(struct ubifs_info *c, struct ubifs_pnode *old_pnode,
90462306a36Sopenharmony_ci			 struct ubifs_pnode *new_pnode)
90562306a36Sopenharmony_ci{
90662306a36Sopenharmony_ci	int i;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
90962306a36Sopenharmony_ci		if (!new_pnode->lprops[i].lnum)
91062306a36Sopenharmony_ci			return;
91162306a36Sopenharmony_ci		ubifs_replace_cat(c, &old_pnode->lprops[i],
91262306a36Sopenharmony_ci				  &new_pnode->lprops[i]);
91362306a36Sopenharmony_ci	}
91462306a36Sopenharmony_ci}
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci/**
91762306a36Sopenharmony_ci * check_lpt_crc - check LPT node crc is correct.
91862306a36Sopenharmony_ci * @c: UBIFS file-system description object
91962306a36Sopenharmony_ci * @buf: buffer containing node
92062306a36Sopenharmony_ci * @len: length of node
92162306a36Sopenharmony_ci *
92262306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
92362306a36Sopenharmony_ci */
92462306a36Sopenharmony_cistatic int check_lpt_crc(const struct ubifs_info *c, void *buf, int len)
92562306a36Sopenharmony_ci{
92662306a36Sopenharmony_ci	int pos = 0;
92762306a36Sopenharmony_ci	uint8_t *addr = buf;
92862306a36Sopenharmony_ci	uint16_t crc, calc_crc;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	crc = ubifs_unpack_bits(c, &addr, &pos, UBIFS_LPT_CRC_BITS);
93162306a36Sopenharmony_ci	calc_crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
93262306a36Sopenharmony_ci			 len - UBIFS_LPT_CRC_BYTES);
93362306a36Sopenharmony_ci	if (crc != calc_crc) {
93462306a36Sopenharmony_ci		ubifs_err(c, "invalid crc in LPT node: crc %hx calc %hx",
93562306a36Sopenharmony_ci			  crc, calc_crc);
93662306a36Sopenharmony_ci		dump_stack();
93762306a36Sopenharmony_ci		return -EINVAL;
93862306a36Sopenharmony_ci	}
93962306a36Sopenharmony_ci	return 0;
94062306a36Sopenharmony_ci}
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci/**
94362306a36Sopenharmony_ci * check_lpt_type - check LPT node type is correct.
94462306a36Sopenharmony_ci * @c: UBIFS file-system description object
94562306a36Sopenharmony_ci * @addr: address of type bit field is passed and returned updated here
94662306a36Sopenharmony_ci * @pos: position of type bit field is passed and returned updated here
94762306a36Sopenharmony_ci * @type: expected type
94862306a36Sopenharmony_ci *
94962306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
95062306a36Sopenharmony_ci */
95162306a36Sopenharmony_cistatic int check_lpt_type(const struct ubifs_info *c, uint8_t **addr,
95262306a36Sopenharmony_ci			  int *pos, int type)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	int node_type;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	node_type = ubifs_unpack_bits(c, addr, pos, UBIFS_LPT_TYPE_BITS);
95762306a36Sopenharmony_ci	if (node_type != type) {
95862306a36Sopenharmony_ci		ubifs_err(c, "invalid type (%d) in LPT node type %d",
95962306a36Sopenharmony_ci			  node_type, type);
96062306a36Sopenharmony_ci		dump_stack();
96162306a36Sopenharmony_ci		return -EINVAL;
96262306a36Sopenharmony_ci	}
96362306a36Sopenharmony_ci	return 0;
96462306a36Sopenharmony_ci}
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci/**
96762306a36Sopenharmony_ci * unpack_pnode - unpack a pnode.
96862306a36Sopenharmony_ci * @c: UBIFS file-system description object
96962306a36Sopenharmony_ci * @buf: buffer containing packed pnode to unpack
97062306a36Sopenharmony_ci * @pnode: pnode structure to fill
97162306a36Sopenharmony_ci *
97262306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
97362306a36Sopenharmony_ci */
97462306a36Sopenharmony_cistatic int unpack_pnode(const struct ubifs_info *c, void *buf,
97562306a36Sopenharmony_ci			struct ubifs_pnode *pnode)
97662306a36Sopenharmony_ci{
97762306a36Sopenharmony_ci	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
97862306a36Sopenharmony_ci	int i, pos = 0, err;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	err = check_lpt_type(c, &addr, &pos, UBIFS_LPT_PNODE);
98162306a36Sopenharmony_ci	if (err)
98262306a36Sopenharmony_ci		return err;
98362306a36Sopenharmony_ci	if (c->big_lpt)
98462306a36Sopenharmony_ci		pnode->num = ubifs_unpack_bits(c, &addr, &pos, c->pcnt_bits);
98562306a36Sopenharmony_ci	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
98662306a36Sopenharmony_ci		struct ubifs_lprops * const lprops = &pnode->lprops[i];
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci		lprops->free = ubifs_unpack_bits(c, &addr, &pos, c->space_bits);
98962306a36Sopenharmony_ci		lprops->free <<= 3;
99062306a36Sopenharmony_ci		lprops->dirty = ubifs_unpack_bits(c, &addr, &pos, c->space_bits);
99162306a36Sopenharmony_ci		lprops->dirty <<= 3;
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci		if (ubifs_unpack_bits(c, &addr, &pos, 1))
99462306a36Sopenharmony_ci			lprops->flags = LPROPS_INDEX;
99562306a36Sopenharmony_ci		else
99662306a36Sopenharmony_ci			lprops->flags = 0;
99762306a36Sopenharmony_ci		lprops->flags |= ubifs_categorize_lprops(c, lprops);
99862306a36Sopenharmony_ci	}
99962306a36Sopenharmony_ci	err = check_lpt_crc(c, buf, c->pnode_sz);
100062306a36Sopenharmony_ci	return err;
100162306a36Sopenharmony_ci}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci/**
100462306a36Sopenharmony_ci * ubifs_unpack_nnode - unpack a nnode.
100562306a36Sopenharmony_ci * @c: UBIFS file-system description object
100662306a36Sopenharmony_ci * @buf: buffer containing packed nnode to unpack
100762306a36Sopenharmony_ci * @nnode: nnode structure to fill
100862306a36Sopenharmony_ci *
100962306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
101062306a36Sopenharmony_ci */
101162306a36Sopenharmony_ciint ubifs_unpack_nnode(const struct ubifs_info *c, void *buf,
101262306a36Sopenharmony_ci		       struct ubifs_nnode *nnode)
101362306a36Sopenharmony_ci{
101462306a36Sopenharmony_ci	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
101562306a36Sopenharmony_ci	int i, pos = 0, err;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	err = check_lpt_type(c, &addr, &pos, UBIFS_LPT_NNODE);
101862306a36Sopenharmony_ci	if (err)
101962306a36Sopenharmony_ci		return err;
102062306a36Sopenharmony_ci	if (c->big_lpt)
102162306a36Sopenharmony_ci		nnode->num = ubifs_unpack_bits(c, &addr, &pos, c->pcnt_bits);
102262306a36Sopenharmony_ci	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
102362306a36Sopenharmony_ci		int lnum;
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci		lnum = ubifs_unpack_bits(c, &addr, &pos, c->lpt_lnum_bits) +
102662306a36Sopenharmony_ci		       c->lpt_first;
102762306a36Sopenharmony_ci		if (lnum == c->lpt_last + 1)
102862306a36Sopenharmony_ci			lnum = 0;
102962306a36Sopenharmony_ci		nnode->nbranch[i].lnum = lnum;
103062306a36Sopenharmony_ci		nnode->nbranch[i].offs = ubifs_unpack_bits(c, &addr, &pos,
103162306a36Sopenharmony_ci						     c->lpt_offs_bits);
103262306a36Sopenharmony_ci	}
103362306a36Sopenharmony_ci	err = check_lpt_crc(c, buf, c->nnode_sz);
103462306a36Sopenharmony_ci	return err;
103562306a36Sopenharmony_ci}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci/**
103862306a36Sopenharmony_ci * unpack_ltab - unpack the LPT's own lprops table.
103962306a36Sopenharmony_ci * @c: UBIFS file-system description object
104062306a36Sopenharmony_ci * @buf: buffer from which to unpack
104162306a36Sopenharmony_ci *
104262306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
104362306a36Sopenharmony_ci */
104462306a36Sopenharmony_cistatic int unpack_ltab(const struct ubifs_info *c, void *buf)
104562306a36Sopenharmony_ci{
104662306a36Sopenharmony_ci	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
104762306a36Sopenharmony_ci	int i, pos = 0, err;
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	err = check_lpt_type(c, &addr, &pos, UBIFS_LPT_LTAB);
105062306a36Sopenharmony_ci	if (err)
105162306a36Sopenharmony_ci		return err;
105262306a36Sopenharmony_ci	for (i = 0; i < c->lpt_lebs; i++) {
105362306a36Sopenharmony_ci		int free = ubifs_unpack_bits(c, &addr, &pos, c->lpt_spc_bits);
105462306a36Sopenharmony_ci		int dirty = ubifs_unpack_bits(c, &addr, &pos, c->lpt_spc_bits);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci		if (free < 0 || free > c->leb_size || dirty < 0 ||
105762306a36Sopenharmony_ci		    dirty > c->leb_size || free + dirty > c->leb_size)
105862306a36Sopenharmony_ci			return -EINVAL;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci		c->ltab[i].free = free;
106162306a36Sopenharmony_ci		c->ltab[i].dirty = dirty;
106262306a36Sopenharmony_ci		c->ltab[i].tgc = 0;
106362306a36Sopenharmony_ci		c->ltab[i].cmt = 0;
106462306a36Sopenharmony_ci	}
106562306a36Sopenharmony_ci	err = check_lpt_crc(c, buf, c->ltab_sz);
106662306a36Sopenharmony_ci	return err;
106762306a36Sopenharmony_ci}
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci/**
107062306a36Sopenharmony_ci * unpack_lsave - unpack the LPT's save table.
107162306a36Sopenharmony_ci * @c: UBIFS file-system description object
107262306a36Sopenharmony_ci * @buf: buffer from which to unpack
107362306a36Sopenharmony_ci *
107462306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
107562306a36Sopenharmony_ci */
107662306a36Sopenharmony_cistatic int unpack_lsave(const struct ubifs_info *c, void *buf)
107762306a36Sopenharmony_ci{
107862306a36Sopenharmony_ci	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
107962306a36Sopenharmony_ci	int i, pos = 0, err;
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	err = check_lpt_type(c, &addr, &pos, UBIFS_LPT_LSAVE);
108262306a36Sopenharmony_ci	if (err)
108362306a36Sopenharmony_ci		return err;
108462306a36Sopenharmony_ci	for (i = 0; i < c->lsave_cnt; i++) {
108562306a36Sopenharmony_ci		int lnum = ubifs_unpack_bits(c, &addr, &pos, c->lnum_bits);
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci		if (lnum < c->main_first || lnum >= c->leb_cnt)
108862306a36Sopenharmony_ci			return -EINVAL;
108962306a36Sopenharmony_ci		c->lsave[i] = lnum;
109062306a36Sopenharmony_ci	}
109162306a36Sopenharmony_ci	err = check_lpt_crc(c, buf, c->lsave_sz);
109262306a36Sopenharmony_ci	return err;
109362306a36Sopenharmony_ci}
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci/**
109662306a36Sopenharmony_ci * validate_nnode - validate a nnode.
109762306a36Sopenharmony_ci * @c: UBIFS file-system description object
109862306a36Sopenharmony_ci * @nnode: nnode to validate
109962306a36Sopenharmony_ci * @parent: parent nnode (or NULL for the root nnode)
110062306a36Sopenharmony_ci * @iip: index in parent
110162306a36Sopenharmony_ci *
110262306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
110362306a36Sopenharmony_ci */
110462306a36Sopenharmony_cistatic int validate_nnode(const struct ubifs_info *c, struct ubifs_nnode *nnode,
110562306a36Sopenharmony_ci			  struct ubifs_nnode *parent, int iip)
110662306a36Sopenharmony_ci{
110762306a36Sopenharmony_ci	int i, lvl, max_offs;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	if (c->big_lpt) {
111062306a36Sopenharmony_ci		int num = calc_nnode_num_from_parent(c, parent, iip);
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci		if (nnode->num != num)
111362306a36Sopenharmony_ci			return -EINVAL;
111462306a36Sopenharmony_ci	}
111562306a36Sopenharmony_ci	lvl = parent ? parent->level - 1 : c->lpt_hght;
111662306a36Sopenharmony_ci	if (lvl < 1)
111762306a36Sopenharmony_ci		return -EINVAL;
111862306a36Sopenharmony_ci	if (lvl == 1)
111962306a36Sopenharmony_ci		max_offs = c->leb_size - c->pnode_sz;
112062306a36Sopenharmony_ci	else
112162306a36Sopenharmony_ci		max_offs = c->leb_size - c->nnode_sz;
112262306a36Sopenharmony_ci	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
112362306a36Sopenharmony_ci		int lnum = nnode->nbranch[i].lnum;
112462306a36Sopenharmony_ci		int offs = nnode->nbranch[i].offs;
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci		if (lnum == 0) {
112762306a36Sopenharmony_ci			if (offs != 0)
112862306a36Sopenharmony_ci				return -EINVAL;
112962306a36Sopenharmony_ci			continue;
113062306a36Sopenharmony_ci		}
113162306a36Sopenharmony_ci		if (lnum < c->lpt_first || lnum > c->lpt_last)
113262306a36Sopenharmony_ci			return -EINVAL;
113362306a36Sopenharmony_ci		if (offs < 0 || offs > max_offs)
113462306a36Sopenharmony_ci			return -EINVAL;
113562306a36Sopenharmony_ci	}
113662306a36Sopenharmony_ci	return 0;
113762306a36Sopenharmony_ci}
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci/**
114062306a36Sopenharmony_ci * validate_pnode - validate a pnode.
114162306a36Sopenharmony_ci * @c: UBIFS file-system description object
114262306a36Sopenharmony_ci * @pnode: pnode to validate
114362306a36Sopenharmony_ci * @parent: parent nnode
114462306a36Sopenharmony_ci * @iip: index in parent
114562306a36Sopenharmony_ci *
114662306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
114762306a36Sopenharmony_ci */
114862306a36Sopenharmony_cistatic int validate_pnode(const struct ubifs_info *c, struct ubifs_pnode *pnode,
114962306a36Sopenharmony_ci			  struct ubifs_nnode *parent, int iip)
115062306a36Sopenharmony_ci{
115162306a36Sopenharmony_ci	int i;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	if (c->big_lpt) {
115462306a36Sopenharmony_ci		int num = calc_pnode_num_from_parent(c, parent, iip);
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci		if (pnode->num != num)
115762306a36Sopenharmony_ci			return -EINVAL;
115862306a36Sopenharmony_ci	}
115962306a36Sopenharmony_ci	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
116062306a36Sopenharmony_ci		int free = pnode->lprops[i].free;
116162306a36Sopenharmony_ci		int dirty = pnode->lprops[i].dirty;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci		if (free < 0 || free > c->leb_size || free % c->min_io_size ||
116462306a36Sopenharmony_ci		    (free & 7))
116562306a36Sopenharmony_ci			return -EINVAL;
116662306a36Sopenharmony_ci		if (dirty < 0 || dirty > c->leb_size || (dirty & 7))
116762306a36Sopenharmony_ci			return -EINVAL;
116862306a36Sopenharmony_ci		if (dirty + free > c->leb_size)
116962306a36Sopenharmony_ci			return -EINVAL;
117062306a36Sopenharmony_ci	}
117162306a36Sopenharmony_ci	return 0;
117262306a36Sopenharmony_ci}
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci/**
117562306a36Sopenharmony_ci * set_pnode_lnum - set LEB numbers on a pnode.
117662306a36Sopenharmony_ci * @c: UBIFS file-system description object
117762306a36Sopenharmony_ci * @pnode: pnode to update
117862306a36Sopenharmony_ci *
117962306a36Sopenharmony_ci * This function calculates the LEB numbers for the LEB properties it contains
118062306a36Sopenharmony_ci * based on the pnode number.
118162306a36Sopenharmony_ci */
118262306a36Sopenharmony_cistatic void set_pnode_lnum(const struct ubifs_info *c,
118362306a36Sopenharmony_ci			   struct ubifs_pnode *pnode)
118462306a36Sopenharmony_ci{
118562306a36Sopenharmony_ci	int i, lnum;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	lnum = (pnode->num << UBIFS_LPT_FANOUT_SHIFT) + c->main_first;
118862306a36Sopenharmony_ci	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
118962306a36Sopenharmony_ci		if (lnum >= c->leb_cnt)
119062306a36Sopenharmony_ci			return;
119162306a36Sopenharmony_ci		pnode->lprops[i].lnum = lnum++;
119262306a36Sopenharmony_ci	}
119362306a36Sopenharmony_ci}
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci/**
119662306a36Sopenharmony_ci * ubifs_read_nnode - read a nnode from flash and link it to the tree in memory.
119762306a36Sopenharmony_ci * @c: UBIFS file-system description object
119862306a36Sopenharmony_ci * @parent: parent nnode (or NULL for the root)
119962306a36Sopenharmony_ci * @iip: index in parent
120062306a36Sopenharmony_ci *
120162306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
120262306a36Sopenharmony_ci */
120362306a36Sopenharmony_ciint ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
120462306a36Sopenharmony_ci{
120562306a36Sopenharmony_ci	struct ubifs_nbranch *branch = NULL;
120662306a36Sopenharmony_ci	struct ubifs_nnode *nnode = NULL;
120762306a36Sopenharmony_ci	void *buf = c->lpt_nod_buf;
120862306a36Sopenharmony_ci	int err, lnum, offs;
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	if (parent) {
121162306a36Sopenharmony_ci		branch = &parent->nbranch[iip];
121262306a36Sopenharmony_ci		lnum = branch->lnum;
121362306a36Sopenharmony_ci		offs = branch->offs;
121462306a36Sopenharmony_ci	} else {
121562306a36Sopenharmony_ci		lnum = c->lpt_lnum;
121662306a36Sopenharmony_ci		offs = c->lpt_offs;
121762306a36Sopenharmony_ci	}
121862306a36Sopenharmony_ci	nnode = kzalloc(sizeof(struct ubifs_nnode), GFP_NOFS);
121962306a36Sopenharmony_ci	if (!nnode) {
122062306a36Sopenharmony_ci		err = -ENOMEM;
122162306a36Sopenharmony_ci		goto out;
122262306a36Sopenharmony_ci	}
122362306a36Sopenharmony_ci	if (lnum == 0) {
122462306a36Sopenharmony_ci		/*
122562306a36Sopenharmony_ci		 * This nnode was not written which just means that the LEB
122662306a36Sopenharmony_ci		 * properties in the subtree below it describe empty LEBs. We
122762306a36Sopenharmony_ci		 * make the nnode as though we had read it, which in fact means
122862306a36Sopenharmony_ci		 * doing almost nothing.
122962306a36Sopenharmony_ci		 */
123062306a36Sopenharmony_ci		if (c->big_lpt)
123162306a36Sopenharmony_ci			nnode->num = calc_nnode_num_from_parent(c, parent, iip);
123262306a36Sopenharmony_ci	} else {
123362306a36Sopenharmony_ci		err = ubifs_leb_read(c, lnum, buf, offs, c->nnode_sz, 1);
123462306a36Sopenharmony_ci		if (err)
123562306a36Sopenharmony_ci			goto out;
123662306a36Sopenharmony_ci		err = ubifs_unpack_nnode(c, buf, nnode);
123762306a36Sopenharmony_ci		if (err)
123862306a36Sopenharmony_ci			goto out;
123962306a36Sopenharmony_ci	}
124062306a36Sopenharmony_ci	err = validate_nnode(c, nnode, parent, iip);
124162306a36Sopenharmony_ci	if (err)
124262306a36Sopenharmony_ci		goto out;
124362306a36Sopenharmony_ci	if (!c->big_lpt)
124462306a36Sopenharmony_ci		nnode->num = calc_nnode_num_from_parent(c, parent, iip);
124562306a36Sopenharmony_ci	if (parent) {
124662306a36Sopenharmony_ci		branch->nnode = nnode;
124762306a36Sopenharmony_ci		nnode->level = parent->level - 1;
124862306a36Sopenharmony_ci	} else {
124962306a36Sopenharmony_ci		c->nroot = nnode;
125062306a36Sopenharmony_ci		nnode->level = c->lpt_hght;
125162306a36Sopenharmony_ci	}
125262306a36Sopenharmony_ci	nnode->parent = parent;
125362306a36Sopenharmony_ci	nnode->iip = iip;
125462306a36Sopenharmony_ci	return 0;
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ciout:
125762306a36Sopenharmony_ci	ubifs_err(c, "error %d reading nnode at %d:%d", err, lnum, offs);
125862306a36Sopenharmony_ci	dump_stack();
125962306a36Sopenharmony_ci	kfree(nnode);
126062306a36Sopenharmony_ci	return err;
126162306a36Sopenharmony_ci}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci/**
126462306a36Sopenharmony_ci * read_pnode - read a pnode from flash and link it to the tree in memory.
126562306a36Sopenharmony_ci * @c: UBIFS file-system description object
126662306a36Sopenharmony_ci * @parent: parent nnode
126762306a36Sopenharmony_ci * @iip: index in parent
126862306a36Sopenharmony_ci *
126962306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
127062306a36Sopenharmony_ci */
127162306a36Sopenharmony_cistatic int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
127262306a36Sopenharmony_ci{
127362306a36Sopenharmony_ci	struct ubifs_nbranch *branch;
127462306a36Sopenharmony_ci	struct ubifs_pnode *pnode = NULL;
127562306a36Sopenharmony_ci	void *buf = c->lpt_nod_buf;
127662306a36Sopenharmony_ci	int err, lnum, offs;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	branch = &parent->nbranch[iip];
127962306a36Sopenharmony_ci	lnum = branch->lnum;
128062306a36Sopenharmony_ci	offs = branch->offs;
128162306a36Sopenharmony_ci	pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_NOFS);
128262306a36Sopenharmony_ci	if (!pnode)
128362306a36Sopenharmony_ci		return -ENOMEM;
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	if (lnum == 0) {
128662306a36Sopenharmony_ci		/*
128762306a36Sopenharmony_ci		 * This pnode was not written which just means that the LEB
128862306a36Sopenharmony_ci		 * properties in it describe empty LEBs. We make the pnode as
128962306a36Sopenharmony_ci		 * though we had read it.
129062306a36Sopenharmony_ci		 */
129162306a36Sopenharmony_ci		int i;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci		if (c->big_lpt)
129462306a36Sopenharmony_ci			pnode->num = calc_pnode_num_from_parent(c, parent, iip);
129562306a36Sopenharmony_ci		for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
129662306a36Sopenharmony_ci			struct ubifs_lprops * const lprops = &pnode->lprops[i];
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci			lprops->free = c->leb_size;
129962306a36Sopenharmony_ci			lprops->flags = ubifs_categorize_lprops(c, lprops);
130062306a36Sopenharmony_ci		}
130162306a36Sopenharmony_ci	} else {
130262306a36Sopenharmony_ci		err = ubifs_leb_read(c, lnum, buf, offs, c->pnode_sz, 1);
130362306a36Sopenharmony_ci		if (err)
130462306a36Sopenharmony_ci			goto out;
130562306a36Sopenharmony_ci		err = unpack_pnode(c, buf, pnode);
130662306a36Sopenharmony_ci		if (err)
130762306a36Sopenharmony_ci			goto out;
130862306a36Sopenharmony_ci	}
130962306a36Sopenharmony_ci	err = validate_pnode(c, pnode, parent, iip);
131062306a36Sopenharmony_ci	if (err)
131162306a36Sopenharmony_ci		goto out;
131262306a36Sopenharmony_ci	if (!c->big_lpt)
131362306a36Sopenharmony_ci		pnode->num = calc_pnode_num_from_parent(c, parent, iip);
131462306a36Sopenharmony_ci	branch->pnode = pnode;
131562306a36Sopenharmony_ci	pnode->parent = parent;
131662306a36Sopenharmony_ci	pnode->iip = iip;
131762306a36Sopenharmony_ci	set_pnode_lnum(c, pnode);
131862306a36Sopenharmony_ci	c->pnodes_have += 1;
131962306a36Sopenharmony_ci	return 0;
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ciout:
132262306a36Sopenharmony_ci	ubifs_err(c, "error %d reading pnode at %d:%d", err, lnum, offs);
132362306a36Sopenharmony_ci	ubifs_dump_pnode(c, pnode, parent, iip);
132462306a36Sopenharmony_ci	dump_stack();
132562306a36Sopenharmony_ci	ubifs_err(c, "calc num: %d", calc_pnode_num_from_parent(c, parent, iip));
132662306a36Sopenharmony_ci	kfree(pnode);
132762306a36Sopenharmony_ci	return err;
132862306a36Sopenharmony_ci}
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci/**
133162306a36Sopenharmony_ci * read_ltab - read LPT's own lprops table.
133262306a36Sopenharmony_ci * @c: UBIFS file-system description object
133362306a36Sopenharmony_ci *
133462306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
133562306a36Sopenharmony_ci */
133662306a36Sopenharmony_cistatic int read_ltab(struct ubifs_info *c)
133762306a36Sopenharmony_ci{
133862306a36Sopenharmony_ci	int err;
133962306a36Sopenharmony_ci	void *buf;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	buf = vmalloc(c->ltab_sz);
134262306a36Sopenharmony_ci	if (!buf)
134362306a36Sopenharmony_ci		return -ENOMEM;
134462306a36Sopenharmony_ci	err = ubifs_leb_read(c, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz, 1);
134562306a36Sopenharmony_ci	if (err)
134662306a36Sopenharmony_ci		goto out;
134762306a36Sopenharmony_ci	err = unpack_ltab(c, buf);
134862306a36Sopenharmony_ciout:
134962306a36Sopenharmony_ci	vfree(buf);
135062306a36Sopenharmony_ci	return err;
135162306a36Sopenharmony_ci}
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci/**
135462306a36Sopenharmony_ci * read_lsave - read LPT's save table.
135562306a36Sopenharmony_ci * @c: UBIFS file-system description object
135662306a36Sopenharmony_ci *
135762306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
135862306a36Sopenharmony_ci */
135962306a36Sopenharmony_cistatic int read_lsave(struct ubifs_info *c)
136062306a36Sopenharmony_ci{
136162306a36Sopenharmony_ci	int err, i;
136262306a36Sopenharmony_ci	void *buf;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	buf = vmalloc(c->lsave_sz);
136562306a36Sopenharmony_ci	if (!buf)
136662306a36Sopenharmony_ci		return -ENOMEM;
136762306a36Sopenharmony_ci	err = ubifs_leb_read(c, c->lsave_lnum, buf, c->lsave_offs,
136862306a36Sopenharmony_ci			     c->lsave_sz, 1);
136962306a36Sopenharmony_ci	if (err)
137062306a36Sopenharmony_ci		goto out;
137162306a36Sopenharmony_ci	err = unpack_lsave(c, buf);
137262306a36Sopenharmony_ci	if (err)
137362306a36Sopenharmony_ci		goto out;
137462306a36Sopenharmony_ci	for (i = 0; i < c->lsave_cnt; i++) {
137562306a36Sopenharmony_ci		int lnum = c->lsave[i];
137662306a36Sopenharmony_ci		struct ubifs_lprops *lprops;
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci		/*
137962306a36Sopenharmony_ci		 * Due to automatic resizing, the values in the lsave table
138062306a36Sopenharmony_ci		 * could be beyond the volume size - just ignore them.
138162306a36Sopenharmony_ci		 */
138262306a36Sopenharmony_ci		if (lnum >= c->leb_cnt)
138362306a36Sopenharmony_ci			continue;
138462306a36Sopenharmony_ci		lprops = ubifs_lpt_lookup(c, lnum);
138562306a36Sopenharmony_ci		if (IS_ERR(lprops)) {
138662306a36Sopenharmony_ci			err = PTR_ERR(lprops);
138762306a36Sopenharmony_ci			goto out;
138862306a36Sopenharmony_ci		}
138962306a36Sopenharmony_ci	}
139062306a36Sopenharmony_ciout:
139162306a36Sopenharmony_ci	vfree(buf);
139262306a36Sopenharmony_ci	return err;
139362306a36Sopenharmony_ci}
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci/**
139662306a36Sopenharmony_ci * ubifs_get_nnode - get a nnode.
139762306a36Sopenharmony_ci * @c: UBIFS file-system description object
139862306a36Sopenharmony_ci * @parent: parent nnode (or NULL for the root)
139962306a36Sopenharmony_ci * @iip: index in parent
140062306a36Sopenharmony_ci *
140162306a36Sopenharmony_ci * This function returns a pointer to the nnode on success or a negative error
140262306a36Sopenharmony_ci * code on failure.
140362306a36Sopenharmony_ci */
140462306a36Sopenharmony_cistruct ubifs_nnode *ubifs_get_nnode(struct ubifs_info *c,
140562306a36Sopenharmony_ci				    struct ubifs_nnode *parent, int iip)
140662306a36Sopenharmony_ci{
140762306a36Sopenharmony_ci	struct ubifs_nbranch *branch;
140862306a36Sopenharmony_ci	struct ubifs_nnode *nnode;
140962306a36Sopenharmony_ci	int err;
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	branch = &parent->nbranch[iip];
141262306a36Sopenharmony_ci	nnode = branch->nnode;
141362306a36Sopenharmony_ci	if (nnode)
141462306a36Sopenharmony_ci		return nnode;
141562306a36Sopenharmony_ci	err = ubifs_read_nnode(c, parent, iip);
141662306a36Sopenharmony_ci	if (err)
141762306a36Sopenharmony_ci		return ERR_PTR(err);
141862306a36Sopenharmony_ci	return branch->nnode;
141962306a36Sopenharmony_ci}
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci/**
142262306a36Sopenharmony_ci * ubifs_get_pnode - get a pnode.
142362306a36Sopenharmony_ci * @c: UBIFS file-system description object
142462306a36Sopenharmony_ci * @parent: parent nnode
142562306a36Sopenharmony_ci * @iip: index in parent
142662306a36Sopenharmony_ci *
142762306a36Sopenharmony_ci * This function returns a pointer to the pnode on success or a negative error
142862306a36Sopenharmony_ci * code on failure.
142962306a36Sopenharmony_ci */
143062306a36Sopenharmony_cistruct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c,
143162306a36Sopenharmony_ci				    struct ubifs_nnode *parent, int iip)
143262306a36Sopenharmony_ci{
143362306a36Sopenharmony_ci	struct ubifs_nbranch *branch;
143462306a36Sopenharmony_ci	struct ubifs_pnode *pnode;
143562306a36Sopenharmony_ci	int err;
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	branch = &parent->nbranch[iip];
143862306a36Sopenharmony_ci	pnode = branch->pnode;
143962306a36Sopenharmony_ci	if (pnode)
144062306a36Sopenharmony_ci		return pnode;
144162306a36Sopenharmony_ci	err = read_pnode(c, parent, iip);
144262306a36Sopenharmony_ci	if (err)
144362306a36Sopenharmony_ci		return ERR_PTR(err);
144462306a36Sopenharmony_ci	update_cats(c, branch->pnode);
144562306a36Sopenharmony_ci	return branch->pnode;
144662306a36Sopenharmony_ci}
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci/**
144962306a36Sopenharmony_ci * ubifs_pnode_lookup - lookup a pnode in the LPT.
145062306a36Sopenharmony_ci * @c: UBIFS file-system description object
145162306a36Sopenharmony_ci * @i: pnode number (0 to (main_lebs - 1) / UBIFS_LPT_FANOUT)
145262306a36Sopenharmony_ci *
145362306a36Sopenharmony_ci * This function returns a pointer to the pnode on success or a negative
145462306a36Sopenharmony_ci * error code on failure.
145562306a36Sopenharmony_ci */
145662306a36Sopenharmony_cistruct ubifs_pnode *ubifs_pnode_lookup(struct ubifs_info *c, int i)
145762306a36Sopenharmony_ci{
145862306a36Sopenharmony_ci	int err, h, iip, shft;
145962306a36Sopenharmony_ci	struct ubifs_nnode *nnode;
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	if (!c->nroot) {
146262306a36Sopenharmony_ci		err = ubifs_read_nnode(c, NULL, 0);
146362306a36Sopenharmony_ci		if (err)
146462306a36Sopenharmony_ci			return ERR_PTR(err);
146562306a36Sopenharmony_ci	}
146662306a36Sopenharmony_ci	i <<= UBIFS_LPT_FANOUT_SHIFT;
146762306a36Sopenharmony_ci	nnode = c->nroot;
146862306a36Sopenharmony_ci	shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
146962306a36Sopenharmony_ci	for (h = 1; h < c->lpt_hght; h++) {
147062306a36Sopenharmony_ci		iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
147162306a36Sopenharmony_ci		shft -= UBIFS_LPT_FANOUT_SHIFT;
147262306a36Sopenharmony_ci		nnode = ubifs_get_nnode(c, nnode, iip);
147362306a36Sopenharmony_ci		if (IS_ERR(nnode))
147462306a36Sopenharmony_ci			return ERR_CAST(nnode);
147562306a36Sopenharmony_ci	}
147662306a36Sopenharmony_ci	iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
147762306a36Sopenharmony_ci	return ubifs_get_pnode(c, nnode, iip);
147862306a36Sopenharmony_ci}
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci/**
148162306a36Sopenharmony_ci * ubifs_lpt_lookup - lookup LEB properties in the LPT.
148262306a36Sopenharmony_ci * @c: UBIFS file-system description object
148362306a36Sopenharmony_ci * @lnum: LEB number to lookup
148462306a36Sopenharmony_ci *
148562306a36Sopenharmony_ci * This function returns a pointer to the LEB properties on success or a
148662306a36Sopenharmony_ci * negative error code on failure.
148762306a36Sopenharmony_ci */
148862306a36Sopenharmony_cistruct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum)
148962306a36Sopenharmony_ci{
149062306a36Sopenharmony_ci	int i, iip;
149162306a36Sopenharmony_ci	struct ubifs_pnode *pnode;
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	i = lnum - c->main_first;
149462306a36Sopenharmony_ci	pnode = ubifs_pnode_lookup(c, i >> UBIFS_LPT_FANOUT_SHIFT);
149562306a36Sopenharmony_ci	if (IS_ERR(pnode))
149662306a36Sopenharmony_ci		return ERR_CAST(pnode);
149762306a36Sopenharmony_ci	iip = (i & (UBIFS_LPT_FANOUT - 1));
149862306a36Sopenharmony_ci	dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum,
149962306a36Sopenharmony_ci	       pnode->lprops[iip].free, pnode->lprops[iip].dirty,
150062306a36Sopenharmony_ci	       pnode->lprops[iip].flags);
150162306a36Sopenharmony_ci	return &pnode->lprops[iip];
150262306a36Sopenharmony_ci}
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci/**
150562306a36Sopenharmony_ci * dirty_cow_nnode - ensure a nnode is not being committed.
150662306a36Sopenharmony_ci * @c: UBIFS file-system description object
150762306a36Sopenharmony_ci * @nnode: nnode to check
150862306a36Sopenharmony_ci *
150962306a36Sopenharmony_ci * Returns dirtied nnode on success or negative error code on failure.
151062306a36Sopenharmony_ci */
151162306a36Sopenharmony_cistatic struct ubifs_nnode *dirty_cow_nnode(struct ubifs_info *c,
151262306a36Sopenharmony_ci					   struct ubifs_nnode *nnode)
151362306a36Sopenharmony_ci{
151462306a36Sopenharmony_ci	struct ubifs_nnode *n;
151562306a36Sopenharmony_ci	int i;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	if (!test_bit(COW_CNODE, &nnode->flags)) {
151862306a36Sopenharmony_ci		/* nnode is not being committed */
151962306a36Sopenharmony_ci		if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) {
152062306a36Sopenharmony_ci			c->dirty_nn_cnt += 1;
152162306a36Sopenharmony_ci			ubifs_add_nnode_dirt(c, nnode);
152262306a36Sopenharmony_ci		}
152362306a36Sopenharmony_ci		return nnode;
152462306a36Sopenharmony_ci	}
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	/* nnode is being committed, so copy it */
152762306a36Sopenharmony_ci	n = kmemdup(nnode, sizeof(struct ubifs_nnode), GFP_NOFS);
152862306a36Sopenharmony_ci	if (unlikely(!n))
152962306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	n->cnext = NULL;
153262306a36Sopenharmony_ci	__set_bit(DIRTY_CNODE, &n->flags);
153362306a36Sopenharmony_ci	__clear_bit(COW_CNODE, &n->flags);
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	/* The children now have new parent */
153662306a36Sopenharmony_ci	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
153762306a36Sopenharmony_ci		struct ubifs_nbranch *branch = &n->nbranch[i];
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci		if (branch->cnode)
154062306a36Sopenharmony_ci			branch->cnode->parent = n;
154162306a36Sopenharmony_ci	}
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	ubifs_assert(c, !test_bit(OBSOLETE_CNODE, &nnode->flags));
154462306a36Sopenharmony_ci	__set_bit(OBSOLETE_CNODE, &nnode->flags);
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	c->dirty_nn_cnt += 1;
154762306a36Sopenharmony_ci	ubifs_add_nnode_dirt(c, nnode);
154862306a36Sopenharmony_ci	if (nnode->parent)
154962306a36Sopenharmony_ci		nnode->parent->nbranch[n->iip].nnode = n;
155062306a36Sopenharmony_ci	else
155162306a36Sopenharmony_ci		c->nroot = n;
155262306a36Sopenharmony_ci	return n;
155362306a36Sopenharmony_ci}
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci/**
155662306a36Sopenharmony_ci * dirty_cow_pnode - ensure a pnode is not being committed.
155762306a36Sopenharmony_ci * @c: UBIFS file-system description object
155862306a36Sopenharmony_ci * @pnode: pnode to check
155962306a36Sopenharmony_ci *
156062306a36Sopenharmony_ci * Returns dirtied pnode on success or negative error code on failure.
156162306a36Sopenharmony_ci */
156262306a36Sopenharmony_cistatic struct ubifs_pnode *dirty_cow_pnode(struct ubifs_info *c,
156362306a36Sopenharmony_ci					   struct ubifs_pnode *pnode)
156462306a36Sopenharmony_ci{
156562306a36Sopenharmony_ci	struct ubifs_pnode *p;
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	if (!test_bit(COW_CNODE, &pnode->flags)) {
156862306a36Sopenharmony_ci		/* pnode is not being committed */
156962306a36Sopenharmony_ci		if (!test_and_set_bit(DIRTY_CNODE, &pnode->flags)) {
157062306a36Sopenharmony_ci			c->dirty_pn_cnt += 1;
157162306a36Sopenharmony_ci			add_pnode_dirt(c, pnode);
157262306a36Sopenharmony_ci		}
157362306a36Sopenharmony_ci		return pnode;
157462306a36Sopenharmony_ci	}
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	/* pnode is being committed, so copy it */
157762306a36Sopenharmony_ci	p = kmemdup(pnode, sizeof(struct ubifs_pnode), GFP_NOFS);
157862306a36Sopenharmony_ci	if (unlikely(!p))
157962306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	p->cnext = NULL;
158262306a36Sopenharmony_ci	__set_bit(DIRTY_CNODE, &p->flags);
158362306a36Sopenharmony_ci	__clear_bit(COW_CNODE, &p->flags);
158462306a36Sopenharmony_ci	replace_cats(c, pnode, p);
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	ubifs_assert(c, !test_bit(OBSOLETE_CNODE, &pnode->flags));
158762306a36Sopenharmony_ci	__set_bit(OBSOLETE_CNODE, &pnode->flags);
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	c->dirty_pn_cnt += 1;
159062306a36Sopenharmony_ci	add_pnode_dirt(c, pnode);
159162306a36Sopenharmony_ci	pnode->parent->nbranch[p->iip].pnode = p;
159262306a36Sopenharmony_ci	return p;
159362306a36Sopenharmony_ci}
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci/**
159662306a36Sopenharmony_ci * ubifs_lpt_lookup_dirty - lookup LEB properties in the LPT.
159762306a36Sopenharmony_ci * @c: UBIFS file-system description object
159862306a36Sopenharmony_ci * @lnum: LEB number to lookup
159962306a36Sopenharmony_ci *
160062306a36Sopenharmony_ci * This function returns a pointer to the LEB properties on success or a
160162306a36Sopenharmony_ci * negative error code on failure.
160262306a36Sopenharmony_ci */
160362306a36Sopenharmony_cistruct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum)
160462306a36Sopenharmony_ci{
160562306a36Sopenharmony_ci	int err, i, h, iip, shft;
160662306a36Sopenharmony_ci	struct ubifs_nnode *nnode;
160762306a36Sopenharmony_ci	struct ubifs_pnode *pnode;
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	if (!c->nroot) {
161062306a36Sopenharmony_ci		err = ubifs_read_nnode(c, NULL, 0);
161162306a36Sopenharmony_ci		if (err)
161262306a36Sopenharmony_ci			return ERR_PTR(err);
161362306a36Sopenharmony_ci	}
161462306a36Sopenharmony_ci	nnode = c->nroot;
161562306a36Sopenharmony_ci	nnode = dirty_cow_nnode(c, nnode);
161662306a36Sopenharmony_ci	if (IS_ERR(nnode))
161762306a36Sopenharmony_ci		return ERR_CAST(nnode);
161862306a36Sopenharmony_ci	i = lnum - c->main_first;
161962306a36Sopenharmony_ci	shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
162062306a36Sopenharmony_ci	for (h = 1; h < c->lpt_hght; h++) {
162162306a36Sopenharmony_ci		iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
162262306a36Sopenharmony_ci		shft -= UBIFS_LPT_FANOUT_SHIFT;
162362306a36Sopenharmony_ci		nnode = ubifs_get_nnode(c, nnode, iip);
162462306a36Sopenharmony_ci		if (IS_ERR(nnode))
162562306a36Sopenharmony_ci			return ERR_CAST(nnode);
162662306a36Sopenharmony_ci		nnode = dirty_cow_nnode(c, nnode);
162762306a36Sopenharmony_ci		if (IS_ERR(nnode))
162862306a36Sopenharmony_ci			return ERR_CAST(nnode);
162962306a36Sopenharmony_ci	}
163062306a36Sopenharmony_ci	iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
163162306a36Sopenharmony_ci	pnode = ubifs_get_pnode(c, nnode, iip);
163262306a36Sopenharmony_ci	if (IS_ERR(pnode))
163362306a36Sopenharmony_ci		return ERR_CAST(pnode);
163462306a36Sopenharmony_ci	pnode = dirty_cow_pnode(c, pnode);
163562306a36Sopenharmony_ci	if (IS_ERR(pnode))
163662306a36Sopenharmony_ci		return ERR_CAST(pnode);
163762306a36Sopenharmony_ci	iip = (i & (UBIFS_LPT_FANOUT - 1));
163862306a36Sopenharmony_ci	dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum,
163962306a36Sopenharmony_ci	       pnode->lprops[iip].free, pnode->lprops[iip].dirty,
164062306a36Sopenharmony_ci	       pnode->lprops[iip].flags);
164162306a36Sopenharmony_ci	ubifs_assert(c, test_bit(DIRTY_CNODE, &pnode->flags));
164262306a36Sopenharmony_ci	return &pnode->lprops[iip];
164362306a36Sopenharmony_ci}
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci/**
164662306a36Sopenharmony_ci * ubifs_lpt_calc_hash - Calculate hash of the LPT pnodes
164762306a36Sopenharmony_ci * @c: UBIFS file-system description object
164862306a36Sopenharmony_ci * @hash: the returned hash of the LPT pnodes
164962306a36Sopenharmony_ci *
165062306a36Sopenharmony_ci * This function iterates over the LPT pnodes and creates a hash over them.
165162306a36Sopenharmony_ci * Returns 0 for success or a negative error code otherwise.
165262306a36Sopenharmony_ci */
165362306a36Sopenharmony_ciint ubifs_lpt_calc_hash(struct ubifs_info *c, u8 *hash)
165462306a36Sopenharmony_ci{
165562306a36Sopenharmony_ci	struct ubifs_nnode *nnode, *nn;
165662306a36Sopenharmony_ci	struct ubifs_cnode *cnode;
165762306a36Sopenharmony_ci	struct shash_desc *desc;
165862306a36Sopenharmony_ci	int iip = 0, i;
165962306a36Sopenharmony_ci	int bufsiz = max_t(int, c->nnode_sz, c->pnode_sz);
166062306a36Sopenharmony_ci	void *buf;
166162306a36Sopenharmony_ci	int err;
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	if (!ubifs_authenticated(c))
166462306a36Sopenharmony_ci		return 0;
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	if (!c->nroot) {
166762306a36Sopenharmony_ci		err = ubifs_read_nnode(c, NULL, 0);
166862306a36Sopenharmony_ci		if (err)
166962306a36Sopenharmony_ci			return err;
167062306a36Sopenharmony_ci	}
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	desc = ubifs_hash_get_desc(c);
167362306a36Sopenharmony_ci	if (IS_ERR(desc))
167462306a36Sopenharmony_ci		return PTR_ERR(desc);
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	buf = kmalloc(bufsiz, GFP_NOFS);
167762306a36Sopenharmony_ci	if (!buf) {
167862306a36Sopenharmony_ci		err = -ENOMEM;
167962306a36Sopenharmony_ci		goto out;
168062306a36Sopenharmony_ci	}
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	cnode = (struct ubifs_cnode *)c->nroot;
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	while (cnode) {
168562306a36Sopenharmony_ci		nnode = cnode->parent;
168662306a36Sopenharmony_ci		nn = (struct ubifs_nnode *)cnode;
168762306a36Sopenharmony_ci		if (cnode->level > 1) {
168862306a36Sopenharmony_ci			while (iip < UBIFS_LPT_FANOUT) {
168962306a36Sopenharmony_ci				if (nn->nbranch[iip].lnum == 0) {
169062306a36Sopenharmony_ci					/* Go right */
169162306a36Sopenharmony_ci					iip++;
169262306a36Sopenharmony_ci					continue;
169362306a36Sopenharmony_ci				}
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci				nnode = ubifs_get_nnode(c, nn, iip);
169662306a36Sopenharmony_ci				if (IS_ERR(nnode)) {
169762306a36Sopenharmony_ci					err = PTR_ERR(nnode);
169862306a36Sopenharmony_ci					goto out;
169962306a36Sopenharmony_ci				}
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci				/* Go down */
170262306a36Sopenharmony_ci				iip = 0;
170362306a36Sopenharmony_ci				cnode = (struct ubifs_cnode *)nnode;
170462306a36Sopenharmony_ci				break;
170562306a36Sopenharmony_ci			}
170662306a36Sopenharmony_ci			if (iip < UBIFS_LPT_FANOUT)
170762306a36Sopenharmony_ci				continue;
170862306a36Sopenharmony_ci		} else {
170962306a36Sopenharmony_ci			struct ubifs_pnode *pnode;
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci			for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
171262306a36Sopenharmony_ci				if (nn->nbranch[i].lnum == 0)
171362306a36Sopenharmony_ci					continue;
171462306a36Sopenharmony_ci				pnode = ubifs_get_pnode(c, nn, i);
171562306a36Sopenharmony_ci				if (IS_ERR(pnode)) {
171662306a36Sopenharmony_ci					err = PTR_ERR(pnode);
171762306a36Sopenharmony_ci					goto out;
171862306a36Sopenharmony_ci				}
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci				ubifs_pack_pnode(c, buf, pnode);
172162306a36Sopenharmony_ci				err = ubifs_shash_update(c, desc, buf,
172262306a36Sopenharmony_ci							 c->pnode_sz);
172362306a36Sopenharmony_ci				if (err)
172462306a36Sopenharmony_ci					goto out;
172562306a36Sopenharmony_ci			}
172662306a36Sopenharmony_ci		}
172762306a36Sopenharmony_ci		/* Go up and to the right */
172862306a36Sopenharmony_ci		iip = cnode->iip + 1;
172962306a36Sopenharmony_ci		cnode = (struct ubifs_cnode *)nnode;
173062306a36Sopenharmony_ci	}
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	err = ubifs_shash_final(c, desc, hash);
173362306a36Sopenharmony_ciout:
173462306a36Sopenharmony_ci	kfree(desc);
173562306a36Sopenharmony_ci	kfree(buf);
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci	return err;
173862306a36Sopenharmony_ci}
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci/**
174162306a36Sopenharmony_ci * lpt_check_hash - check the hash of the LPT.
174262306a36Sopenharmony_ci * @c: UBIFS file-system description object
174362306a36Sopenharmony_ci *
174462306a36Sopenharmony_ci * This function calculates a hash over all pnodes in the LPT and compares it with
174562306a36Sopenharmony_ci * the hash stored in the master node. Returns %0 on success and a negative error
174662306a36Sopenharmony_ci * code on failure.
174762306a36Sopenharmony_ci */
174862306a36Sopenharmony_cistatic int lpt_check_hash(struct ubifs_info *c)
174962306a36Sopenharmony_ci{
175062306a36Sopenharmony_ci	int err;
175162306a36Sopenharmony_ci	u8 hash[UBIFS_HASH_ARR_SZ];
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	if (!ubifs_authenticated(c))
175462306a36Sopenharmony_ci		return 0;
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	err = ubifs_lpt_calc_hash(c, hash);
175762306a36Sopenharmony_ci	if (err)
175862306a36Sopenharmony_ci		return err;
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	if (ubifs_check_hash(c, c->mst_node->hash_lpt, hash)) {
176162306a36Sopenharmony_ci		err = -EPERM;
176262306a36Sopenharmony_ci		ubifs_err(c, "Failed to authenticate LPT");
176362306a36Sopenharmony_ci	} else {
176462306a36Sopenharmony_ci		err = 0;
176562306a36Sopenharmony_ci	}
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	return err;
176862306a36Sopenharmony_ci}
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci/**
177162306a36Sopenharmony_ci * lpt_init_rd - initialize the LPT for reading.
177262306a36Sopenharmony_ci * @c: UBIFS file-system description object
177362306a36Sopenharmony_ci *
177462306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
177562306a36Sopenharmony_ci */
177662306a36Sopenharmony_cistatic int lpt_init_rd(struct ubifs_info *c)
177762306a36Sopenharmony_ci{
177862306a36Sopenharmony_ci	int err, i;
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	c->ltab = vmalloc(array_size(sizeof(struct ubifs_lpt_lprops),
178162306a36Sopenharmony_ci				     c->lpt_lebs));
178262306a36Sopenharmony_ci	if (!c->ltab)
178362306a36Sopenharmony_ci		return -ENOMEM;
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	i = max_t(int, c->nnode_sz, c->pnode_sz);
178662306a36Sopenharmony_ci	c->lpt_nod_buf = kmalloc(i, GFP_KERNEL);
178762306a36Sopenharmony_ci	if (!c->lpt_nod_buf)
178862306a36Sopenharmony_ci		return -ENOMEM;
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	for (i = 0; i < LPROPS_HEAP_CNT; i++) {
179162306a36Sopenharmony_ci		c->lpt_heap[i].arr = kmalloc_array(LPT_HEAP_SZ,
179262306a36Sopenharmony_ci						   sizeof(void *),
179362306a36Sopenharmony_ci						   GFP_KERNEL);
179462306a36Sopenharmony_ci		if (!c->lpt_heap[i].arr)
179562306a36Sopenharmony_ci			return -ENOMEM;
179662306a36Sopenharmony_ci		c->lpt_heap[i].cnt = 0;
179762306a36Sopenharmony_ci		c->lpt_heap[i].max_cnt = LPT_HEAP_SZ;
179862306a36Sopenharmony_ci	}
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	c->dirty_idx.arr = kmalloc_array(LPT_HEAP_SZ, sizeof(void *),
180162306a36Sopenharmony_ci					 GFP_KERNEL);
180262306a36Sopenharmony_ci	if (!c->dirty_idx.arr)
180362306a36Sopenharmony_ci		return -ENOMEM;
180462306a36Sopenharmony_ci	c->dirty_idx.cnt = 0;
180562306a36Sopenharmony_ci	c->dirty_idx.max_cnt = LPT_HEAP_SZ;
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	err = read_ltab(c);
180862306a36Sopenharmony_ci	if (err)
180962306a36Sopenharmony_ci		return err;
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	err = lpt_check_hash(c);
181262306a36Sopenharmony_ci	if (err)
181362306a36Sopenharmony_ci		return err;
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	dbg_lp("space_bits %d", c->space_bits);
181662306a36Sopenharmony_ci	dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits);
181762306a36Sopenharmony_ci	dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits);
181862306a36Sopenharmony_ci	dbg_lp("lpt_spc_bits %d", c->lpt_spc_bits);
181962306a36Sopenharmony_ci	dbg_lp("pcnt_bits %d", c->pcnt_bits);
182062306a36Sopenharmony_ci	dbg_lp("lnum_bits %d", c->lnum_bits);
182162306a36Sopenharmony_ci	dbg_lp("pnode_sz %d", c->pnode_sz);
182262306a36Sopenharmony_ci	dbg_lp("nnode_sz %d", c->nnode_sz);
182362306a36Sopenharmony_ci	dbg_lp("ltab_sz %d", c->ltab_sz);
182462306a36Sopenharmony_ci	dbg_lp("lsave_sz %d", c->lsave_sz);
182562306a36Sopenharmony_ci	dbg_lp("lsave_cnt %d", c->lsave_cnt);
182662306a36Sopenharmony_ci	dbg_lp("lpt_hght %d", c->lpt_hght);
182762306a36Sopenharmony_ci	dbg_lp("big_lpt %u", c->big_lpt);
182862306a36Sopenharmony_ci	dbg_lp("LPT root is at %d:%d", c->lpt_lnum, c->lpt_offs);
182962306a36Sopenharmony_ci	dbg_lp("LPT head is at %d:%d", c->nhead_lnum, c->nhead_offs);
183062306a36Sopenharmony_ci	dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs);
183162306a36Sopenharmony_ci	if (c->big_lpt)
183262306a36Sopenharmony_ci		dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs);
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci	return 0;
183562306a36Sopenharmony_ci}
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci/**
183862306a36Sopenharmony_ci * lpt_init_wr - initialize the LPT for writing.
183962306a36Sopenharmony_ci * @c: UBIFS file-system description object
184062306a36Sopenharmony_ci *
184162306a36Sopenharmony_ci * 'lpt_init_rd()' must have been called already.
184262306a36Sopenharmony_ci *
184362306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
184462306a36Sopenharmony_ci */
184562306a36Sopenharmony_cistatic int lpt_init_wr(struct ubifs_info *c)
184662306a36Sopenharmony_ci{
184762306a36Sopenharmony_ci	int err, i;
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci	c->ltab_cmt = vmalloc(array_size(sizeof(struct ubifs_lpt_lprops),
185062306a36Sopenharmony_ci					 c->lpt_lebs));
185162306a36Sopenharmony_ci	if (!c->ltab_cmt)
185262306a36Sopenharmony_ci		return -ENOMEM;
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	c->lpt_buf = vmalloc(c->leb_size);
185562306a36Sopenharmony_ci	if (!c->lpt_buf)
185662306a36Sopenharmony_ci		return -ENOMEM;
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	if (c->big_lpt) {
185962306a36Sopenharmony_ci		c->lsave = kmalloc_array(c->lsave_cnt, sizeof(int), GFP_NOFS);
186062306a36Sopenharmony_ci		if (!c->lsave)
186162306a36Sopenharmony_ci			return -ENOMEM;
186262306a36Sopenharmony_ci		err = read_lsave(c);
186362306a36Sopenharmony_ci		if (err)
186462306a36Sopenharmony_ci			return err;
186562306a36Sopenharmony_ci	}
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	for (i = 0; i < c->lpt_lebs; i++)
186862306a36Sopenharmony_ci		if (c->ltab[i].free == c->leb_size) {
186962306a36Sopenharmony_ci			err = ubifs_leb_unmap(c, i + c->lpt_first);
187062306a36Sopenharmony_ci			if (err)
187162306a36Sopenharmony_ci				return err;
187262306a36Sopenharmony_ci		}
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	return 0;
187562306a36Sopenharmony_ci}
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci/**
187862306a36Sopenharmony_ci * ubifs_lpt_init - initialize the LPT.
187962306a36Sopenharmony_ci * @c: UBIFS file-system description object
188062306a36Sopenharmony_ci * @rd: whether to initialize lpt for reading
188162306a36Sopenharmony_ci * @wr: whether to initialize lpt for writing
188262306a36Sopenharmony_ci *
188362306a36Sopenharmony_ci * For mounting 'rw', @rd and @wr are both true. For mounting 'ro', @rd is true
188462306a36Sopenharmony_ci * and @wr is false. For mounting from 'ro' to 'rw', @rd is false and @wr is
188562306a36Sopenharmony_ci * true.
188662306a36Sopenharmony_ci *
188762306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
188862306a36Sopenharmony_ci */
188962306a36Sopenharmony_ciint ubifs_lpt_init(struct ubifs_info *c, int rd, int wr)
189062306a36Sopenharmony_ci{
189162306a36Sopenharmony_ci	int err;
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	if (rd) {
189462306a36Sopenharmony_ci		err = lpt_init_rd(c);
189562306a36Sopenharmony_ci		if (err)
189662306a36Sopenharmony_ci			goto out_err;
189762306a36Sopenharmony_ci	}
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci	if (wr) {
190062306a36Sopenharmony_ci		err = lpt_init_wr(c);
190162306a36Sopenharmony_ci		if (err)
190262306a36Sopenharmony_ci			goto out_err;
190362306a36Sopenharmony_ci	}
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	return 0;
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ciout_err:
190862306a36Sopenharmony_ci	if (wr)
190962306a36Sopenharmony_ci		ubifs_lpt_free(c, 1);
191062306a36Sopenharmony_ci	if (rd)
191162306a36Sopenharmony_ci		ubifs_lpt_free(c, 0);
191262306a36Sopenharmony_ci	return err;
191362306a36Sopenharmony_ci}
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci/**
191662306a36Sopenharmony_ci * struct lpt_scan_node - somewhere to put nodes while we scan LPT.
191762306a36Sopenharmony_ci * @nnode: where to keep a nnode
191862306a36Sopenharmony_ci * @pnode: where to keep a pnode
191962306a36Sopenharmony_ci * @cnode: where to keep a cnode
192062306a36Sopenharmony_ci * @in_tree: is the node in the tree in memory
192162306a36Sopenharmony_ci * @ptr.nnode: pointer to the nnode (if it is an nnode) which may be here or in
192262306a36Sopenharmony_ci * the tree
192362306a36Sopenharmony_ci * @ptr.pnode: ditto for pnode
192462306a36Sopenharmony_ci * @ptr.cnode: ditto for cnode
192562306a36Sopenharmony_ci */
192662306a36Sopenharmony_cistruct lpt_scan_node {
192762306a36Sopenharmony_ci	union {
192862306a36Sopenharmony_ci		struct ubifs_nnode nnode;
192962306a36Sopenharmony_ci		struct ubifs_pnode pnode;
193062306a36Sopenharmony_ci		struct ubifs_cnode cnode;
193162306a36Sopenharmony_ci	};
193262306a36Sopenharmony_ci	int in_tree;
193362306a36Sopenharmony_ci	union {
193462306a36Sopenharmony_ci		struct ubifs_nnode *nnode;
193562306a36Sopenharmony_ci		struct ubifs_pnode *pnode;
193662306a36Sopenharmony_ci		struct ubifs_cnode *cnode;
193762306a36Sopenharmony_ci	} ptr;
193862306a36Sopenharmony_ci};
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci/**
194162306a36Sopenharmony_ci * scan_get_nnode - for the scan, get a nnode from either the tree or flash.
194262306a36Sopenharmony_ci * @c: the UBIFS file-system description object
194362306a36Sopenharmony_ci * @path: where to put the nnode
194462306a36Sopenharmony_ci * @parent: parent of the nnode
194562306a36Sopenharmony_ci * @iip: index in parent of the nnode
194662306a36Sopenharmony_ci *
194762306a36Sopenharmony_ci * This function returns a pointer to the nnode on success or a negative error
194862306a36Sopenharmony_ci * code on failure.
194962306a36Sopenharmony_ci */
195062306a36Sopenharmony_cistatic struct ubifs_nnode *scan_get_nnode(struct ubifs_info *c,
195162306a36Sopenharmony_ci					  struct lpt_scan_node *path,
195262306a36Sopenharmony_ci					  struct ubifs_nnode *parent, int iip)
195362306a36Sopenharmony_ci{
195462306a36Sopenharmony_ci	struct ubifs_nbranch *branch;
195562306a36Sopenharmony_ci	struct ubifs_nnode *nnode;
195662306a36Sopenharmony_ci	void *buf = c->lpt_nod_buf;
195762306a36Sopenharmony_ci	int err;
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	branch = &parent->nbranch[iip];
196062306a36Sopenharmony_ci	nnode = branch->nnode;
196162306a36Sopenharmony_ci	if (nnode) {
196262306a36Sopenharmony_ci		path->in_tree = 1;
196362306a36Sopenharmony_ci		path->ptr.nnode = nnode;
196462306a36Sopenharmony_ci		return nnode;
196562306a36Sopenharmony_ci	}
196662306a36Sopenharmony_ci	nnode = &path->nnode;
196762306a36Sopenharmony_ci	path->in_tree = 0;
196862306a36Sopenharmony_ci	path->ptr.nnode = nnode;
196962306a36Sopenharmony_ci	memset(nnode, 0, sizeof(struct ubifs_nnode));
197062306a36Sopenharmony_ci	if (branch->lnum == 0) {
197162306a36Sopenharmony_ci		/*
197262306a36Sopenharmony_ci		 * This nnode was not written which just means that the LEB
197362306a36Sopenharmony_ci		 * properties in the subtree below it describe empty LEBs. We
197462306a36Sopenharmony_ci		 * make the nnode as though we had read it, which in fact means
197562306a36Sopenharmony_ci		 * doing almost nothing.
197662306a36Sopenharmony_ci		 */
197762306a36Sopenharmony_ci		if (c->big_lpt)
197862306a36Sopenharmony_ci			nnode->num = calc_nnode_num_from_parent(c, parent, iip);
197962306a36Sopenharmony_ci	} else {
198062306a36Sopenharmony_ci		err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
198162306a36Sopenharmony_ci				     c->nnode_sz, 1);
198262306a36Sopenharmony_ci		if (err)
198362306a36Sopenharmony_ci			return ERR_PTR(err);
198462306a36Sopenharmony_ci		err = ubifs_unpack_nnode(c, buf, nnode);
198562306a36Sopenharmony_ci		if (err)
198662306a36Sopenharmony_ci			return ERR_PTR(err);
198762306a36Sopenharmony_ci	}
198862306a36Sopenharmony_ci	err = validate_nnode(c, nnode, parent, iip);
198962306a36Sopenharmony_ci	if (err)
199062306a36Sopenharmony_ci		return ERR_PTR(err);
199162306a36Sopenharmony_ci	if (!c->big_lpt)
199262306a36Sopenharmony_ci		nnode->num = calc_nnode_num_from_parent(c, parent, iip);
199362306a36Sopenharmony_ci	nnode->level = parent->level - 1;
199462306a36Sopenharmony_ci	nnode->parent = parent;
199562306a36Sopenharmony_ci	nnode->iip = iip;
199662306a36Sopenharmony_ci	return nnode;
199762306a36Sopenharmony_ci}
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci/**
200062306a36Sopenharmony_ci * scan_get_pnode - for the scan, get a pnode from either the tree or flash.
200162306a36Sopenharmony_ci * @c: the UBIFS file-system description object
200262306a36Sopenharmony_ci * @path: where to put the pnode
200362306a36Sopenharmony_ci * @parent: parent of the pnode
200462306a36Sopenharmony_ci * @iip: index in parent of the pnode
200562306a36Sopenharmony_ci *
200662306a36Sopenharmony_ci * This function returns a pointer to the pnode on success or a negative error
200762306a36Sopenharmony_ci * code on failure.
200862306a36Sopenharmony_ci */
200962306a36Sopenharmony_cistatic struct ubifs_pnode *scan_get_pnode(struct ubifs_info *c,
201062306a36Sopenharmony_ci					  struct lpt_scan_node *path,
201162306a36Sopenharmony_ci					  struct ubifs_nnode *parent, int iip)
201262306a36Sopenharmony_ci{
201362306a36Sopenharmony_ci	struct ubifs_nbranch *branch;
201462306a36Sopenharmony_ci	struct ubifs_pnode *pnode;
201562306a36Sopenharmony_ci	void *buf = c->lpt_nod_buf;
201662306a36Sopenharmony_ci	int err;
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci	branch = &parent->nbranch[iip];
201962306a36Sopenharmony_ci	pnode = branch->pnode;
202062306a36Sopenharmony_ci	if (pnode) {
202162306a36Sopenharmony_ci		path->in_tree = 1;
202262306a36Sopenharmony_ci		path->ptr.pnode = pnode;
202362306a36Sopenharmony_ci		return pnode;
202462306a36Sopenharmony_ci	}
202562306a36Sopenharmony_ci	pnode = &path->pnode;
202662306a36Sopenharmony_ci	path->in_tree = 0;
202762306a36Sopenharmony_ci	path->ptr.pnode = pnode;
202862306a36Sopenharmony_ci	memset(pnode, 0, sizeof(struct ubifs_pnode));
202962306a36Sopenharmony_ci	if (branch->lnum == 0) {
203062306a36Sopenharmony_ci		/*
203162306a36Sopenharmony_ci		 * This pnode was not written which just means that the LEB
203262306a36Sopenharmony_ci		 * properties in it describe empty LEBs. We make the pnode as
203362306a36Sopenharmony_ci		 * though we had read it.
203462306a36Sopenharmony_ci		 */
203562306a36Sopenharmony_ci		int i;
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci		if (c->big_lpt)
203862306a36Sopenharmony_ci			pnode->num = calc_pnode_num_from_parent(c, parent, iip);
203962306a36Sopenharmony_ci		for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
204062306a36Sopenharmony_ci			struct ubifs_lprops * const lprops = &pnode->lprops[i];
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci			lprops->free = c->leb_size;
204362306a36Sopenharmony_ci			lprops->flags = ubifs_categorize_lprops(c, lprops);
204462306a36Sopenharmony_ci		}
204562306a36Sopenharmony_ci	} else {
204662306a36Sopenharmony_ci		ubifs_assert(c, branch->lnum >= c->lpt_first &&
204762306a36Sopenharmony_ci			     branch->lnum <= c->lpt_last);
204862306a36Sopenharmony_ci		ubifs_assert(c, branch->offs >= 0 && branch->offs < c->leb_size);
204962306a36Sopenharmony_ci		err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
205062306a36Sopenharmony_ci				     c->pnode_sz, 1);
205162306a36Sopenharmony_ci		if (err)
205262306a36Sopenharmony_ci			return ERR_PTR(err);
205362306a36Sopenharmony_ci		err = unpack_pnode(c, buf, pnode);
205462306a36Sopenharmony_ci		if (err)
205562306a36Sopenharmony_ci			return ERR_PTR(err);
205662306a36Sopenharmony_ci	}
205762306a36Sopenharmony_ci	err = validate_pnode(c, pnode, parent, iip);
205862306a36Sopenharmony_ci	if (err)
205962306a36Sopenharmony_ci		return ERR_PTR(err);
206062306a36Sopenharmony_ci	if (!c->big_lpt)
206162306a36Sopenharmony_ci		pnode->num = calc_pnode_num_from_parent(c, parent, iip);
206262306a36Sopenharmony_ci	pnode->parent = parent;
206362306a36Sopenharmony_ci	pnode->iip = iip;
206462306a36Sopenharmony_ci	set_pnode_lnum(c, pnode);
206562306a36Sopenharmony_ci	return pnode;
206662306a36Sopenharmony_ci}
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci/**
206962306a36Sopenharmony_ci * ubifs_lpt_scan_nolock - scan the LPT.
207062306a36Sopenharmony_ci * @c: the UBIFS file-system description object
207162306a36Sopenharmony_ci * @start_lnum: LEB number from which to start scanning
207262306a36Sopenharmony_ci * @end_lnum: LEB number at which to stop scanning
207362306a36Sopenharmony_ci * @scan_cb: callback function called for each lprops
207462306a36Sopenharmony_ci * @data: data to be passed to the callback function
207562306a36Sopenharmony_ci *
207662306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
207762306a36Sopenharmony_ci */
207862306a36Sopenharmony_ciint ubifs_lpt_scan_nolock(struct ubifs_info *c, int start_lnum, int end_lnum,
207962306a36Sopenharmony_ci			  ubifs_lpt_scan_callback scan_cb, void *data)
208062306a36Sopenharmony_ci{
208162306a36Sopenharmony_ci	int err = 0, i, h, iip, shft;
208262306a36Sopenharmony_ci	struct ubifs_nnode *nnode;
208362306a36Sopenharmony_ci	struct ubifs_pnode *pnode;
208462306a36Sopenharmony_ci	struct lpt_scan_node *path;
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	if (start_lnum == -1) {
208762306a36Sopenharmony_ci		start_lnum = end_lnum + 1;
208862306a36Sopenharmony_ci		if (start_lnum >= c->leb_cnt)
208962306a36Sopenharmony_ci			start_lnum = c->main_first;
209062306a36Sopenharmony_ci	}
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	ubifs_assert(c, start_lnum >= c->main_first && start_lnum < c->leb_cnt);
209362306a36Sopenharmony_ci	ubifs_assert(c, end_lnum >= c->main_first && end_lnum < c->leb_cnt);
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	if (!c->nroot) {
209662306a36Sopenharmony_ci		err = ubifs_read_nnode(c, NULL, 0);
209762306a36Sopenharmony_ci		if (err)
209862306a36Sopenharmony_ci			return err;
209962306a36Sopenharmony_ci	}
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci	path = kmalloc_array(c->lpt_hght + 1, sizeof(struct lpt_scan_node),
210262306a36Sopenharmony_ci			     GFP_NOFS);
210362306a36Sopenharmony_ci	if (!path)
210462306a36Sopenharmony_ci		return -ENOMEM;
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci	path[0].ptr.nnode = c->nroot;
210762306a36Sopenharmony_ci	path[0].in_tree = 1;
210862306a36Sopenharmony_ciagain:
210962306a36Sopenharmony_ci	/* Descend to the pnode containing start_lnum */
211062306a36Sopenharmony_ci	nnode = c->nroot;
211162306a36Sopenharmony_ci	i = start_lnum - c->main_first;
211262306a36Sopenharmony_ci	shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
211362306a36Sopenharmony_ci	for (h = 1; h < c->lpt_hght; h++) {
211462306a36Sopenharmony_ci		iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
211562306a36Sopenharmony_ci		shft -= UBIFS_LPT_FANOUT_SHIFT;
211662306a36Sopenharmony_ci		nnode = scan_get_nnode(c, path + h, nnode, iip);
211762306a36Sopenharmony_ci		if (IS_ERR(nnode)) {
211862306a36Sopenharmony_ci			err = PTR_ERR(nnode);
211962306a36Sopenharmony_ci			goto out;
212062306a36Sopenharmony_ci		}
212162306a36Sopenharmony_ci	}
212262306a36Sopenharmony_ci	iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
212362306a36Sopenharmony_ci	pnode = scan_get_pnode(c, path + h, nnode, iip);
212462306a36Sopenharmony_ci	if (IS_ERR(pnode)) {
212562306a36Sopenharmony_ci		err = PTR_ERR(pnode);
212662306a36Sopenharmony_ci		goto out;
212762306a36Sopenharmony_ci	}
212862306a36Sopenharmony_ci	iip = (i & (UBIFS_LPT_FANOUT - 1));
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci	/* Loop for each lprops */
213162306a36Sopenharmony_ci	while (1) {
213262306a36Sopenharmony_ci		struct ubifs_lprops *lprops = &pnode->lprops[iip];
213362306a36Sopenharmony_ci		int ret, lnum = lprops->lnum;
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci		ret = scan_cb(c, lprops, path[h].in_tree, data);
213662306a36Sopenharmony_ci		if (ret < 0) {
213762306a36Sopenharmony_ci			err = ret;
213862306a36Sopenharmony_ci			goto out;
213962306a36Sopenharmony_ci		}
214062306a36Sopenharmony_ci		if (ret & LPT_SCAN_ADD) {
214162306a36Sopenharmony_ci			/* Add all the nodes in path to the tree in memory */
214262306a36Sopenharmony_ci			for (h = 1; h < c->lpt_hght; h++) {
214362306a36Sopenharmony_ci				const size_t sz = sizeof(struct ubifs_nnode);
214462306a36Sopenharmony_ci				struct ubifs_nnode *parent;
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci				if (path[h].in_tree)
214762306a36Sopenharmony_ci					continue;
214862306a36Sopenharmony_ci				nnode = kmemdup(&path[h].nnode, sz, GFP_NOFS);
214962306a36Sopenharmony_ci				if (!nnode) {
215062306a36Sopenharmony_ci					err = -ENOMEM;
215162306a36Sopenharmony_ci					goto out;
215262306a36Sopenharmony_ci				}
215362306a36Sopenharmony_ci				parent = nnode->parent;
215462306a36Sopenharmony_ci				parent->nbranch[nnode->iip].nnode = nnode;
215562306a36Sopenharmony_ci				path[h].ptr.nnode = nnode;
215662306a36Sopenharmony_ci				path[h].in_tree = 1;
215762306a36Sopenharmony_ci				path[h + 1].cnode.parent = nnode;
215862306a36Sopenharmony_ci			}
215962306a36Sopenharmony_ci			if (path[h].in_tree)
216062306a36Sopenharmony_ci				ubifs_ensure_cat(c, lprops);
216162306a36Sopenharmony_ci			else {
216262306a36Sopenharmony_ci				const size_t sz = sizeof(struct ubifs_pnode);
216362306a36Sopenharmony_ci				struct ubifs_nnode *parent;
216462306a36Sopenharmony_ci
216562306a36Sopenharmony_ci				pnode = kmemdup(&path[h].pnode, sz, GFP_NOFS);
216662306a36Sopenharmony_ci				if (!pnode) {
216762306a36Sopenharmony_ci					err = -ENOMEM;
216862306a36Sopenharmony_ci					goto out;
216962306a36Sopenharmony_ci				}
217062306a36Sopenharmony_ci				parent = pnode->parent;
217162306a36Sopenharmony_ci				parent->nbranch[pnode->iip].pnode = pnode;
217262306a36Sopenharmony_ci				path[h].ptr.pnode = pnode;
217362306a36Sopenharmony_ci				path[h].in_tree = 1;
217462306a36Sopenharmony_ci				update_cats(c, pnode);
217562306a36Sopenharmony_ci				c->pnodes_have += 1;
217662306a36Sopenharmony_ci			}
217762306a36Sopenharmony_ci			err = dbg_check_lpt_nodes(c, (struct ubifs_cnode *)
217862306a36Sopenharmony_ci						  c->nroot, 0, 0);
217962306a36Sopenharmony_ci			if (err)
218062306a36Sopenharmony_ci				goto out;
218162306a36Sopenharmony_ci			err = dbg_check_cats(c);
218262306a36Sopenharmony_ci			if (err)
218362306a36Sopenharmony_ci				goto out;
218462306a36Sopenharmony_ci		}
218562306a36Sopenharmony_ci		if (ret & LPT_SCAN_STOP) {
218662306a36Sopenharmony_ci			err = 0;
218762306a36Sopenharmony_ci			break;
218862306a36Sopenharmony_ci		}
218962306a36Sopenharmony_ci		/* Get the next lprops */
219062306a36Sopenharmony_ci		if (lnum == end_lnum) {
219162306a36Sopenharmony_ci			/*
219262306a36Sopenharmony_ci			 * We got to the end without finding what we were
219362306a36Sopenharmony_ci			 * looking for
219462306a36Sopenharmony_ci			 */
219562306a36Sopenharmony_ci			err = -ENOSPC;
219662306a36Sopenharmony_ci			goto out;
219762306a36Sopenharmony_ci		}
219862306a36Sopenharmony_ci		if (lnum + 1 >= c->leb_cnt) {
219962306a36Sopenharmony_ci			/* Wrap-around to the beginning */
220062306a36Sopenharmony_ci			start_lnum = c->main_first;
220162306a36Sopenharmony_ci			goto again;
220262306a36Sopenharmony_ci		}
220362306a36Sopenharmony_ci		if (iip + 1 < UBIFS_LPT_FANOUT) {
220462306a36Sopenharmony_ci			/* Next lprops is in the same pnode */
220562306a36Sopenharmony_ci			iip += 1;
220662306a36Sopenharmony_ci			continue;
220762306a36Sopenharmony_ci		}
220862306a36Sopenharmony_ci		/* We need to get the next pnode. Go up until we can go right */
220962306a36Sopenharmony_ci		iip = pnode->iip;
221062306a36Sopenharmony_ci		while (1) {
221162306a36Sopenharmony_ci			h -= 1;
221262306a36Sopenharmony_ci			ubifs_assert(c, h >= 0);
221362306a36Sopenharmony_ci			nnode = path[h].ptr.nnode;
221462306a36Sopenharmony_ci			if (iip + 1 < UBIFS_LPT_FANOUT)
221562306a36Sopenharmony_ci				break;
221662306a36Sopenharmony_ci			iip = nnode->iip;
221762306a36Sopenharmony_ci		}
221862306a36Sopenharmony_ci		/* Go right */
221962306a36Sopenharmony_ci		iip += 1;
222062306a36Sopenharmony_ci		/* Descend to the pnode */
222162306a36Sopenharmony_ci		h += 1;
222262306a36Sopenharmony_ci		for (; h < c->lpt_hght; h++) {
222362306a36Sopenharmony_ci			nnode = scan_get_nnode(c, path + h, nnode, iip);
222462306a36Sopenharmony_ci			if (IS_ERR(nnode)) {
222562306a36Sopenharmony_ci				err = PTR_ERR(nnode);
222662306a36Sopenharmony_ci				goto out;
222762306a36Sopenharmony_ci			}
222862306a36Sopenharmony_ci			iip = 0;
222962306a36Sopenharmony_ci		}
223062306a36Sopenharmony_ci		pnode = scan_get_pnode(c, path + h, nnode, iip);
223162306a36Sopenharmony_ci		if (IS_ERR(pnode)) {
223262306a36Sopenharmony_ci			err = PTR_ERR(pnode);
223362306a36Sopenharmony_ci			goto out;
223462306a36Sopenharmony_ci		}
223562306a36Sopenharmony_ci		iip = 0;
223662306a36Sopenharmony_ci	}
223762306a36Sopenharmony_ciout:
223862306a36Sopenharmony_ci	kfree(path);
223962306a36Sopenharmony_ci	return err;
224062306a36Sopenharmony_ci}
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci/**
224362306a36Sopenharmony_ci * dbg_chk_pnode - check a pnode.
224462306a36Sopenharmony_ci * @c: the UBIFS file-system description object
224562306a36Sopenharmony_ci * @pnode: pnode to check
224662306a36Sopenharmony_ci * @col: pnode column
224762306a36Sopenharmony_ci *
224862306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
224962306a36Sopenharmony_ci */
225062306a36Sopenharmony_cistatic int dbg_chk_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
225162306a36Sopenharmony_ci			 int col)
225262306a36Sopenharmony_ci{
225362306a36Sopenharmony_ci	int i;
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci	if (pnode->num != col) {
225662306a36Sopenharmony_ci		ubifs_err(c, "pnode num %d expected %d parent num %d iip %d",
225762306a36Sopenharmony_ci			  pnode->num, col, pnode->parent->num, pnode->iip);
225862306a36Sopenharmony_ci		return -EINVAL;
225962306a36Sopenharmony_ci	}
226062306a36Sopenharmony_ci	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
226162306a36Sopenharmony_ci		struct ubifs_lprops *lp, *lprops = &pnode->lprops[i];
226262306a36Sopenharmony_ci		int lnum = (pnode->num << UBIFS_LPT_FANOUT_SHIFT) + i +
226362306a36Sopenharmony_ci			   c->main_first;
226462306a36Sopenharmony_ci		int found, cat = lprops->flags & LPROPS_CAT_MASK;
226562306a36Sopenharmony_ci		struct ubifs_lpt_heap *heap;
226662306a36Sopenharmony_ci		struct list_head *list = NULL;
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_ci		if (lnum >= c->leb_cnt)
226962306a36Sopenharmony_ci			continue;
227062306a36Sopenharmony_ci		if (lprops->lnum != lnum) {
227162306a36Sopenharmony_ci			ubifs_err(c, "bad LEB number %d expected %d",
227262306a36Sopenharmony_ci				  lprops->lnum, lnum);
227362306a36Sopenharmony_ci			return -EINVAL;
227462306a36Sopenharmony_ci		}
227562306a36Sopenharmony_ci		if (lprops->flags & LPROPS_TAKEN) {
227662306a36Sopenharmony_ci			if (cat != LPROPS_UNCAT) {
227762306a36Sopenharmony_ci				ubifs_err(c, "LEB %d taken but not uncat %d",
227862306a36Sopenharmony_ci					  lprops->lnum, cat);
227962306a36Sopenharmony_ci				return -EINVAL;
228062306a36Sopenharmony_ci			}
228162306a36Sopenharmony_ci			continue;
228262306a36Sopenharmony_ci		}
228362306a36Sopenharmony_ci		if (lprops->flags & LPROPS_INDEX) {
228462306a36Sopenharmony_ci			switch (cat) {
228562306a36Sopenharmony_ci			case LPROPS_UNCAT:
228662306a36Sopenharmony_ci			case LPROPS_DIRTY_IDX:
228762306a36Sopenharmony_ci			case LPROPS_FRDI_IDX:
228862306a36Sopenharmony_ci				break;
228962306a36Sopenharmony_ci			default:
229062306a36Sopenharmony_ci				ubifs_err(c, "LEB %d index but cat %d",
229162306a36Sopenharmony_ci					  lprops->lnum, cat);
229262306a36Sopenharmony_ci				return -EINVAL;
229362306a36Sopenharmony_ci			}
229462306a36Sopenharmony_ci		} else {
229562306a36Sopenharmony_ci			switch (cat) {
229662306a36Sopenharmony_ci			case LPROPS_UNCAT:
229762306a36Sopenharmony_ci			case LPROPS_DIRTY:
229862306a36Sopenharmony_ci			case LPROPS_FREE:
229962306a36Sopenharmony_ci			case LPROPS_EMPTY:
230062306a36Sopenharmony_ci			case LPROPS_FREEABLE:
230162306a36Sopenharmony_ci				break;
230262306a36Sopenharmony_ci			default:
230362306a36Sopenharmony_ci				ubifs_err(c, "LEB %d not index but cat %d",
230462306a36Sopenharmony_ci					  lprops->lnum, cat);
230562306a36Sopenharmony_ci				return -EINVAL;
230662306a36Sopenharmony_ci			}
230762306a36Sopenharmony_ci		}
230862306a36Sopenharmony_ci		switch (cat) {
230962306a36Sopenharmony_ci		case LPROPS_UNCAT:
231062306a36Sopenharmony_ci			list = &c->uncat_list;
231162306a36Sopenharmony_ci			break;
231262306a36Sopenharmony_ci		case LPROPS_EMPTY:
231362306a36Sopenharmony_ci			list = &c->empty_list;
231462306a36Sopenharmony_ci			break;
231562306a36Sopenharmony_ci		case LPROPS_FREEABLE:
231662306a36Sopenharmony_ci			list = &c->freeable_list;
231762306a36Sopenharmony_ci			break;
231862306a36Sopenharmony_ci		case LPROPS_FRDI_IDX:
231962306a36Sopenharmony_ci			list = &c->frdi_idx_list;
232062306a36Sopenharmony_ci			break;
232162306a36Sopenharmony_ci		}
232262306a36Sopenharmony_ci		found = 0;
232362306a36Sopenharmony_ci		switch (cat) {
232462306a36Sopenharmony_ci		case LPROPS_DIRTY:
232562306a36Sopenharmony_ci		case LPROPS_DIRTY_IDX:
232662306a36Sopenharmony_ci		case LPROPS_FREE:
232762306a36Sopenharmony_ci			heap = &c->lpt_heap[cat - 1];
232862306a36Sopenharmony_ci			if (lprops->hpos < heap->cnt &&
232962306a36Sopenharmony_ci			    heap->arr[lprops->hpos] == lprops)
233062306a36Sopenharmony_ci				found = 1;
233162306a36Sopenharmony_ci			break;
233262306a36Sopenharmony_ci		case LPROPS_UNCAT:
233362306a36Sopenharmony_ci		case LPROPS_EMPTY:
233462306a36Sopenharmony_ci		case LPROPS_FREEABLE:
233562306a36Sopenharmony_ci		case LPROPS_FRDI_IDX:
233662306a36Sopenharmony_ci			list_for_each_entry(lp, list, list)
233762306a36Sopenharmony_ci				if (lprops == lp) {
233862306a36Sopenharmony_ci					found = 1;
233962306a36Sopenharmony_ci					break;
234062306a36Sopenharmony_ci				}
234162306a36Sopenharmony_ci			break;
234262306a36Sopenharmony_ci		}
234362306a36Sopenharmony_ci		if (!found) {
234462306a36Sopenharmony_ci			ubifs_err(c, "LEB %d cat %d not found in cat heap/list",
234562306a36Sopenharmony_ci				  lprops->lnum, cat);
234662306a36Sopenharmony_ci			return -EINVAL;
234762306a36Sopenharmony_ci		}
234862306a36Sopenharmony_ci		switch (cat) {
234962306a36Sopenharmony_ci		case LPROPS_EMPTY:
235062306a36Sopenharmony_ci			if (lprops->free != c->leb_size) {
235162306a36Sopenharmony_ci				ubifs_err(c, "LEB %d cat %d free %d dirty %d",
235262306a36Sopenharmony_ci					  lprops->lnum, cat, lprops->free,
235362306a36Sopenharmony_ci					  lprops->dirty);
235462306a36Sopenharmony_ci				return -EINVAL;
235562306a36Sopenharmony_ci			}
235662306a36Sopenharmony_ci			break;
235762306a36Sopenharmony_ci		case LPROPS_FREEABLE:
235862306a36Sopenharmony_ci		case LPROPS_FRDI_IDX:
235962306a36Sopenharmony_ci			if (lprops->free + lprops->dirty != c->leb_size) {
236062306a36Sopenharmony_ci				ubifs_err(c, "LEB %d cat %d free %d dirty %d",
236162306a36Sopenharmony_ci					  lprops->lnum, cat, lprops->free,
236262306a36Sopenharmony_ci					  lprops->dirty);
236362306a36Sopenharmony_ci				return -EINVAL;
236462306a36Sopenharmony_ci			}
236562306a36Sopenharmony_ci			break;
236662306a36Sopenharmony_ci		}
236762306a36Sopenharmony_ci	}
236862306a36Sopenharmony_ci	return 0;
236962306a36Sopenharmony_ci}
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci/**
237262306a36Sopenharmony_ci * dbg_check_lpt_nodes - check nnodes and pnodes.
237362306a36Sopenharmony_ci * @c: the UBIFS file-system description object
237462306a36Sopenharmony_ci * @cnode: next cnode (nnode or pnode) to check
237562306a36Sopenharmony_ci * @row: row of cnode (root is zero)
237662306a36Sopenharmony_ci * @col: column of cnode (leftmost is zero)
237762306a36Sopenharmony_ci *
237862306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
237962306a36Sopenharmony_ci */
238062306a36Sopenharmony_ciint dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
238162306a36Sopenharmony_ci			int row, int col)
238262306a36Sopenharmony_ci{
238362306a36Sopenharmony_ci	struct ubifs_nnode *nnode, *nn;
238462306a36Sopenharmony_ci	struct ubifs_cnode *cn;
238562306a36Sopenharmony_ci	int num, iip = 0, err;
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci	if (!dbg_is_chk_lprops(c))
238862306a36Sopenharmony_ci		return 0;
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_ci	while (cnode) {
239162306a36Sopenharmony_ci		ubifs_assert(c, row >= 0);
239262306a36Sopenharmony_ci		nnode = cnode->parent;
239362306a36Sopenharmony_ci		if (cnode->level) {
239462306a36Sopenharmony_ci			/* cnode is a nnode */
239562306a36Sopenharmony_ci			num = calc_nnode_num(row, col);
239662306a36Sopenharmony_ci			if (cnode->num != num) {
239762306a36Sopenharmony_ci				ubifs_err(c, "nnode num %d expected %d parent num %d iip %d",
239862306a36Sopenharmony_ci					  cnode->num, num,
239962306a36Sopenharmony_ci					  (nnode ? nnode->num : 0), cnode->iip);
240062306a36Sopenharmony_ci				return -EINVAL;
240162306a36Sopenharmony_ci			}
240262306a36Sopenharmony_ci			nn = (struct ubifs_nnode *)cnode;
240362306a36Sopenharmony_ci			while (iip < UBIFS_LPT_FANOUT) {
240462306a36Sopenharmony_ci				cn = nn->nbranch[iip].cnode;
240562306a36Sopenharmony_ci				if (cn) {
240662306a36Sopenharmony_ci					/* Go down */
240762306a36Sopenharmony_ci					row += 1;
240862306a36Sopenharmony_ci					col <<= UBIFS_LPT_FANOUT_SHIFT;
240962306a36Sopenharmony_ci					col += iip;
241062306a36Sopenharmony_ci					iip = 0;
241162306a36Sopenharmony_ci					cnode = cn;
241262306a36Sopenharmony_ci					break;
241362306a36Sopenharmony_ci				}
241462306a36Sopenharmony_ci				/* Go right */
241562306a36Sopenharmony_ci				iip += 1;
241662306a36Sopenharmony_ci			}
241762306a36Sopenharmony_ci			if (iip < UBIFS_LPT_FANOUT)
241862306a36Sopenharmony_ci				continue;
241962306a36Sopenharmony_ci		} else {
242062306a36Sopenharmony_ci			struct ubifs_pnode *pnode;
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci			/* cnode is a pnode */
242362306a36Sopenharmony_ci			pnode = (struct ubifs_pnode *)cnode;
242462306a36Sopenharmony_ci			err = dbg_chk_pnode(c, pnode, col);
242562306a36Sopenharmony_ci			if (err)
242662306a36Sopenharmony_ci				return err;
242762306a36Sopenharmony_ci		}
242862306a36Sopenharmony_ci		/* Go up and to the right */
242962306a36Sopenharmony_ci		row -= 1;
243062306a36Sopenharmony_ci		col >>= UBIFS_LPT_FANOUT_SHIFT;
243162306a36Sopenharmony_ci		iip = cnode->iip + 1;
243262306a36Sopenharmony_ci		cnode = (struct ubifs_cnode *)nnode;
243362306a36Sopenharmony_ci	}
243462306a36Sopenharmony_ci	return 0;
243562306a36Sopenharmony_ci}
2436