18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This file is part of UBIFS. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2006-2008 Nokia Corporation. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: Artem Bityutskiy (Битюцкий Артём) 88c2ecf20Sopenharmony_ci * Adrian Hunter 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci/* This file implements reading and writing the master node */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "ubifs.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/** 168c2ecf20Sopenharmony_ci * ubifs_compare_master_node - compare two UBIFS master nodes 178c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 188c2ecf20Sopenharmony_ci * @m1: the first node 198c2ecf20Sopenharmony_ci * @m2: the second node 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * This function compares two UBIFS master nodes. Returns 0 if they are equal 228c2ecf20Sopenharmony_ci * and nonzero if not. 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ciint ubifs_compare_master_node(struct ubifs_info *c, void *m1, void *m2) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci int ret; 278c2ecf20Sopenharmony_ci int behind; 288c2ecf20Sopenharmony_ci int hmac_offs = offsetof(struct ubifs_mst_node, hmac); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci /* 318c2ecf20Sopenharmony_ci * Do not compare the common node header since the sequence number and 328c2ecf20Sopenharmony_ci * hence the CRC are different. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci ret = memcmp(m1 + UBIFS_CH_SZ, m2 + UBIFS_CH_SZ, 358c2ecf20Sopenharmony_ci hmac_offs - UBIFS_CH_SZ); 368c2ecf20Sopenharmony_ci if (ret) 378c2ecf20Sopenharmony_ci return ret; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci /* 408c2ecf20Sopenharmony_ci * Do not compare the embedded HMAC aswell which also must be different 418c2ecf20Sopenharmony_ci * due to the different common node header. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_ci behind = hmac_offs + UBIFS_MAX_HMAC_LEN; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci if (UBIFS_MST_NODE_SZ > behind) 468c2ecf20Sopenharmony_ci return memcmp(m1 + behind, m2 + behind, UBIFS_MST_NODE_SZ - behind); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci return 0; 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* mst_node_check_hash - Check hash of a master node 528c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 538c2ecf20Sopenharmony_ci * @mst: The master node 548c2ecf20Sopenharmony_ci * @expected: The expected hash of the master node 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * This checks the hash of a master node against a given expected hash. 578c2ecf20Sopenharmony_ci * Note that we have two master nodes on a UBIFS image which have different 588c2ecf20Sopenharmony_ci * sequence numbers and consequently different CRCs. To be able to match 598c2ecf20Sopenharmony_ci * both master nodes we exclude the common node header containing the sequence 608c2ecf20Sopenharmony_ci * number and CRC from the hash. 618c2ecf20Sopenharmony_ci * 628c2ecf20Sopenharmony_ci * Returns 0 if the hashes are equal, a negative error code otherwise. 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_cistatic int mst_node_check_hash(const struct ubifs_info *c, 658c2ecf20Sopenharmony_ci const struct ubifs_mst_node *mst, 668c2ecf20Sopenharmony_ci const u8 *expected) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci u8 calc[UBIFS_MAX_HASH_LEN]; 698c2ecf20Sopenharmony_ci const void *node = mst; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci crypto_shash_tfm_digest(c->hash_tfm, node + sizeof(struct ubifs_ch), 728c2ecf20Sopenharmony_ci UBIFS_MST_NODE_SZ - sizeof(struct ubifs_ch), 738c2ecf20Sopenharmony_ci calc); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (ubifs_check_hash(c, expected, calc)) 768c2ecf20Sopenharmony_ci return -EPERM; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return 0; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/** 828c2ecf20Sopenharmony_ci * scan_for_master - search the valid master node. 838c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 848c2ecf20Sopenharmony_ci * 858c2ecf20Sopenharmony_ci * This function scans the master node LEBs and search for the latest master 868c2ecf20Sopenharmony_ci * node. Returns zero in case of success, %-EUCLEAN if there master area is 878c2ecf20Sopenharmony_ci * corrupted and requires recovery, and a negative error code in case of 888c2ecf20Sopenharmony_ci * failure. 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_cistatic int scan_for_master(struct ubifs_info *c) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci struct ubifs_scan_leb *sleb; 938c2ecf20Sopenharmony_ci struct ubifs_scan_node *snod; 948c2ecf20Sopenharmony_ci int lnum, offs = 0, nodes_cnt, err; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci lnum = UBIFS_MST_LNUM; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1); 998c2ecf20Sopenharmony_ci if (IS_ERR(sleb)) 1008c2ecf20Sopenharmony_ci return PTR_ERR(sleb); 1018c2ecf20Sopenharmony_ci nodes_cnt = sleb->nodes_cnt; 1028c2ecf20Sopenharmony_ci if (nodes_cnt > 0) { 1038c2ecf20Sopenharmony_ci snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node, 1048c2ecf20Sopenharmony_ci list); 1058c2ecf20Sopenharmony_ci if (snod->type != UBIFS_MST_NODE) 1068c2ecf20Sopenharmony_ci goto out_dump; 1078c2ecf20Sopenharmony_ci memcpy(c->mst_node, snod->node, snod->len); 1088c2ecf20Sopenharmony_ci offs = snod->offs; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci ubifs_scan_destroy(sleb); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci lnum += 1; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1); 1158c2ecf20Sopenharmony_ci if (IS_ERR(sleb)) 1168c2ecf20Sopenharmony_ci return PTR_ERR(sleb); 1178c2ecf20Sopenharmony_ci if (sleb->nodes_cnt != nodes_cnt) 1188c2ecf20Sopenharmony_ci goto out; 1198c2ecf20Sopenharmony_ci if (!sleb->nodes_cnt) 1208c2ecf20Sopenharmony_ci goto out; 1218c2ecf20Sopenharmony_ci snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node, list); 1228c2ecf20Sopenharmony_ci if (snod->type != UBIFS_MST_NODE) 1238c2ecf20Sopenharmony_ci goto out_dump; 1248c2ecf20Sopenharmony_ci if (snod->offs != offs) 1258c2ecf20Sopenharmony_ci goto out; 1268c2ecf20Sopenharmony_ci if (ubifs_compare_master_node(c, c->mst_node, snod->node)) 1278c2ecf20Sopenharmony_ci goto out; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci c->mst_offs = offs; 1308c2ecf20Sopenharmony_ci ubifs_scan_destroy(sleb); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (!ubifs_authenticated(c)) 1338c2ecf20Sopenharmony_ci return 0; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (ubifs_hmac_zero(c, c->mst_node->hmac)) { 1368c2ecf20Sopenharmony_ci err = mst_node_check_hash(c, c->mst_node, 1378c2ecf20Sopenharmony_ci c->sup_node->hash_mst); 1388c2ecf20Sopenharmony_ci if (err) 1398c2ecf20Sopenharmony_ci ubifs_err(c, "Failed to verify master node hash"); 1408c2ecf20Sopenharmony_ci } else { 1418c2ecf20Sopenharmony_ci err = ubifs_node_verify_hmac(c, c->mst_node, 1428c2ecf20Sopenharmony_ci sizeof(struct ubifs_mst_node), 1438c2ecf20Sopenharmony_ci offsetof(struct ubifs_mst_node, hmac)); 1448c2ecf20Sopenharmony_ci if (err) 1458c2ecf20Sopenharmony_ci ubifs_err(c, "Failed to verify master node HMAC"); 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (err) 1498c2ecf20Sopenharmony_ci return -EPERM; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci return 0; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ciout: 1548c2ecf20Sopenharmony_ci ubifs_scan_destroy(sleb); 1558c2ecf20Sopenharmony_ci return -EUCLEAN; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ciout_dump: 1588c2ecf20Sopenharmony_ci ubifs_err(c, "unexpected node type %d master LEB %d:%d", 1598c2ecf20Sopenharmony_ci snod->type, lnum, snod->offs); 1608c2ecf20Sopenharmony_ci ubifs_scan_destroy(sleb); 1618c2ecf20Sopenharmony_ci return -EINVAL; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/** 1658c2ecf20Sopenharmony_ci * validate_master - validate master node. 1668c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 1678c2ecf20Sopenharmony_ci * 1688c2ecf20Sopenharmony_ci * This function validates data which was read from master node. Returns zero 1698c2ecf20Sopenharmony_ci * if the data is all right and %-EINVAL if not. 1708c2ecf20Sopenharmony_ci */ 1718c2ecf20Sopenharmony_cistatic int validate_master(const struct ubifs_info *c) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci long long main_sz; 1748c2ecf20Sopenharmony_ci int err; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci if (c->max_sqnum >= SQNUM_WATERMARK) { 1778c2ecf20Sopenharmony_ci err = 1; 1788c2ecf20Sopenharmony_ci goto out; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (c->cmt_no >= c->max_sqnum) { 1828c2ecf20Sopenharmony_ci err = 2; 1838c2ecf20Sopenharmony_ci goto out; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (c->highest_inum >= INUM_WATERMARK) { 1878c2ecf20Sopenharmony_ci err = 3; 1888c2ecf20Sopenharmony_ci goto out; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (c->lhead_lnum < UBIFS_LOG_LNUM || 1928c2ecf20Sopenharmony_ci c->lhead_lnum >= UBIFS_LOG_LNUM + c->log_lebs || 1938c2ecf20Sopenharmony_ci c->lhead_offs < 0 || c->lhead_offs >= c->leb_size || 1948c2ecf20Sopenharmony_ci c->lhead_offs & (c->min_io_size - 1)) { 1958c2ecf20Sopenharmony_ci err = 4; 1968c2ecf20Sopenharmony_ci goto out; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (c->zroot.lnum >= c->leb_cnt || c->zroot.lnum < c->main_first || 2008c2ecf20Sopenharmony_ci c->zroot.offs >= c->leb_size || c->zroot.offs & 7) { 2018c2ecf20Sopenharmony_ci err = 5; 2028c2ecf20Sopenharmony_ci goto out; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (c->zroot.len < c->ranges[UBIFS_IDX_NODE].min_len || 2068c2ecf20Sopenharmony_ci c->zroot.len > c->ranges[UBIFS_IDX_NODE].max_len) { 2078c2ecf20Sopenharmony_ci err = 6; 2088c2ecf20Sopenharmony_ci goto out; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (c->gc_lnum >= c->leb_cnt || c->gc_lnum < c->main_first) { 2128c2ecf20Sopenharmony_ci err = 7; 2138c2ecf20Sopenharmony_ci goto out; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (c->ihead_lnum >= c->leb_cnt || c->ihead_lnum < c->main_first || 2178c2ecf20Sopenharmony_ci c->ihead_offs % c->min_io_size || c->ihead_offs < 0 || 2188c2ecf20Sopenharmony_ci c->ihead_offs > c->leb_size || c->ihead_offs & 7) { 2198c2ecf20Sopenharmony_ci err = 8; 2208c2ecf20Sopenharmony_ci goto out; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci main_sz = (long long)c->main_lebs * c->leb_size; 2248c2ecf20Sopenharmony_ci if (c->bi.old_idx_sz & 7 || c->bi.old_idx_sz >= main_sz) { 2258c2ecf20Sopenharmony_ci err = 9; 2268c2ecf20Sopenharmony_ci goto out; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (c->lpt_lnum < c->lpt_first || c->lpt_lnum > c->lpt_last || 2308c2ecf20Sopenharmony_ci c->lpt_offs < 0 || c->lpt_offs + c->nnode_sz > c->leb_size) { 2318c2ecf20Sopenharmony_ci err = 10; 2328c2ecf20Sopenharmony_ci goto out; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (c->nhead_lnum < c->lpt_first || c->nhead_lnum > c->lpt_last || 2368c2ecf20Sopenharmony_ci c->nhead_offs < 0 || c->nhead_offs % c->min_io_size || 2378c2ecf20Sopenharmony_ci c->nhead_offs > c->leb_size) { 2388c2ecf20Sopenharmony_ci err = 11; 2398c2ecf20Sopenharmony_ci goto out; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (c->ltab_lnum < c->lpt_first || c->ltab_lnum > c->lpt_last || 2438c2ecf20Sopenharmony_ci c->ltab_offs < 0 || 2448c2ecf20Sopenharmony_ci c->ltab_offs + c->ltab_sz > c->leb_size) { 2458c2ecf20Sopenharmony_ci err = 12; 2468c2ecf20Sopenharmony_ci goto out; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (c->big_lpt && (c->lsave_lnum < c->lpt_first || 2508c2ecf20Sopenharmony_ci c->lsave_lnum > c->lpt_last || c->lsave_offs < 0 || 2518c2ecf20Sopenharmony_ci c->lsave_offs + c->lsave_sz > c->leb_size)) { 2528c2ecf20Sopenharmony_ci err = 13; 2538c2ecf20Sopenharmony_ci goto out; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (c->lscan_lnum < c->main_first || c->lscan_lnum >= c->leb_cnt) { 2578c2ecf20Sopenharmony_ci err = 14; 2588c2ecf20Sopenharmony_ci goto out; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (c->lst.empty_lebs < 0 || c->lst.empty_lebs > c->main_lebs - 2) { 2628c2ecf20Sopenharmony_ci err = 15; 2638c2ecf20Sopenharmony_ci goto out; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (c->lst.idx_lebs < 0 || c->lst.idx_lebs > c->main_lebs - 1) { 2678c2ecf20Sopenharmony_ci err = 16; 2688c2ecf20Sopenharmony_ci goto out; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (c->lst.total_free < 0 || c->lst.total_free > main_sz || 2728c2ecf20Sopenharmony_ci c->lst.total_free & 7) { 2738c2ecf20Sopenharmony_ci err = 17; 2748c2ecf20Sopenharmony_ci goto out; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (c->lst.total_dirty < 0 || (c->lst.total_dirty & 7)) { 2788c2ecf20Sopenharmony_ci err = 18; 2798c2ecf20Sopenharmony_ci goto out; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (c->lst.total_used < 0 || (c->lst.total_used & 7)) { 2838c2ecf20Sopenharmony_ci err = 19; 2848c2ecf20Sopenharmony_ci goto out; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (c->lst.total_free + c->lst.total_dirty + 2888c2ecf20Sopenharmony_ci c->lst.total_used > main_sz) { 2898c2ecf20Sopenharmony_ci err = 20; 2908c2ecf20Sopenharmony_ci goto out; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (c->lst.total_dead + c->lst.total_dark + 2948c2ecf20Sopenharmony_ci c->lst.total_used + c->bi.old_idx_sz > main_sz) { 2958c2ecf20Sopenharmony_ci err = 21; 2968c2ecf20Sopenharmony_ci goto out; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (c->lst.total_dead < 0 || 3008c2ecf20Sopenharmony_ci c->lst.total_dead > c->lst.total_free + c->lst.total_dirty || 3018c2ecf20Sopenharmony_ci c->lst.total_dead & 7) { 3028c2ecf20Sopenharmony_ci err = 22; 3038c2ecf20Sopenharmony_ci goto out; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (c->lst.total_dark < 0 || 3078c2ecf20Sopenharmony_ci c->lst.total_dark > c->lst.total_free + c->lst.total_dirty || 3088c2ecf20Sopenharmony_ci c->lst.total_dark & 7) { 3098c2ecf20Sopenharmony_ci err = 23; 3108c2ecf20Sopenharmony_ci goto out; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci return 0; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ciout: 3168c2ecf20Sopenharmony_ci ubifs_err(c, "bad master node at offset %d error %d", c->mst_offs, err); 3178c2ecf20Sopenharmony_ci ubifs_dump_node(c, c->mst_node, c->mst_node_alsz); 3188c2ecf20Sopenharmony_ci return -EINVAL; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci/** 3228c2ecf20Sopenharmony_ci * ubifs_read_master - read master node. 3238c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 3248c2ecf20Sopenharmony_ci * 3258c2ecf20Sopenharmony_ci * This function finds and reads the master node during file-system mount. If 3268c2ecf20Sopenharmony_ci * the flash is empty, it creates default master node as well. Returns zero in 3278c2ecf20Sopenharmony_ci * case of success and a negative error code in case of failure. 3288c2ecf20Sopenharmony_ci */ 3298c2ecf20Sopenharmony_ciint ubifs_read_master(struct ubifs_info *c) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci int err, old_leb_cnt; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci c->mst_node = kzalloc(c->mst_node_alsz, GFP_KERNEL); 3348c2ecf20Sopenharmony_ci if (!c->mst_node) 3358c2ecf20Sopenharmony_ci return -ENOMEM; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci err = scan_for_master(c); 3388c2ecf20Sopenharmony_ci if (err) { 3398c2ecf20Sopenharmony_ci if (err == -EUCLEAN) 3408c2ecf20Sopenharmony_ci err = ubifs_recover_master_node(c); 3418c2ecf20Sopenharmony_ci if (err) 3428c2ecf20Sopenharmony_ci /* 3438c2ecf20Sopenharmony_ci * Note, we do not free 'c->mst_node' here because the 3448c2ecf20Sopenharmony_ci * unmount routine will take care of this. 3458c2ecf20Sopenharmony_ci */ 3468c2ecf20Sopenharmony_ci return err; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /* Make sure that the recovery flag is clear */ 3508c2ecf20Sopenharmony_ci c->mst_node->flags &= cpu_to_le32(~UBIFS_MST_RCVRY); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci c->max_sqnum = le64_to_cpu(c->mst_node->ch.sqnum); 3538c2ecf20Sopenharmony_ci c->highest_inum = le64_to_cpu(c->mst_node->highest_inum); 3548c2ecf20Sopenharmony_ci c->cmt_no = le64_to_cpu(c->mst_node->cmt_no); 3558c2ecf20Sopenharmony_ci c->zroot.lnum = le32_to_cpu(c->mst_node->root_lnum); 3568c2ecf20Sopenharmony_ci c->zroot.offs = le32_to_cpu(c->mst_node->root_offs); 3578c2ecf20Sopenharmony_ci c->zroot.len = le32_to_cpu(c->mst_node->root_len); 3588c2ecf20Sopenharmony_ci c->lhead_lnum = le32_to_cpu(c->mst_node->log_lnum); 3598c2ecf20Sopenharmony_ci c->gc_lnum = le32_to_cpu(c->mst_node->gc_lnum); 3608c2ecf20Sopenharmony_ci c->ihead_lnum = le32_to_cpu(c->mst_node->ihead_lnum); 3618c2ecf20Sopenharmony_ci c->ihead_offs = le32_to_cpu(c->mst_node->ihead_offs); 3628c2ecf20Sopenharmony_ci c->bi.old_idx_sz = le64_to_cpu(c->mst_node->index_size); 3638c2ecf20Sopenharmony_ci c->lpt_lnum = le32_to_cpu(c->mst_node->lpt_lnum); 3648c2ecf20Sopenharmony_ci c->lpt_offs = le32_to_cpu(c->mst_node->lpt_offs); 3658c2ecf20Sopenharmony_ci c->nhead_lnum = le32_to_cpu(c->mst_node->nhead_lnum); 3668c2ecf20Sopenharmony_ci c->nhead_offs = le32_to_cpu(c->mst_node->nhead_offs); 3678c2ecf20Sopenharmony_ci c->ltab_lnum = le32_to_cpu(c->mst_node->ltab_lnum); 3688c2ecf20Sopenharmony_ci c->ltab_offs = le32_to_cpu(c->mst_node->ltab_offs); 3698c2ecf20Sopenharmony_ci c->lsave_lnum = le32_to_cpu(c->mst_node->lsave_lnum); 3708c2ecf20Sopenharmony_ci c->lsave_offs = le32_to_cpu(c->mst_node->lsave_offs); 3718c2ecf20Sopenharmony_ci c->lscan_lnum = le32_to_cpu(c->mst_node->lscan_lnum); 3728c2ecf20Sopenharmony_ci c->lst.empty_lebs = le32_to_cpu(c->mst_node->empty_lebs); 3738c2ecf20Sopenharmony_ci c->lst.idx_lebs = le32_to_cpu(c->mst_node->idx_lebs); 3748c2ecf20Sopenharmony_ci old_leb_cnt = le32_to_cpu(c->mst_node->leb_cnt); 3758c2ecf20Sopenharmony_ci c->lst.total_free = le64_to_cpu(c->mst_node->total_free); 3768c2ecf20Sopenharmony_ci c->lst.total_dirty = le64_to_cpu(c->mst_node->total_dirty); 3778c2ecf20Sopenharmony_ci c->lst.total_used = le64_to_cpu(c->mst_node->total_used); 3788c2ecf20Sopenharmony_ci c->lst.total_dead = le64_to_cpu(c->mst_node->total_dead); 3798c2ecf20Sopenharmony_ci c->lst.total_dark = le64_to_cpu(c->mst_node->total_dark); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci ubifs_copy_hash(c, c->mst_node->hash_root_idx, c->zroot.hash); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci c->calc_idx_sz = c->bi.old_idx_sz; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS)) 3868c2ecf20Sopenharmony_ci c->no_orphs = 1; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (old_leb_cnt != c->leb_cnt) { 3898c2ecf20Sopenharmony_ci /* The file system has been resized */ 3908c2ecf20Sopenharmony_ci int growth = c->leb_cnt - old_leb_cnt; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (c->leb_cnt < old_leb_cnt || 3938c2ecf20Sopenharmony_ci c->leb_cnt < UBIFS_MIN_LEB_CNT) { 3948c2ecf20Sopenharmony_ci ubifs_err(c, "bad leb_cnt on master node"); 3958c2ecf20Sopenharmony_ci ubifs_dump_node(c, c->mst_node, c->mst_node_alsz); 3968c2ecf20Sopenharmony_ci return -EINVAL; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci dbg_mnt("Auto resizing (master) from %d LEBs to %d LEBs", 4008c2ecf20Sopenharmony_ci old_leb_cnt, c->leb_cnt); 4018c2ecf20Sopenharmony_ci c->lst.empty_lebs += growth; 4028c2ecf20Sopenharmony_ci c->lst.total_free += growth * (long long)c->leb_size; 4038c2ecf20Sopenharmony_ci c->lst.total_dark += growth * (long long)c->dark_wm; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci /* 4068c2ecf20Sopenharmony_ci * Reflect changes back onto the master node. N.B. the master 4078c2ecf20Sopenharmony_ci * node gets written immediately whenever mounting (or 4088c2ecf20Sopenharmony_ci * remounting) in read-write mode, so we do not need to write it 4098c2ecf20Sopenharmony_ci * here. 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_ci c->mst_node->leb_cnt = cpu_to_le32(c->leb_cnt); 4128c2ecf20Sopenharmony_ci c->mst_node->empty_lebs = cpu_to_le32(c->lst.empty_lebs); 4138c2ecf20Sopenharmony_ci c->mst_node->total_free = cpu_to_le64(c->lst.total_free); 4148c2ecf20Sopenharmony_ci c->mst_node->total_dark = cpu_to_le64(c->lst.total_dark); 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci err = validate_master(c); 4188c2ecf20Sopenharmony_ci if (err) 4198c2ecf20Sopenharmony_ci return err; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci err = dbg_old_index_check_init(c, &c->zroot); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci return err; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci/** 4278c2ecf20Sopenharmony_ci * ubifs_write_master - write master node. 4288c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 4298c2ecf20Sopenharmony_ci * 4308c2ecf20Sopenharmony_ci * This function writes the master node. Returns zero in case of success and a 4318c2ecf20Sopenharmony_ci * negative error code in case of failure. The master node is written twice to 4328c2ecf20Sopenharmony_ci * enable recovery. 4338c2ecf20Sopenharmony_ci */ 4348c2ecf20Sopenharmony_ciint ubifs_write_master(struct ubifs_info *c) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci int err, lnum, offs, len; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci ubifs_assert(c, !c->ro_media && !c->ro_mount); 4398c2ecf20Sopenharmony_ci if (c->ro_error) 4408c2ecf20Sopenharmony_ci return -EROFS; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci lnum = UBIFS_MST_LNUM; 4438c2ecf20Sopenharmony_ci offs = c->mst_offs + c->mst_node_alsz; 4448c2ecf20Sopenharmony_ci len = UBIFS_MST_NODE_SZ; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (offs + UBIFS_MST_NODE_SZ > c->leb_size) { 4478c2ecf20Sopenharmony_ci err = ubifs_leb_unmap(c, lnum); 4488c2ecf20Sopenharmony_ci if (err) 4498c2ecf20Sopenharmony_ci return err; 4508c2ecf20Sopenharmony_ci offs = 0; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci c->mst_offs = offs; 4548c2ecf20Sopenharmony_ci c->mst_node->highest_inum = cpu_to_le64(c->highest_inum); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci ubifs_copy_hash(c, c->zroot.hash, c->mst_node->hash_root_idx); 4578c2ecf20Sopenharmony_ci err = ubifs_write_node_hmac(c, c->mst_node, len, lnum, offs, 4588c2ecf20Sopenharmony_ci offsetof(struct ubifs_mst_node, hmac)); 4598c2ecf20Sopenharmony_ci if (err) 4608c2ecf20Sopenharmony_ci return err; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci lnum += 1; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (offs == 0) { 4658c2ecf20Sopenharmony_ci err = ubifs_leb_unmap(c, lnum); 4668c2ecf20Sopenharmony_ci if (err) 4678c2ecf20Sopenharmony_ci return err; 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci err = ubifs_write_node_hmac(c, c->mst_node, len, lnum, offs, 4708c2ecf20Sopenharmony_ci offsetof(struct ubifs_mst_node, hmac)); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci return err; 4738c2ecf20Sopenharmony_ci} 474