12b27bdccSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21e51764aSArtem Bityutskiy /*
31e51764aSArtem Bityutskiy * This file is part of UBIFS.
41e51764aSArtem Bityutskiy *
51e51764aSArtem Bityutskiy * Copyright (C) 2006-2008 Nokia Corporation.
61e51764aSArtem Bityutskiy *
71e51764aSArtem Bityutskiy * Authors: Artem Bityutskiy (Битюцкий Артём)
81e51764aSArtem Bityutskiy * Adrian Hunter
91e51764aSArtem Bityutskiy */
101e51764aSArtem Bityutskiy
111e51764aSArtem Bityutskiy /* This file implements reading and writing the master node */
121e51764aSArtem Bityutskiy
131e51764aSArtem Bityutskiy #include "ubifs.h"
141e51764aSArtem Bityutskiy
151e51764aSArtem Bityutskiy /**
16625700ccSSascha Hauer * ubifs_compare_master_node - compare two UBIFS master nodes
17625700ccSSascha Hauer * @c: UBIFS file-system description object
18625700ccSSascha Hauer * @m1: the first node
19625700ccSSascha Hauer * @m2: the second node
20625700ccSSascha Hauer *
21625700ccSSascha Hauer * This function compares two UBIFS master nodes. Returns 0 if they are equal
22625700ccSSascha Hauer * and nonzero if not.
23625700ccSSascha Hauer */
ubifs_compare_master_node(struct ubifs_info * c,void * m1,void * m2)24625700ccSSascha Hauer int ubifs_compare_master_node(struct ubifs_info *c, void *m1, void *m2)
25625700ccSSascha Hauer {
26625700ccSSascha Hauer int ret;
27625700ccSSascha Hauer int behind;
28625700ccSSascha Hauer int hmac_offs = offsetof(struct ubifs_mst_node, hmac);
29625700ccSSascha Hauer
30625700ccSSascha Hauer /*
31625700ccSSascha Hauer * Do not compare the common node header since the sequence number and
32625700ccSSascha Hauer * hence the CRC are different.
33625700ccSSascha Hauer */
34625700ccSSascha Hauer ret = memcmp(m1 + UBIFS_CH_SZ, m2 + UBIFS_CH_SZ,
35625700ccSSascha Hauer hmac_offs - UBIFS_CH_SZ);
36625700ccSSascha Hauer if (ret)
37625700ccSSascha Hauer return ret;
38625700ccSSascha Hauer
39625700ccSSascha Hauer /*
40625700ccSSascha Hauer * Do not compare the embedded HMAC as well which also must be different
41625700ccSSascha Hauer * due to the different common node header.
42625700ccSSascha Hauer */
43625700ccSSascha Hauer behind = hmac_offs + UBIFS_MAX_HMAC_LEN;
44625700ccSSascha Hauer
45625700ccSSascha Hauer if (UBIFS_MST_NODE_SZ > behind)
46625700ccSSascha Hauer return memcmp(m1 + behind, m2 + behind, UBIFS_MST_NODE_SZ - behind);
47625700ccSSascha Hauer
48625700ccSSascha Hauer return 0;
49625700ccSSascha Hauer }
50625700ccSSascha Hauer
51817aa094SSascha Hauer /* mst_node_check_hash - Check hash of a master node
52817aa094SSascha Hauer * @c: UBIFS file-system description object
53817aa094SSascha Hauer * @mst: The master node
54817aa094SSascha Hauer * @expected: The expected hash of the master node
55817aa094SSascha Hauer *
56817aa094SSascha Hauer * This checks the hash of a master node against a given expected hash.
57817aa094SSascha Hauer * Note that we have two master nodes on a UBIFS image which have different
58817aa094SSascha Hauer * sequence numbers and consequently different CRCs. To be able to match
59817aa094SSascha Hauer * both master nodes we exclude the common node header containing the sequence
60817aa094SSascha Hauer * number and CRC from the hash.
61817aa094SSascha Hauer *
62817aa094SSascha Hauer * Returns 0 if the hashes are equal, a negative error code otherwise.
63817aa094SSascha Hauer */
mst_node_check_hash(const struct ubifs_info * c,const struct ubifs_mst_node * mst,const u8 * expected)64817aa094SSascha Hauer static int mst_node_check_hash(const struct ubifs_info *c,
65817aa094SSascha Hauer const struct ubifs_mst_node *mst,
66817aa094SSascha Hauer const u8 *expected)
67817aa094SSascha Hauer {
68817aa094SSascha Hauer u8 calc[UBIFS_MAX_HASH_LEN];
69817aa094SSascha Hauer const void *node = mst;
70817aa094SSascha Hauer
71f80df385SEric Biggers crypto_shash_tfm_digest(c->hash_tfm, node + sizeof(struct ubifs_ch),
72f80df385SEric Biggers UBIFS_MST_NODE_SZ - sizeof(struct ubifs_ch),
73f80df385SEric Biggers calc);
74817aa094SSascha Hauer
75817aa094SSascha Hauer if (ubifs_check_hash(c, expected, calc))
76817aa094SSascha Hauer return -EPERM;
77817aa094SSascha Hauer
78817aa094SSascha Hauer return 0;
79817aa094SSascha Hauer }
80817aa094SSascha Hauer
81625700ccSSascha Hauer /**
821e51764aSArtem Bityutskiy * scan_for_master - search the valid master node.
831e51764aSArtem Bityutskiy * @c: UBIFS file-system description object
841e51764aSArtem Bityutskiy *
851e51764aSArtem Bityutskiy * This function scans the master node LEBs and search for the latest master
860dcd18e4SArtem Bityutskiy * node. Returns zero in case of success, %-EUCLEAN if there master area is
870dcd18e4SArtem Bityutskiy * corrupted and requires recovery, and a negative error code in case of
881e51764aSArtem Bityutskiy * failure.
891e51764aSArtem Bityutskiy */
scan_for_master(struct ubifs_info * c)901e51764aSArtem Bityutskiy static int scan_for_master(struct ubifs_info *c)
911e51764aSArtem Bityutskiy {
921e51764aSArtem Bityutskiy struct ubifs_scan_leb *sleb;
931e51764aSArtem Bityutskiy struct ubifs_scan_node *snod;
94625700ccSSascha Hauer int lnum, offs = 0, nodes_cnt, err;
951e51764aSArtem Bityutskiy
961e51764aSArtem Bityutskiy lnum = UBIFS_MST_LNUM;
971e51764aSArtem Bityutskiy
98348709baSArtem Bityutskiy sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1);
991e51764aSArtem Bityutskiy if (IS_ERR(sleb))
1001e51764aSArtem Bityutskiy return PTR_ERR(sleb);
1011e51764aSArtem Bityutskiy nodes_cnt = sleb->nodes_cnt;
1021e51764aSArtem Bityutskiy if (nodes_cnt > 0) {
1031e51764aSArtem Bityutskiy snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node,
1041e51764aSArtem Bityutskiy list);
1051e51764aSArtem Bityutskiy if (snod->type != UBIFS_MST_NODE)
1060dcd18e4SArtem Bityutskiy goto out_dump;
1071e51764aSArtem Bityutskiy memcpy(c->mst_node, snod->node, snod->len);
1081e51764aSArtem Bityutskiy offs = snod->offs;
1091e51764aSArtem Bityutskiy }
1101e51764aSArtem Bityutskiy ubifs_scan_destroy(sleb);
1111e51764aSArtem Bityutskiy
1121e51764aSArtem Bityutskiy lnum += 1;
1131e51764aSArtem Bityutskiy
114348709baSArtem Bityutskiy sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1);
1151e51764aSArtem Bityutskiy if (IS_ERR(sleb))
1161e51764aSArtem Bityutskiy return PTR_ERR(sleb);
1171e51764aSArtem Bityutskiy if (sleb->nodes_cnt != nodes_cnt)
1181e51764aSArtem Bityutskiy goto out;
1191e51764aSArtem Bityutskiy if (!sleb->nodes_cnt)
1201e51764aSArtem Bityutskiy goto out;
1211e51764aSArtem Bityutskiy snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node, list);
1221e51764aSArtem Bityutskiy if (snod->type != UBIFS_MST_NODE)
1230dcd18e4SArtem Bityutskiy goto out_dump;
1241e51764aSArtem Bityutskiy if (snod->offs != offs)
1251e51764aSArtem Bityutskiy goto out;
126625700ccSSascha Hauer if (ubifs_compare_master_node(c, c->mst_node, snod->node))
1271e51764aSArtem Bityutskiy goto out;
128625700ccSSascha Hauer
1291e51764aSArtem Bityutskiy c->mst_offs = offs;
1301e51764aSArtem Bityutskiy ubifs_scan_destroy(sleb);
131625700ccSSascha Hauer
132625700ccSSascha Hauer if (!ubifs_authenticated(c))
133625700ccSSascha Hauer return 0;
134625700ccSSascha Hauer
135817aa094SSascha Hauer if (ubifs_hmac_zero(c, c->mst_node->hmac)) {
136817aa094SSascha Hauer err = mst_node_check_hash(c, c->mst_node,
137817aa094SSascha Hauer c->sup_node->hash_mst);
138817aa094SSascha Hauer if (err)
139817aa094SSascha Hauer ubifs_err(c, "Failed to verify master node hash");
140817aa094SSascha Hauer } else {
141625700ccSSascha Hauer err = ubifs_node_verify_hmac(c, c->mst_node,
142625700ccSSascha Hauer sizeof(struct ubifs_mst_node),
143625700ccSSascha Hauer offsetof(struct ubifs_mst_node, hmac));
144817aa094SSascha Hauer if (err)
145625700ccSSascha Hauer ubifs_err(c, "Failed to verify master node HMAC");
146625700ccSSascha Hauer }
147625700ccSSascha Hauer
148817aa094SSascha Hauer if (err)
149817aa094SSascha Hauer return -EPERM;
150817aa094SSascha Hauer
1511e51764aSArtem Bityutskiy return 0;
1521e51764aSArtem Bityutskiy
1531e51764aSArtem Bityutskiy out:
1541e51764aSArtem Bityutskiy ubifs_scan_destroy(sleb);
1550dcd18e4SArtem Bityutskiy return -EUCLEAN;
1560dcd18e4SArtem Bityutskiy
1570dcd18e4SArtem Bityutskiy out_dump:
158235c362bSSheng Yong ubifs_err(c, "unexpected node type %d master LEB %d:%d",
1590dcd18e4SArtem Bityutskiy snod->type, lnum, snod->offs);
1600dcd18e4SArtem Bityutskiy ubifs_scan_destroy(sleb);
1611e51764aSArtem Bityutskiy return -EINVAL;
1621e51764aSArtem Bityutskiy }
1631e51764aSArtem Bityutskiy
1641e51764aSArtem Bityutskiy /**
1651e51764aSArtem Bityutskiy * validate_master - validate master node.
1661e51764aSArtem Bityutskiy * @c: UBIFS file-system description object
1671e51764aSArtem Bityutskiy *
1681e51764aSArtem Bityutskiy * This function validates data which was read from master node. Returns zero
1691e51764aSArtem Bityutskiy * if the data is all right and %-EINVAL if not.
1701e51764aSArtem Bityutskiy */
validate_master(const struct ubifs_info * c)1711e51764aSArtem Bityutskiy static int validate_master(const struct ubifs_info *c)
1721e51764aSArtem Bityutskiy {
1731e51764aSArtem Bityutskiy long long main_sz;
1741e51764aSArtem Bityutskiy int err;
1751e51764aSArtem Bityutskiy
1761e51764aSArtem Bityutskiy if (c->max_sqnum >= SQNUM_WATERMARK) {
1771e51764aSArtem Bityutskiy err = 1;
1781e51764aSArtem Bityutskiy goto out;
1791e51764aSArtem Bityutskiy }
1801e51764aSArtem Bityutskiy
1811e51764aSArtem Bityutskiy if (c->cmt_no >= c->max_sqnum) {
1821e51764aSArtem Bityutskiy err = 2;
1831e51764aSArtem Bityutskiy goto out;
1841e51764aSArtem Bityutskiy }
1851e51764aSArtem Bityutskiy
1861e51764aSArtem Bityutskiy if (c->highest_inum >= INUM_WATERMARK) {
1871e51764aSArtem Bityutskiy err = 3;
1881e51764aSArtem Bityutskiy goto out;
1891e51764aSArtem Bityutskiy }
1901e51764aSArtem Bityutskiy
1911e51764aSArtem Bityutskiy if (c->lhead_lnum < UBIFS_LOG_LNUM ||
1921e51764aSArtem Bityutskiy c->lhead_lnum >= UBIFS_LOG_LNUM + c->log_lebs ||
1931e51764aSArtem Bityutskiy c->lhead_offs < 0 || c->lhead_offs >= c->leb_size ||
1941e51764aSArtem Bityutskiy c->lhead_offs & (c->min_io_size - 1)) {
1951e51764aSArtem Bityutskiy err = 4;
1961e51764aSArtem Bityutskiy goto out;
1971e51764aSArtem Bityutskiy }
1981e51764aSArtem Bityutskiy
1991e51764aSArtem Bityutskiy if (c->zroot.lnum >= c->leb_cnt || c->zroot.lnum < c->main_first ||
2001e51764aSArtem Bityutskiy c->zroot.offs >= c->leb_size || c->zroot.offs & 7) {
2011e51764aSArtem Bityutskiy err = 5;
2021e51764aSArtem Bityutskiy goto out;
2031e51764aSArtem Bityutskiy }
2041e51764aSArtem Bityutskiy
2051e51764aSArtem Bityutskiy if (c->zroot.len < c->ranges[UBIFS_IDX_NODE].min_len ||
2061e51764aSArtem Bityutskiy c->zroot.len > c->ranges[UBIFS_IDX_NODE].max_len) {
2071e51764aSArtem Bityutskiy err = 6;
2081e51764aSArtem Bityutskiy goto out;
2091e51764aSArtem Bityutskiy }
2101e51764aSArtem Bityutskiy
2111e51764aSArtem Bityutskiy if (c->gc_lnum >= c->leb_cnt || c->gc_lnum < c->main_first) {
2121e51764aSArtem Bityutskiy err = 7;
2131e51764aSArtem Bityutskiy goto out;
2141e51764aSArtem Bityutskiy }
2151e51764aSArtem Bityutskiy
2161e51764aSArtem Bityutskiy if (c->ihead_lnum >= c->leb_cnt || c->ihead_lnum < c->main_first ||
2171e51764aSArtem Bityutskiy c->ihead_offs % c->min_io_size || c->ihead_offs < 0 ||
2181e51764aSArtem Bityutskiy c->ihead_offs > c->leb_size || c->ihead_offs & 7) {
2191e51764aSArtem Bityutskiy err = 8;
2201e51764aSArtem Bityutskiy goto out;
2211e51764aSArtem Bityutskiy }
2221e51764aSArtem Bityutskiy
2231e51764aSArtem Bityutskiy main_sz = (long long)c->main_lebs * c->leb_size;
224b137545cSArtem Bityutskiy if (c->bi.old_idx_sz & 7 || c->bi.old_idx_sz >= main_sz) {
2251e51764aSArtem Bityutskiy err = 9;
2261e51764aSArtem Bityutskiy goto out;
2271e51764aSArtem Bityutskiy }
2281e51764aSArtem Bityutskiy
2291e51764aSArtem Bityutskiy if (c->lpt_lnum < c->lpt_first || c->lpt_lnum > c->lpt_last ||
2301e51764aSArtem Bityutskiy c->lpt_offs < 0 || c->lpt_offs + c->nnode_sz > c->leb_size) {
2311e51764aSArtem Bityutskiy err = 10;
2321e51764aSArtem Bityutskiy goto out;
2331e51764aSArtem Bityutskiy }
2341e51764aSArtem Bityutskiy
2351e51764aSArtem Bityutskiy if (c->nhead_lnum < c->lpt_first || c->nhead_lnum > c->lpt_last ||
2361e51764aSArtem Bityutskiy c->nhead_offs < 0 || c->nhead_offs % c->min_io_size ||
2371e51764aSArtem Bityutskiy c->nhead_offs > c->leb_size) {
2381e51764aSArtem Bityutskiy err = 11;
2391e51764aSArtem Bityutskiy goto out;
2401e51764aSArtem Bityutskiy }
2411e51764aSArtem Bityutskiy
2421e51764aSArtem Bityutskiy if (c->ltab_lnum < c->lpt_first || c->ltab_lnum > c->lpt_last ||
2431e51764aSArtem Bityutskiy c->ltab_offs < 0 ||
2441e51764aSArtem Bityutskiy c->ltab_offs + c->ltab_sz > c->leb_size) {
2451e51764aSArtem Bityutskiy err = 12;
2461e51764aSArtem Bityutskiy goto out;
2471e51764aSArtem Bityutskiy }
2481e51764aSArtem Bityutskiy
2491e51764aSArtem Bityutskiy if (c->big_lpt && (c->lsave_lnum < c->lpt_first ||
2501e51764aSArtem Bityutskiy c->lsave_lnum > c->lpt_last || c->lsave_offs < 0 ||
2511e51764aSArtem Bityutskiy c->lsave_offs + c->lsave_sz > c->leb_size)) {
2521e51764aSArtem Bityutskiy err = 13;
2531e51764aSArtem Bityutskiy goto out;
2541e51764aSArtem Bityutskiy }
2551e51764aSArtem Bityutskiy
2561e51764aSArtem Bityutskiy if (c->lscan_lnum < c->main_first || c->lscan_lnum >= c->leb_cnt) {
2571e51764aSArtem Bityutskiy err = 14;
2581e51764aSArtem Bityutskiy goto out;
2591e51764aSArtem Bityutskiy }
2601e51764aSArtem Bityutskiy
2611e51764aSArtem Bityutskiy if (c->lst.empty_lebs < 0 || c->lst.empty_lebs > c->main_lebs - 2) {
2621e51764aSArtem Bityutskiy err = 15;
2631e51764aSArtem Bityutskiy goto out;
2641e51764aSArtem Bityutskiy }
2651e51764aSArtem Bityutskiy
2661e51764aSArtem Bityutskiy if (c->lst.idx_lebs < 0 || c->lst.idx_lebs > c->main_lebs - 1) {
2671e51764aSArtem Bityutskiy err = 16;
2681e51764aSArtem Bityutskiy goto out;
2691e51764aSArtem Bityutskiy }
2701e51764aSArtem Bityutskiy
2711e51764aSArtem Bityutskiy if (c->lst.total_free < 0 || c->lst.total_free > main_sz ||
2721e51764aSArtem Bityutskiy c->lst.total_free & 7) {
2731e51764aSArtem Bityutskiy err = 17;
2741e51764aSArtem Bityutskiy goto out;
2751e51764aSArtem Bityutskiy }
2761e51764aSArtem Bityutskiy
2771e51764aSArtem Bityutskiy if (c->lst.total_dirty < 0 || (c->lst.total_dirty & 7)) {
2781e51764aSArtem Bityutskiy err = 18;
2791e51764aSArtem Bityutskiy goto out;
2801e51764aSArtem Bityutskiy }
2811e51764aSArtem Bityutskiy
2821e51764aSArtem Bityutskiy if (c->lst.total_used < 0 || (c->lst.total_used & 7)) {
2831e51764aSArtem Bityutskiy err = 19;
2841e51764aSArtem Bityutskiy goto out;
2851e51764aSArtem Bityutskiy }
2861e51764aSArtem Bityutskiy
2871e51764aSArtem Bityutskiy if (c->lst.total_free + c->lst.total_dirty +
2881e51764aSArtem Bityutskiy c->lst.total_used > main_sz) {
2891e51764aSArtem Bityutskiy err = 20;
2901e51764aSArtem Bityutskiy goto out;
2911e51764aSArtem Bityutskiy }
2921e51764aSArtem Bityutskiy
2931e51764aSArtem Bityutskiy if (c->lst.total_dead + c->lst.total_dark +
294b137545cSArtem Bityutskiy c->lst.total_used + c->bi.old_idx_sz > main_sz) {
2951e51764aSArtem Bityutskiy err = 21;
2961e51764aSArtem Bityutskiy goto out;
2971e51764aSArtem Bityutskiy }
2981e51764aSArtem Bityutskiy
2991e51764aSArtem Bityutskiy if (c->lst.total_dead < 0 ||
3001e51764aSArtem Bityutskiy c->lst.total_dead > c->lst.total_free + c->lst.total_dirty ||
3011e51764aSArtem Bityutskiy c->lst.total_dead & 7) {
3021e51764aSArtem Bityutskiy err = 22;
3031e51764aSArtem Bityutskiy goto out;
3041e51764aSArtem Bityutskiy }
3051e51764aSArtem Bityutskiy
3061e51764aSArtem Bityutskiy if (c->lst.total_dark < 0 ||
3071e51764aSArtem Bityutskiy c->lst.total_dark > c->lst.total_free + c->lst.total_dirty ||
3081e51764aSArtem Bityutskiy c->lst.total_dark & 7) {
3091e51764aSArtem Bityutskiy err = 23;
3101e51764aSArtem Bityutskiy goto out;
3111e51764aSArtem Bityutskiy }
3121e51764aSArtem Bityutskiy
3131e51764aSArtem Bityutskiy return 0;
3141e51764aSArtem Bityutskiy
3151e51764aSArtem Bityutskiy out:
316235c362bSSheng Yong ubifs_err(c, "bad master node at offset %d error %d", c->mst_offs, err);
317*a33e30a0SZhihao Cheng ubifs_dump_node(c, c->mst_node, c->mst_node_alsz);
3181e51764aSArtem Bityutskiy return -EINVAL;
3191e51764aSArtem Bityutskiy }
3201e51764aSArtem Bityutskiy
3211e51764aSArtem Bityutskiy /**
3221e51764aSArtem Bityutskiy * ubifs_read_master - read master node.
3231e51764aSArtem Bityutskiy * @c: UBIFS file-system description object
3241e51764aSArtem Bityutskiy *
3251e51764aSArtem Bityutskiy * This function finds and reads the master node during file-system mount. If
3261e51764aSArtem Bityutskiy * the flash is empty, it creates default master node as well. Returns zero in
3271e51764aSArtem Bityutskiy * case of success and a negative error code in case of failure.
3281e51764aSArtem Bityutskiy */
ubifs_read_master(struct ubifs_info * c)3291e51764aSArtem Bityutskiy int ubifs_read_master(struct ubifs_info *c)
3301e51764aSArtem Bityutskiy {
3311e51764aSArtem Bityutskiy int err, old_leb_cnt;
3321e51764aSArtem Bityutskiy
3331e51764aSArtem Bityutskiy c->mst_node = kzalloc(c->mst_node_alsz, GFP_KERNEL);
3341e51764aSArtem Bityutskiy if (!c->mst_node)
3351e51764aSArtem Bityutskiy return -ENOMEM;
3361e51764aSArtem Bityutskiy
3371e51764aSArtem Bityutskiy err = scan_for_master(c);
3381e51764aSArtem Bityutskiy if (err) {
3390dcd18e4SArtem Bityutskiy if (err == -EUCLEAN)
3401e51764aSArtem Bityutskiy err = ubifs_recover_master_node(c);
3411e51764aSArtem Bityutskiy if (err)
3421e51764aSArtem Bityutskiy /*
3431e51764aSArtem Bityutskiy * Note, we do not free 'c->mst_node' here because the
3441e51764aSArtem Bityutskiy * unmount routine will take care of this.
3451e51764aSArtem Bityutskiy */
3461e51764aSArtem Bityutskiy return err;
3471e51764aSArtem Bityutskiy }
3481e51764aSArtem Bityutskiy
3491e51764aSArtem Bityutskiy /* Make sure that the recovery flag is clear */
3501e51764aSArtem Bityutskiy c->mst_node->flags &= cpu_to_le32(~UBIFS_MST_RCVRY);
3511e51764aSArtem Bityutskiy
3521e51764aSArtem Bityutskiy c->max_sqnum = le64_to_cpu(c->mst_node->ch.sqnum);
3531e51764aSArtem Bityutskiy c->highest_inum = le64_to_cpu(c->mst_node->highest_inum);
3541e51764aSArtem Bityutskiy c->cmt_no = le64_to_cpu(c->mst_node->cmt_no);
3551e51764aSArtem Bityutskiy c->zroot.lnum = le32_to_cpu(c->mst_node->root_lnum);
3561e51764aSArtem Bityutskiy c->zroot.offs = le32_to_cpu(c->mst_node->root_offs);
3571e51764aSArtem Bityutskiy c->zroot.len = le32_to_cpu(c->mst_node->root_len);
3581e51764aSArtem Bityutskiy c->lhead_lnum = le32_to_cpu(c->mst_node->log_lnum);
3591e51764aSArtem Bityutskiy c->gc_lnum = le32_to_cpu(c->mst_node->gc_lnum);
3601e51764aSArtem Bityutskiy c->ihead_lnum = le32_to_cpu(c->mst_node->ihead_lnum);
3611e51764aSArtem Bityutskiy c->ihead_offs = le32_to_cpu(c->mst_node->ihead_offs);
362b137545cSArtem Bityutskiy c->bi.old_idx_sz = le64_to_cpu(c->mst_node->index_size);
3631e51764aSArtem Bityutskiy c->lpt_lnum = le32_to_cpu(c->mst_node->lpt_lnum);
3641e51764aSArtem Bityutskiy c->lpt_offs = le32_to_cpu(c->mst_node->lpt_offs);
3651e51764aSArtem Bityutskiy c->nhead_lnum = le32_to_cpu(c->mst_node->nhead_lnum);
3661e51764aSArtem Bityutskiy c->nhead_offs = le32_to_cpu(c->mst_node->nhead_offs);
3671e51764aSArtem Bityutskiy c->ltab_lnum = le32_to_cpu(c->mst_node->ltab_lnum);
3681e51764aSArtem Bityutskiy c->ltab_offs = le32_to_cpu(c->mst_node->ltab_offs);
3691e51764aSArtem Bityutskiy c->lsave_lnum = le32_to_cpu(c->mst_node->lsave_lnum);
3701e51764aSArtem Bityutskiy c->lsave_offs = le32_to_cpu(c->mst_node->lsave_offs);
3711e51764aSArtem Bityutskiy c->lscan_lnum = le32_to_cpu(c->mst_node->lscan_lnum);
3721e51764aSArtem Bityutskiy c->lst.empty_lebs = le32_to_cpu(c->mst_node->empty_lebs);
3731e51764aSArtem Bityutskiy c->lst.idx_lebs = le32_to_cpu(c->mst_node->idx_lebs);
3741e51764aSArtem Bityutskiy old_leb_cnt = le32_to_cpu(c->mst_node->leb_cnt);
3751e51764aSArtem Bityutskiy c->lst.total_free = le64_to_cpu(c->mst_node->total_free);
3761e51764aSArtem Bityutskiy c->lst.total_dirty = le64_to_cpu(c->mst_node->total_dirty);
3771e51764aSArtem Bityutskiy c->lst.total_used = le64_to_cpu(c->mst_node->total_used);
3781e51764aSArtem Bityutskiy c->lst.total_dead = le64_to_cpu(c->mst_node->total_dead);
3791e51764aSArtem Bityutskiy c->lst.total_dark = le64_to_cpu(c->mst_node->total_dark);
3801e51764aSArtem Bityutskiy
38116a26b20SSascha Hauer ubifs_copy_hash(c, c->mst_node->hash_root_idx, c->zroot.hash);
38216a26b20SSascha Hauer
383b137545cSArtem Bityutskiy c->calc_idx_sz = c->bi.old_idx_sz;
3841e51764aSArtem Bityutskiy
3851e51764aSArtem Bityutskiy if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS))
3861e51764aSArtem Bityutskiy c->no_orphs = 1;
3871e51764aSArtem Bityutskiy
3881e51764aSArtem Bityutskiy if (old_leb_cnt != c->leb_cnt) {
3891e51764aSArtem Bityutskiy /* The file system has been resized */
3901e51764aSArtem Bityutskiy int growth = c->leb_cnt - old_leb_cnt;
3911e51764aSArtem Bityutskiy
3921e51764aSArtem Bityutskiy if (c->leb_cnt < old_leb_cnt ||
3931e51764aSArtem Bityutskiy c->leb_cnt < UBIFS_MIN_LEB_CNT) {
394235c362bSSheng Yong ubifs_err(c, "bad leb_cnt on master node");
395*a33e30a0SZhihao Cheng ubifs_dump_node(c, c->mst_node, c->mst_node_alsz);
3961e51764aSArtem Bityutskiy return -EINVAL;
3971e51764aSArtem Bityutskiy }
3981e51764aSArtem Bityutskiy
3991e51764aSArtem Bityutskiy dbg_mnt("Auto resizing (master) from %d LEBs to %d LEBs",
4001e51764aSArtem Bityutskiy old_leb_cnt, c->leb_cnt);
4011e51764aSArtem Bityutskiy c->lst.empty_lebs += growth;
4021e51764aSArtem Bityutskiy c->lst.total_free += growth * (long long)c->leb_size;
4031e51764aSArtem Bityutskiy c->lst.total_dark += growth * (long long)c->dark_wm;
4041e51764aSArtem Bityutskiy
4051e51764aSArtem Bityutskiy /*
4061e51764aSArtem Bityutskiy * Reflect changes back onto the master node. N.B. the master
4071e51764aSArtem Bityutskiy * node gets written immediately whenever mounting (or
4081e51764aSArtem Bityutskiy * remounting) in read-write mode, so we do not need to write it
4091e51764aSArtem Bityutskiy * here.
4101e51764aSArtem Bityutskiy */
4111e51764aSArtem Bityutskiy c->mst_node->leb_cnt = cpu_to_le32(c->leb_cnt);
4121e51764aSArtem Bityutskiy c->mst_node->empty_lebs = cpu_to_le32(c->lst.empty_lebs);
4131e51764aSArtem Bityutskiy c->mst_node->total_free = cpu_to_le64(c->lst.total_free);
4141e51764aSArtem Bityutskiy c->mst_node->total_dark = cpu_to_le64(c->lst.total_dark);
4151e51764aSArtem Bityutskiy }
4161e51764aSArtem Bityutskiy
4171e51764aSArtem Bityutskiy err = validate_master(c);
4181e51764aSArtem Bityutskiy if (err)
4191e51764aSArtem Bityutskiy return err;
4201e51764aSArtem Bityutskiy
4211e51764aSArtem Bityutskiy err = dbg_old_index_check_init(c, &c->zroot);
4221e51764aSArtem Bityutskiy
4231e51764aSArtem Bityutskiy return err;
4241e51764aSArtem Bityutskiy }
4251e51764aSArtem Bityutskiy
4261e51764aSArtem Bityutskiy /**
4271e51764aSArtem Bityutskiy * ubifs_write_master - write master node.
4281e51764aSArtem Bityutskiy * @c: UBIFS file-system description object
4291e51764aSArtem Bityutskiy *
43007e19dffSArtem Bityutskiy * This function writes the master node. Returns zero in case of success and a
43107e19dffSArtem Bityutskiy * negative error code in case of failure. The master node is written twice to
43207e19dffSArtem Bityutskiy * enable recovery.
4331e51764aSArtem Bityutskiy */
ubifs_write_master(struct ubifs_info * c)4341e51764aSArtem Bityutskiy int ubifs_write_master(struct ubifs_info *c)
4351e51764aSArtem Bityutskiy {
4361e51764aSArtem Bityutskiy int err, lnum, offs, len;
4371e51764aSArtem Bityutskiy
4386eb61d58SRichard Weinberger ubifs_assert(c, !c->ro_media && !c->ro_mount);
4392680d722SArtem Bityutskiy if (c->ro_error)
440a2b9df3fSArtem Bityutskiy return -EROFS;
4411e51764aSArtem Bityutskiy
4421e51764aSArtem Bityutskiy lnum = UBIFS_MST_LNUM;
4431e51764aSArtem Bityutskiy offs = c->mst_offs + c->mst_node_alsz;
4441e51764aSArtem Bityutskiy len = UBIFS_MST_NODE_SZ;
4451e51764aSArtem Bityutskiy
4461e51764aSArtem Bityutskiy if (offs + UBIFS_MST_NODE_SZ > c->leb_size) {
4471e51764aSArtem Bityutskiy err = ubifs_leb_unmap(c, lnum);
4481e51764aSArtem Bityutskiy if (err)
4491e51764aSArtem Bityutskiy return err;
4501e51764aSArtem Bityutskiy offs = 0;
4511e51764aSArtem Bityutskiy }
4521e51764aSArtem Bityutskiy
4531e51764aSArtem Bityutskiy c->mst_offs = offs;
4541e51764aSArtem Bityutskiy c->mst_node->highest_inum = cpu_to_le64(c->highest_inum);
4551e51764aSArtem Bityutskiy
45616a26b20SSascha Hauer ubifs_copy_hash(c, c->zroot.hash, c->mst_node->hash_root_idx);
457625700ccSSascha Hauer err = ubifs_write_node_hmac(c, c->mst_node, len, lnum, offs,
458625700ccSSascha Hauer offsetof(struct ubifs_mst_node, hmac));
4591e51764aSArtem Bityutskiy if (err)
4601e51764aSArtem Bityutskiy return err;
4611e51764aSArtem Bityutskiy
4621e51764aSArtem Bityutskiy lnum += 1;
4631e51764aSArtem Bityutskiy
4641e51764aSArtem Bityutskiy if (offs == 0) {
4651e51764aSArtem Bityutskiy err = ubifs_leb_unmap(c, lnum);
4661e51764aSArtem Bityutskiy if (err)
4671e51764aSArtem Bityutskiy return err;
4681e51764aSArtem Bityutskiy }
469625700ccSSascha Hauer err = ubifs_write_node_hmac(c, c->mst_node, len, lnum, offs,
470625700ccSSascha Hauer offsetof(struct ubifs_mst_node, hmac));
4711e51764aSArtem Bityutskiy
4721e51764aSArtem Bityutskiy return err;
4731e51764aSArtem Bityutskiy }
474