19eefe2a2SStefan Roese /*
29eefe2a2SStefan Roese * This file is part of UBIFS.
39eefe2a2SStefan Roese *
49eefe2a2SStefan Roese * Copyright (C) 2006-2008 Nokia Corporation.
59eefe2a2SStefan Roese *
6ff94bc40SHeiko Schocher * SPDX-License-Identifier: GPL-2.0+
79eefe2a2SStefan Roese *
89eefe2a2SStefan Roese * Authors: Adrian Hunter
99eefe2a2SStefan Roese * Artem Bityutskiy (Битюцкий Артём)
109eefe2a2SStefan Roese */
119eefe2a2SStefan Roese
129eefe2a2SStefan Roese /*
139eefe2a2SStefan Roese * This file implements the LEB properties tree (LPT) area. The LPT area
149eefe2a2SStefan Roese * contains the LEB properties tree, a table of LPT area eraseblocks (ltab), and
159eefe2a2SStefan Roese * (for the "big" model) a table of saved LEB numbers (lsave). The LPT area sits
169eefe2a2SStefan Roese * between the log and the orphan area.
179eefe2a2SStefan Roese *
189eefe2a2SStefan Roese * The LPT area is like a miniature self-contained file system. It is required
199eefe2a2SStefan Roese * that it never runs out of space, is fast to access and update, and scales
209eefe2a2SStefan Roese * logarithmically. The LEB properties tree is implemented as a wandering tree
219eefe2a2SStefan Roese * much like the TNC, and the LPT area has its own garbage collection.
229eefe2a2SStefan Roese *
239eefe2a2SStefan Roese * The LPT has two slightly different forms called the "small model" and the
249eefe2a2SStefan Roese * "big model". The small model is used when the entire LEB properties table
259eefe2a2SStefan Roese * can be written into a single eraseblock. In that case, garbage collection
269eefe2a2SStefan Roese * consists of just writing the whole table, which therefore makes all other
279eefe2a2SStefan Roese * eraseblocks reusable. In the case of the big model, dirty eraseblocks are
289eefe2a2SStefan Roese * selected for garbage collection, which consists of marking the clean nodes in
299eefe2a2SStefan Roese * that LEB as dirty, and then only the dirty nodes are written out. Also, in
309eefe2a2SStefan Roese * the case of the big model, a table of LEB numbers is saved so that the entire
319eefe2a2SStefan Roese * LPT does not to be scanned looking for empty eraseblocks when UBIFS is first
329eefe2a2SStefan Roese * mounted.
339eefe2a2SStefan Roese */
349eefe2a2SStefan Roese
359eefe2a2SStefan Roese #include "ubifs.h"
36ff94bc40SHeiko Schocher #ifndef __UBOOT__
37ff94bc40SHeiko Schocher #include <linux/crc16.h>
389eefe2a2SStefan Roese #include <linux/math64.h>
39ff94bc40SHeiko Schocher #include <linux/slab.h>
40ff94bc40SHeiko Schocher #else
41ff94bc40SHeiko Schocher #include <linux/compat.h>
42ff94bc40SHeiko Schocher #include <linux/err.h>
43ff94bc40SHeiko Schocher #include <ubi_uboot.h>
44ff94bc40SHeiko Schocher #include "crc16.h"
45ff94bc40SHeiko Schocher #endif
469eefe2a2SStefan Roese
479eefe2a2SStefan Roese /**
489eefe2a2SStefan Roese * do_calc_lpt_geom - calculate sizes for the LPT area.
499eefe2a2SStefan Roese * @c: the UBIFS file-system description object
509eefe2a2SStefan Roese *
519eefe2a2SStefan Roese * Calculate the sizes of LPT bit fields, nodes, and tree, based on the
529eefe2a2SStefan Roese * properties of the flash and whether LPT is "big" (c->big_lpt).
539eefe2a2SStefan Roese */
do_calc_lpt_geom(struct ubifs_info * c)549eefe2a2SStefan Roese static void do_calc_lpt_geom(struct ubifs_info *c)
559eefe2a2SStefan Roese {
569eefe2a2SStefan Roese int i, n, bits, per_leb_wastage, max_pnode_cnt;
579eefe2a2SStefan Roese long long sz, tot_wastage;
589eefe2a2SStefan Roese
599eefe2a2SStefan Roese n = c->main_lebs + c->max_leb_cnt - c->leb_cnt;
609eefe2a2SStefan Roese max_pnode_cnt = DIV_ROUND_UP(n, UBIFS_LPT_FANOUT);
619eefe2a2SStefan Roese
629eefe2a2SStefan Roese c->lpt_hght = 1;
639eefe2a2SStefan Roese n = UBIFS_LPT_FANOUT;
649eefe2a2SStefan Roese while (n < max_pnode_cnt) {
659eefe2a2SStefan Roese c->lpt_hght += 1;
669eefe2a2SStefan Roese n <<= UBIFS_LPT_FANOUT_SHIFT;
679eefe2a2SStefan Roese }
689eefe2a2SStefan Roese
699eefe2a2SStefan Roese c->pnode_cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT);
709eefe2a2SStefan Roese
719eefe2a2SStefan Roese n = DIV_ROUND_UP(c->pnode_cnt, UBIFS_LPT_FANOUT);
729eefe2a2SStefan Roese c->nnode_cnt = n;
739eefe2a2SStefan Roese for (i = 1; i < c->lpt_hght; i++) {
749eefe2a2SStefan Roese n = DIV_ROUND_UP(n, UBIFS_LPT_FANOUT);
759eefe2a2SStefan Roese c->nnode_cnt += n;
769eefe2a2SStefan Roese }
779eefe2a2SStefan Roese
789eefe2a2SStefan Roese c->space_bits = fls(c->leb_size) - 3;
799eefe2a2SStefan Roese c->lpt_lnum_bits = fls(c->lpt_lebs);
809eefe2a2SStefan Roese c->lpt_offs_bits = fls(c->leb_size - 1);
819eefe2a2SStefan Roese c->lpt_spc_bits = fls(c->leb_size);
829eefe2a2SStefan Roese
839eefe2a2SStefan Roese n = DIV_ROUND_UP(c->max_leb_cnt, UBIFS_LPT_FANOUT);
849eefe2a2SStefan Roese c->pcnt_bits = fls(n - 1);
859eefe2a2SStefan Roese
869eefe2a2SStefan Roese c->lnum_bits = fls(c->max_leb_cnt - 1);
879eefe2a2SStefan Roese
889eefe2a2SStefan Roese bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
899eefe2a2SStefan Roese (c->big_lpt ? c->pcnt_bits : 0) +
909eefe2a2SStefan Roese (c->space_bits * 2 + 1) * UBIFS_LPT_FANOUT;
919eefe2a2SStefan Roese c->pnode_sz = (bits + 7) / 8;
929eefe2a2SStefan Roese
939eefe2a2SStefan Roese bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
949eefe2a2SStefan Roese (c->big_lpt ? c->pcnt_bits : 0) +
959eefe2a2SStefan Roese (c->lpt_lnum_bits + c->lpt_offs_bits) * UBIFS_LPT_FANOUT;
969eefe2a2SStefan Roese c->nnode_sz = (bits + 7) / 8;
979eefe2a2SStefan Roese
989eefe2a2SStefan Roese bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
999eefe2a2SStefan Roese c->lpt_lebs * c->lpt_spc_bits * 2;
1009eefe2a2SStefan Roese c->ltab_sz = (bits + 7) / 8;
1019eefe2a2SStefan Roese
1029eefe2a2SStefan Roese bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
1039eefe2a2SStefan Roese c->lnum_bits * c->lsave_cnt;
1049eefe2a2SStefan Roese c->lsave_sz = (bits + 7) / 8;
1059eefe2a2SStefan Roese
1069eefe2a2SStefan Roese /* Calculate the minimum LPT size */
1079eefe2a2SStefan Roese c->lpt_sz = (long long)c->pnode_cnt * c->pnode_sz;
1089eefe2a2SStefan Roese c->lpt_sz += (long long)c->nnode_cnt * c->nnode_sz;
1099eefe2a2SStefan Roese c->lpt_sz += c->ltab_sz;
1109eefe2a2SStefan Roese if (c->big_lpt)
1119eefe2a2SStefan Roese c->lpt_sz += c->lsave_sz;
1129eefe2a2SStefan Roese
1139eefe2a2SStefan Roese /* Add wastage */
1149eefe2a2SStefan Roese sz = c->lpt_sz;
1159eefe2a2SStefan Roese per_leb_wastage = max_t(int, c->pnode_sz, c->nnode_sz);
1169eefe2a2SStefan Roese sz += per_leb_wastage;
1179eefe2a2SStefan Roese tot_wastage = per_leb_wastage;
1189eefe2a2SStefan Roese while (sz > c->leb_size) {
1199eefe2a2SStefan Roese sz += per_leb_wastage;
1209eefe2a2SStefan Roese sz -= c->leb_size;
1219eefe2a2SStefan Roese tot_wastage += per_leb_wastage;
1229eefe2a2SStefan Roese }
1239eefe2a2SStefan Roese tot_wastage += ALIGN(sz, c->min_io_size) - sz;
1249eefe2a2SStefan Roese c->lpt_sz += tot_wastage;
1259eefe2a2SStefan Roese }
1269eefe2a2SStefan Roese
1279eefe2a2SStefan Roese /**
1289eefe2a2SStefan Roese * ubifs_calc_lpt_geom - calculate and check sizes for the LPT area.
1299eefe2a2SStefan Roese * @c: the UBIFS file-system description object
1309eefe2a2SStefan Roese *
1319eefe2a2SStefan Roese * This function returns %0 on success and a negative error code on failure.
1329eefe2a2SStefan Roese */
ubifs_calc_lpt_geom(struct ubifs_info * c)1339eefe2a2SStefan Roese int ubifs_calc_lpt_geom(struct ubifs_info *c)
1349eefe2a2SStefan Roese {
1359eefe2a2SStefan Roese int lebs_needed;
1369eefe2a2SStefan Roese long long sz;
1379eefe2a2SStefan Roese
1389eefe2a2SStefan Roese do_calc_lpt_geom(c);
1399eefe2a2SStefan Roese
1409eefe2a2SStefan Roese /* Verify that lpt_lebs is big enough */
1419eefe2a2SStefan Roese sz = c->lpt_sz * 2; /* Must have at least 2 times the size */
1429eefe2a2SStefan Roese lebs_needed = div_u64(sz + c->leb_size - 1, c->leb_size);
1439eefe2a2SStefan Roese if (lebs_needed > c->lpt_lebs) {
144*0195a7bbSHeiko Schocher ubifs_err(c, "too few LPT LEBs");
1459eefe2a2SStefan Roese return -EINVAL;
1469eefe2a2SStefan Roese }
1479eefe2a2SStefan Roese
1489eefe2a2SStefan Roese /* Verify that ltab fits in a single LEB (since ltab is a single node */
1499eefe2a2SStefan Roese if (c->ltab_sz > c->leb_size) {
150*0195a7bbSHeiko Schocher ubifs_err(c, "LPT ltab too big");
1519eefe2a2SStefan Roese return -EINVAL;
1529eefe2a2SStefan Roese }
1539eefe2a2SStefan Roese
1549eefe2a2SStefan Roese c->check_lpt_free = c->big_lpt;
1559eefe2a2SStefan Roese return 0;
1569eefe2a2SStefan Roese }
1579eefe2a2SStefan Roese
1589eefe2a2SStefan Roese /**
159ff94bc40SHeiko Schocher * calc_dflt_lpt_geom - calculate default LPT geometry.
160ff94bc40SHeiko Schocher * @c: the UBIFS file-system description object
161ff94bc40SHeiko Schocher * @main_lebs: number of main area LEBs is passed and returned here
162ff94bc40SHeiko Schocher * @big_lpt: whether the LPT area is "big" is returned here
163ff94bc40SHeiko Schocher *
164ff94bc40SHeiko Schocher * The size of the LPT area depends on parameters that themselves are dependent
165ff94bc40SHeiko Schocher * on the size of the LPT area. This function, successively recalculates the LPT
166ff94bc40SHeiko Schocher * area geometry until the parameters and resultant geometry are consistent.
167ff94bc40SHeiko Schocher *
168ff94bc40SHeiko Schocher * This function returns %0 on success and a negative error code on failure.
169ff94bc40SHeiko Schocher */
calc_dflt_lpt_geom(struct ubifs_info * c,int * main_lebs,int * big_lpt)170ff94bc40SHeiko Schocher static int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs,
171ff94bc40SHeiko Schocher int *big_lpt)
172ff94bc40SHeiko Schocher {
173ff94bc40SHeiko Schocher int i, lebs_needed;
174ff94bc40SHeiko Schocher long long sz;
175ff94bc40SHeiko Schocher
176ff94bc40SHeiko Schocher /* Start by assuming the minimum number of LPT LEBs */
177ff94bc40SHeiko Schocher c->lpt_lebs = UBIFS_MIN_LPT_LEBS;
178ff94bc40SHeiko Schocher c->main_lebs = *main_lebs - c->lpt_lebs;
179ff94bc40SHeiko Schocher if (c->main_lebs <= 0)
180ff94bc40SHeiko Schocher return -EINVAL;
181ff94bc40SHeiko Schocher
182ff94bc40SHeiko Schocher /* And assume we will use the small LPT model */
183ff94bc40SHeiko Schocher c->big_lpt = 0;
184ff94bc40SHeiko Schocher
185ff94bc40SHeiko Schocher /*
186ff94bc40SHeiko Schocher * Calculate the geometry based on assumptions above and then see if it
187ff94bc40SHeiko Schocher * makes sense
188ff94bc40SHeiko Schocher */
189ff94bc40SHeiko Schocher do_calc_lpt_geom(c);
190ff94bc40SHeiko Schocher
191ff94bc40SHeiko Schocher /* Small LPT model must have lpt_sz < leb_size */
192ff94bc40SHeiko Schocher if (c->lpt_sz > c->leb_size) {
193ff94bc40SHeiko Schocher /* Nope, so try again using big LPT model */
194ff94bc40SHeiko Schocher c->big_lpt = 1;
195ff94bc40SHeiko Schocher do_calc_lpt_geom(c);
196ff94bc40SHeiko Schocher }
197ff94bc40SHeiko Schocher
198ff94bc40SHeiko Schocher /* Now check there are enough LPT LEBs */
199ff94bc40SHeiko Schocher for (i = 0; i < 64 ; i++) {
200ff94bc40SHeiko Schocher sz = c->lpt_sz * 4; /* Allow 4 times the size */
201ff94bc40SHeiko Schocher lebs_needed = div_u64(sz + c->leb_size - 1, c->leb_size);
202ff94bc40SHeiko Schocher if (lebs_needed > c->lpt_lebs) {
203ff94bc40SHeiko Schocher /* Not enough LPT LEBs so try again with more */
204ff94bc40SHeiko Schocher c->lpt_lebs = lebs_needed;
205ff94bc40SHeiko Schocher c->main_lebs = *main_lebs - c->lpt_lebs;
206ff94bc40SHeiko Schocher if (c->main_lebs <= 0)
207ff94bc40SHeiko Schocher return -EINVAL;
208ff94bc40SHeiko Schocher do_calc_lpt_geom(c);
209ff94bc40SHeiko Schocher continue;
210ff94bc40SHeiko Schocher }
211ff94bc40SHeiko Schocher if (c->ltab_sz > c->leb_size) {
212*0195a7bbSHeiko Schocher ubifs_err(c, "LPT ltab too big");
213ff94bc40SHeiko Schocher return -EINVAL;
214ff94bc40SHeiko Schocher }
215ff94bc40SHeiko Schocher *main_lebs = c->main_lebs;
216ff94bc40SHeiko Schocher *big_lpt = c->big_lpt;
217ff94bc40SHeiko Schocher return 0;
218ff94bc40SHeiko Schocher }
219ff94bc40SHeiko Schocher return -EINVAL;
220ff94bc40SHeiko Schocher }
221ff94bc40SHeiko Schocher
222ff94bc40SHeiko Schocher /**
223ff94bc40SHeiko Schocher * pack_bits - pack bit fields end-to-end.
224ff94bc40SHeiko Schocher * @addr: address at which to pack (passed and next address returned)
225ff94bc40SHeiko Schocher * @pos: bit position at which to pack (passed and next position returned)
226ff94bc40SHeiko Schocher * @val: value to pack
227ff94bc40SHeiko Schocher * @nrbits: number of bits of value to pack (1-32)
228ff94bc40SHeiko Schocher */
pack_bits(uint8_t ** addr,int * pos,uint32_t val,int nrbits)229ff94bc40SHeiko Schocher static void pack_bits(uint8_t **addr, int *pos, uint32_t val, int nrbits)
230ff94bc40SHeiko Schocher {
231ff94bc40SHeiko Schocher uint8_t *p = *addr;
232ff94bc40SHeiko Schocher int b = *pos;
233ff94bc40SHeiko Schocher
234ff94bc40SHeiko Schocher ubifs_assert(nrbits > 0);
235ff94bc40SHeiko Schocher ubifs_assert(nrbits <= 32);
236ff94bc40SHeiko Schocher ubifs_assert(*pos >= 0);
237ff94bc40SHeiko Schocher ubifs_assert(*pos < 8);
238ff94bc40SHeiko Schocher ubifs_assert((val >> nrbits) == 0 || nrbits == 32);
239ff94bc40SHeiko Schocher if (b) {
240ff94bc40SHeiko Schocher *p |= ((uint8_t)val) << b;
241ff94bc40SHeiko Schocher nrbits += b;
242ff94bc40SHeiko Schocher if (nrbits > 8) {
243ff94bc40SHeiko Schocher *++p = (uint8_t)(val >>= (8 - b));
244ff94bc40SHeiko Schocher if (nrbits > 16) {
245ff94bc40SHeiko Schocher *++p = (uint8_t)(val >>= 8);
246ff94bc40SHeiko Schocher if (nrbits > 24) {
247ff94bc40SHeiko Schocher *++p = (uint8_t)(val >>= 8);
248ff94bc40SHeiko Schocher if (nrbits > 32)
249ff94bc40SHeiko Schocher *++p = (uint8_t)(val >>= 8);
250ff94bc40SHeiko Schocher }
251ff94bc40SHeiko Schocher }
252ff94bc40SHeiko Schocher }
253ff94bc40SHeiko Schocher } else {
254ff94bc40SHeiko Schocher *p = (uint8_t)val;
255ff94bc40SHeiko Schocher if (nrbits > 8) {
256ff94bc40SHeiko Schocher *++p = (uint8_t)(val >>= 8);
257ff94bc40SHeiko Schocher if (nrbits > 16) {
258ff94bc40SHeiko Schocher *++p = (uint8_t)(val >>= 8);
259ff94bc40SHeiko Schocher if (nrbits > 24)
260ff94bc40SHeiko Schocher *++p = (uint8_t)(val >>= 8);
261ff94bc40SHeiko Schocher }
262ff94bc40SHeiko Schocher }
263ff94bc40SHeiko Schocher }
264ff94bc40SHeiko Schocher b = nrbits & 7;
265ff94bc40SHeiko Schocher if (b == 0)
266ff94bc40SHeiko Schocher p++;
267ff94bc40SHeiko Schocher *addr = p;
268ff94bc40SHeiko Schocher *pos = b;
269ff94bc40SHeiko Schocher }
270ff94bc40SHeiko Schocher
271ff94bc40SHeiko Schocher /**
2729eefe2a2SStefan Roese * ubifs_unpack_bits - unpack bit fields.
2739eefe2a2SStefan Roese * @addr: address at which to unpack (passed and next address returned)
2749eefe2a2SStefan Roese * @pos: bit position at which to unpack (passed and next position returned)
2759eefe2a2SStefan Roese * @nrbits: number of bits of value to unpack (1-32)
2769eefe2a2SStefan Roese *
2779eefe2a2SStefan Roese * This functions returns the value unpacked.
2789eefe2a2SStefan Roese */
ubifs_unpack_bits(uint8_t ** addr,int * pos,int nrbits)2799eefe2a2SStefan Roese uint32_t ubifs_unpack_bits(uint8_t **addr, int *pos, int nrbits)
2809eefe2a2SStefan Roese {
2819eefe2a2SStefan Roese const int k = 32 - nrbits;
2829eefe2a2SStefan Roese uint8_t *p = *addr;
2839eefe2a2SStefan Roese int b = *pos;
2849eefe2a2SStefan Roese uint32_t uninitialized_var(val);
2859eefe2a2SStefan Roese const int bytes = (nrbits + b + 7) >> 3;
2869eefe2a2SStefan Roese
2879eefe2a2SStefan Roese ubifs_assert(nrbits > 0);
2889eefe2a2SStefan Roese ubifs_assert(nrbits <= 32);
2899eefe2a2SStefan Roese ubifs_assert(*pos >= 0);
2909eefe2a2SStefan Roese ubifs_assert(*pos < 8);
2919eefe2a2SStefan Roese if (b) {
2929eefe2a2SStefan Roese switch (bytes) {
2939eefe2a2SStefan Roese case 2:
2949eefe2a2SStefan Roese val = p[1];
2959eefe2a2SStefan Roese break;
2969eefe2a2SStefan Roese case 3:
2979eefe2a2SStefan Roese val = p[1] | ((uint32_t)p[2] << 8);
2989eefe2a2SStefan Roese break;
2999eefe2a2SStefan Roese case 4:
3009eefe2a2SStefan Roese val = p[1] | ((uint32_t)p[2] << 8) |
3019eefe2a2SStefan Roese ((uint32_t)p[3] << 16);
3029eefe2a2SStefan Roese break;
3039eefe2a2SStefan Roese case 5:
3049eefe2a2SStefan Roese val = p[1] | ((uint32_t)p[2] << 8) |
3059eefe2a2SStefan Roese ((uint32_t)p[3] << 16) |
3069eefe2a2SStefan Roese ((uint32_t)p[4] << 24);
3079eefe2a2SStefan Roese }
3089eefe2a2SStefan Roese val <<= (8 - b);
3099eefe2a2SStefan Roese val |= *p >> b;
3109eefe2a2SStefan Roese nrbits += b;
3119eefe2a2SStefan Roese } else {
3129eefe2a2SStefan Roese switch (bytes) {
3139eefe2a2SStefan Roese case 1:
3149eefe2a2SStefan Roese val = p[0];
3159eefe2a2SStefan Roese break;
3169eefe2a2SStefan Roese case 2:
3179eefe2a2SStefan Roese val = p[0] | ((uint32_t)p[1] << 8);
3189eefe2a2SStefan Roese break;
3199eefe2a2SStefan Roese case 3:
3209eefe2a2SStefan Roese val = p[0] | ((uint32_t)p[1] << 8) |
3219eefe2a2SStefan Roese ((uint32_t)p[2] << 16);
3229eefe2a2SStefan Roese break;
3239eefe2a2SStefan Roese case 4:
3249eefe2a2SStefan Roese val = p[0] | ((uint32_t)p[1] << 8) |
3259eefe2a2SStefan Roese ((uint32_t)p[2] << 16) |
3269eefe2a2SStefan Roese ((uint32_t)p[3] << 24);
3279eefe2a2SStefan Roese break;
3289eefe2a2SStefan Roese }
3299eefe2a2SStefan Roese }
3309eefe2a2SStefan Roese val <<= k;
3319eefe2a2SStefan Roese val >>= k;
3329eefe2a2SStefan Roese b = nrbits & 7;
3339eefe2a2SStefan Roese p += nrbits >> 3;
3349eefe2a2SStefan Roese *addr = p;
3359eefe2a2SStefan Roese *pos = b;
3369eefe2a2SStefan Roese ubifs_assert((val >> nrbits) == 0 || nrbits - b == 32);
3379eefe2a2SStefan Roese return val;
3389eefe2a2SStefan Roese }
3399eefe2a2SStefan Roese
3409eefe2a2SStefan Roese /**
341ff94bc40SHeiko Schocher * ubifs_pack_pnode - pack all the bit fields of a pnode.
342ff94bc40SHeiko Schocher * @c: UBIFS file-system description object
343ff94bc40SHeiko Schocher * @buf: buffer into which to pack
344ff94bc40SHeiko Schocher * @pnode: pnode to pack
345ff94bc40SHeiko Schocher */
ubifs_pack_pnode(struct ubifs_info * c,void * buf,struct ubifs_pnode * pnode)346ff94bc40SHeiko Schocher void ubifs_pack_pnode(struct ubifs_info *c, void *buf,
347ff94bc40SHeiko Schocher struct ubifs_pnode *pnode)
348ff94bc40SHeiko Schocher {
349ff94bc40SHeiko Schocher uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
350ff94bc40SHeiko Schocher int i, pos = 0;
351ff94bc40SHeiko Schocher uint16_t crc;
352ff94bc40SHeiko Schocher
353ff94bc40SHeiko Schocher pack_bits(&addr, &pos, UBIFS_LPT_PNODE, UBIFS_LPT_TYPE_BITS);
354ff94bc40SHeiko Schocher if (c->big_lpt)
355ff94bc40SHeiko Schocher pack_bits(&addr, &pos, pnode->num, c->pcnt_bits);
356ff94bc40SHeiko Schocher for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
357ff94bc40SHeiko Schocher pack_bits(&addr, &pos, pnode->lprops[i].free >> 3,
358ff94bc40SHeiko Schocher c->space_bits);
359ff94bc40SHeiko Schocher pack_bits(&addr, &pos, pnode->lprops[i].dirty >> 3,
360ff94bc40SHeiko Schocher c->space_bits);
361ff94bc40SHeiko Schocher if (pnode->lprops[i].flags & LPROPS_INDEX)
362ff94bc40SHeiko Schocher pack_bits(&addr, &pos, 1, 1);
363ff94bc40SHeiko Schocher else
364ff94bc40SHeiko Schocher pack_bits(&addr, &pos, 0, 1);
365ff94bc40SHeiko Schocher }
366ff94bc40SHeiko Schocher crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
367ff94bc40SHeiko Schocher c->pnode_sz - UBIFS_LPT_CRC_BYTES);
368ff94bc40SHeiko Schocher addr = buf;
369ff94bc40SHeiko Schocher pos = 0;
370ff94bc40SHeiko Schocher pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
371ff94bc40SHeiko Schocher }
372ff94bc40SHeiko Schocher
373ff94bc40SHeiko Schocher /**
374ff94bc40SHeiko Schocher * ubifs_pack_nnode - pack all the bit fields of a nnode.
375ff94bc40SHeiko Schocher * @c: UBIFS file-system description object
376ff94bc40SHeiko Schocher * @buf: buffer into which to pack
377ff94bc40SHeiko Schocher * @nnode: nnode to pack
378ff94bc40SHeiko Schocher */
ubifs_pack_nnode(struct ubifs_info * c,void * buf,struct ubifs_nnode * nnode)379ff94bc40SHeiko Schocher void ubifs_pack_nnode(struct ubifs_info *c, void *buf,
380ff94bc40SHeiko Schocher struct ubifs_nnode *nnode)
381ff94bc40SHeiko Schocher {
382ff94bc40SHeiko Schocher uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
383ff94bc40SHeiko Schocher int i, pos = 0;
384ff94bc40SHeiko Schocher uint16_t crc;
385ff94bc40SHeiko Schocher
386ff94bc40SHeiko Schocher pack_bits(&addr, &pos, UBIFS_LPT_NNODE, UBIFS_LPT_TYPE_BITS);
387ff94bc40SHeiko Schocher if (c->big_lpt)
388ff94bc40SHeiko Schocher pack_bits(&addr, &pos, nnode->num, c->pcnt_bits);
389ff94bc40SHeiko Schocher for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
390ff94bc40SHeiko Schocher int lnum = nnode->nbranch[i].lnum;
391ff94bc40SHeiko Schocher
392ff94bc40SHeiko Schocher if (lnum == 0)
393ff94bc40SHeiko Schocher lnum = c->lpt_last + 1;
394ff94bc40SHeiko Schocher pack_bits(&addr, &pos, lnum - c->lpt_first, c->lpt_lnum_bits);
395ff94bc40SHeiko Schocher pack_bits(&addr, &pos, nnode->nbranch[i].offs,
396ff94bc40SHeiko Schocher c->lpt_offs_bits);
397ff94bc40SHeiko Schocher }
398ff94bc40SHeiko Schocher crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
399ff94bc40SHeiko Schocher c->nnode_sz - UBIFS_LPT_CRC_BYTES);
400ff94bc40SHeiko Schocher addr = buf;
401ff94bc40SHeiko Schocher pos = 0;
402ff94bc40SHeiko Schocher pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
403ff94bc40SHeiko Schocher }
404ff94bc40SHeiko Schocher
405ff94bc40SHeiko Schocher /**
406ff94bc40SHeiko Schocher * ubifs_pack_ltab - pack the LPT's own lprops table.
407ff94bc40SHeiko Schocher * @c: UBIFS file-system description object
408ff94bc40SHeiko Schocher * @buf: buffer into which to pack
409ff94bc40SHeiko Schocher * @ltab: LPT's own lprops table to pack
410ff94bc40SHeiko Schocher */
ubifs_pack_ltab(struct ubifs_info * c,void * buf,struct ubifs_lpt_lprops * ltab)411ff94bc40SHeiko Schocher void ubifs_pack_ltab(struct ubifs_info *c, void *buf,
412ff94bc40SHeiko Schocher struct ubifs_lpt_lprops *ltab)
413ff94bc40SHeiko Schocher {
414ff94bc40SHeiko Schocher uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
415ff94bc40SHeiko Schocher int i, pos = 0;
416ff94bc40SHeiko Schocher uint16_t crc;
417ff94bc40SHeiko Schocher
418ff94bc40SHeiko Schocher pack_bits(&addr, &pos, UBIFS_LPT_LTAB, UBIFS_LPT_TYPE_BITS);
419ff94bc40SHeiko Schocher for (i = 0; i < c->lpt_lebs; i++) {
420ff94bc40SHeiko Schocher pack_bits(&addr, &pos, ltab[i].free, c->lpt_spc_bits);
421ff94bc40SHeiko Schocher pack_bits(&addr, &pos, ltab[i].dirty, c->lpt_spc_bits);
422ff94bc40SHeiko Schocher }
423ff94bc40SHeiko Schocher crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
424ff94bc40SHeiko Schocher c->ltab_sz - UBIFS_LPT_CRC_BYTES);
425ff94bc40SHeiko Schocher addr = buf;
426ff94bc40SHeiko Schocher pos = 0;
427ff94bc40SHeiko Schocher pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
428ff94bc40SHeiko Schocher }
429ff94bc40SHeiko Schocher
430ff94bc40SHeiko Schocher /**
431ff94bc40SHeiko Schocher * ubifs_pack_lsave - pack the LPT's save table.
432ff94bc40SHeiko Schocher * @c: UBIFS file-system description object
433ff94bc40SHeiko Schocher * @buf: buffer into which to pack
434ff94bc40SHeiko Schocher * @lsave: LPT's save table to pack
435ff94bc40SHeiko Schocher */
ubifs_pack_lsave(struct ubifs_info * c,void * buf,int * lsave)436ff94bc40SHeiko Schocher void ubifs_pack_lsave(struct ubifs_info *c, void *buf, int *lsave)
437ff94bc40SHeiko Schocher {
438ff94bc40SHeiko Schocher uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
439ff94bc40SHeiko Schocher int i, pos = 0;
440ff94bc40SHeiko Schocher uint16_t crc;
441ff94bc40SHeiko Schocher
442ff94bc40SHeiko Schocher pack_bits(&addr, &pos, UBIFS_LPT_LSAVE, UBIFS_LPT_TYPE_BITS);
443ff94bc40SHeiko Schocher for (i = 0; i < c->lsave_cnt; i++)
444ff94bc40SHeiko Schocher pack_bits(&addr, &pos, lsave[i], c->lnum_bits);
445ff94bc40SHeiko Schocher crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
446ff94bc40SHeiko Schocher c->lsave_sz - UBIFS_LPT_CRC_BYTES);
447ff94bc40SHeiko Schocher addr = buf;
448ff94bc40SHeiko Schocher pos = 0;
449ff94bc40SHeiko Schocher pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
450ff94bc40SHeiko Schocher }
451ff94bc40SHeiko Schocher
452ff94bc40SHeiko Schocher /**
4539eefe2a2SStefan Roese * ubifs_add_lpt_dirt - add dirty space to LPT LEB properties.
4549eefe2a2SStefan Roese * @c: UBIFS file-system description object
4559eefe2a2SStefan Roese * @lnum: LEB number to which to add dirty space
4569eefe2a2SStefan Roese * @dirty: amount of dirty space to add
4579eefe2a2SStefan Roese */
ubifs_add_lpt_dirt(struct ubifs_info * c,int lnum,int dirty)4589eefe2a2SStefan Roese void ubifs_add_lpt_dirt(struct ubifs_info *c, int lnum, int dirty)
4599eefe2a2SStefan Roese {
4609eefe2a2SStefan Roese if (!dirty || !lnum)
4619eefe2a2SStefan Roese return;
4629eefe2a2SStefan Roese dbg_lp("LEB %d add %d to %d",
4639eefe2a2SStefan Roese lnum, dirty, c->ltab[lnum - c->lpt_first].dirty);
4649eefe2a2SStefan Roese ubifs_assert(lnum >= c->lpt_first && lnum <= c->lpt_last);
4659eefe2a2SStefan Roese c->ltab[lnum - c->lpt_first].dirty += dirty;
4669eefe2a2SStefan Roese }
4679eefe2a2SStefan Roese
4689eefe2a2SStefan Roese /**
469ff94bc40SHeiko Schocher * set_ltab - set LPT LEB properties.
470ff94bc40SHeiko Schocher * @c: UBIFS file-system description object
471ff94bc40SHeiko Schocher * @lnum: LEB number
472ff94bc40SHeiko Schocher * @free: amount of free space
473ff94bc40SHeiko Schocher * @dirty: amount of dirty space
474ff94bc40SHeiko Schocher */
set_ltab(struct ubifs_info * c,int lnum,int free,int dirty)475ff94bc40SHeiko Schocher static void set_ltab(struct ubifs_info *c, int lnum, int free, int dirty)
476ff94bc40SHeiko Schocher {
477ff94bc40SHeiko Schocher dbg_lp("LEB %d free %d dirty %d to %d %d",
478ff94bc40SHeiko Schocher lnum, c->ltab[lnum - c->lpt_first].free,
479ff94bc40SHeiko Schocher c->ltab[lnum - c->lpt_first].dirty, free, dirty);
480ff94bc40SHeiko Schocher ubifs_assert(lnum >= c->lpt_first && lnum <= c->lpt_last);
481ff94bc40SHeiko Schocher c->ltab[lnum - c->lpt_first].free = free;
482ff94bc40SHeiko Schocher c->ltab[lnum - c->lpt_first].dirty = dirty;
483ff94bc40SHeiko Schocher }
484ff94bc40SHeiko Schocher
485ff94bc40SHeiko Schocher /**
4869eefe2a2SStefan Roese * ubifs_add_nnode_dirt - add dirty space to LPT LEB properties.
4879eefe2a2SStefan Roese * @c: UBIFS file-system description object
4889eefe2a2SStefan Roese * @nnode: nnode for which to add dirt
4899eefe2a2SStefan Roese */
ubifs_add_nnode_dirt(struct ubifs_info * c,struct ubifs_nnode * nnode)4909eefe2a2SStefan Roese void ubifs_add_nnode_dirt(struct ubifs_info *c, struct ubifs_nnode *nnode)
4919eefe2a2SStefan Roese {
4929eefe2a2SStefan Roese struct ubifs_nnode *np = nnode->parent;
4939eefe2a2SStefan Roese
4949eefe2a2SStefan Roese if (np)
4959eefe2a2SStefan Roese ubifs_add_lpt_dirt(c, np->nbranch[nnode->iip].lnum,
4969eefe2a2SStefan Roese c->nnode_sz);
4979eefe2a2SStefan Roese else {
4989eefe2a2SStefan Roese ubifs_add_lpt_dirt(c, c->lpt_lnum, c->nnode_sz);
4999eefe2a2SStefan Roese if (!(c->lpt_drty_flgs & LTAB_DIRTY)) {
5009eefe2a2SStefan Roese c->lpt_drty_flgs |= LTAB_DIRTY;
5019eefe2a2SStefan Roese ubifs_add_lpt_dirt(c, c->ltab_lnum, c->ltab_sz);
5029eefe2a2SStefan Roese }
5039eefe2a2SStefan Roese }
5049eefe2a2SStefan Roese }
5059eefe2a2SStefan Roese
5069eefe2a2SStefan Roese /**
5079eefe2a2SStefan Roese * add_pnode_dirt - add dirty space to LPT LEB properties.
5089eefe2a2SStefan Roese * @c: UBIFS file-system description object
5099eefe2a2SStefan Roese * @pnode: pnode for which to add dirt
5109eefe2a2SStefan Roese */
add_pnode_dirt(struct ubifs_info * c,struct ubifs_pnode * pnode)5119eefe2a2SStefan Roese static void add_pnode_dirt(struct ubifs_info *c, struct ubifs_pnode *pnode)
5129eefe2a2SStefan Roese {
5139eefe2a2SStefan Roese ubifs_add_lpt_dirt(c, pnode->parent->nbranch[pnode->iip].lnum,
5149eefe2a2SStefan Roese c->pnode_sz);
5159eefe2a2SStefan Roese }
5169eefe2a2SStefan Roese
5179eefe2a2SStefan Roese /**
518ff94bc40SHeiko Schocher * calc_nnode_num - calculate nnode number.
519ff94bc40SHeiko Schocher * @row: the row in the tree (root is zero)
520ff94bc40SHeiko Schocher * @col: the column in the row (leftmost is zero)
521ff94bc40SHeiko Schocher *
522ff94bc40SHeiko Schocher * The nnode number is a number that uniquely identifies a nnode and can be used
523ff94bc40SHeiko Schocher * easily to traverse the tree from the root to that nnode.
524ff94bc40SHeiko Schocher *
525ff94bc40SHeiko Schocher * This function calculates and returns the nnode number for the nnode at @row
526ff94bc40SHeiko Schocher * and @col.
527ff94bc40SHeiko Schocher */
calc_nnode_num(int row,int col)528ff94bc40SHeiko Schocher static int calc_nnode_num(int row, int col)
529ff94bc40SHeiko Schocher {
530ff94bc40SHeiko Schocher int num, bits;
531ff94bc40SHeiko Schocher
532ff94bc40SHeiko Schocher num = 1;
533ff94bc40SHeiko Schocher while (row--) {
534ff94bc40SHeiko Schocher bits = (col & (UBIFS_LPT_FANOUT - 1));
535ff94bc40SHeiko Schocher col >>= UBIFS_LPT_FANOUT_SHIFT;
536ff94bc40SHeiko Schocher num <<= UBIFS_LPT_FANOUT_SHIFT;
537ff94bc40SHeiko Schocher num |= bits;
538ff94bc40SHeiko Schocher }
539ff94bc40SHeiko Schocher return num;
540ff94bc40SHeiko Schocher }
541ff94bc40SHeiko Schocher
542ff94bc40SHeiko Schocher /**
5439eefe2a2SStefan Roese * calc_nnode_num_from_parent - calculate nnode number.
5449eefe2a2SStefan Roese * @c: UBIFS file-system description object
5459eefe2a2SStefan Roese * @parent: parent nnode
5469eefe2a2SStefan Roese * @iip: index in parent
5479eefe2a2SStefan Roese *
5489eefe2a2SStefan Roese * The nnode number is a number that uniquely identifies a nnode and can be used
5499eefe2a2SStefan Roese * easily to traverse the tree from the root to that nnode.
5509eefe2a2SStefan Roese *
5519eefe2a2SStefan Roese * This function calculates and returns the nnode number based on the parent's
5529eefe2a2SStefan Roese * nnode number and the index in parent.
5539eefe2a2SStefan Roese */
calc_nnode_num_from_parent(const struct ubifs_info * c,struct ubifs_nnode * parent,int iip)5549eefe2a2SStefan Roese static int calc_nnode_num_from_parent(const struct ubifs_info *c,
5559eefe2a2SStefan Roese struct ubifs_nnode *parent, int iip)
5569eefe2a2SStefan Roese {
5579eefe2a2SStefan Roese int num, shft;
5589eefe2a2SStefan Roese
5599eefe2a2SStefan Roese if (!parent)
5609eefe2a2SStefan Roese return 1;
5619eefe2a2SStefan Roese shft = (c->lpt_hght - parent->level) * UBIFS_LPT_FANOUT_SHIFT;
5629eefe2a2SStefan Roese num = parent->num ^ (1 << shft);
5639eefe2a2SStefan Roese num |= (UBIFS_LPT_FANOUT + iip) << shft;
5649eefe2a2SStefan Roese return num;
5659eefe2a2SStefan Roese }
5669eefe2a2SStefan Roese
5679eefe2a2SStefan Roese /**
5689eefe2a2SStefan Roese * calc_pnode_num_from_parent - calculate pnode number.
5699eefe2a2SStefan Roese * @c: UBIFS file-system description object
5709eefe2a2SStefan Roese * @parent: parent nnode
5719eefe2a2SStefan Roese * @iip: index in parent
5729eefe2a2SStefan Roese *
5739eefe2a2SStefan Roese * The pnode number is a number that uniquely identifies a pnode and can be used
5749eefe2a2SStefan Roese * easily to traverse the tree from the root to that pnode.
5759eefe2a2SStefan Roese *
5769eefe2a2SStefan Roese * This function calculates and returns the pnode number based on the parent's
5779eefe2a2SStefan Roese * nnode number and the index in parent.
5789eefe2a2SStefan Roese */
calc_pnode_num_from_parent(const struct ubifs_info * c,struct ubifs_nnode * parent,int iip)5799eefe2a2SStefan Roese static int calc_pnode_num_from_parent(const struct ubifs_info *c,
5809eefe2a2SStefan Roese struct ubifs_nnode *parent, int iip)
5819eefe2a2SStefan Roese {
5829eefe2a2SStefan Roese int i, n = c->lpt_hght - 1, pnum = parent->num, num = 0;
5839eefe2a2SStefan Roese
5849eefe2a2SStefan Roese for (i = 0; i < n; i++) {
5859eefe2a2SStefan Roese num <<= UBIFS_LPT_FANOUT_SHIFT;
5869eefe2a2SStefan Roese num |= pnum & (UBIFS_LPT_FANOUT - 1);
5879eefe2a2SStefan Roese pnum >>= UBIFS_LPT_FANOUT_SHIFT;
5889eefe2a2SStefan Roese }
5899eefe2a2SStefan Roese num <<= UBIFS_LPT_FANOUT_SHIFT;
5909eefe2a2SStefan Roese num |= iip;
5919eefe2a2SStefan Roese return num;
5929eefe2a2SStefan Roese }
5939eefe2a2SStefan Roese
5949eefe2a2SStefan Roese /**
595ff94bc40SHeiko Schocher * ubifs_create_dflt_lpt - create default LPT.
596ff94bc40SHeiko Schocher * @c: UBIFS file-system description object
597ff94bc40SHeiko Schocher * @main_lebs: number of main area LEBs is passed and returned here
598ff94bc40SHeiko Schocher * @lpt_first: LEB number of first LPT LEB
599ff94bc40SHeiko Schocher * @lpt_lebs: number of LEBs for LPT is passed and returned here
600ff94bc40SHeiko Schocher * @big_lpt: use big LPT model is passed and returned here
601ff94bc40SHeiko Schocher *
602ff94bc40SHeiko Schocher * This function returns %0 on success and a negative error code on failure.
603ff94bc40SHeiko Schocher */
ubifs_create_dflt_lpt(struct ubifs_info * c,int * main_lebs,int lpt_first,int * lpt_lebs,int * big_lpt)604ff94bc40SHeiko Schocher int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
605ff94bc40SHeiko Schocher int *lpt_lebs, int *big_lpt)
606ff94bc40SHeiko Schocher {
607ff94bc40SHeiko Schocher int lnum, err = 0, node_sz, iopos, i, j, cnt, len, alen, row;
608ff94bc40SHeiko Schocher int blnum, boffs, bsz, bcnt;
609ff94bc40SHeiko Schocher struct ubifs_pnode *pnode = NULL;
610ff94bc40SHeiko Schocher struct ubifs_nnode *nnode = NULL;
611ff94bc40SHeiko Schocher void *buf = NULL, *p;
612ff94bc40SHeiko Schocher struct ubifs_lpt_lprops *ltab = NULL;
613ff94bc40SHeiko Schocher int *lsave = NULL;
614ff94bc40SHeiko Schocher
615ff94bc40SHeiko Schocher err = calc_dflt_lpt_geom(c, main_lebs, big_lpt);
616ff94bc40SHeiko Schocher if (err)
617ff94bc40SHeiko Schocher return err;
618ff94bc40SHeiko Schocher *lpt_lebs = c->lpt_lebs;
619ff94bc40SHeiko Schocher
620ff94bc40SHeiko Schocher /* Needed by 'ubifs_pack_nnode()' and 'set_ltab()' */
621ff94bc40SHeiko Schocher c->lpt_first = lpt_first;
622ff94bc40SHeiko Schocher /* Needed by 'set_ltab()' */
623ff94bc40SHeiko Schocher c->lpt_last = lpt_first + c->lpt_lebs - 1;
624ff94bc40SHeiko Schocher /* Needed by 'ubifs_pack_lsave()' */
625ff94bc40SHeiko Schocher c->main_first = c->leb_cnt - *main_lebs;
626ff94bc40SHeiko Schocher
627ff94bc40SHeiko Schocher lsave = kmalloc(sizeof(int) * c->lsave_cnt, GFP_KERNEL);
628ff94bc40SHeiko Schocher pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_KERNEL);
629ff94bc40SHeiko Schocher nnode = kzalloc(sizeof(struct ubifs_nnode), GFP_KERNEL);
630ff94bc40SHeiko Schocher buf = vmalloc(c->leb_size);
631ff94bc40SHeiko Schocher ltab = vmalloc(sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs);
632ff94bc40SHeiko Schocher if (!pnode || !nnode || !buf || !ltab || !lsave) {
633ff94bc40SHeiko Schocher err = -ENOMEM;
634ff94bc40SHeiko Schocher goto out;
635ff94bc40SHeiko Schocher }
636ff94bc40SHeiko Schocher
637ff94bc40SHeiko Schocher ubifs_assert(!c->ltab);
638ff94bc40SHeiko Schocher c->ltab = ltab; /* Needed by set_ltab */
639ff94bc40SHeiko Schocher
640ff94bc40SHeiko Schocher /* Initialize LPT's own lprops */
641ff94bc40SHeiko Schocher for (i = 0; i < c->lpt_lebs; i++) {
642ff94bc40SHeiko Schocher ltab[i].free = c->leb_size;
643ff94bc40SHeiko Schocher ltab[i].dirty = 0;
644ff94bc40SHeiko Schocher ltab[i].tgc = 0;
645ff94bc40SHeiko Schocher ltab[i].cmt = 0;
646ff94bc40SHeiko Schocher }
647ff94bc40SHeiko Schocher
648ff94bc40SHeiko Schocher lnum = lpt_first;
649ff94bc40SHeiko Schocher p = buf;
650ff94bc40SHeiko Schocher /* Number of leaf nodes (pnodes) */
651ff94bc40SHeiko Schocher cnt = c->pnode_cnt;
652ff94bc40SHeiko Schocher
653ff94bc40SHeiko Schocher /*
654ff94bc40SHeiko Schocher * The first pnode contains the LEB properties for the LEBs that contain
655ff94bc40SHeiko Schocher * the root inode node and the root index node of the index tree.
656ff94bc40SHeiko Schocher */
657ff94bc40SHeiko Schocher node_sz = ALIGN(ubifs_idx_node_sz(c, 1), 8);
658ff94bc40SHeiko Schocher iopos = ALIGN(node_sz, c->min_io_size);
659ff94bc40SHeiko Schocher pnode->lprops[0].free = c->leb_size - iopos;
660ff94bc40SHeiko Schocher pnode->lprops[0].dirty = iopos - node_sz;
661ff94bc40SHeiko Schocher pnode->lprops[0].flags = LPROPS_INDEX;
662ff94bc40SHeiko Schocher
663ff94bc40SHeiko Schocher node_sz = UBIFS_INO_NODE_SZ;
664ff94bc40SHeiko Schocher iopos = ALIGN(node_sz, c->min_io_size);
665ff94bc40SHeiko Schocher pnode->lprops[1].free = c->leb_size - iopos;
666ff94bc40SHeiko Schocher pnode->lprops[1].dirty = iopos - node_sz;
667ff94bc40SHeiko Schocher
668ff94bc40SHeiko Schocher for (i = 2; i < UBIFS_LPT_FANOUT; i++)
669ff94bc40SHeiko Schocher pnode->lprops[i].free = c->leb_size;
670ff94bc40SHeiko Schocher
671ff94bc40SHeiko Schocher /* Add first pnode */
672ff94bc40SHeiko Schocher ubifs_pack_pnode(c, p, pnode);
673ff94bc40SHeiko Schocher p += c->pnode_sz;
674ff94bc40SHeiko Schocher len = c->pnode_sz;
675ff94bc40SHeiko Schocher pnode->num += 1;
676ff94bc40SHeiko Schocher
677ff94bc40SHeiko Schocher /* Reset pnode values for remaining pnodes */
678ff94bc40SHeiko Schocher pnode->lprops[0].free = c->leb_size;
679ff94bc40SHeiko Schocher pnode->lprops[0].dirty = 0;
680ff94bc40SHeiko Schocher pnode->lprops[0].flags = 0;
681ff94bc40SHeiko Schocher
682ff94bc40SHeiko Schocher pnode->lprops[1].free = c->leb_size;
683ff94bc40SHeiko Schocher pnode->lprops[1].dirty = 0;
684ff94bc40SHeiko Schocher
685ff94bc40SHeiko Schocher /*
686ff94bc40SHeiko Schocher * To calculate the internal node branches, we keep information about
687ff94bc40SHeiko Schocher * the level below.
688ff94bc40SHeiko Schocher */
689ff94bc40SHeiko Schocher blnum = lnum; /* LEB number of level below */
690ff94bc40SHeiko Schocher boffs = 0; /* Offset of level below */
691ff94bc40SHeiko Schocher bcnt = cnt; /* Number of nodes in level below */
692ff94bc40SHeiko Schocher bsz = c->pnode_sz; /* Size of nodes in level below */
693ff94bc40SHeiko Schocher
694ff94bc40SHeiko Schocher /* Add all remaining pnodes */
695ff94bc40SHeiko Schocher for (i = 1; i < cnt; i++) {
696ff94bc40SHeiko Schocher if (len + c->pnode_sz > c->leb_size) {
697ff94bc40SHeiko Schocher alen = ALIGN(len, c->min_io_size);
698ff94bc40SHeiko Schocher set_ltab(c, lnum, c->leb_size - alen, alen - len);
699ff94bc40SHeiko Schocher memset(p, 0xff, alen - len);
700ff94bc40SHeiko Schocher err = ubifs_leb_change(c, lnum++, buf, alen);
701ff94bc40SHeiko Schocher if (err)
702ff94bc40SHeiko Schocher goto out;
703ff94bc40SHeiko Schocher p = buf;
704ff94bc40SHeiko Schocher len = 0;
705ff94bc40SHeiko Schocher }
706ff94bc40SHeiko Schocher ubifs_pack_pnode(c, p, pnode);
707ff94bc40SHeiko Schocher p += c->pnode_sz;
708ff94bc40SHeiko Schocher len += c->pnode_sz;
709ff94bc40SHeiko Schocher /*
710ff94bc40SHeiko Schocher * pnodes are simply numbered left to right starting at zero,
711ff94bc40SHeiko Schocher * which means the pnode number can be used easily to traverse
712ff94bc40SHeiko Schocher * down the tree to the corresponding pnode.
713ff94bc40SHeiko Schocher */
714ff94bc40SHeiko Schocher pnode->num += 1;
715ff94bc40SHeiko Schocher }
716ff94bc40SHeiko Schocher
717ff94bc40SHeiko Schocher row = 0;
718ff94bc40SHeiko Schocher for (i = UBIFS_LPT_FANOUT; cnt > i; i <<= UBIFS_LPT_FANOUT_SHIFT)
719ff94bc40SHeiko Schocher row += 1;
720ff94bc40SHeiko Schocher /* Add all nnodes, one level at a time */
721ff94bc40SHeiko Schocher while (1) {
722ff94bc40SHeiko Schocher /* Number of internal nodes (nnodes) at next level */
723ff94bc40SHeiko Schocher cnt = DIV_ROUND_UP(cnt, UBIFS_LPT_FANOUT);
724ff94bc40SHeiko Schocher for (i = 0; i < cnt; i++) {
725ff94bc40SHeiko Schocher if (len + c->nnode_sz > c->leb_size) {
726ff94bc40SHeiko Schocher alen = ALIGN(len, c->min_io_size);
727ff94bc40SHeiko Schocher set_ltab(c, lnum, c->leb_size - alen,
728ff94bc40SHeiko Schocher alen - len);
729ff94bc40SHeiko Schocher memset(p, 0xff, alen - len);
730ff94bc40SHeiko Schocher err = ubifs_leb_change(c, lnum++, buf, alen);
731ff94bc40SHeiko Schocher if (err)
732ff94bc40SHeiko Schocher goto out;
733ff94bc40SHeiko Schocher p = buf;
734ff94bc40SHeiko Schocher len = 0;
735ff94bc40SHeiko Schocher }
736ff94bc40SHeiko Schocher /* Only 1 nnode at this level, so it is the root */
737ff94bc40SHeiko Schocher if (cnt == 1) {
738ff94bc40SHeiko Schocher c->lpt_lnum = lnum;
739ff94bc40SHeiko Schocher c->lpt_offs = len;
740ff94bc40SHeiko Schocher }
741ff94bc40SHeiko Schocher /* Set branches to the level below */
742ff94bc40SHeiko Schocher for (j = 0; j < UBIFS_LPT_FANOUT; j++) {
743ff94bc40SHeiko Schocher if (bcnt) {
744ff94bc40SHeiko Schocher if (boffs + bsz > c->leb_size) {
745ff94bc40SHeiko Schocher blnum += 1;
746ff94bc40SHeiko Schocher boffs = 0;
747ff94bc40SHeiko Schocher }
748ff94bc40SHeiko Schocher nnode->nbranch[j].lnum = blnum;
749ff94bc40SHeiko Schocher nnode->nbranch[j].offs = boffs;
750ff94bc40SHeiko Schocher boffs += bsz;
751ff94bc40SHeiko Schocher bcnt--;
752ff94bc40SHeiko Schocher } else {
753ff94bc40SHeiko Schocher nnode->nbranch[j].lnum = 0;
754ff94bc40SHeiko Schocher nnode->nbranch[j].offs = 0;
755ff94bc40SHeiko Schocher }
756ff94bc40SHeiko Schocher }
757ff94bc40SHeiko Schocher nnode->num = calc_nnode_num(row, i);
758ff94bc40SHeiko Schocher ubifs_pack_nnode(c, p, nnode);
759ff94bc40SHeiko Schocher p += c->nnode_sz;
760ff94bc40SHeiko Schocher len += c->nnode_sz;
761ff94bc40SHeiko Schocher }
762ff94bc40SHeiko Schocher /* Only 1 nnode at this level, so it is the root */
763ff94bc40SHeiko Schocher if (cnt == 1)
764ff94bc40SHeiko Schocher break;
765ff94bc40SHeiko Schocher /* Update the information about the level below */
766ff94bc40SHeiko Schocher bcnt = cnt;
767ff94bc40SHeiko Schocher bsz = c->nnode_sz;
768ff94bc40SHeiko Schocher row -= 1;
769ff94bc40SHeiko Schocher }
770ff94bc40SHeiko Schocher
771ff94bc40SHeiko Schocher if (*big_lpt) {
772ff94bc40SHeiko Schocher /* Need to add LPT's save table */
773ff94bc40SHeiko Schocher if (len + c->lsave_sz > c->leb_size) {
774ff94bc40SHeiko Schocher alen = ALIGN(len, c->min_io_size);
775ff94bc40SHeiko Schocher set_ltab(c, lnum, c->leb_size - alen, alen - len);
776ff94bc40SHeiko Schocher memset(p, 0xff, alen - len);
777ff94bc40SHeiko Schocher err = ubifs_leb_change(c, lnum++, buf, alen);
778ff94bc40SHeiko Schocher if (err)
779ff94bc40SHeiko Schocher goto out;
780ff94bc40SHeiko Schocher p = buf;
781ff94bc40SHeiko Schocher len = 0;
782ff94bc40SHeiko Schocher }
783ff94bc40SHeiko Schocher
784ff94bc40SHeiko Schocher c->lsave_lnum = lnum;
785ff94bc40SHeiko Schocher c->lsave_offs = len;
786ff94bc40SHeiko Schocher
787ff94bc40SHeiko Schocher for (i = 0; i < c->lsave_cnt && i < *main_lebs; i++)
788ff94bc40SHeiko Schocher lsave[i] = c->main_first + i;
789ff94bc40SHeiko Schocher for (; i < c->lsave_cnt; i++)
790ff94bc40SHeiko Schocher lsave[i] = c->main_first;
791ff94bc40SHeiko Schocher
792ff94bc40SHeiko Schocher ubifs_pack_lsave(c, p, lsave);
793ff94bc40SHeiko Schocher p += c->lsave_sz;
794ff94bc40SHeiko Schocher len += c->lsave_sz;
795ff94bc40SHeiko Schocher }
796ff94bc40SHeiko Schocher
797ff94bc40SHeiko Schocher /* Need to add LPT's own LEB properties table */
798ff94bc40SHeiko Schocher if (len + c->ltab_sz > c->leb_size) {
799ff94bc40SHeiko Schocher alen = ALIGN(len, c->min_io_size);
800ff94bc40SHeiko Schocher set_ltab(c, lnum, c->leb_size - alen, alen - len);
801ff94bc40SHeiko Schocher memset(p, 0xff, alen - len);
802ff94bc40SHeiko Schocher err = ubifs_leb_change(c, lnum++, buf, alen);
803ff94bc40SHeiko Schocher if (err)
804ff94bc40SHeiko Schocher goto out;
805ff94bc40SHeiko Schocher p = buf;
806ff94bc40SHeiko Schocher len = 0;
807ff94bc40SHeiko Schocher }
808ff94bc40SHeiko Schocher
809ff94bc40SHeiko Schocher c->ltab_lnum = lnum;
810ff94bc40SHeiko Schocher c->ltab_offs = len;
811ff94bc40SHeiko Schocher
812ff94bc40SHeiko Schocher /* Update ltab before packing it */
813ff94bc40SHeiko Schocher len += c->ltab_sz;
814ff94bc40SHeiko Schocher alen = ALIGN(len, c->min_io_size);
815ff94bc40SHeiko Schocher set_ltab(c, lnum, c->leb_size - alen, alen - len);
816ff94bc40SHeiko Schocher
817ff94bc40SHeiko Schocher ubifs_pack_ltab(c, p, ltab);
818ff94bc40SHeiko Schocher p += c->ltab_sz;
819ff94bc40SHeiko Schocher
820ff94bc40SHeiko Schocher /* Write remaining buffer */
821ff94bc40SHeiko Schocher memset(p, 0xff, alen - len);
822ff94bc40SHeiko Schocher err = ubifs_leb_change(c, lnum, buf, alen);
823ff94bc40SHeiko Schocher if (err)
824ff94bc40SHeiko Schocher goto out;
825ff94bc40SHeiko Schocher
826ff94bc40SHeiko Schocher c->nhead_lnum = lnum;
827ff94bc40SHeiko Schocher c->nhead_offs = ALIGN(len, c->min_io_size);
828ff94bc40SHeiko Schocher
829ff94bc40SHeiko Schocher dbg_lp("space_bits %d", c->space_bits);
830ff94bc40SHeiko Schocher dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits);
831ff94bc40SHeiko Schocher dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits);
832ff94bc40SHeiko Schocher dbg_lp("lpt_spc_bits %d", c->lpt_spc_bits);
833ff94bc40SHeiko Schocher dbg_lp("pcnt_bits %d", c->pcnt_bits);
834ff94bc40SHeiko Schocher dbg_lp("lnum_bits %d", c->lnum_bits);
835ff94bc40SHeiko Schocher dbg_lp("pnode_sz %d", c->pnode_sz);
836ff94bc40SHeiko Schocher dbg_lp("nnode_sz %d", c->nnode_sz);
837ff94bc40SHeiko Schocher dbg_lp("ltab_sz %d", c->ltab_sz);
838ff94bc40SHeiko Schocher dbg_lp("lsave_sz %d", c->lsave_sz);
839ff94bc40SHeiko Schocher dbg_lp("lsave_cnt %d", c->lsave_cnt);
840ff94bc40SHeiko Schocher dbg_lp("lpt_hght %d", c->lpt_hght);
841ff94bc40SHeiko Schocher dbg_lp("big_lpt %d", c->big_lpt);
842ff94bc40SHeiko Schocher dbg_lp("LPT root is at %d:%d", c->lpt_lnum, c->lpt_offs);
843ff94bc40SHeiko Schocher dbg_lp("LPT head is at %d:%d", c->nhead_lnum, c->nhead_offs);
844ff94bc40SHeiko Schocher dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs);
845ff94bc40SHeiko Schocher if (c->big_lpt)
846ff94bc40SHeiko Schocher dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs);
847ff94bc40SHeiko Schocher out:
848ff94bc40SHeiko Schocher c->ltab = NULL;
849ff94bc40SHeiko Schocher kfree(lsave);
850ff94bc40SHeiko Schocher vfree(ltab);
851ff94bc40SHeiko Schocher vfree(buf);
852ff94bc40SHeiko Schocher kfree(nnode);
853ff94bc40SHeiko Schocher kfree(pnode);
854ff94bc40SHeiko Schocher return err;
855ff94bc40SHeiko Schocher }
856ff94bc40SHeiko Schocher
857ff94bc40SHeiko Schocher /**
8589eefe2a2SStefan Roese * update_cats - add LEB properties of a pnode to LEB category lists and heaps.
8599eefe2a2SStefan Roese * @c: UBIFS file-system description object
8609eefe2a2SStefan Roese * @pnode: pnode
8619eefe2a2SStefan Roese *
8629eefe2a2SStefan Roese * When a pnode is loaded into memory, the LEB properties it contains are added,
8639eefe2a2SStefan Roese * by this function, to the LEB category lists and heaps.
8649eefe2a2SStefan Roese */
update_cats(struct ubifs_info * c,struct ubifs_pnode * pnode)8659eefe2a2SStefan Roese static void update_cats(struct ubifs_info *c, struct ubifs_pnode *pnode)
8669eefe2a2SStefan Roese {
8679eefe2a2SStefan Roese int i;
8689eefe2a2SStefan Roese
8699eefe2a2SStefan Roese for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
8709eefe2a2SStefan Roese int cat = pnode->lprops[i].flags & LPROPS_CAT_MASK;
8719eefe2a2SStefan Roese int lnum = pnode->lprops[i].lnum;
8729eefe2a2SStefan Roese
8739eefe2a2SStefan Roese if (!lnum)
8749eefe2a2SStefan Roese return;
8759eefe2a2SStefan Roese ubifs_add_to_cat(c, &pnode->lprops[i], cat);
8769eefe2a2SStefan Roese }
8779eefe2a2SStefan Roese }
8789eefe2a2SStefan Roese
8799eefe2a2SStefan Roese /**
8809eefe2a2SStefan Roese * replace_cats - add LEB properties of a pnode to LEB category lists and heaps.
8819eefe2a2SStefan Roese * @c: UBIFS file-system description object
8829eefe2a2SStefan Roese * @old_pnode: pnode copied
8839eefe2a2SStefan Roese * @new_pnode: pnode copy
8849eefe2a2SStefan Roese *
8859eefe2a2SStefan Roese * During commit it is sometimes necessary to copy a pnode
8869eefe2a2SStefan Roese * (see dirty_cow_pnode). When that happens, references in
8879eefe2a2SStefan Roese * category lists and heaps must be replaced. This function does that.
8889eefe2a2SStefan Roese */
replace_cats(struct ubifs_info * c,struct ubifs_pnode * old_pnode,struct ubifs_pnode * new_pnode)8899eefe2a2SStefan Roese static void replace_cats(struct ubifs_info *c, struct ubifs_pnode *old_pnode,
8909eefe2a2SStefan Roese struct ubifs_pnode *new_pnode)
8919eefe2a2SStefan Roese {
8929eefe2a2SStefan Roese int i;
8939eefe2a2SStefan Roese
8949eefe2a2SStefan Roese for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
8959eefe2a2SStefan Roese if (!new_pnode->lprops[i].lnum)
8969eefe2a2SStefan Roese return;
8979eefe2a2SStefan Roese ubifs_replace_cat(c, &old_pnode->lprops[i],
8989eefe2a2SStefan Roese &new_pnode->lprops[i]);
8999eefe2a2SStefan Roese }
9009eefe2a2SStefan Roese }
9019eefe2a2SStefan Roese
9029eefe2a2SStefan Roese /**
9039eefe2a2SStefan Roese * check_lpt_crc - check LPT node crc is correct.
9049eefe2a2SStefan Roese * @c: UBIFS file-system description object
9059eefe2a2SStefan Roese * @buf: buffer containing node
9069eefe2a2SStefan Roese * @len: length of node
9079eefe2a2SStefan Roese *
9089eefe2a2SStefan Roese * This function returns %0 on success and a negative error code on failure.
9099eefe2a2SStefan Roese */
check_lpt_crc(const struct ubifs_info * c,void * buf,int len)910*0195a7bbSHeiko Schocher static int check_lpt_crc(const struct ubifs_info *c, void *buf, int len)
9119eefe2a2SStefan Roese {
9129eefe2a2SStefan Roese int pos = 0;
9139eefe2a2SStefan Roese uint8_t *addr = buf;
9149eefe2a2SStefan Roese uint16_t crc, calc_crc;
9159eefe2a2SStefan Roese
9169eefe2a2SStefan Roese crc = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_CRC_BITS);
9179eefe2a2SStefan Roese calc_crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
9189eefe2a2SStefan Roese len - UBIFS_LPT_CRC_BYTES);
9199eefe2a2SStefan Roese if (crc != calc_crc) {
920*0195a7bbSHeiko Schocher ubifs_err(c, "invalid crc in LPT node: crc %hx calc %hx",
921*0195a7bbSHeiko Schocher crc, calc_crc);
922ff94bc40SHeiko Schocher dump_stack();
9239eefe2a2SStefan Roese return -EINVAL;
9249eefe2a2SStefan Roese }
9259eefe2a2SStefan Roese return 0;
9269eefe2a2SStefan Roese }
9279eefe2a2SStefan Roese
9289eefe2a2SStefan Roese /**
9299eefe2a2SStefan Roese * check_lpt_type - check LPT node type is correct.
9309eefe2a2SStefan Roese * @c: UBIFS file-system description object
9319eefe2a2SStefan Roese * @addr: address of type bit field is passed and returned updated here
9329eefe2a2SStefan Roese * @pos: position of type bit field is passed and returned updated here
9339eefe2a2SStefan Roese * @type: expected type
9349eefe2a2SStefan Roese *
9359eefe2a2SStefan Roese * This function returns %0 on success and a negative error code on failure.
9369eefe2a2SStefan Roese */
check_lpt_type(const struct ubifs_info * c,uint8_t ** addr,int * pos,int type)937*0195a7bbSHeiko Schocher static int check_lpt_type(const struct ubifs_info *c, uint8_t **addr,
938*0195a7bbSHeiko Schocher int *pos, int type)
9399eefe2a2SStefan Roese {
9409eefe2a2SStefan Roese int node_type;
9419eefe2a2SStefan Roese
9429eefe2a2SStefan Roese node_type = ubifs_unpack_bits(addr, pos, UBIFS_LPT_TYPE_BITS);
9439eefe2a2SStefan Roese if (node_type != type) {
944*0195a7bbSHeiko Schocher ubifs_err(c, "invalid type (%d) in LPT node type %d",
945*0195a7bbSHeiko Schocher node_type, type);
946ff94bc40SHeiko Schocher dump_stack();
9479eefe2a2SStefan Roese return -EINVAL;
9489eefe2a2SStefan Roese }
9499eefe2a2SStefan Roese return 0;
9509eefe2a2SStefan Roese }
9519eefe2a2SStefan Roese
9529eefe2a2SStefan Roese /**
9539eefe2a2SStefan Roese * unpack_pnode - unpack a pnode.
9549eefe2a2SStefan Roese * @c: UBIFS file-system description object
9559eefe2a2SStefan Roese * @buf: buffer containing packed pnode to unpack
9569eefe2a2SStefan Roese * @pnode: pnode structure to fill
9579eefe2a2SStefan Roese *
9589eefe2a2SStefan Roese * This function returns %0 on success and a negative error code on failure.
9599eefe2a2SStefan Roese */
unpack_pnode(const struct ubifs_info * c,void * buf,struct ubifs_pnode * pnode)9609eefe2a2SStefan Roese static int unpack_pnode(const struct ubifs_info *c, void *buf,
9619eefe2a2SStefan Roese struct ubifs_pnode *pnode)
9629eefe2a2SStefan Roese {
9639eefe2a2SStefan Roese uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
9649eefe2a2SStefan Roese int i, pos = 0, err;
9659eefe2a2SStefan Roese
966*0195a7bbSHeiko Schocher err = check_lpt_type(c, &addr, &pos, UBIFS_LPT_PNODE);
9679eefe2a2SStefan Roese if (err)
9689eefe2a2SStefan Roese return err;
9699eefe2a2SStefan Roese if (c->big_lpt)
9709eefe2a2SStefan Roese pnode->num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits);
9719eefe2a2SStefan Roese for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
9729eefe2a2SStefan Roese struct ubifs_lprops * const lprops = &pnode->lprops[i];
9739eefe2a2SStefan Roese
9749eefe2a2SStefan Roese lprops->free = ubifs_unpack_bits(&addr, &pos, c->space_bits);
9759eefe2a2SStefan Roese lprops->free <<= 3;
9769eefe2a2SStefan Roese lprops->dirty = ubifs_unpack_bits(&addr, &pos, c->space_bits);
9779eefe2a2SStefan Roese lprops->dirty <<= 3;
9789eefe2a2SStefan Roese
9799eefe2a2SStefan Roese if (ubifs_unpack_bits(&addr, &pos, 1))
9809eefe2a2SStefan Roese lprops->flags = LPROPS_INDEX;
9819eefe2a2SStefan Roese else
9829eefe2a2SStefan Roese lprops->flags = 0;
9839eefe2a2SStefan Roese lprops->flags |= ubifs_categorize_lprops(c, lprops);
9849eefe2a2SStefan Roese }
985*0195a7bbSHeiko Schocher err = check_lpt_crc(c, buf, c->pnode_sz);
9869eefe2a2SStefan Roese return err;
9879eefe2a2SStefan Roese }
9889eefe2a2SStefan Roese
9899eefe2a2SStefan Roese /**
9909eefe2a2SStefan Roese * ubifs_unpack_nnode - unpack a nnode.
9919eefe2a2SStefan Roese * @c: UBIFS file-system description object
9929eefe2a2SStefan Roese * @buf: buffer containing packed nnode to unpack
9939eefe2a2SStefan Roese * @nnode: nnode structure to fill
9949eefe2a2SStefan Roese *
9959eefe2a2SStefan Roese * This function returns %0 on success and a negative error code on failure.
9969eefe2a2SStefan Roese */
ubifs_unpack_nnode(const struct ubifs_info * c,void * buf,struct ubifs_nnode * nnode)9979eefe2a2SStefan Roese int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf,
9989eefe2a2SStefan Roese struct ubifs_nnode *nnode)
9999eefe2a2SStefan Roese {
10009eefe2a2SStefan Roese uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
10019eefe2a2SStefan Roese int i, pos = 0, err;
10029eefe2a2SStefan Roese
1003*0195a7bbSHeiko Schocher err = check_lpt_type(c, &addr, &pos, UBIFS_LPT_NNODE);
10049eefe2a2SStefan Roese if (err)
10059eefe2a2SStefan Roese return err;
10069eefe2a2SStefan Roese if (c->big_lpt)
10079eefe2a2SStefan Roese nnode->num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits);
10089eefe2a2SStefan Roese for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
10099eefe2a2SStefan Roese int lnum;
10109eefe2a2SStefan Roese
10119eefe2a2SStefan Roese lnum = ubifs_unpack_bits(&addr, &pos, c->lpt_lnum_bits) +
10129eefe2a2SStefan Roese c->lpt_first;
10139eefe2a2SStefan Roese if (lnum == c->lpt_last + 1)
10149eefe2a2SStefan Roese lnum = 0;
10159eefe2a2SStefan Roese nnode->nbranch[i].lnum = lnum;
10169eefe2a2SStefan Roese nnode->nbranch[i].offs = ubifs_unpack_bits(&addr, &pos,
10179eefe2a2SStefan Roese c->lpt_offs_bits);
10189eefe2a2SStefan Roese }
1019*0195a7bbSHeiko Schocher err = check_lpt_crc(c, buf, c->nnode_sz);
10209eefe2a2SStefan Roese return err;
10219eefe2a2SStefan Roese }
10229eefe2a2SStefan Roese
10239eefe2a2SStefan Roese /**
10249eefe2a2SStefan Roese * unpack_ltab - unpack the LPT's own lprops table.
10259eefe2a2SStefan Roese * @c: UBIFS file-system description object
10269eefe2a2SStefan Roese * @buf: buffer from which to unpack
10279eefe2a2SStefan Roese *
10289eefe2a2SStefan Roese * This function returns %0 on success and a negative error code on failure.
10299eefe2a2SStefan Roese */
unpack_ltab(const struct ubifs_info * c,void * buf)10309eefe2a2SStefan Roese static int unpack_ltab(const struct ubifs_info *c, void *buf)
10319eefe2a2SStefan Roese {
10329eefe2a2SStefan Roese uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
10339eefe2a2SStefan Roese int i, pos = 0, err;
10349eefe2a2SStefan Roese
1035*0195a7bbSHeiko Schocher err = check_lpt_type(c, &addr, &pos, UBIFS_LPT_LTAB);
10369eefe2a2SStefan Roese if (err)
10379eefe2a2SStefan Roese return err;
10389eefe2a2SStefan Roese for (i = 0; i < c->lpt_lebs; i++) {
10399eefe2a2SStefan Roese int free = ubifs_unpack_bits(&addr, &pos, c->lpt_spc_bits);
10409eefe2a2SStefan Roese int dirty = ubifs_unpack_bits(&addr, &pos, c->lpt_spc_bits);
10419eefe2a2SStefan Roese
10429eefe2a2SStefan Roese if (free < 0 || free > c->leb_size || dirty < 0 ||
10439eefe2a2SStefan Roese dirty > c->leb_size || free + dirty > c->leb_size)
10449eefe2a2SStefan Roese return -EINVAL;
10459eefe2a2SStefan Roese
10469eefe2a2SStefan Roese c->ltab[i].free = free;
10479eefe2a2SStefan Roese c->ltab[i].dirty = dirty;
10489eefe2a2SStefan Roese c->ltab[i].tgc = 0;
10499eefe2a2SStefan Roese c->ltab[i].cmt = 0;
10509eefe2a2SStefan Roese }
1051*0195a7bbSHeiko Schocher err = check_lpt_crc(c, buf, c->ltab_sz);
10529eefe2a2SStefan Roese return err;
10539eefe2a2SStefan Roese }
10549eefe2a2SStefan Roese
1055ff94bc40SHeiko Schocher #ifndef __UBOOT__
1056ff94bc40SHeiko Schocher /**
1057ff94bc40SHeiko Schocher * unpack_lsave - unpack the LPT's save table.
1058ff94bc40SHeiko Schocher * @c: UBIFS file-system description object
1059ff94bc40SHeiko Schocher * @buf: buffer from which to unpack
1060ff94bc40SHeiko Schocher *
1061ff94bc40SHeiko Schocher * This function returns %0 on success and a negative error code on failure.
1062ff94bc40SHeiko Schocher */
unpack_lsave(const struct ubifs_info * c,void * buf)1063ff94bc40SHeiko Schocher static int unpack_lsave(const struct ubifs_info *c, void *buf)
1064ff94bc40SHeiko Schocher {
1065ff94bc40SHeiko Schocher uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
1066ff94bc40SHeiko Schocher int i, pos = 0, err;
1067ff94bc40SHeiko Schocher
1068*0195a7bbSHeiko Schocher err = check_lpt_type(c, &addr, &pos, UBIFS_LPT_LSAVE);
1069ff94bc40SHeiko Schocher if (err)
1070ff94bc40SHeiko Schocher return err;
1071ff94bc40SHeiko Schocher for (i = 0; i < c->lsave_cnt; i++) {
1072ff94bc40SHeiko Schocher int lnum = ubifs_unpack_bits(&addr, &pos, c->lnum_bits);
1073ff94bc40SHeiko Schocher
1074ff94bc40SHeiko Schocher if (lnum < c->main_first || lnum >= c->leb_cnt)
1075ff94bc40SHeiko Schocher return -EINVAL;
1076ff94bc40SHeiko Schocher c->lsave[i] = lnum;
1077ff94bc40SHeiko Schocher }
1078*0195a7bbSHeiko Schocher err = check_lpt_crc(c, buf, c->lsave_sz);
1079ff94bc40SHeiko Schocher return err;
1080ff94bc40SHeiko Schocher }
1081ff94bc40SHeiko Schocher #endif
1082ff94bc40SHeiko Schocher
10839eefe2a2SStefan Roese /**
10849eefe2a2SStefan Roese * validate_nnode - validate a nnode.
10859eefe2a2SStefan Roese * @c: UBIFS file-system description object
10869eefe2a2SStefan Roese * @nnode: nnode to validate
10879eefe2a2SStefan Roese * @parent: parent nnode (or NULL for the root nnode)
10889eefe2a2SStefan Roese * @iip: index in parent
10899eefe2a2SStefan Roese *
10909eefe2a2SStefan Roese * This function returns %0 on success and a negative error code on failure.
10919eefe2a2SStefan Roese */
validate_nnode(const struct ubifs_info * c,struct ubifs_nnode * nnode,struct ubifs_nnode * parent,int iip)10929eefe2a2SStefan Roese static int validate_nnode(const struct ubifs_info *c, struct ubifs_nnode *nnode,
10939eefe2a2SStefan Roese struct ubifs_nnode *parent, int iip)
10949eefe2a2SStefan Roese {
10959eefe2a2SStefan Roese int i, lvl, max_offs;
10969eefe2a2SStefan Roese
10979eefe2a2SStefan Roese if (c->big_lpt) {
10989eefe2a2SStefan Roese int num = calc_nnode_num_from_parent(c, parent, iip);
10999eefe2a2SStefan Roese
11009eefe2a2SStefan Roese if (nnode->num != num)
11019eefe2a2SStefan Roese return -EINVAL;
11029eefe2a2SStefan Roese }
11039eefe2a2SStefan Roese lvl = parent ? parent->level - 1 : c->lpt_hght;
11049eefe2a2SStefan Roese if (lvl < 1)
11059eefe2a2SStefan Roese return -EINVAL;
11069eefe2a2SStefan Roese if (lvl == 1)
11079eefe2a2SStefan Roese max_offs = c->leb_size - c->pnode_sz;
11089eefe2a2SStefan Roese else
11099eefe2a2SStefan Roese max_offs = c->leb_size - c->nnode_sz;
11109eefe2a2SStefan Roese for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
11119eefe2a2SStefan Roese int lnum = nnode->nbranch[i].lnum;
11129eefe2a2SStefan Roese int offs = nnode->nbranch[i].offs;
11139eefe2a2SStefan Roese
11149eefe2a2SStefan Roese if (lnum == 0) {
11159eefe2a2SStefan Roese if (offs != 0)
11169eefe2a2SStefan Roese return -EINVAL;
11179eefe2a2SStefan Roese continue;
11189eefe2a2SStefan Roese }
11199eefe2a2SStefan Roese if (lnum < c->lpt_first || lnum > c->lpt_last)
11209eefe2a2SStefan Roese return -EINVAL;
11219eefe2a2SStefan Roese if (offs < 0 || offs > max_offs)
11229eefe2a2SStefan Roese return -EINVAL;
11239eefe2a2SStefan Roese }
11249eefe2a2SStefan Roese return 0;
11259eefe2a2SStefan Roese }
11269eefe2a2SStefan Roese
11279eefe2a2SStefan Roese /**
11289eefe2a2SStefan Roese * validate_pnode - validate a pnode.
11299eefe2a2SStefan Roese * @c: UBIFS file-system description object
11309eefe2a2SStefan Roese * @pnode: pnode to validate
11319eefe2a2SStefan Roese * @parent: parent nnode
11329eefe2a2SStefan Roese * @iip: index in parent
11339eefe2a2SStefan Roese *
11349eefe2a2SStefan Roese * This function returns %0 on success and a negative error code on failure.
11359eefe2a2SStefan Roese */
validate_pnode(const struct ubifs_info * c,struct ubifs_pnode * pnode,struct ubifs_nnode * parent,int iip)11369eefe2a2SStefan Roese static int validate_pnode(const struct ubifs_info *c, struct ubifs_pnode *pnode,
11379eefe2a2SStefan Roese struct ubifs_nnode *parent, int iip)
11389eefe2a2SStefan Roese {
11399eefe2a2SStefan Roese int i;
11409eefe2a2SStefan Roese
11419eefe2a2SStefan Roese if (c->big_lpt) {
11429eefe2a2SStefan Roese int num = calc_pnode_num_from_parent(c, parent, iip);
11439eefe2a2SStefan Roese
11449eefe2a2SStefan Roese if (pnode->num != num)
11459eefe2a2SStefan Roese return -EINVAL;
11469eefe2a2SStefan Roese }
11479eefe2a2SStefan Roese for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
11489eefe2a2SStefan Roese int free = pnode->lprops[i].free;
11499eefe2a2SStefan Roese int dirty = pnode->lprops[i].dirty;
11509eefe2a2SStefan Roese
11519eefe2a2SStefan Roese if (free < 0 || free > c->leb_size || free % c->min_io_size ||
11529eefe2a2SStefan Roese (free & 7))
11539eefe2a2SStefan Roese return -EINVAL;
11549eefe2a2SStefan Roese if (dirty < 0 || dirty > c->leb_size || (dirty & 7))
11559eefe2a2SStefan Roese return -EINVAL;
11569eefe2a2SStefan Roese if (dirty + free > c->leb_size)
11579eefe2a2SStefan Roese return -EINVAL;
11589eefe2a2SStefan Roese }
11599eefe2a2SStefan Roese return 0;
11609eefe2a2SStefan Roese }
11619eefe2a2SStefan Roese
11629eefe2a2SStefan Roese /**
11639eefe2a2SStefan Roese * set_pnode_lnum - set LEB numbers on a pnode.
11649eefe2a2SStefan Roese * @c: UBIFS file-system description object
11659eefe2a2SStefan Roese * @pnode: pnode to update
11669eefe2a2SStefan Roese *
11679eefe2a2SStefan Roese * This function calculates the LEB numbers for the LEB properties it contains
11689eefe2a2SStefan Roese * based on the pnode number.
11699eefe2a2SStefan Roese */
set_pnode_lnum(const struct ubifs_info * c,struct ubifs_pnode * pnode)11709eefe2a2SStefan Roese static void set_pnode_lnum(const struct ubifs_info *c,
11719eefe2a2SStefan Roese struct ubifs_pnode *pnode)
11729eefe2a2SStefan Roese {
11739eefe2a2SStefan Roese int i, lnum;
11749eefe2a2SStefan Roese
11759eefe2a2SStefan Roese lnum = (pnode->num << UBIFS_LPT_FANOUT_SHIFT) + c->main_first;
11769eefe2a2SStefan Roese for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
11779eefe2a2SStefan Roese if (lnum >= c->leb_cnt)
11789eefe2a2SStefan Roese return;
11799eefe2a2SStefan Roese pnode->lprops[i].lnum = lnum++;
11809eefe2a2SStefan Roese }
11819eefe2a2SStefan Roese }
11829eefe2a2SStefan Roese
11839eefe2a2SStefan Roese /**
11849eefe2a2SStefan Roese * ubifs_read_nnode - read a nnode from flash and link it to the tree in memory.
11859eefe2a2SStefan Roese * @c: UBIFS file-system description object
11869eefe2a2SStefan Roese * @parent: parent nnode (or NULL for the root)
11879eefe2a2SStefan Roese * @iip: index in parent
11889eefe2a2SStefan Roese *
11899eefe2a2SStefan Roese * This function returns %0 on success and a negative error code on failure.
11909eefe2a2SStefan Roese */
ubifs_read_nnode(struct ubifs_info * c,struct ubifs_nnode * parent,int iip)11919eefe2a2SStefan Roese int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
11929eefe2a2SStefan Roese {
11939eefe2a2SStefan Roese struct ubifs_nbranch *branch = NULL;
11949eefe2a2SStefan Roese struct ubifs_nnode *nnode = NULL;
11959eefe2a2SStefan Roese void *buf = c->lpt_nod_buf;
11969eefe2a2SStefan Roese int err, lnum, offs;
11979eefe2a2SStefan Roese
11989eefe2a2SStefan Roese if (parent) {
11999eefe2a2SStefan Roese branch = &parent->nbranch[iip];
12009eefe2a2SStefan Roese lnum = branch->lnum;
12019eefe2a2SStefan Roese offs = branch->offs;
12029eefe2a2SStefan Roese } else {
12039eefe2a2SStefan Roese lnum = c->lpt_lnum;
12049eefe2a2SStefan Roese offs = c->lpt_offs;
12059eefe2a2SStefan Roese }
12069eefe2a2SStefan Roese nnode = kzalloc(sizeof(struct ubifs_nnode), GFP_NOFS);
12079eefe2a2SStefan Roese if (!nnode) {
12089eefe2a2SStefan Roese err = -ENOMEM;
12099eefe2a2SStefan Roese goto out;
12109eefe2a2SStefan Roese }
12119eefe2a2SStefan Roese if (lnum == 0) {
12129eefe2a2SStefan Roese /*
12139eefe2a2SStefan Roese * This nnode was not written which just means that the LEB
12149eefe2a2SStefan Roese * properties in the subtree below it describe empty LEBs. We
12159eefe2a2SStefan Roese * make the nnode as though we had read it, which in fact means
12169eefe2a2SStefan Roese * doing almost nothing.
12179eefe2a2SStefan Roese */
12189eefe2a2SStefan Roese if (c->big_lpt)
12199eefe2a2SStefan Roese nnode->num = calc_nnode_num_from_parent(c, parent, iip);
12209eefe2a2SStefan Roese } else {
1221ff94bc40SHeiko Schocher err = ubifs_leb_read(c, lnum, buf, offs, c->nnode_sz, 1);
12229eefe2a2SStefan Roese if (err)
12239eefe2a2SStefan Roese goto out;
12249eefe2a2SStefan Roese err = ubifs_unpack_nnode(c, buf, nnode);
12259eefe2a2SStefan Roese if (err)
12269eefe2a2SStefan Roese goto out;
12279eefe2a2SStefan Roese }
12289eefe2a2SStefan Roese err = validate_nnode(c, nnode, parent, iip);
12299eefe2a2SStefan Roese if (err)
12309eefe2a2SStefan Roese goto out;
12319eefe2a2SStefan Roese if (!c->big_lpt)
12329eefe2a2SStefan Roese nnode->num = calc_nnode_num_from_parent(c, parent, iip);
12339eefe2a2SStefan Roese if (parent) {
12349eefe2a2SStefan Roese branch->nnode = nnode;
12359eefe2a2SStefan Roese nnode->level = parent->level - 1;
12369eefe2a2SStefan Roese } else {
12379eefe2a2SStefan Roese c->nroot = nnode;
12389eefe2a2SStefan Roese nnode->level = c->lpt_hght;
12399eefe2a2SStefan Roese }
12409eefe2a2SStefan Roese nnode->parent = parent;
12419eefe2a2SStefan Roese nnode->iip = iip;
12429eefe2a2SStefan Roese return 0;
12439eefe2a2SStefan Roese
12449eefe2a2SStefan Roese out:
1245*0195a7bbSHeiko Schocher ubifs_err(c, "error %d reading nnode at %d:%d", err, lnum, offs);
1246ff94bc40SHeiko Schocher dump_stack();
12479eefe2a2SStefan Roese kfree(nnode);
12489eefe2a2SStefan Roese return err;
12499eefe2a2SStefan Roese }
12509eefe2a2SStefan Roese
12519eefe2a2SStefan Roese /**
12529eefe2a2SStefan Roese * read_pnode - read a pnode from flash and link it to the tree in memory.
12539eefe2a2SStefan Roese * @c: UBIFS file-system description object
12549eefe2a2SStefan Roese * @parent: parent nnode
12559eefe2a2SStefan Roese * @iip: index in parent
12569eefe2a2SStefan Roese *
12579eefe2a2SStefan Roese * This function returns %0 on success and a negative error code on failure.
12589eefe2a2SStefan Roese */
read_pnode(struct ubifs_info * c,struct ubifs_nnode * parent,int iip)12599eefe2a2SStefan Roese static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
12609eefe2a2SStefan Roese {
12619eefe2a2SStefan Roese struct ubifs_nbranch *branch;
12629eefe2a2SStefan Roese struct ubifs_pnode *pnode = NULL;
12639eefe2a2SStefan Roese void *buf = c->lpt_nod_buf;
12649eefe2a2SStefan Roese int err, lnum, offs;
12659eefe2a2SStefan Roese
12669eefe2a2SStefan Roese branch = &parent->nbranch[iip];
12679eefe2a2SStefan Roese lnum = branch->lnum;
12689eefe2a2SStefan Roese offs = branch->offs;
12699eefe2a2SStefan Roese pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_NOFS);
1270ff94bc40SHeiko Schocher if (!pnode)
1271ff94bc40SHeiko Schocher return -ENOMEM;
1272ff94bc40SHeiko Schocher
12739eefe2a2SStefan Roese if (lnum == 0) {
12749eefe2a2SStefan Roese /*
12759eefe2a2SStefan Roese * This pnode was not written which just means that the LEB
12769eefe2a2SStefan Roese * properties in it describe empty LEBs. We make the pnode as
12779eefe2a2SStefan Roese * though we had read it.
12789eefe2a2SStefan Roese */
12799eefe2a2SStefan Roese int i;
12809eefe2a2SStefan Roese
12819eefe2a2SStefan Roese if (c->big_lpt)
12829eefe2a2SStefan Roese pnode->num = calc_pnode_num_from_parent(c, parent, iip);
12839eefe2a2SStefan Roese for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
12849eefe2a2SStefan Roese struct ubifs_lprops * const lprops = &pnode->lprops[i];
12859eefe2a2SStefan Roese
12869eefe2a2SStefan Roese lprops->free = c->leb_size;
12879eefe2a2SStefan Roese lprops->flags = ubifs_categorize_lprops(c, lprops);
12889eefe2a2SStefan Roese }
12899eefe2a2SStefan Roese } else {
1290ff94bc40SHeiko Schocher err = ubifs_leb_read(c, lnum, buf, offs, c->pnode_sz, 1);
12919eefe2a2SStefan Roese if (err)
12929eefe2a2SStefan Roese goto out;
12939eefe2a2SStefan Roese err = unpack_pnode(c, buf, pnode);
12949eefe2a2SStefan Roese if (err)
12959eefe2a2SStefan Roese goto out;
12969eefe2a2SStefan Roese }
12979eefe2a2SStefan Roese err = validate_pnode(c, pnode, parent, iip);
12989eefe2a2SStefan Roese if (err)
12999eefe2a2SStefan Roese goto out;
13009eefe2a2SStefan Roese if (!c->big_lpt)
13019eefe2a2SStefan Roese pnode->num = calc_pnode_num_from_parent(c, parent, iip);
13029eefe2a2SStefan Roese branch->pnode = pnode;
13039eefe2a2SStefan Roese pnode->parent = parent;
13049eefe2a2SStefan Roese pnode->iip = iip;
13059eefe2a2SStefan Roese set_pnode_lnum(c, pnode);
13069eefe2a2SStefan Roese c->pnodes_have += 1;
13079eefe2a2SStefan Roese return 0;
13089eefe2a2SStefan Roese
13099eefe2a2SStefan Roese out:
1310*0195a7bbSHeiko Schocher ubifs_err(c, "error %d reading pnode at %d:%d", err, lnum, offs);
1311ff94bc40SHeiko Schocher ubifs_dump_pnode(c, pnode, parent, iip);
1312ff94bc40SHeiko Schocher dump_stack();
1313*0195a7bbSHeiko Schocher ubifs_err(c, "calc num: %d", calc_pnode_num_from_parent(c, parent, iip));
13149eefe2a2SStefan Roese kfree(pnode);
13159eefe2a2SStefan Roese return err;
13169eefe2a2SStefan Roese }
13179eefe2a2SStefan Roese
13189eefe2a2SStefan Roese /**
13199eefe2a2SStefan Roese * read_ltab - read LPT's own lprops table.
13209eefe2a2SStefan Roese * @c: UBIFS file-system description object
13219eefe2a2SStefan Roese *
13229eefe2a2SStefan Roese * This function returns %0 on success and a negative error code on failure.
13239eefe2a2SStefan Roese */
read_ltab(struct ubifs_info * c)13249eefe2a2SStefan Roese static int read_ltab(struct ubifs_info *c)
13259eefe2a2SStefan Roese {
13269eefe2a2SStefan Roese int err;
13279eefe2a2SStefan Roese void *buf;
13289eefe2a2SStefan Roese
13299eefe2a2SStefan Roese buf = vmalloc(c->ltab_sz);
13309eefe2a2SStefan Roese if (!buf)
13319eefe2a2SStefan Roese return -ENOMEM;
1332ff94bc40SHeiko Schocher err = ubifs_leb_read(c, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz, 1);
13339eefe2a2SStefan Roese if (err)
13349eefe2a2SStefan Roese goto out;
13359eefe2a2SStefan Roese err = unpack_ltab(c, buf);
13369eefe2a2SStefan Roese out:
13379eefe2a2SStefan Roese vfree(buf);
13389eefe2a2SStefan Roese return err;
13399eefe2a2SStefan Roese }
13409eefe2a2SStefan Roese
1341ff94bc40SHeiko Schocher #ifndef __UBOOT__
1342ff94bc40SHeiko Schocher /**
1343ff94bc40SHeiko Schocher * read_lsave - read LPT's save table.
1344ff94bc40SHeiko Schocher * @c: UBIFS file-system description object
1345ff94bc40SHeiko Schocher *
1346ff94bc40SHeiko Schocher * This function returns %0 on success and a negative error code on failure.
1347ff94bc40SHeiko Schocher */
read_lsave(struct ubifs_info * c)1348ff94bc40SHeiko Schocher static int read_lsave(struct ubifs_info *c)
1349ff94bc40SHeiko Schocher {
1350ff94bc40SHeiko Schocher int err, i;
1351ff94bc40SHeiko Schocher void *buf;
1352ff94bc40SHeiko Schocher
1353ff94bc40SHeiko Schocher buf = vmalloc(c->lsave_sz);
1354ff94bc40SHeiko Schocher if (!buf)
1355ff94bc40SHeiko Schocher return -ENOMEM;
1356ff94bc40SHeiko Schocher err = ubifs_leb_read(c, c->lsave_lnum, buf, c->lsave_offs,
1357ff94bc40SHeiko Schocher c->lsave_sz, 1);
1358ff94bc40SHeiko Schocher if (err)
1359ff94bc40SHeiko Schocher goto out;
1360ff94bc40SHeiko Schocher err = unpack_lsave(c, buf);
1361ff94bc40SHeiko Schocher if (err)
1362ff94bc40SHeiko Schocher goto out;
1363ff94bc40SHeiko Schocher for (i = 0; i < c->lsave_cnt; i++) {
1364ff94bc40SHeiko Schocher int lnum = c->lsave[i];
1365ff94bc40SHeiko Schocher struct ubifs_lprops *lprops;
1366ff94bc40SHeiko Schocher
1367ff94bc40SHeiko Schocher /*
1368ff94bc40SHeiko Schocher * Due to automatic resizing, the values in the lsave table
1369ff94bc40SHeiko Schocher * could be beyond the volume size - just ignore them.
1370ff94bc40SHeiko Schocher */
1371ff94bc40SHeiko Schocher if (lnum >= c->leb_cnt)
1372ff94bc40SHeiko Schocher continue;
1373ff94bc40SHeiko Schocher lprops = ubifs_lpt_lookup(c, lnum);
1374ff94bc40SHeiko Schocher if (IS_ERR(lprops)) {
1375ff94bc40SHeiko Schocher err = PTR_ERR(lprops);
1376ff94bc40SHeiko Schocher goto out;
1377ff94bc40SHeiko Schocher }
1378ff94bc40SHeiko Schocher }
1379ff94bc40SHeiko Schocher out:
1380ff94bc40SHeiko Schocher vfree(buf);
1381ff94bc40SHeiko Schocher return err;
1382ff94bc40SHeiko Schocher }
1383ff94bc40SHeiko Schocher #endif
1384ff94bc40SHeiko Schocher
13859eefe2a2SStefan Roese /**
13869eefe2a2SStefan Roese * ubifs_get_nnode - get a nnode.
13879eefe2a2SStefan Roese * @c: UBIFS file-system description object
13889eefe2a2SStefan Roese * @parent: parent nnode (or NULL for the root)
13899eefe2a2SStefan Roese * @iip: index in parent
13909eefe2a2SStefan Roese *
13919eefe2a2SStefan Roese * This function returns a pointer to the nnode on success or a negative error
13929eefe2a2SStefan Roese * code on failure.
13939eefe2a2SStefan Roese */
ubifs_get_nnode(struct ubifs_info * c,struct ubifs_nnode * parent,int iip)13949eefe2a2SStefan Roese struct ubifs_nnode *ubifs_get_nnode(struct ubifs_info *c,
13959eefe2a2SStefan Roese struct ubifs_nnode *parent, int iip)
13969eefe2a2SStefan Roese {
13979eefe2a2SStefan Roese struct ubifs_nbranch *branch;
13989eefe2a2SStefan Roese struct ubifs_nnode *nnode;
13999eefe2a2SStefan Roese int err;
14009eefe2a2SStefan Roese
14019eefe2a2SStefan Roese branch = &parent->nbranch[iip];
14029eefe2a2SStefan Roese nnode = branch->nnode;
14039eefe2a2SStefan Roese if (nnode)
14049eefe2a2SStefan Roese return nnode;
14059eefe2a2SStefan Roese err = ubifs_read_nnode(c, parent, iip);
14069eefe2a2SStefan Roese if (err)
14079eefe2a2SStefan Roese return ERR_PTR(err);
14089eefe2a2SStefan Roese return branch->nnode;
14099eefe2a2SStefan Roese }
14109eefe2a2SStefan Roese
14119eefe2a2SStefan Roese /**
14129eefe2a2SStefan Roese * ubifs_get_pnode - get a pnode.
14139eefe2a2SStefan Roese * @c: UBIFS file-system description object
14149eefe2a2SStefan Roese * @parent: parent nnode
14159eefe2a2SStefan Roese * @iip: index in parent
14169eefe2a2SStefan Roese *
14179eefe2a2SStefan Roese * This function returns a pointer to the pnode on success or a negative error
14189eefe2a2SStefan Roese * code on failure.
14199eefe2a2SStefan Roese */
ubifs_get_pnode(struct ubifs_info * c,struct ubifs_nnode * parent,int iip)14209eefe2a2SStefan Roese struct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c,
14219eefe2a2SStefan Roese struct ubifs_nnode *parent, int iip)
14229eefe2a2SStefan Roese {
14239eefe2a2SStefan Roese struct ubifs_nbranch *branch;
14249eefe2a2SStefan Roese struct ubifs_pnode *pnode;
14259eefe2a2SStefan Roese int err;
14269eefe2a2SStefan Roese
14279eefe2a2SStefan Roese branch = &parent->nbranch[iip];
14289eefe2a2SStefan Roese pnode = branch->pnode;
14299eefe2a2SStefan Roese if (pnode)
14309eefe2a2SStefan Roese return pnode;
14319eefe2a2SStefan Roese err = read_pnode(c, parent, iip);
14329eefe2a2SStefan Roese if (err)
14339eefe2a2SStefan Roese return ERR_PTR(err);
14349eefe2a2SStefan Roese update_cats(c, branch->pnode);
14359eefe2a2SStefan Roese return branch->pnode;
14369eefe2a2SStefan Roese }
14379eefe2a2SStefan Roese
14389eefe2a2SStefan Roese /**
14399eefe2a2SStefan Roese * ubifs_lpt_lookup - lookup LEB properties in the LPT.
14409eefe2a2SStefan Roese * @c: UBIFS file-system description object
14419eefe2a2SStefan Roese * @lnum: LEB number to lookup
14429eefe2a2SStefan Roese *
14439eefe2a2SStefan Roese * This function returns a pointer to the LEB properties on success or a
14449eefe2a2SStefan Roese * negative error code on failure.
14459eefe2a2SStefan Roese */
ubifs_lpt_lookup(struct ubifs_info * c,int lnum)14469eefe2a2SStefan Roese struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum)
14479eefe2a2SStefan Roese {
14489eefe2a2SStefan Roese int err, i, h, iip, shft;
14499eefe2a2SStefan Roese struct ubifs_nnode *nnode;
14509eefe2a2SStefan Roese struct ubifs_pnode *pnode;
14519eefe2a2SStefan Roese
14529eefe2a2SStefan Roese if (!c->nroot) {
14539eefe2a2SStefan Roese err = ubifs_read_nnode(c, NULL, 0);
14549eefe2a2SStefan Roese if (err)
14559eefe2a2SStefan Roese return ERR_PTR(err);
14569eefe2a2SStefan Roese }
14579eefe2a2SStefan Roese nnode = c->nroot;
14589eefe2a2SStefan Roese i = lnum - c->main_first;
14599eefe2a2SStefan Roese shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
14609eefe2a2SStefan Roese for (h = 1; h < c->lpt_hght; h++) {
14619eefe2a2SStefan Roese iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
14629eefe2a2SStefan Roese shft -= UBIFS_LPT_FANOUT_SHIFT;
14639eefe2a2SStefan Roese nnode = ubifs_get_nnode(c, nnode, iip);
14649eefe2a2SStefan Roese if (IS_ERR(nnode))
1465ff94bc40SHeiko Schocher return ERR_CAST(nnode);
14669eefe2a2SStefan Roese }
14679eefe2a2SStefan Roese iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
14689eefe2a2SStefan Roese pnode = ubifs_get_pnode(c, nnode, iip);
14699eefe2a2SStefan Roese if (IS_ERR(pnode))
1470ff94bc40SHeiko Schocher return ERR_CAST(pnode);
14719eefe2a2SStefan Roese iip = (i & (UBIFS_LPT_FANOUT - 1));
14729eefe2a2SStefan Roese dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum,
14739eefe2a2SStefan Roese pnode->lprops[iip].free, pnode->lprops[iip].dirty,
14749eefe2a2SStefan Roese pnode->lprops[iip].flags);
14759eefe2a2SStefan Roese return &pnode->lprops[iip];
14769eefe2a2SStefan Roese }
14779eefe2a2SStefan Roese
14789eefe2a2SStefan Roese /**
14799eefe2a2SStefan Roese * dirty_cow_nnode - ensure a nnode is not being committed.
14809eefe2a2SStefan Roese * @c: UBIFS file-system description object
14819eefe2a2SStefan Roese * @nnode: nnode to check
14829eefe2a2SStefan Roese *
14839eefe2a2SStefan Roese * Returns dirtied nnode on success or negative error code on failure.
14849eefe2a2SStefan Roese */
dirty_cow_nnode(struct ubifs_info * c,struct ubifs_nnode * nnode)14859eefe2a2SStefan Roese static struct ubifs_nnode *dirty_cow_nnode(struct ubifs_info *c,
14869eefe2a2SStefan Roese struct ubifs_nnode *nnode)
14879eefe2a2SStefan Roese {
14889eefe2a2SStefan Roese struct ubifs_nnode *n;
14899eefe2a2SStefan Roese int i;
14909eefe2a2SStefan Roese
14919eefe2a2SStefan Roese if (!test_bit(COW_CNODE, &nnode->flags)) {
14929eefe2a2SStefan Roese /* nnode is not being committed */
14939eefe2a2SStefan Roese if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) {
14949eefe2a2SStefan Roese c->dirty_nn_cnt += 1;
14959eefe2a2SStefan Roese ubifs_add_nnode_dirt(c, nnode);
14969eefe2a2SStefan Roese }
14979eefe2a2SStefan Roese return nnode;
14989eefe2a2SStefan Roese }
14999eefe2a2SStefan Roese
15009eefe2a2SStefan Roese /* nnode is being committed, so copy it */
15019eefe2a2SStefan Roese n = kmalloc(sizeof(struct ubifs_nnode), GFP_NOFS);
15029eefe2a2SStefan Roese if (unlikely(!n))
15039eefe2a2SStefan Roese return ERR_PTR(-ENOMEM);
15049eefe2a2SStefan Roese
15059eefe2a2SStefan Roese memcpy(n, nnode, sizeof(struct ubifs_nnode));
15069eefe2a2SStefan Roese n->cnext = NULL;
15079eefe2a2SStefan Roese __set_bit(DIRTY_CNODE, &n->flags);
15089eefe2a2SStefan Roese __clear_bit(COW_CNODE, &n->flags);
15099eefe2a2SStefan Roese
15109eefe2a2SStefan Roese /* The children now have new parent */
15119eefe2a2SStefan Roese for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
15129eefe2a2SStefan Roese struct ubifs_nbranch *branch = &n->nbranch[i];
15139eefe2a2SStefan Roese
15149eefe2a2SStefan Roese if (branch->cnode)
15159eefe2a2SStefan Roese branch->cnode->parent = n;
15169eefe2a2SStefan Roese }
15179eefe2a2SStefan Roese
15189eefe2a2SStefan Roese ubifs_assert(!test_bit(OBSOLETE_CNODE, &nnode->flags));
15199eefe2a2SStefan Roese __set_bit(OBSOLETE_CNODE, &nnode->flags);
15209eefe2a2SStefan Roese
15219eefe2a2SStefan Roese c->dirty_nn_cnt += 1;
15229eefe2a2SStefan Roese ubifs_add_nnode_dirt(c, nnode);
15239eefe2a2SStefan Roese if (nnode->parent)
15249eefe2a2SStefan Roese nnode->parent->nbranch[n->iip].nnode = n;
15259eefe2a2SStefan Roese else
15269eefe2a2SStefan Roese c->nroot = n;
15279eefe2a2SStefan Roese return n;
15289eefe2a2SStefan Roese }
15299eefe2a2SStefan Roese
15309eefe2a2SStefan Roese /**
15319eefe2a2SStefan Roese * dirty_cow_pnode - ensure a pnode is not being committed.
15329eefe2a2SStefan Roese * @c: UBIFS file-system description object
15339eefe2a2SStefan Roese * @pnode: pnode to check
15349eefe2a2SStefan Roese *
15359eefe2a2SStefan Roese * Returns dirtied pnode on success or negative error code on failure.
15369eefe2a2SStefan Roese */
dirty_cow_pnode(struct ubifs_info * c,struct ubifs_pnode * pnode)15379eefe2a2SStefan Roese static struct ubifs_pnode *dirty_cow_pnode(struct ubifs_info *c,
15389eefe2a2SStefan Roese struct ubifs_pnode *pnode)
15399eefe2a2SStefan Roese {
15409eefe2a2SStefan Roese struct ubifs_pnode *p;
15419eefe2a2SStefan Roese
15429eefe2a2SStefan Roese if (!test_bit(COW_CNODE, &pnode->flags)) {
15439eefe2a2SStefan Roese /* pnode is not being committed */
15449eefe2a2SStefan Roese if (!test_and_set_bit(DIRTY_CNODE, &pnode->flags)) {
15459eefe2a2SStefan Roese c->dirty_pn_cnt += 1;
15469eefe2a2SStefan Roese add_pnode_dirt(c, pnode);
15479eefe2a2SStefan Roese }
15489eefe2a2SStefan Roese return pnode;
15499eefe2a2SStefan Roese }
15509eefe2a2SStefan Roese
15519eefe2a2SStefan Roese /* pnode is being committed, so copy it */
15529eefe2a2SStefan Roese p = kmalloc(sizeof(struct ubifs_pnode), GFP_NOFS);
15539eefe2a2SStefan Roese if (unlikely(!p))
15549eefe2a2SStefan Roese return ERR_PTR(-ENOMEM);
15559eefe2a2SStefan Roese
15569eefe2a2SStefan Roese memcpy(p, pnode, sizeof(struct ubifs_pnode));
15579eefe2a2SStefan Roese p->cnext = NULL;
15589eefe2a2SStefan Roese __set_bit(DIRTY_CNODE, &p->flags);
15599eefe2a2SStefan Roese __clear_bit(COW_CNODE, &p->flags);
15609eefe2a2SStefan Roese replace_cats(c, pnode, p);
15619eefe2a2SStefan Roese
15629eefe2a2SStefan Roese ubifs_assert(!test_bit(OBSOLETE_CNODE, &pnode->flags));
15639eefe2a2SStefan Roese __set_bit(OBSOLETE_CNODE, &pnode->flags);
15649eefe2a2SStefan Roese
15659eefe2a2SStefan Roese c->dirty_pn_cnt += 1;
15669eefe2a2SStefan Roese add_pnode_dirt(c, pnode);
15679eefe2a2SStefan Roese pnode->parent->nbranch[p->iip].pnode = p;
15689eefe2a2SStefan Roese return p;
15699eefe2a2SStefan Roese }
15709eefe2a2SStefan Roese
15719eefe2a2SStefan Roese /**
15729eefe2a2SStefan Roese * ubifs_lpt_lookup_dirty - lookup LEB properties in the LPT.
15739eefe2a2SStefan Roese * @c: UBIFS file-system description object
15749eefe2a2SStefan Roese * @lnum: LEB number to lookup
15759eefe2a2SStefan Roese *
15769eefe2a2SStefan Roese * This function returns a pointer to the LEB properties on success or a
15779eefe2a2SStefan Roese * negative error code on failure.
15789eefe2a2SStefan Roese */
ubifs_lpt_lookup_dirty(struct ubifs_info * c,int lnum)15799eefe2a2SStefan Roese struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum)
15809eefe2a2SStefan Roese {
15819eefe2a2SStefan Roese int err, i, h, iip, shft;
15829eefe2a2SStefan Roese struct ubifs_nnode *nnode;
15839eefe2a2SStefan Roese struct ubifs_pnode *pnode;
15849eefe2a2SStefan Roese
15859eefe2a2SStefan Roese if (!c->nroot) {
15869eefe2a2SStefan Roese err = ubifs_read_nnode(c, NULL, 0);
15879eefe2a2SStefan Roese if (err)
15889eefe2a2SStefan Roese return ERR_PTR(err);
15899eefe2a2SStefan Roese }
15909eefe2a2SStefan Roese nnode = c->nroot;
15919eefe2a2SStefan Roese nnode = dirty_cow_nnode(c, nnode);
15929eefe2a2SStefan Roese if (IS_ERR(nnode))
1593ff94bc40SHeiko Schocher return ERR_CAST(nnode);
15949eefe2a2SStefan Roese i = lnum - c->main_first;
15959eefe2a2SStefan Roese shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
15969eefe2a2SStefan Roese for (h = 1; h < c->lpt_hght; h++) {
15979eefe2a2SStefan Roese iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
15989eefe2a2SStefan Roese shft -= UBIFS_LPT_FANOUT_SHIFT;
15999eefe2a2SStefan Roese nnode = ubifs_get_nnode(c, nnode, iip);
16009eefe2a2SStefan Roese if (IS_ERR(nnode))
1601ff94bc40SHeiko Schocher return ERR_CAST(nnode);
16029eefe2a2SStefan Roese nnode = dirty_cow_nnode(c, nnode);
16039eefe2a2SStefan Roese if (IS_ERR(nnode))
1604ff94bc40SHeiko Schocher return ERR_CAST(nnode);
16059eefe2a2SStefan Roese }
16069eefe2a2SStefan Roese iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
16079eefe2a2SStefan Roese pnode = ubifs_get_pnode(c, nnode, iip);
16089eefe2a2SStefan Roese if (IS_ERR(pnode))
1609ff94bc40SHeiko Schocher return ERR_CAST(pnode);
16109eefe2a2SStefan Roese pnode = dirty_cow_pnode(c, pnode);
16119eefe2a2SStefan Roese if (IS_ERR(pnode))
1612ff94bc40SHeiko Schocher return ERR_CAST(pnode);
16139eefe2a2SStefan Roese iip = (i & (UBIFS_LPT_FANOUT - 1));
16149eefe2a2SStefan Roese dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum,
16159eefe2a2SStefan Roese pnode->lprops[iip].free, pnode->lprops[iip].dirty,
16169eefe2a2SStefan Roese pnode->lprops[iip].flags);
16179eefe2a2SStefan Roese ubifs_assert(test_bit(DIRTY_CNODE, &pnode->flags));
16189eefe2a2SStefan Roese return &pnode->lprops[iip];
16199eefe2a2SStefan Roese }
16209eefe2a2SStefan Roese
16219eefe2a2SStefan Roese /**
16229eefe2a2SStefan Roese * lpt_init_rd - initialize the LPT for reading.
16239eefe2a2SStefan Roese * @c: UBIFS file-system description object
16249eefe2a2SStefan Roese *
16259eefe2a2SStefan Roese * This function returns %0 on success and a negative error code on failure.
16269eefe2a2SStefan Roese */
lpt_init_rd(struct ubifs_info * c)16279eefe2a2SStefan Roese static int lpt_init_rd(struct ubifs_info *c)
16289eefe2a2SStefan Roese {
16299eefe2a2SStefan Roese int err, i;
16309eefe2a2SStefan Roese
16319eefe2a2SStefan Roese c->ltab = vmalloc(sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs);
16329eefe2a2SStefan Roese if (!c->ltab)
16339eefe2a2SStefan Roese return -ENOMEM;
16349eefe2a2SStefan Roese
16359eefe2a2SStefan Roese i = max_t(int, c->nnode_sz, c->pnode_sz);
16369eefe2a2SStefan Roese c->lpt_nod_buf = kmalloc(i, GFP_KERNEL);
16379eefe2a2SStefan Roese if (!c->lpt_nod_buf)
16389eefe2a2SStefan Roese return -ENOMEM;
16399eefe2a2SStefan Roese
16409eefe2a2SStefan Roese for (i = 0; i < LPROPS_HEAP_CNT; i++) {
16419eefe2a2SStefan Roese c->lpt_heap[i].arr = kmalloc(sizeof(void *) * LPT_HEAP_SZ,
16429eefe2a2SStefan Roese GFP_KERNEL);
16439eefe2a2SStefan Roese if (!c->lpt_heap[i].arr)
16449eefe2a2SStefan Roese return -ENOMEM;
16459eefe2a2SStefan Roese c->lpt_heap[i].cnt = 0;
16469eefe2a2SStefan Roese c->lpt_heap[i].max_cnt = LPT_HEAP_SZ;
16479eefe2a2SStefan Roese }
16489eefe2a2SStefan Roese
16499eefe2a2SStefan Roese c->dirty_idx.arr = kmalloc(sizeof(void *) * LPT_HEAP_SZ, GFP_KERNEL);
16509eefe2a2SStefan Roese if (!c->dirty_idx.arr)
16519eefe2a2SStefan Roese return -ENOMEM;
16529eefe2a2SStefan Roese c->dirty_idx.cnt = 0;
16539eefe2a2SStefan Roese c->dirty_idx.max_cnt = LPT_HEAP_SZ;
16549eefe2a2SStefan Roese
16559eefe2a2SStefan Roese err = read_ltab(c);
16569eefe2a2SStefan Roese if (err)
16579eefe2a2SStefan Roese return err;
16589eefe2a2SStefan Roese
16599eefe2a2SStefan Roese dbg_lp("space_bits %d", c->space_bits);
16609eefe2a2SStefan Roese dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits);
16619eefe2a2SStefan Roese dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits);
16629eefe2a2SStefan Roese dbg_lp("lpt_spc_bits %d", c->lpt_spc_bits);
16639eefe2a2SStefan Roese dbg_lp("pcnt_bits %d", c->pcnt_bits);
16649eefe2a2SStefan Roese dbg_lp("lnum_bits %d", c->lnum_bits);
16659eefe2a2SStefan Roese dbg_lp("pnode_sz %d", c->pnode_sz);
16669eefe2a2SStefan Roese dbg_lp("nnode_sz %d", c->nnode_sz);
16679eefe2a2SStefan Roese dbg_lp("ltab_sz %d", c->ltab_sz);
16689eefe2a2SStefan Roese dbg_lp("lsave_sz %d", c->lsave_sz);
16699eefe2a2SStefan Roese dbg_lp("lsave_cnt %d", c->lsave_cnt);
16709eefe2a2SStefan Roese dbg_lp("lpt_hght %d", c->lpt_hght);
16719eefe2a2SStefan Roese dbg_lp("big_lpt %d", c->big_lpt);
16729eefe2a2SStefan Roese dbg_lp("LPT root is at %d:%d", c->lpt_lnum, c->lpt_offs);
16739eefe2a2SStefan Roese dbg_lp("LPT head is at %d:%d", c->nhead_lnum, c->nhead_offs);
16749eefe2a2SStefan Roese dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs);
16759eefe2a2SStefan Roese if (c->big_lpt)
16769eefe2a2SStefan Roese dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs);
16779eefe2a2SStefan Roese
16789eefe2a2SStefan Roese return 0;
16799eefe2a2SStefan Roese }
16809eefe2a2SStefan Roese
1681ff94bc40SHeiko Schocher #ifndef __UBOOT__
1682ff94bc40SHeiko Schocher /**
1683ff94bc40SHeiko Schocher * lpt_init_wr - initialize the LPT for writing.
1684ff94bc40SHeiko Schocher * @c: UBIFS file-system description object
1685ff94bc40SHeiko Schocher *
1686ff94bc40SHeiko Schocher * 'lpt_init_rd()' must have been called already.
1687ff94bc40SHeiko Schocher *
1688ff94bc40SHeiko Schocher * This function returns %0 on success and a negative error code on failure.
1689ff94bc40SHeiko Schocher */
lpt_init_wr(struct ubifs_info * c)1690ff94bc40SHeiko Schocher static int lpt_init_wr(struct ubifs_info *c)
1691ff94bc40SHeiko Schocher {
1692ff94bc40SHeiko Schocher int err, i;
1693ff94bc40SHeiko Schocher
1694ff94bc40SHeiko Schocher c->ltab_cmt = vmalloc(sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs);
1695ff94bc40SHeiko Schocher if (!c->ltab_cmt)
1696ff94bc40SHeiko Schocher return -ENOMEM;
1697ff94bc40SHeiko Schocher
1698ff94bc40SHeiko Schocher c->lpt_buf = vmalloc(c->leb_size);
1699ff94bc40SHeiko Schocher if (!c->lpt_buf)
1700ff94bc40SHeiko Schocher return -ENOMEM;
1701ff94bc40SHeiko Schocher
1702ff94bc40SHeiko Schocher if (c->big_lpt) {
1703ff94bc40SHeiko Schocher c->lsave = kmalloc(sizeof(int) * c->lsave_cnt, GFP_NOFS);
1704ff94bc40SHeiko Schocher if (!c->lsave)
1705ff94bc40SHeiko Schocher return -ENOMEM;
1706ff94bc40SHeiko Schocher err = read_lsave(c);
1707ff94bc40SHeiko Schocher if (err)
1708ff94bc40SHeiko Schocher return err;
1709ff94bc40SHeiko Schocher }
1710ff94bc40SHeiko Schocher
1711ff94bc40SHeiko Schocher for (i = 0; i < c->lpt_lebs; i++)
1712ff94bc40SHeiko Schocher if (c->ltab[i].free == c->leb_size) {
1713ff94bc40SHeiko Schocher err = ubifs_leb_unmap(c, i + c->lpt_first);
1714ff94bc40SHeiko Schocher if (err)
1715ff94bc40SHeiko Schocher return err;
1716ff94bc40SHeiko Schocher }
1717ff94bc40SHeiko Schocher
1718ff94bc40SHeiko Schocher return 0;
1719ff94bc40SHeiko Schocher }
1720ff94bc40SHeiko Schocher #endif
1721ff94bc40SHeiko Schocher
17229eefe2a2SStefan Roese /**
17239eefe2a2SStefan Roese * ubifs_lpt_init - initialize the LPT.
17249eefe2a2SStefan Roese * @c: UBIFS file-system description object
17259eefe2a2SStefan Roese * @rd: whether to initialize lpt for reading
17269eefe2a2SStefan Roese * @wr: whether to initialize lpt for writing
17279eefe2a2SStefan Roese *
17289eefe2a2SStefan Roese * For mounting 'rw', @rd and @wr are both true. For mounting 'ro', @rd is true
17299eefe2a2SStefan Roese * and @wr is false. For mounting from 'ro' to 'rw', @rd is false and @wr is
17309eefe2a2SStefan Roese * true.
17319eefe2a2SStefan Roese *
17329eefe2a2SStefan Roese * This function returns %0 on success and a negative error code on failure.
17339eefe2a2SStefan Roese */
ubifs_lpt_init(struct ubifs_info * c,int rd,int wr)17349eefe2a2SStefan Roese int ubifs_lpt_init(struct ubifs_info *c, int rd, int wr)
17359eefe2a2SStefan Roese {
17369eefe2a2SStefan Roese int err;
17379eefe2a2SStefan Roese
17389eefe2a2SStefan Roese if (rd) {
17399eefe2a2SStefan Roese err = lpt_init_rd(c);
17409eefe2a2SStefan Roese if (err)
1741ff94bc40SHeiko Schocher goto out_err;
1742ff94bc40SHeiko Schocher }
1743ff94bc40SHeiko Schocher
1744ff94bc40SHeiko Schocher #ifndef __UBOOT__
1745ff94bc40SHeiko Schocher if (wr) {
1746ff94bc40SHeiko Schocher err = lpt_init_wr(c);
1747ff94bc40SHeiko Schocher if (err)
1748ff94bc40SHeiko Schocher goto out_err;
1749ff94bc40SHeiko Schocher }
1750ff94bc40SHeiko Schocher #endif
1751ff94bc40SHeiko Schocher
1752ff94bc40SHeiko Schocher return 0;
1753ff94bc40SHeiko Schocher
1754ff94bc40SHeiko Schocher out_err:
1755ff94bc40SHeiko Schocher #ifndef __UBOOT__
1756ff94bc40SHeiko Schocher if (wr)
1757ff94bc40SHeiko Schocher ubifs_lpt_free(c, 1);
1758ff94bc40SHeiko Schocher #endif
1759ff94bc40SHeiko Schocher if (rd)
1760ff94bc40SHeiko Schocher ubifs_lpt_free(c, 0);
17619eefe2a2SStefan Roese return err;
17629eefe2a2SStefan Roese }
17639eefe2a2SStefan Roese
1764ff94bc40SHeiko Schocher /**
1765ff94bc40SHeiko Schocher * struct lpt_scan_node - somewhere to put nodes while we scan LPT.
1766ff94bc40SHeiko Schocher * @nnode: where to keep a nnode
1767ff94bc40SHeiko Schocher * @pnode: where to keep a pnode
1768ff94bc40SHeiko Schocher * @cnode: where to keep a cnode
1769ff94bc40SHeiko Schocher * @in_tree: is the node in the tree in memory
1770ff94bc40SHeiko Schocher * @ptr.nnode: pointer to the nnode (if it is an nnode) which may be here or in
1771ff94bc40SHeiko Schocher * the tree
1772ff94bc40SHeiko Schocher * @ptr.pnode: ditto for pnode
1773ff94bc40SHeiko Schocher * @ptr.cnode: ditto for cnode
1774ff94bc40SHeiko Schocher */
1775ff94bc40SHeiko Schocher struct lpt_scan_node {
1776ff94bc40SHeiko Schocher union {
1777ff94bc40SHeiko Schocher struct ubifs_nnode nnode;
1778ff94bc40SHeiko Schocher struct ubifs_pnode pnode;
1779ff94bc40SHeiko Schocher struct ubifs_cnode cnode;
1780ff94bc40SHeiko Schocher };
1781ff94bc40SHeiko Schocher int in_tree;
1782ff94bc40SHeiko Schocher union {
1783ff94bc40SHeiko Schocher struct ubifs_nnode *nnode;
1784ff94bc40SHeiko Schocher struct ubifs_pnode *pnode;
1785ff94bc40SHeiko Schocher struct ubifs_cnode *cnode;
1786ff94bc40SHeiko Schocher } ptr;
1787ff94bc40SHeiko Schocher };
1788ff94bc40SHeiko Schocher
1789ff94bc40SHeiko Schocher /**
1790ff94bc40SHeiko Schocher * scan_get_nnode - for the scan, get a nnode from either the tree or flash.
1791ff94bc40SHeiko Schocher * @c: the UBIFS file-system description object
1792ff94bc40SHeiko Schocher * @path: where to put the nnode
1793ff94bc40SHeiko Schocher * @parent: parent of the nnode
1794ff94bc40SHeiko Schocher * @iip: index in parent of the nnode
1795ff94bc40SHeiko Schocher *
1796ff94bc40SHeiko Schocher * This function returns a pointer to the nnode on success or a negative error
1797ff94bc40SHeiko Schocher * code on failure.
1798ff94bc40SHeiko Schocher */
scan_get_nnode(struct ubifs_info * c,struct lpt_scan_node * path,struct ubifs_nnode * parent,int iip)1799ff94bc40SHeiko Schocher static struct ubifs_nnode *scan_get_nnode(struct ubifs_info *c,
1800ff94bc40SHeiko Schocher struct lpt_scan_node *path,
1801ff94bc40SHeiko Schocher struct ubifs_nnode *parent, int iip)
1802ff94bc40SHeiko Schocher {
1803ff94bc40SHeiko Schocher struct ubifs_nbranch *branch;
1804ff94bc40SHeiko Schocher struct ubifs_nnode *nnode;
1805ff94bc40SHeiko Schocher void *buf = c->lpt_nod_buf;
1806ff94bc40SHeiko Schocher int err;
1807ff94bc40SHeiko Schocher
1808ff94bc40SHeiko Schocher branch = &parent->nbranch[iip];
1809ff94bc40SHeiko Schocher nnode = branch->nnode;
1810ff94bc40SHeiko Schocher if (nnode) {
1811ff94bc40SHeiko Schocher path->in_tree = 1;
1812ff94bc40SHeiko Schocher path->ptr.nnode = nnode;
1813ff94bc40SHeiko Schocher return nnode;
1814ff94bc40SHeiko Schocher }
1815ff94bc40SHeiko Schocher nnode = &path->nnode;
1816ff94bc40SHeiko Schocher path->in_tree = 0;
1817ff94bc40SHeiko Schocher path->ptr.nnode = nnode;
1818ff94bc40SHeiko Schocher memset(nnode, 0, sizeof(struct ubifs_nnode));
1819ff94bc40SHeiko Schocher if (branch->lnum == 0) {
1820ff94bc40SHeiko Schocher /*
1821ff94bc40SHeiko Schocher * This nnode was not written which just means that the LEB
1822ff94bc40SHeiko Schocher * properties in the subtree below it describe empty LEBs. We
1823ff94bc40SHeiko Schocher * make the nnode as though we had read it, which in fact means
1824ff94bc40SHeiko Schocher * doing almost nothing.
1825ff94bc40SHeiko Schocher */
1826ff94bc40SHeiko Schocher if (c->big_lpt)
1827ff94bc40SHeiko Schocher nnode->num = calc_nnode_num_from_parent(c, parent, iip);
1828ff94bc40SHeiko Schocher } else {
1829ff94bc40SHeiko Schocher err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
1830ff94bc40SHeiko Schocher c->nnode_sz, 1);
1831ff94bc40SHeiko Schocher if (err)
1832ff94bc40SHeiko Schocher return ERR_PTR(err);
1833ff94bc40SHeiko Schocher err = ubifs_unpack_nnode(c, buf, nnode);
1834ff94bc40SHeiko Schocher if (err)
1835ff94bc40SHeiko Schocher return ERR_PTR(err);
1836ff94bc40SHeiko Schocher }
1837ff94bc40SHeiko Schocher err = validate_nnode(c, nnode, parent, iip);
1838ff94bc40SHeiko Schocher if (err)
1839ff94bc40SHeiko Schocher return ERR_PTR(err);
1840ff94bc40SHeiko Schocher if (!c->big_lpt)
1841ff94bc40SHeiko Schocher nnode->num = calc_nnode_num_from_parent(c, parent, iip);
1842ff94bc40SHeiko Schocher nnode->level = parent->level - 1;
1843ff94bc40SHeiko Schocher nnode->parent = parent;
1844ff94bc40SHeiko Schocher nnode->iip = iip;
1845ff94bc40SHeiko Schocher return nnode;
1846ff94bc40SHeiko Schocher }
1847ff94bc40SHeiko Schocher
1848ff94bc40SHeiko Schocher /**
1849ff94bc40SHeiko Schocher * scan_get_pnode - for the scan, get a pnode from either the tree or flash.
1850ff94bc40SHeiko Schocher * @c: the UBIFS file-system description object
1851ff94bc40SHeiko Schocher * @path: where to put the pnode
1852ff94bc40SHeiko Schocher * @parent: parent of the pnode
1853ff94bc40SHeiko Schocher * @iip: index in parent of the pnode
1854ff94bc40SHeiko Schocher *
1855ff94bc40SHeiko Schocher * This function returns a pointer to the pnode on success or a negative error
1856ff94bc40SHeiko Schocher * code on failure.
1857ff94bc40SHeiko Schocher */
scan_get_pnode(struct ubifs_info * c,struct lpt_scan_node * path,struct ubifs_nnode * parent,int iip)1858ff94bc40SHeiko Schocher static struct ubifs_pnode *scan_get_pnode(struct ubifs_info *c,
1859ff94bc40SHeiko Schocher struct lpt_scan_node *path,
1860ff94bc40SHeiko Schocher struct ubifs_nnode *parent, int iip)
1861ff94bc40SHeiko Schocher {
1862ff94bc40SHeiko Schocher struct ubifs_nbranch *branch;
1863ff94bc40SHeiko Schocher struct ubifs_pnode *pnode;
1864ff94bc40SHeiko Schocher void *buf = c->lpt_nod_buf;
1865ff94bc40SHeiko Schocher int err;
1866ff94bc40SHeiko Schocher
1867ff94bc40SHeiko Schocher branch = &parent->nbranch[iip];
1868ff94bc40SHeiko Schocher pnode = branch->pnode;
1869ff94bc40SHeiko Schocher if (pnode) {
1870ff94bc40SHeiko Schocher path->in_tree = 1;
1871ff94bc40SHeiko Schocher path->ptr.pnode = pnode;
1872ff94bc40SHeiko Schocher return pnode;
1873ff94bc40SHeiko Schocher }
1874ff94bc40SHeiko Schocher pnode = &path->pnode;
1875ff94bc40SHeiko Schocher path->in_tree = 0;
1876ff94bc40SHeiko Schocher path->ptr.pnode = pnode;
1877ff94bc40SHeiko Schocher memset(pnode, 0, sizeof(struct ubifs_pnode));
1878ff94bc40SHeiko Schocher if (branch->lnum == 0) {
1879ff94bc40SHeiko Schocher /*
1880ff94bc40SHeiko Schocher * This pnode was not written which just means that the LEB
1881ff94bc40SHeiko Schocher * properties in it describe empty LEBs. We make the pnode as
1882ff94bc40SHeiko Schocher * though we had read it.
1883ff94bc40SHeiko Schocher */
1884ff94bc40SHeiko Schocher int i;
1885ff94bc40SHeiko Schocher
1886ff94bc40SHeiko Schocher if (c->big_lpt)
1887ff94bc40SHeiko Schocher pnode->num = calc_pnode_num_from_parent(c, parent, iip);
1888ff94bc40SHeiko Schocher for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
1889ff94bc40SHeiko Schocher struct ubifs_lprops * const lprops = &pnode->lprops[i];
1890ff94bc40SHeiko Schocher
1891ff94bc40SHeiko Schocher lprops->free = c->leb_size;
1892ff94bc40SHeiko Schocher lprops->flags = ubifs_categorize_lprops(c, lprops);
1893ff94bc40SHeiko Schocher }
1894ff94bc40SHeiko Schocher } else {
1895ff94bc40SHeiko Schocher ubifs_assert(branch->lnum >= c->lpt_first &&
1896ff94bc40SHeiko Schocher branch->lnum <= c->lpt_last);
1897ff94bc40SHeiko Schocher ubifs_assert(branch->offs >= 0 && branch->offs < c->leb_size);
1898ff94bc40SHeiko Schocher err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
1899ff94bc40SHeiko Schocher c->pnode_sz, 1);
1900ff94bc40SHeiko Schocher if (err)
1901ff94bc40SHeiko Schocher return ERR_PTR(err);
1902ff94bc40SHeiko Schocher err = unpack_pnode(c, buf, pnode);
1903ff94bc40SHeiko Schocher if (err)
1904ff94bc40SHeiko Schocher return ERR_PTR(err);
1905ff94bc40SHeiko Schocher }
1906ff94bc40SHeiko Schocher err = validate_pnode(c, pnode, parent, iip);
1907ff94bc40SHeiko Schocher if (err)
1908ff94bc40SHeiko Schocher return ERR_PTR(err);
1909ff94bc40SHeiko Schocher if (!c->big_lpt)
1910ff94bc40SHeiko Schocher pnode->num = calc_pnode_num_from_parent(c, parent, iip);
1911ff94bc40SHeiko Schocher pnode->parent = parent;
1912ff94bc40SHeiko Schocher pnode->iip = iip;
1913ff94bc40SHeiko Schocher set_pnode_lnum(c, pnode);
1914ff94bc40SHeiko Schocher return pnode;
1915ff94bc40SHeiko Schocher }
1916ff94bc40SHeiko Schocher
1917ff94bc40SHeiko Schocher /**
1918ff94bc40SHeiko Schocher * ubifs_lpt_scan_nolock - scan the LPT.
1919ff94bc40SHeiko Schocher * @c: the UBIFS file-system description object
1920ff94bc40SHeiko Schocher * @start_lnum: LEB number from which to start scanning
1921ff94bc40SHeiko Schocher * @end_lnum: LEB number at which to stop scanning
1922ff94bc40SHeiko Schocher * @scan_cb: callback function called for each lprops
1923ff94bc40SHeiko Schocher * @data: data to be passed to the callback function
1924ff94bc40SHeiko Schocher *
1925ff94bc40SHeiko Schocher * This function returns %0 on success and a negative error code on failure.
1926ff94bc40SHeiko Schocher */
ubifs_lpt_scan_nolock(struct ubifs_info * c,int start_lnum,int end_lnum,ubifs_lpt_scan_callback scan_cb,void * data)1927ff94bc40SHeiko Schocher int ubifs_lpt_scan_nolock(struct ubifs_info *c, int start_lnum, int end_lnum,
1928ff94bc40SHeiko Schocher ubifs_lpt_scan_callback scan_cb, void *data)
1929ff94bc40SHeiko Schocher {
1930ff94bc40SHeiko Schocher int err = 0, i, h, iip, shft;
1931ff94bc40SHeiko Schocher struct ubifs_nnode *nnode;
1932ff94bc40SHeiko Schocher struct ubifs_pnode *pnode;
1933ff94bc40SHeiko Schocher struct lpt_scan_node *path;
1934ff94bc40SHeiko Schocher
1935ff94bc40SHeiko Schocher if (start_lnum == -1) {
1936ff94bc40SHeiko Schocher start_lnum = end_lnum + 1;
1937ff94bc40SHeiko Schocher if (start_lnum >= c->leb_cnt)
1938ff94bc40SHeiko Schocher start_lnum = c->main_first;
1939ff94bc40SHeiko Schocher }
1940ff94bc40SHeiko Schocher
1941ff94bc40SHeiko Schocher ubifs_assert(start_lnum >= c->main_first && start_lnum < c->leb_cnt);
1942ff94bc40SHeiko Schocher ubifs_assert(end_lnum >= c->main_first && end_lnum < c->leb_cnt);
1943ff94bc40SHeiko Schocher
1944ff94bc40SHeiko Schocher if (!c->nroot) {
1945ff94bc40SHeiko Schocher err = ubifs_read_nnode(c, NULL, 0);
1946ff94bc40SHeiko Schocher if (err)
1947ff94bc40SHeiko Schocher return err;
1948ff94bc40SHeiko Schocher }
1949ff94bc40SHeiko Schocher
1950ff94bc40SHeiko Schocher path = kmalloc(sizeof(struct lpt_scan_node) * (c->lpt_hght + 1),
1951ff94bc40SHeiko Schocher GFP_NOFS);
1952ff94bc40SHeiko Schocher if (!path)
1953ff94bc40SHeiko Schocher return -ENOMEM;
1954ff94bc40SHeiko Schocher
1955ff94bc40SHeiko Schocher path[0].ptr.nnode = c->nroot;
1956ff94bc40SHeiko Schocher path[0].in_tree = 1;
1957ff94bc40SHeiko Schocher again:
1958ff94bc40SHeiko Schocher /* Descend to the pnode containing start_lnum */
1959ff94bc40SHeiko Schocher nnode = c->nroot;
1960ff94bc40SHeiko Schocher i = start_lnum - c->main_first;
1961ff94bc40SHeiko Schocher shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
1962ff94bc40SHeiko Schocher for (h = 1; h < c->lpt_hght; h++) {
1963ff94bc40SHeiko Schocher iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
1964ff94bc40SHeiko Schocher shft -= UBIFS_LPT_FANOUT_SHIFT;
1965ff94bc40SHeiko Schocher nnode = scan_get_nnode(c, path + h, nnode, iip);
1966ff94bc40SHeiko Schocher if (IS_ERR(nnode)) {
1967ff94bc40SHeiko Schocher err = PTR_ERR(nnode);
1968ff94bc40SHeiko Schocher goto out;
1969ff94bc40SHeiko Schocher }
1970ff94bc40SHeiko Schocher }
1971ff94bc40SHeiko Schocher iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
1972ff94bc40SHeiko Schocher pnode = scan_get_pnode(c, path + h, nnode, iip);
1973ff94bc40SHeiko Schocher if (IS_ERR(pnode)) {
1974ff94bc40SHeiko Schocher err = PTR_ERR(pnode);
1975ff94bc40SHeiko Schocher goto out;
1976ff94bc40SHeiko Schocher }
1977ff94bc40SHeiko Schocher iip = (i & (UBIFS_LPT_FANOUT - 1));
1978ff94bc40SHeiko Schocher
1979ff94bc40SHeiko Schocher /* Loop for each lprops */
1980ff94bc40SHeiko Schocher while (1) {
1981ff94bc40SHeiko Schocher struct ubifs_lprops *lprops = &pnode->lprops[iip];
1982ff94bc40SHeiko Schocher int ret, lnum = lprops->lnum;
1983ff94bc40SHeiko Schocher
1984ff94bc40SHeiko Schocher ret = scan_cb(c, lprops, path[h].in_tree, data);
1985ff94bc40SHeiko Schocher if (ret < 0) {
1986ff94bc40SHeiko Schocher err = ret;
1987ff94bc40SHeiko Schocher goto out;
1988ff94bc40SHeiko Schocher }
1989ff94bc40SHeiko Schocher if (ret & LPT_SCAN_ADD) {
1990ff94bc40SHeiko Schocher /* Add all the nodes in path to the tree in memory */
1991ff94bc40SHeiko Schocher for (h = 1; h < c->lpt_hght; h++) {
1992ff94bc40SHeiko Schocher const size_t sz = sizeof(struct ubifs_nnode);
1993ff94bc40SHeiko Schocher struct ubifs_nnode *parent;
1994ff94bc40SHeiko Schocher
1995ff94bc40SHeiko Schocher if (path[h].in_tree)
1996ff94bc40SHeiko Schocher continue;
1997ff94bc40SHeiko Schocher nnode = kmemdup(&path[h].nnode, sz, GFP_NOFS);
1998ff94bc40SHeiko Schocher if (!nnode) {
1999ff94bc40SHeiko Schocher err = -ENOMEM;
2000ff94bc40SHeiko Schocher goto out;
2001ff94bc40SHeiko Schocher }
2002ff94bc40SHeiko Schocher parent = nnode->parent;
2003ff94bc40SHeiko Schocher parent->nbranch[nnode->iip].nnode = nnode;
2004ff94bc40SHeiko Schocher path[h].ptr.nnode = nnode;
2005ff94bc40SHeiko Schocher path[h].in_tree = 1;
2006ff94bc40SHeiko Schocher path[h + 1].cnode.parent = nnode;
2007ff94bc40SHeiko Schocher }
2008ff94bc40SHeiko Schocher if (path[h].in_tree)
2009ff94bc40SHeiko Schocher ubifs_ensure_cat(c, lprops);
2010ff94bc40SHeiko Schocher else {
2011ff94bc40SHeiko Schocher const size_t sz = sizeof(struct ubifs_pnode);
2012ff94bc40SHeiko Schocher struct ubifs_nnode *parent;
2013ff94bc40SHeiko Schocher
2014ff94bc40SHeiko Schocher pnode = kmemdup(&path[h].pnode, sz, GFP_NOFS);
2015ff94bc40SHeiko Schocher if (!pnode) {
2016ff94bc40SHeiko Schocher err = -ENOMEM;
2017ff94bc40SHeiko Schocher goto out;
2018ff94bc40SHeiko Schocher }
2019ff94bc40SHeiko Schocher parent = pnode->parent;
2020ff94bc40SHeiko Schocher parent->nbranch[pnode->iip].pnode = pnode;
2021ff94bc40SHeiko Schocher path[h].ptr.pnode = pnode;
2022ff94bc40SHeiko Schocher path[h].in_tree = 1;
2023ff94bc40SHeiko Schocher update_cats(c, pnode);
2024ff94bc40SHeiko Schocher c->pnodes_have += 1;
2025ff94bc40SHeiko Schocher }
2026ff94bc40SHeiko Schocher err = dbg_check_lpt_nodes(c, (struct ubifs_cnode *)
2027ff94bc40SHeiko Schocher c->nroot, 0, 0);
2028ff94bc40SHeiko Schocher if (err)
2029ff94bc40SHeiko Schocher goto out;
2030ff94bc40SHeiko Schocher err = dbg_check_cats(c);
2031ff94bc40SHeiko Schocher if (err)
2032ff94bc40SHeiko Schocher goto out;
2033ff94bc40SHeiko Schocher }
2034ff94bc40SHeiko Schocher if (ret & LPT_SCAN_STOP) {
2035ff94bc40SHeiko Schocher err = 0;
2036ff94bc40SHeiko Schocher break;
2037ff94bc40SHeiko Schocher }
2038ff94bc40SHeiko Schocher /* Get the next lprops */
2039ff94bc40SHeiko Schocher if (lnum == end_lnum) {
2040ff94bc40SHeiko Schocher /*
2041ff94bc40SHeiko Schocher * We got to the end without finding what we were
2042ff94bc40SHeiko Schocher * looking for
2043ff94bc40SHeiko Schocher */
2044ff94bc40SHeiko Schocher err = -ENOSPC;
2045ff94bc40SHeiko Schocher goto out;
2046ff94bc40SHeiko Schocher }
2047ff94bc40SHeiko Schocher if (lnum + 1 >= c->leb_cnt) {
2048ff94bc40SHeiko Schocher /* Wrap-around to the beginning */
2049ff94bc40SHeiko Schocher start_lnum = c->main_first;
2050ff94bc40SHeiko Schocher goto again;
2051ff94bc40SHeiko Schocher }
2052ff94bc40SHeiko Schocher if (iip + 1 < UBIFS_LPT_FANOUT) {
2053ff94bc40SHeiko Schocher /* Next lprops is in the same pnode */
2054ff94bc40SHeiko Schocher iip += 1;
2055ff94bc40SHeiko Schocher continue;
2056ff94bc40SHeiko Schocher }
2057ff94bc40SHeiko Schocher /* We need to get the next pnode. Go up until we can go right */
2058ff94bc40SHeiko Schocher iip = pnode->iip;
2059ff94bc40SHeiko Schocher while (1) {
2060ff94bc40SHeiko Schocher h -= 1;
2061ff94bc40SHeiko Schocher ubifs_assert(h >= 0);
2062ff94bc40SHeiko Schocher nnode = path[h].ptr.nnode;
2063ff94bc40SHeiko Schocher if (iip + 1 < UBIFS_LPT_FANOUT)
2064ff94bc40SHeiko Schocher break;
2065ff94bc40SHeiko Schocher iip = nnode->iip;
2066ff94bc40SHeiko Schocher }
2067ff94bc40SHeiko Schocher /* Go right */
2068ff94bc40SHeiko Schocher iip += 1;
2069ff94bc40SHeiko Schocher /* Descend to the pnode */
2070ff94bc40SHeiko Schocher h += 1;
2071ff94bc40SHeiko Schocher for (; h < c->lpt_hght; h++) {
2072ff94bc40SHeiko Schocher nnode = scan_get_nnode(c, path + h, nnode, iip);
2073ff94bc40SHeiko Schocher if (IS_ERR(nnode)) {
2074ff94bc40SHeiko Schocher err = PTR_ERR(nnode);
2075ff94bc40SHeiko Schocher goto out;
2076ff94bc40SHeiko Schocher }
2077ff94bc40SHeiko Schocher iip = 0;
2078ff94bc40SHeiko Schocher }
2079ff94bc40SHeiko Schocher pnode = scan_get_pnode(c, path + h, nnode, iip);
2080ff94bc40SHeiko Schocher if (IS_ERR(pnode)) {
2081ff94bc40SHeiko Schocher err = PTR_ERR(pnode);
2082ff94bc40SHeiko Schocher goto out;
2083ff94bc40SHeiko Schocher }
2084ff94bc40SHeiko Schocher iip = 0;
2085ff94bc40SHeiko Schocher }
2086ff94bc40SHeiko Schocher out:
2087ff94bc40SHeiko Schocher kfree(path);
2088ff94bc40SHeiko Schocher return err;
2089ff94bc40SHeiko Schocher }
2090ff94bc40SHeiko Schocher
2091ff94bc40SHeiko Schocher /**
2092ff94bc40SHeiko Schocher * dbg_chk_pnode - check a pnode.
2093ff94bc40SHeiko Schocher * @c: the UBIFS file-system description object
2094ff94bc40SHeiko Schocher * @pnode: pnode to check
2095ff94bc40SHeiko Schocher * @col: pnode column
2096ff94bc40SHeiko Schocher *
2097ff94bc40SHeiko Schocher * This function returns %0 on success and a negative error code on failure.
2098ff94bc40SHeiko Schocher */
dbg_chk_pnode(struct ubifs_info * c,struct ubifs_pnode * pnode,int col)2099ff94bc40SHeiko Schocher static int dbg_chk_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
2100ff94bc40SHeiko Schocher int col)
2101ff94bc40SHeiko Schocher {
2102ff94bc40SHeiko Schocher int i;
2103ff94bc40SHeiko Schocher
2104ff94bc40SHeiko Schocher if (pnode->num != col) {
2105*0195a7bbSHeiko Schocher ubifs_err(c, "pnode num %d expected %d parent num %d iip %d",
2106ff94bc40SHeiko Schocher pnode->num, col, pnode->parent->num, pnode->iip);
2107ff94bc40SHeiko Schocher return -EINVAL;
2108ff94bc40SHeiko Schocher }
2109ff94bc40SHeiko Schocher for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
2110ff94bc40SHeiko Schocher struct ubifs_lprops *lp, *lprops = &pnode->lprops[i];
2111ff94bc40SHeiko Schocher int lnum = (pnode->num << UBIFS_LPT_FANOUT_SHIFT) + i +
2112ff94bc40SHeiko Schocher c->main_first;
2113ff94bc40SHeiko Schocher int found, cat = lprops->flags & LPROPS_CAT_MASK;
2114ff94bc40SHeiko Schocher struct ubifs_lpt_heap *heap;
2115ff94bc40SHeiko Schocher struct list_head *list = NULL;
2116ff94bc40SHeiko Schocher
2117ff94bc40SHeiko Schocher if (lnum >= c->leb_cnt)
2118ff94bc40SHeiko Schocher continue;
2119ff94bc40SHeiko Schocher if (lprops->lnum != lnum) {
2120*0195a7bbSHeiko Schocher ubifs_err(c, "bad LEB number %d expected %d",
2121ff94bc40SHeiko Schocher lprops->lnum, lnum);
2122ff94bc40SHeiko Schocher return -EINVAL;
2123ff94bc40SHeiko Schocher }
2124ff94bc40SHeiko Schocher if (lprops->flags & LPROPS_TAKEN) {
2125ff94bc40SHeiko Schocher if (cat != LPROPS_UNCAT) {
2126*0195a7bbSHeiko Schocher ubifs_err(c, "LEB %d taken but not uncat %d",
2127ff94bc40SHeiko Schocher lprops->lnum, cat);
2128ff94bc40SHeiko Schocher return -EINVAL;
2129ff94bc40SHeiko Schocher }
2130ff94bc40SHeiko Schocher continue;
2131ff94bc40SHeiko Schocher }
2132ff94bc40SHeiko Schocher if (lprops->flags & LPROPS_INDEX) {
2133ff94bc40SHeiko Schocher switch (cat) {
2134ff94bc40SHeiko Schocher case LPROPS_UNCAT:
2135ff94bc40SHeiko Schocher case LPROPS_DIRTY_IDX:
2136ff94bc40SHeiko Schocher case LPROPS_FRDI_IDX:
2137ff94bc40SHeiko Schocher break;
2138ff94bc40SHeiko Schocher default:
2139*0195a7bbSHeiko Schocher ubifs_err(c, "LEB %d index but cat %d",
2140ff94bc40SHeiko Schocher lprops->lnum, cat);
2141ff94bc40SHeiko Schocher return -EINVAL;
2142ff94bc40SHeiko Schocher }
2143ff94bc40SHeiko Schocher } else {
2144ff94bc40SHeiko Schocher switch (cat) {
2145ff94bc40SHeiko Schocher case LPROPS_UNCAT:
2146ff94bc40SHeiko Schocher case LPROPS_DIRTY:
2147ff94bc40SHeiko Schocher case LPROPS_FREE:
2148ff94bc40SHeiko Schocher case LPROPS_EMPTY:
2149ff94bc40SHeiko Schocher case LPROPS_FREEABLE:
2150ff94bc40SHeiko Schocher break;
2151ff94bc40SHeiko Schocher default:
2152*0195a7bbSHeiko Schocher ubifs_err(c, "LEB %d not index but cat %d",
2153ff94bc40SHeiko Schocher lprops->lnum, cat);
2154ff94bc40SHeiko Schocher return -EINVAL;
2155ff94bc40SHeiko Schocher }
2156ff94bc40SHeiko Schocher }
2157ff94bc40SHeiko Schocher switch (cat) {
2158ff94bc40SHeiko Schocher case LPROPS_UNCAT:
2159ff94bc40SHeiko Schocher list = &c->uncat_list;
2160ff94bc40SHeiko Schocher break;
2161ff94bc40SHeiko Schocher case LPROPS_EMPTY:
2162ff94bc40SHeiko Schocher list = &c->empty_list;
2163ff94bc40SHeiko Schocher break;
2164ff94bc40SHeiko Schocher case LPROPS_FREEABLE:
2165ff94bc40SHeiko Schocher list = &c->freeable_list;
2166ff94bc40SHeiko Schocher break;
2167ff94bc40SHeiko Schocher case LPROPS_FRDI_IDX:
2168ff94bc40SHeiko Schocher list = &c->frdi_idx_list;
2169ff94bc40SHeiko Schocher break;
2170ff94bc40SHeiko Schocher }
2171ff94bc40SHeiko Schocher found = 0;
2172ff94bc40SHeiko Schocher switch (cat) {
2173ff94bc40SHeiko Schocher case LPROPS_DIRTY:
2174ff94bc40SHeiko Schocher case LPROPS_DIRTY_IDX:
2175ff94bc40SHeiko Schocher case LPROPS_FREE:
2176ff94bc40SHeiko Schocher heap = &c->lpt_heap[cat - 1];
2177ff94bc40SHeiko Schocher if (lprops->hpos < heap->cnt &&
2178ff94bc40SHeiko Schocher heap->arr[lprops->hpos] == lprops)
2179ff94bc40SHeiko Schocher found = 1;
2180ff94bc40SHeiko Schocher break;
2181ff94bc40SHeiko Schocher case LPROPS_UNCAT:
2182ff94bc40SHeiko Schocher case LPROPS_EMPTY:
2183ff94bc40SHeiko Schocher case LPROPS_FREEABLE:
2184ff94bc40SHeiko Schocher case LPROPS_FRDI_IDX:
2185ff94bc40SHeiko Schocher list_for_each_entry(lp, list, list)
2186ff94bc40SHeiko Schocher if (lprops == lp) {
2187ff94bc40SHeiko Schocher found = 1;
2188ff94bc40SHeiko Schocher break;
2189ff94bc40SHeiko Schocher }
2190ff94bc40SHeiko Schocher break;
2191ff94bc40SHeiko Schocher }
2192ff94bc40SHeiko Schocher if (!found) {
2193*0195a7bbSHeiko Schocher ubifs_err(c, "LEB %d cat %d not found in cat heap/list",
2194ff94bc40SHeiko Schocher lprops->lnum, cat);
2195ff94bc40SHeiko Schocher return -EINVAL;
2196ff94bc40SHeiko Schocher }
2197ff94bc40SHeiko Schocher switch (cat) {
2198ff94bc40SHeiko Schocher case LPROPS_EMPTY:
2199ff94bc40SHeiko Schocher if (lprops->free != c->leb_size) {
2200*0195a7bbSHeiko Schocher ubifs_err(c, "LEB %d cat %d free %d dirty %d",
2201ff94bc40SHeiko Schocher lprops->lnum, cat, lprops->free,
2202ff94bc40SHeiko Schocher lprops->dirty);
2203ff94bc40SHeiko Schocher return -EINVAL;
2204ff94bc40SHeiko Schocher }
2205*0195a7bbSHeiko Schocher break;
2206ff94bc40SHeiko Schocher case LPROPS_FREEABLE:
2207ff94bc40SHeiko Schocher case LPROPS_FRDI_IDX:
2208ff94bc40SHeiko Schocher if (lprops->free + lprops->dirty != c->leb_size) {
2209*0195a7bbSHeiko Schocher ubifs_err(c, "LEB %d cat %d free %d dirty %d",
2210ff94bc40SHeiko Schocher lprops->lnum, cat, lprops->free,
2211ff94bc40SHeiko Schocher lprops->dirty);
2212ff94bc40SHeiko Schocher return -EINVAL;
2213ff94bc40SHeiko Schocher }
2214*0195a7bbSHeiko Schocher break;
2215ff94bc40SHeiko Schocher }
2216ff94bc40SHeiko Schocher }
2217ff94bc40SHeiko Schocher return 0;
2218ff94bc40SHeiko Schocher }
2219ff94bc40SHeiko Schocher
2220ff94bc40SHeiko Schocher /**
2221ff94bc40SHeiko Schocher * dbg_check_lpt_nodes - check nnodes and pnodes.
2222ff94bc40SHeiko Schocher * @c: the UBIFS file-system description object
2223ff94bc40SHeiko Schocher * @cnode: next cnode (nnode or pnode) to check
2224ff94bc40SHeiko Schocher * @row: row of cnode (root is zero)
2225ff94bc40SHeiko Schocher * @col: column of cnode (leftmost is zero)
2226ff94bc40SHeiko Schocher *
2227ff94bc40SHeiko Schocher * This function returns %0 on success and a negative error code on failure.
2228ff94bc40SHeiko Schocher */
dbg_check_lpt_nodes(struct ubifs_info * c,struct ubifs_cnode * cnode,int row,int col)2229ff94bc40SHeiko Schocher int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
2230ff94bc40SHeiko Schocher int row, int col)
2231ff94bc40SHeiko Schocher {
2232ff94bc40SHeiko Schocher struct ubifs_nnode *nnode, *nn;
2233ff94bc40SHeiko Schocher struct ubifs_cnode *cn;
2234ff94bc40SHeiko Schocher int num, iip = 0, err;
2235ff94bc40SHeiko Schocher
2236ff94bc40SHeiko Schocher if (!dbg_is_chk_lprops(c))
2237ff94bc40SHeiko Schocher return 0;
2238ff94bc40SHeiko Schocher
2239ff94bc40SHeiko Schocher while (cnode) {
2240ff94bc40SHeiko Schocher ubifs_assert(row >= 0);
2241ff94bc40SHeiko Schocher nnode = cnode->parent;
2242ff94bc40SHeiko Schocher if (cnode->level) {
2243ff94bc40SHeiko Schocher /* cnode is a nnode */
2244ff94bc40SHeiko Schocher num = calc_nnode_num(row, col);
2245ff94bc40SHeiko Schocher if (cnode->num != num) {
2246*0195a7bbSHeiko Schocher ubifs_err(c, "nnode num %d expected %d parent num %d iip %d",
2247ff94bc40SHeiko Schocher cnode->num, num,
2248ff94bc40SHeiko Schocher (nnode ? nnode->num : 0), cnode->iip);
2249ff94bc40SHeiko Schocher return -EINVAL;
2250ff94bc40SHeiko Schocher }
2251ff94bc40SHeiko Schocher nn = (struct ubifs_nnode *)cnode;
2252ff94bc40SHeiko Schocher while (iip < UBIFS_LPT_FANOUT) {
2253ff94bc40SHeiko Schocher cn = nn->nbranch[iip].cnode;
2254ff94bc40SHeiko Schocher if (cn) {
2255ff94bc40SHeiko Schocher /* Go down */
2256ff94bc40SHeiko Schocher row += 1;
2257ff94bc40SHeiko Schocher col <<= UBIFS_LPT_FANOUT_SHIFT;
2258ff94bc40SHeiko Schocher col += iip;
2259ff94bc40SHeiko Schocher iip = 0;
2260ff94bc40SHeiko Schocher cnode = cn;
2261ff94bc40SHeiko Schocher break;
2262ff94bc40SHeiko Schocher }
2263ff94bc40SHeiko Schocher /* Go right */
2264ff94bc40SHeiko Schocher iip += 1;
2265ff94bc40SHeiko Schocher }
2266ff94bc40SHeiko Schocher if (iip < UBIFS_LPT_FANOUT)
2267ff94bc40SHeiko Schocher continue;
2268ff94bc40SHeiko Schocher } else {
2269ff94bc40SHeiko Schocher struct ubifs_pnode *pnode;
2270ff94bc40SHeiko Schocher
2271ff94bc40SHeiko Schocher /* cnode is a pnode */
2272ff94bc40SHeiko Schocher pnode = (struct ubifs_pnode *)cnode;
2273ff94bc40SHeiko Schocher err = dbg_chk_pnode(c, pnode, col);
2274ff94bc40SHeiko Schocher if (err)
2275ff94bc40SHeiko Schocher return err;
2276ff94bc40SHeiko Schocher }
2277ff94bc40SHeiko Schocher /* Go up and to the right */
2278ff94bc40SHeiko Schocher row -= 1;
2279ff94bc40SHeiko Schocher col >>= UBIFS_LPT_FANOUT_SHIFT;
2280ff94bc40SHeiko Schocher iip = cnode->iip + 1;
2281ff94bc40SHeiko Schocher cnode = (struct ubifs_cnode *)nnode;
2282ff94bc40SHeiko Schocher }
22839eefe2a2SStefan Roese return 0;
22849eefe2a2SStefan Roese }
2285