xref: /openbmc/u-boot/fs/ubifs/master.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
29eefe2a2SStefan Roese /*
39eefe2a2SStefan Roese  * This file is part of UBIFS.
49eefe2a2SStefan Roese  *
59eefe2a2SStefan Roese  * Copyright (C) 2006-2008 Nokia Corporation.
69eefe2a2SStefan Roese  *
79eefe2a2SStefan Roese  * Authors: Artem Bityutskiy (Битюцкий Артём)
89eefe2a2SStefan Roese  *          Adrian Hunter
99eefe2a2SStefan Roese  */
109eefe2a2SStefan Roese 
119eefe2a2SStefan Roese /* This file implements reading and writing the master node */
129eefe2a2SStefan Roese 
139eefe2a2SStefan Roese #include "ubifs.h"
14ff94bc40SHeiko Schocher #ifdef __UBOOT__
15ff94bc40SHeiko Schocher #include <linux/compat.h>
16ff94bc40SHeiko Schocher #include <linux/err.h>
17ff94bc40SHeiko Schocher #include <ubi_uboot.h>
18ff94bc40SHeiko Schocher #endif
199eefe2a2SStefan Roese 
209eefe2a2SStefan Roese /**
219eefe2a2SStefan Roese  * scan_for_master - search the valid master node.
229eefe2a2SStefan Roese  * @c: UBIFS file-system description object
239eefe2a2SStefan Roese  *
249eefe2a2SStefan Roese  * This function scans the master node LEBs and search for the latest master
25ff94bc40SHeiko Schocher  * node. Returns zero in case of success, %-EUCLEAN if there master area is
26ff94bc40SHeiko Schocher  * corrupted and requires recovery, and a negative error code in case of
279eefe2a2SStefan Roese  * failure.
289eefe2a2SStefan Roese  */
scan_for_master(struct ubifs_info * c)299eefe2a2SStefan Roese static int scan_for_master(struct ubifs_info *c)
309eefe2a2SStefan Roese {
319eefe2a2SStefan Roese 	struct ubifs_scan_leb *sleb;
329eefe2a2SStefan Roese 	struct ubifs_scan_node *snod;
339eefe2a2SStefan Roese 	int lnum, offs = 0, nodes_cnt;
349eefe2a2SStefan Roese 
359eefe2a2SStefan Roese 	lnum = UBIFS_MST_LNUM;
369eefe2a2SStefan Roese 
37ff94bc40SHeiko Schocher 	sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1);
389eefe2a2SStefan Roese 	if (IS_ERR(sleb))
399eefe2a2SStefan Roese 		return PTR_ERR(sleb);
409eefe2a2SStefan Roese 	nodes_cnt = sleb->nodes_cnt;
419eefe2a2SStefan Roese 	if (nodes_cnt > 0) {
429eefe2a2SStefan Roese 		snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node,
439eefe2a2SStefan Roese 				  list);
449eefe2a2SStefan Roese 		if (snod->type != UBIFS_MST_NODE)
45ff94bc40SHeiko Schocher 			goto out_dump;
469eefe2a2SStefan Roese 		memcpy(c->mst_node, snod->node, snod->len);
479eefe2a2SStefan Roese 		offs = snod->offs;
489eefe2a2SStefan Roese 	}
499eefe2a2SStefan Roese 	ubifs_scan_destroy(sleb);
509eefe2a2SStefan Roese 
519eefe2a2SStefan Roese 	lnum += 1;
529eefe2a2SStefan Roese 
53ff94bc40SHeiko Schocher 	sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1);
549eefe2a2SStefan Roese 	if (IS_ERR(sleb))
559eefe2a2SStefan Roese 		return PTR_ERR(sleb);
569eefe2a2SStefan Roese 	if (sleb->nodes_cnt != nodes_cnt)
579eefe2a2SStefan Roese 		goto out;
589eefe2a2SStefan Roese 	if (!sleb->nodes_cnt)
599eefe2a2SStefan Roese 		goto out;
609eefe2a2SStefan Roese 	snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node, list);
619eefe2a2SStefan Roese 	if (snod->type != UBIFS_MST_NODE)
62ff94bc40SHeiko Schocher 		goto out_dump;
639eefe2a2SStefan Roese 	if (snod->offs != offs)
649eefe2a2SStefan Roese 		goto out;
659eefe2a2SStefan Roese 	if (memcmp((void *)c->mst_node + UBIFS_CH_SZ,
669eefe2a2SStefan Roese 		   (void *)snod->node + UBIFS_CH_SZ,
679eefe2a2SStefan Roese 		   UBIFS_MST_NODE_SZ - UBIFS_CH_SZ))
689eefe2a2SStefan Roese 		goto out;
699eefe2a2SStefan Roese 	c->mst_offs = offs;
709eefe2a2SStefan Roese 	ubifs_scan_destroy(sleb);
719eefe2a2SStefan Roese 	return 0;
729eefe2a2SStefan Roese 
739eefe2a2SStefan Roese out:
749eefe2a2SStefan Roese 	ubifs_scan_destroy(sleb);
75ff94bc40SHeiko Schocher 	return -EUCLEAN;
76ff94bc40SHeiko Schocher 
77ff94bc40SHeiko Schocher out_dump:
780195a7bbSHeiko Schocher 	ubifs_err(c, "unexpected node type %d master LEB %d:%d",
79ff94bc40SHeiko Schocher 		  snod->type, lnum, snod->offs);
80ff94bc40SHeiko Schocher 	ubifs_scan_destroy(sleb);
819eefe2a2SStefan Roese 	return -EINVAL;
829eefe2a2SStefan Roese }
839eefe2a2SStefan Roese 
849eefe2a2SStefan Roese /**
859eefe2a2SStefan Roese  * validate_master - validate master node.
869eefe2a2SStefan Roese  * @c: UBIFS file-system description object
879eefe2a2SStefan Roese  *
889eefe2a2SStefan Roese  * This function validates data which was read from master node. Returns zero
899eefe2a2SStefan Roese  * if the data is all right and %-EINVAL if not.
909eefe2a2SStefan Roese  */
validate_master(const struct ubifs_info * c)919eefe2a2SStefan Roese static int validate_master(const struct ubifs_info *c)
929eefe2a2SStefan Roese {
939eefe2a2SStefan Roese 	long long main_sz;
949eefe2a2SStefan Roese 	int err;
959eefe2a2SStefan Roese 
969eefe2a2SStefan Roese 	if (c->max_sqnum >= SQNUM_WATERMARK) {
979eefe2a2SStefan Roese 		err = 1;
989eefe2a2SStefan Roese 		goto out;
999eefe2a2SStefan Roese 	}
1009eefe2a2SStefan Roese 
1019eefe2a2SStefan Roese 	if (c->cmt_no >= c->max_sqnum) {
1029eefe2a2SStefan Roese 		err = 2;
1039eefe2a2SStefan Roese 		goto out;
1049eefe2a2SStefan Roese 	}
1059eefe2a2SStefan Roese 
1069eefe2a2SStefan Roese 	if (c->highest_inum >= INUM_WATERMARK) {
1079eefe2a2SStefan Roese 		err = 3;
1089eefe2a2SStefan Roese 		goto out;
1099eefe2a2SStefan Roese 	}
1109eefe2a2SStefan Roese 
1119eefe2a2SStefan Roese 	if (c->lhead_lnum < UBIFS_LOG_LNUM ||
1129eefe2a2SStefan Roese 	    c->lhead_lnum >= UBIFS_LOG_LNUM + c->log_lebs ||
1139eefe2a2SStefan Roese 	    c->lhead_offs < 0 || c->lhead_offs >= c->leb_size ||
1149eefe2a2SStefan Roese 	    c->lhead_offs & (c->min_io_size - 1)) {
1159eefe2a2SStefan Roese 		err = 4;
1169eefe2a2SStefan Roese 		goto out;
1179eefe2a2SStefan Roese 	}
1189eefe2a2SStefan Roese 
1199eefe2a2SStefan Roese 	if (c->zroot.lnum >= c->leb_cnt || c->zroot.lnum < c->main_first ||
1209eefe2a2SStefan Roese 	    c->zroot.offs >= c->leb_size || c->zroot.offs & 7) {
1219eefe2a2SStefan Roese 		err = 5;
1229eefe2a2SStefan Roese 		goto out;
1239eefe2a2SStefan Roese 	}
1249eefe2a2SStefan Roese 
1259eefe2a2SStefan Roese 	if (c->zroot.len < c->ranges[UBIFS_IDX_NODE].min_len ||
1269eefe2a2SStefan Roese 	    c->zroot.len > c->ranges[UBIFS_IDX_NODE].max_len) {
1279eefe2a2SStefan Roese 		err = 6;
1289eefe2a2SStefan Roese 		goto out;
1299eefe2a2SStefan Roese 	}
1309eefe2a2SStefan Roese 
1319eefe2a2SStefan Roese 	if (c->gc_lnum >= c->leb_cnt || c->gc_lnum < c->main_first) {
1329eefe2a2SStefan Roese 		err = 7;
1339eefe2a2SStefan Roese 		goto out;
1349eefe2a2SStefan Roese 	}
1359eefe2a2SStefan Roese 
1369eefe2a2SStefan Roese 	if (c->ihead_lnum >= c->leb_cnt || c->ihead_lnum < c->main_first ||
1379eefe2a2SStefan Roese 	    c->ihead_offs % c->min_io_size || c->ihead_offs < 0 ||
1389eefe2a2SStefan Roese 	    c->ihead_offs > c->leb_size || c->ihead_offs & 7) {
1399eefe2a2SStefan Roese 		err = 8;
1409eefe2a2SStefan Roese 		goto out;
1419eefe2a2SStefan Roese 	}
1429eefe2a2SStefan Roese 
1439eefe2a2SStefan Roese 	main_sz = (long long)c->main_lebs * c->leb_size;
144ff94bc40SHeiko Schocher 	if (c->bi.old_idx_sz & 7 || c->bi.old_idx_sz >= main_sz) {
1459eefe2a2SStefan Roese 		err = 9;
1469eefe2a2SStefan Roese 		goto out;
1479eefe2a2SStefan Roese 	}
1489eefe2a2SStefan Roese 
1499eefe2a2SStefan Roese 	if (c->lpt_lnum < c->lpt_first || c->lpt_lnum > c->lpt_last ||
1509eefe2a2SStefan Roese 	    c->lpt_offs < 0 || c->lpt_offs + c->nnode_sz > c->leb_size) {
1519eefe2a2SStefan Roese 		err = 10;
1529eefe2a2SStefan Roese 		goto out;
1539eefe2a2SStefan Roese 	}
1549eefe2a2SStefan Roese 
1559eefe2a2SStefan Roese 	if (c->nhead_lnum < c->lpt_first || c->nhead_lnum > c->lpt_last ||
1569eefe2a2SStefan Roese 	    c->nhead_offs < 0 || c->nhead_offs % c->min_io_size ||
1579eefe2a2SStefan Roese 	    c->nhead_offs > c->leb_size) {
1589eefe2a2SStefan Roese 		err = 11;
1599eefe2a2SStefan Roese 		goto out;
1609eefe2a2SStefan Roese 	}
1619eefe2a2SStefan Roese 
1629eefe2a2SStefan Roese 	if (c->ltab_lnum < c->lpt_first || c->ltab_lnum > c->lpt_last ||
1639eefe2a2SStefan Roese 	    c->ltab_offs < 0 ||
1649eefe2a2SStefan Roese 	    c->ltab_offs + c->ltab_sz > c->leb_size) {
1659eefe2a2SStefan Roese 		err = 12;
1669eefe2a2SStefan Roese 		goto out;
1679eefe2a2SStefan Roese 	}
1689eefe2a2SStefan Roese 
1699eefe2a2SStefan Roese 	if (c->big_lpt && (c->lsave_lnum < c->lpt_first ||
1709eefe2a2SStefan Roese 	    c->lsave_lnum > c->lpt_last || c->lsave_offs < 0 ||
1719eefe2a2SStefan Roese 	    c->lsave_offs + c->lsave_sz > c->leb_size)) {
1729eefe2a2SStefan Roese 		err = 13;
1739eefe2a2SStefan Roese 		goto out;
1749eefe2a2SStefan Roese 	}
1759eefe2a2SStefan Roese 
1769eefe2a2SStefan Roese 	if (c->lscan_lnum < c->main_first || c->lscan_lnum >= c->leb_cnt) {
1779eefe2a2SStefan Roese 		err = 14;
1789eefe2a2SStefan Roese 		goto out;
1799eefe2a2SStefan Roese 	}
1809eefe2a2SStefan Roese 
1819eefe2a2SStefan Roese 	if (c->lst.empty_lebs < 0 || c->lst.empty_lebs > c->main_lebs - 2) {
1829eefe2a2SStefan Roese 		err = 15;
1839eefe2a2SStefan Roese 		goto out;
1849eefe2a2SStefan Roese 	}
1859eefe2a2SStefan Roese 
1869eefe2a2SStefan Roese 	if (c->lst.idx_lebs < 0 || c->lst.idx_lebs > c->main_lebs - 1) {
1879eefe2a2SStefan Roese 		err = 16;
1889eefe2a2SStefan Roese 		goto out;
1899eefe2a2SStefan Roese 	}
1909eefe2a2SStefan Roese 
1919eefe2a2SStefan Roese 	if (c->lst.total_free < 0 || c->lst.total_free > main_sz ||
1929eefe2a2SStefan Roese 	    c->lst.total_free & 7) {
1939eefe2a2SStefan Roese 		err = 17;
1949eefe2a2SStefan Roese 		goto out;
1959eefe2a2SStefan Roese 	}
1969eefe2a2SStefan Roese 
1979eefe2a2SStefan Roese 	if (c->lst.total_dirty < 0 || (c->lst.total_dirty & 7)) {
1989eefe2a2SStefan Roese 		err = 18;
1999eefe2a2SStefan Roese 		goto out;
2009eefe2a2SStefan Roese 	}
2019eefe2a2SStefan Roese 
2029eefe2a2SStefan Roese 	if (c->lst.total_used < 0 || (c->lst.total_used & 7)) {
2039eefe2a2SStefan Roese 		err = 19;
2049eefe2a2SStefan Roese 		goto out;
2059eefe2a2SStefan Roese 	}
2069eefe2a2SStefan Roese 
2079eefe2a2SStefan Roese 	if (c->lst.total_free + c->lst.total_dirty +
2089eefe2a2SStefan Roese 	    c->lst.total_used > main_sz) {
2099eefe2a2SStefan Roese 		err = 20;
2109eefe2a2SStefan Roese 		goto out;
2119eefe2a2SStefan Roese 	}
2129eefe2a2SStefan Roese 
2139eefe2a2SStefan Roese 	if (c->lst.total_dead + c->lst.total_dark +
214ff94bc40SHeiko Schocher 	    c->lst.total_used + c->bi.old_idx_sz > main_sz) {
2159eefe2a2SStefan Roese 		err = 21;
2169eefe2a2SStefan Roese 		goto out;
2179eefe2a2SStefan Roese 	}
2189eefe2a2SStefan Roese 
2199eefe2a2SStefan Roese 	if (c->lst.total_dead < 0 ||
2209eefe2a2SStefan Roese 	    c->lst.total_dead > c->lst.total_free + c->lst.total_dirty ||
2219eefe2a2SStefan Roese 	    c->lst.total_dead & 7) {
2229eefe2a2SStefan Roese 		err = 22;
2239eefe2a2SStefan Roese 		goto out;
2249eefe2a2SStefan Roese 	}
2259eefe2a2SStefan Roese 
2269eefe2a2SStefan Roese 	if (c->lst.total_dark < 0 ||
2279eefe2a2SStefan Roese 	    c->lst.total_dark > c->lst.total_free + c->lst.total_dirty ||
2289eefe2a2SStefan Roese 	    c->lst.total_dark & 7) {
2299eefe2a2SStefan Roese 		err = 23;
2309eefe2a2SStefan Roese 		goto out;
2319eefe2a2SStefan Roese 	}
2329eefe2a2SStefan Roese 
2339eefe2a2SStefan Roese 	return 0;
2349eefe2a2SStefan Roese 
2359eefe2a2SStefan Roese out:
2360195a7bbSHeiko Schocher 	ubifs_err(c, "bad master node at offset %d error %d", c->mst_offs, err);
237ff94bc40SHeiko Schocher 	ubifs_dump_node(c, c->mst_node);
2389eefe2a2SStefan Roese 	return -EINVAL;
2399eefe2a2SStefan Roese }
2409eefe2a2SStefan Roese 
2419eefe2a2SStefan Roese /**
2429eefe2a2SStefan Roese  * ubifs_read_master - read master node.
2439eefe2a2SStefan Roese  * @c: UBIFS file-system description object
2449eefe2a2SStefan Roese  *
2459eefe2a2SStefan Roese  * This function finds and reads the master node during file-system mount. If
2469eefe2a2SStefan Roese  * the flash is empty, it creates default master node as well. Returns zero in
2479eefe2a2SStefan Roese  * case of success and a negative error code in case of failure.
2489eefe2a2SStefan Roese  */
ubifs_read_master(struct ubifs_info * c)2499eefe2a2SStefan Roese int ubifs_read_master(struct ubifs_info *c)
2509eefe2a2SStefan Roese {
2519eefe2a2SStefan Roese 	int err, old_leb_cnt;
2529eefe2a2SStefan Roese 
2539eefe2a2SStefan Roese 	c->mst_node = kzalloc(c->mst_node_alsz, GFP_KERNEL);
2549eefe2a2SStefan Roese 	if (!c->mst_node)
2559eefe2a2SStefan Roese 		return -ENOMEM;
2569eefe2a2SStefan Roese 
2579eefe2a2SStefan Roese 	err = scan_for_master(c);
2589eefe2a2SStefan Roese 	if (err) {
259ff94bc40SHeiko Schocher 		if (err == -EUCLEAN)
2609eefe2a2SStefan Roese 			err = ubifs_recover_master_node(c);
2619eefe2a2SStefan Roese 		if (err)
2629eefe2a2SStefan Roese 			/*
2639eefe2a2SStefan Roese 			 * Note, we do not free 'c->mst_node' here because the
2649eefe2a2SStefan Roese 			 * unmount routine will take care of this.
2659eefe2a2SStefan Roese 			 */
2669eefe2a2SStefan Roese 			return err;
2679eefe2a2SStefan Roese 	}
2689eefe2a2SStefan Roese 
2699eefe2a2SStefan Roese 	/* Make sure that the recovery flag is clear */
2709eefe2a2SStefan Roese 	c->mst_node->flags &= cpu_to_le32(~UBIFS_MST_RCVRY);
2719eefe2a2SStefan Roese 
2729eefe2a2SStefan Roese 	c->max_sqnum       = le64_to_cpu(c->mst_node->ch.sqnum);
2739eefe2a2SStefan Roese 	c->highest_inum    = le64_to_cpu(c->mst_node->highest_inum);
2749eefe2a2SStefan Roese 	c->cmt_no          = le64_to_cpu(c->mst_node->cmt_no);
2759eefe2a2SStefan Roese 	c->zroot.lnum      = le32_to_cpu(c->mst_node->root_lnum);
2769eefe2a2SStefan Roese 	c->zroot.offs      = le32_to_cpu(c->mst_node->root_offs);
2779eefe2a2SStefan Roese 	c->zroot.len       = le32_to_cpu(c->mst_node->root_len);
2789eefe2a2SStefan Roese 	c->lhead_lnum      = le32_to_cpu(c->mst_node->log_lnum);
2799eefe2a2SStefan Roese 	c->gc_lnum         = le32_to_cpu(c->mst_node->gc_lnum);
2809eefe2a2SStefan Roese 	c->ihead_lnum      = le32_to_cpu(c->mst_node->ihead_lnum);
2819eefe2a2SStefan Roese 	c->ihead_offs      = le32_to_cpu(c->mst_node->ihead_offs);
282ff94bc40SHeiko Schocher 	c->bi.old_idx_sz   = le64_to_cpu(c->mst_node->index_size);
2839eefe2a2SStefan Roese 	c->lpt_lnum        = le32_to_cpu(c->mst_node->lpt_lnum);
2849eefe2a2SStefan Roese 	c->lpt_offs        = le32_to_cpu(c->mst_node->lpt_offs);
2859eefe2a2SStefan Roese 	c->nhead_lnum      = le32_to_cpu(c->mst_node->nhead_lnum);
2869eefe2a2SStefan Roese 	c->nhead_offs      = le32_to_cpu(c->mst_node->nhead_offs);
2879eefe2a2SStefan Roese 	c->ltab_lnum       = le32_to_cpu(c->mst_node->ltab_lnum);
2889eefe2a2SStefan Roese 	c->ltab_offs       = le32_to_cpu(c->mst_node->ltab_offs);
2899eefe2a2SStefan Roese 	c->lsave_lnum      = le32_to_cpu(c->mst_node->lsave_lnum);
2909eefe2a2SStefan Roese 	c->lsave_offs      = le32_to_cpu(c->mst_node->lsave_offs);
2919eefe2a2SStefan Roese 	c->lscan_lnum      = le32_to_cpu(c->mst_node->lscan_lnum);
2929eefe2a2SStefan Roese 	c->lst.empty_lebs  = le32_to_cpu(c->mst_node->empty_lebs);
2939eefe2a2SStefan Roese 	c->lst.idx_lebs    = le32_to_cpu(c->mst_node->idx_lebs);
2949eefe2a2SStefan Roese 	old_leb_cnt        = le32_to_cpu(c->mst_node->leb_cnt);
2959eefe2a2SStefan Roese 	c->lst.total_free  = le64_to_cpu(c->mst_node->total_free);
2969eefe2a2SStefan Roese 	c->lst.total_dirty = le64_to_cpu(c->mst_node->total_dirty);
2979eefe2a2SStefan Roese 	c->lst.total_used  = le64_to_cpu(c->mst_node->total_used);
2989eefe2a2SStefan Roese 	c->lst.total_dead  = le64_to_cpu(c->mst_node->total_dead);
2999eefe2a2SStefan Roese 	c->lst.total_dark  = le64_to_cpu(c->mst_node->total_dark);
3009eefe2a2SStefan Roese 
301ff94bc40SHeiko Schocher 	c->calc_idx_sz = c->bi.old_idx_sz;
3029eefe2a2SStefan Roese 
3039eefe2a2SStefan Roese 	if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS))
3049eefe2a2SStefan Roese 		c->no_orphs = 1;
3059eefe2a2SStefan Roese 
3069eefe2a2SStefan Roese 	if (old_leb_cnt != c->leb_cnt) {
3079eefe2a2SStefan Roese 		/* The file system has been resized */
3089eefe2a2SStefan Roese 		int growth = c->leb_cnt - old_leb_cnt;
3099eefe2a2SStefan Roese 
3109eefe2a2SStefan Roese 		if (c->leb_cnt < old_leb_cnt ||
3119eefe2a2SStefan Roese 		    c->leb_cnt < UBIFS_MIN_LEB_CNT) {
3120195a7bbSHeiko Schocher 			ubifs_err(c, "bad leb_cnt on master node");
313ff94bc40SHeiko Schocher 			ubifs_dump_node(c, c->mst_node);
3149eefe2a2SStefan Roese 			return -EINVAL;
3159eefe2a2SStefan Roese 		}
3169eefe2a2SStefan Roese 
3179eefe2a2SStefan Roese 		dbg_mnt("Auto resizing (master) from %d LEBs to %d LEBs",
3189eefe2a2SStefan Roese 			old_leb_cnt, c->leb_cnt);
3199eefe2a2SStefan Roese 		c->lst.empty_lebs += growth;
3209eefe2a2SStefan Roese 		c->lst.total_free += growth * (long long)c->leb_size;
3219eefe2a2SStefan Roese 		c->lst.total_dark += growth * (long long)c->dark_wm;
3229eefe2a2SStefan Roese 
3239eefe2a2SStefan Roese 		/*
3249eefe2a2SStefan Roese 		 * Reflect changes back onto the master node. N.B. the master
3259eefe2a2SStefan Roese 		 * node gets written immediately whenever mounting (or
3269eefe2a2SStefan Roese 		 * remounting) in read-write mode, so we do not need to write it
3279eefe2a2SStefan Roese 		 * here.
3289eefe2a2SStefan Roese 		 */
3299eefe2a2SStefan Roese 		c->mst_node->leb_cnt = cpu_to_le32(c->leb_cnt);
3309eefe2a2SStefan Roese 		c->mst_node->empty_lebs = cpu_to_le32(c->lst.empty_lebs);
3319eefe2a2SStefan Roese 		c->mst_node->total_free = cpu_to_le64(c->lst.total_free);
3329eefe2a2SStefan Roese 		c->mst_node->total_dark = cpu_to_le64(c->lst.total_dark);
3339eefe2a2SStefan Roese 	}
3349eefe2a2SStefan Roese 
3359eefe2a2SStefan Roese 	err = validate_master(c);
3369eefe2a2SStefan Roese 	if (err)
3379eefe2a2SStefan Roese 		return err;
3389eefe2a2SStefan Roese 
339ff94bc40SHeiko Schocher #ifndef __UBOOT__
3409eefe2a2SStefan Roese 	err = dbg_old_index_check_init(c, &c->zroot);
341ff94bc40SHeiko Schocher #endif
3429eefe2a2SStefan Roese 
3439eefe2a2SStefan Roese 	return err;
3449eefe2a2SStefan Roese }
345ff94bc40SHeiko Schocher 
346ff94bc40SHeiko Schocher #ifndef __UBOOT__
347ff94bc40SHeiko Schocher /**
348ff94bc40SHeiko Schocher  * ubifs_write_master - write master node.
349ff94bc40SHeiko Schocher  * @c: UBIFS file-system description object
350ff94bc40SHeiko Schocher  *
3510195a7bbSHeiko Schocher  * This function writes the master node. Returns zero in case of success and a
3520195a7bbSHeiko Schocher  * negative error code in case of failure. The master node is written twice to
3530195a7bbSHeiko Schocher  * enable recovery.
354ff94bc40SHeiko Schocher  */
ubifs_write_master(struct ubifs_info * c)355ff94bc40SHeiko Schocher int ubifs_write_master(struct ubifs_info *c)
356ff94bc40SHeiko Schocher {
357ff94bc40SHeiko Schocher 	int err, lnum, offs, len;
358ff94bc40SHeiko Schocher 
359ff94bc40SHeiko Schocher 	ubifs_assert(!c->ro_media && !c->ro_mount);
360ff94bc40SHeiko Schocher 	if (c->ro_error)
361ff94bc40SHeiko Schocher 		return -EROFS;
362ff94bc40SHeiko Schocher 
363ff94bc40SHeiko Schocher 	lnum = UBIFS_MST_LNUM;
364ff94bc40SHeiko Schocher 	offs = c->mst_offs + c->mst_node_alsz;
365ff94bc40SHeiko Schocher 	len = UBIFS_MST_NODE_SZ;
366ff94bc40SHeiko Schocher 
367ff94bc40SHeiko Schocher 	if (offs + UBIFS_MST_NODE_SZ > c->leb_size) {
368ff94bc40SHeiko Schocher 		err = ubifs_leb_unmap(c, lnum);
369ff94bc40SHeiko Schocher 		if (err)
370ff94bc40SHeiko Schocher 			return err;
371ff94bc40SHeiko Schocher 		offs = 0;
372ff94bc40SHeiko Schocher 	}
373ff94bc40SHeiko Schocher 
374ff94bc40SHeiko Schocher 	c->mst_offs = offs;
375ff94bc40SHeiko Schocher 	c->mst_node->highest_inum = cpu_to_le64(c->highest_inum);
376ff94bc40SHeiko Schocher 
377ff94bc40SHeiko Schocher 	err = ubifs_write_node(c, c->mst_node, len, lnum, offs);
378ff94bc40SHeiko Schocher 	if (err)
379ff94bc40SHeiko Schocher 		return err;
380ff94bc40SHeiko Schocher 
381ff94bc40SHeiko Schocher 	lnum += 1;
382ff94bc40SHeiko Schocher 
383ff94bc40SHeiko Schocher 	if (offs == 0) {
384ff94bc40SHeiko Schocher 		err = ubifs_leb_unmap(c, lnum);
385ff94bc40SHeiko Schocher 		if (err)
386ff94bc40SHeiko Schocher 			return err;
387ff94bc40SHeiko Schocher 	}
388ff94bc40SHeiko Schocher 	err = ubifs_write_node(c, c->mst_node, len, lnum, offs);
389ff94bc40SHeiko Schocher 
390ff94bc40SHeiko Schocher 	return err;
391ff94bc40SHeiko Schocher }
392ff94bc40SHeiko Schocher #endif
393