xref: /kernel/linux/linux-6.6/fs/ubifs/replay.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * This file is part of UBIFS.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2006-2008 Nokia Corporation.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Authors: Adrian Hunter
862306a36Sopenharmony_ci *          Artem Bityutskiy (Битюцкий Артём)
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/*
1262306a36Sopenharmony_ci * This file contains journal replay code. It runs when the file-system is being
1362306a36Sopenharmony_ci * mounted and requires no locking.
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * The larger is the journal, the longer it takes to scan it, so the longer it
1662306a36Sopenharmony_ci * takes to mount UBIFS. This is why the journal has limited size which may be
1762306a36Sopenharmony_ci * changed depending on the system requirements. But a larger journal gives
1862306a36Sopenharmony_ci * faster I/O speed because it writes the index less frequently. So this is a
1962306a36Sopenharmony_ci * trade-off. Also, the journal is indexed by the in-memory index (TNC), so the
2062306a36Sopenharmony_ci * larger is the journal, the more memory its index may consume.
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "ubifs.h"
2462306a36Sopenharmony_ci#include <linux/list_sort.h>
2562306a36Sopenharmony_ci#include <crypto/hash.h>
2662306a36Sopenharmony_ci#include <crypto/algapi.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/**
2962306a36Sopenharmony_ci * struct replay_entry - replay list entry.
3062306a36Sopenharmony_ci * @lnum: logical eraseblock number of the node
3162306a36Sopenharmony_ci * @offs: node offset
3262306a36Sopenharmony_ci * @len: node length
3362306a36Sopenharmony_ci * @deletion: non-zero if this entry corresponds to a node deletion
3462306a36Sopenharmony_ci * @sqnum: node sequence number
3562306a36Sopenharmony_ci * @list: links the replay list
3662306a36Sopenharmony_ci * @key: node key
3762306a36Sopenharmony_ci * @nm: directory entry name
3862306a36Sopenharmony_ci * @old_size: truncation old size
3962306a36Sopenharmony_ci * @new_size: truncation new size
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci * The replay process first scans all buds and builds the replay list, then
4262306a36Sopenharmony_ci * sorts the replay list in nodes sequence number order, and then inserts all
4362306a36Sopenharmony_ci * the replay entries to the TNC.
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_cistruct replay_entry {
4662306a36Sopenharmony_ci	int lnum;
4762306a36Sopenharmony_ci	int offs;
4862306a36Sopenharmony_ci	int len;
4962306a36Sopenharmony_ci	u8 hash[UBIFS_HASH_ARR_SZ];
5062306a36Sopenharmony_ci	unsigned int deletion:1;
5162306a36Sopenharmony_ci	unsigned long long sqnum;
5262306a36Sopenharmony_ci	struct list_head list;
5362306a36Sopenharmony_ci	union ubifs_key key;
5462306a36Sopenharmony_ci	union {
5562306a36Sopenharmony_ci		struct fscrypt_name nm;
5662306a36Sopenharmony_ci		struct {
5762306a36Sopenharmony_ci			loff_t old_size;
5862306a36Sopenharmony_ci			loff_t new_size;
5962306a36Sopenharmony_ci		};
6062306a36Sopenharmony_ci	};
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/**
6462306a36Sopenharmony_ci * struct bud_entry - entry in the list of buds to replay.
6562306a36Sopenharmony_ci * @list: next bud in the list
6662306a36Sopenharmony_ci * @bud: bud description object
6762306a36Sopenharmony_ci * @sqnum: reference node sequence number
6862306a36Sopenharmony_ci * @free: free bytes in the bud
6962306a36Sopenharmony_ci * @dirty: dirty bytes in the bud
7062306a36Sopenharmony_ci */
7162306a36Sopenharmony_cistruct bud_entry {
7262306a36Sopenharmony_ci	struct list_head list;
7362306a36Sopenharmony_ci	struct ubifs_bud *bud;
7462306a36Sopenharmony_ci	unsigned long long sqnum;
7562306a36Sopenharmony_ci	int free;
7662306a36Sopenharmony_ci	int dirty;
7762306a36Sopenharmony_ci};
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/**
8062306a36Sopenharmony_ci * set_bud_lprops - set free and dirty space used by a bud.
8162306a36Sopenharmony_ci * @c: UBIFS file-system description object
8262306a36Sopenharmony_ci * @b: bud entry which describes the bud
8362306a36Sopenharmony_ci *
8462306a36Sopenharmony_ci * This function makes sure the LEB properties of bud @b are set correctly
8562306a36Sopenharmony_ci * after the replay. Returns zero in case of success and a negative error code
8662306a36Sopenharmony_ci * in case of failure.
8762306a36Sopenharmony_ci */
8862306a36Sopenharmony_cistatic int set_bud_lprops(struct ubifs_info *c, struct bud_entry *b)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	const struct ubifs_lprops *lp;
9162306a36Sopenharmony_ci	int err = 0, dirty;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	ubifs_get_lprops(c);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	lp = ubifs_lpt_lookup_dirty(c, b->bud->lnum);
9662306a36Sopenharmony_ci	if (IS_ERR(lp)) {
9762306a36Sopenharmony_ci		err = PTR_ERR(lp);
9862306a36Sopenharmony_ci		goto out;
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	dirty = lp->dirty;
10262306a36Sopenharmony_ci	if (b->bud->start == 0 && (lp->free != c->leb_size || lp->dirty != 0)) {
10362306a36Sopenharmony_ci		/*
10462306a36Sopenharmony_ci		 * The LEB was added to the journal with a starting offset of
10562306a36Sopenharmony_ci		 * zero which means the LEB must have been empty. The LEB
10662306a36Sopenharmony_ci		 * property values should be @lp->free == @c->leb_size and
10762306a36Sopenharmony_ci		 * @lp->dirty == 0, but that is not the case. The reason is that
10862306a36Sopenharmony_ci		 * the LEB had been garbage collected before it became the bud,
10962306a36Sopenharmony_ci		 * and there was no commit in between. The garbage collector
11062306a36Sopenharmony_ci		 * resets the free and dirty space without recording it
11162306a36Sopenharmony_ci		 * anywhere except lprops, so if there was no commit then
11262306a36Sopenharmony_ci		 * lprops does not have that information.
11362306a36Sopenharmony_ci		 *
11462306a36Sopenharmony_ci		 * We do not need to adjust free space because the scan has told
11562306a36Sopenharmony_ci		 * us the exact value which is recorded in the replay entry as
11662306a36Sopenharmony_ci		 * @b->free.
11762306a36Sopenharmony_ci		 *
11862306a36Sopenharmony_ci		 * However we do need to subtract from the dirty space the
11962306a36Sopenharmony_ci		 * amount of space that the garbage collector reclaimed, which
12062306a36Sopenharmony_ci		 * is the whole LEB minus the amount of space that was free.
12162306a36Sopenharmony_ci		 */
12262306a36Sopenharmony_ci		dbg_mnt("bud LEB %d was GC'd (%d free, %d dirty)", b->bud->lnum,
12362306a36Sopenharmony_ci			lp->free, lp->dirty);
12462306a36Sopenharmony_ci		dbg_gc("bud LEB %d was GC'd (%d free, %d dirty)", b->bud->lnum,
12562306a36Sopenharmony_ci			lp->free, lp->dirty);
12662306a36Sopenharmony_ci		dirty -= c->leb_size - lp->free;
12762306a36Sopenharmony_ci		/*
12862306a36Sopenharmony_ci		 * If the replay order was perfect the dirty space would now be
12962306a36Sopenharmony_ci		 * zero. The order is not perfect because the journal heads
13062306a36Sopenharmony_ci		 * race with each other. This is not a problem but is does mean
13162306a36Sopenharmony_ci		 * that the dirty space may temporarily exceed c->leb_size
13262306a36Sopenharmony_ci		 * during the replay.
13362306a36Sopenharmony_ci		 */
13462306a36Sopenharmony_ci		if (dirty != 0)
13562306a36Sopenharmony_ci			dbg_mnt("LEB %d lp: %d free %d dirty replay: %d free %d dirty",
13662306a36Sopenharmony_ci				b->bud->lnum, lp->free, lp->dirty, b->free,
13762306a36Sopenharmony_ci				b->dirty);
13862306a36Sopenharmony_ci	}
13962306a36Sopenharmony_ci	lp = ubifs_change_lp(c, lp, b->free, dirty + b->dirty,
14062306a36Sopenharmony_ci			     lp->flags | LPROPS_TAKEN, 0);
14162306a36Sopenharmony_ci	if (IS_ERR(lp)) {
14262306a36Sopenharmony_ci		err = PTR_ERR(lp);
14362306a36Sopenharmony_ci		goto out;
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	/* Make sure the journal head points to the latest bud */
14762306a36Sopenharmony_ci	err = ubifs_wbuf_seek_nolock(&c->jheads[b->bud->jhead].wbuf,
14862306a36Sopenharmony_ci				     b->bud->lnum, c->leb_size - b->free);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ciout:
15162306a36Sopenharmony_ci	ubifs_release_lprops(c);
15262306a36Sopenharmony_ci	return err;
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci/**
15662306a36Sopenharmony_ci * set_buds_lprops - set free and dirty space for all replayed buds.
15762306a36Sopenharmony_ci * @c: UBIFS file-system description object
15862306a36Sopenharmony_ci *
15962306a36Sopenharmony_ci * This function sets LEB properties for all replayed buds. Returns zero in
16062306a36Sopenharmony_ci * case of success and a negative error code in case of failure.
16162306a36Sopenharmony_ci */
16262306a36Sopenharmony_cistatic int set_buds_lprops(struct ubifs_info *c)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	struct bud_entry *b;
16562306a36Sopenharmony_ci	int err;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	list_for_each_entry(b, &c->replay_buds, list) {
16862306a36Sopenharmony_ci		err = set_bud_lprops(c, b);
16962306a36Sopenharmony_ci		if (err)
17062306a36Sopenharmony_ci			return err;
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return 0;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci/**
17762306a36Sopenharmony_ci * trun_remove_range - apply a replay entry for a truncation to the TNC.
17862306a36Sopenharmony_ci * @c: UBIFS file-system description object
17962306a36Sopenharmony_ci * @r: replay entry of truncation
18062306a36Sopenharmony_ci */
18162306a36Sopenharmony_cistatic int trun_remove_range(struct ubifs_info *c, struct replay_entry *r)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	unsigned min_blk, max_blk;
18462306a36Sopenharmony_ci	union ubifs_key min_key, max_key;
18562306a36Sopenharmony_ci	ino_t ino;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	min_blk = r->new_size / UBIFS_BLOCK_SIZE;
18862306a36Sopenharmony_ci	if (r->new_size & (UBIFS_BLOCK_SIZE - 1))
18962306a36Sopenharmony_ci		min_blk += 1;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	max_blk = r->old_size / UBIFS_BLOCK_SIZE;
19262306a36Sopenharmony_ci	if ((r->old_size & (UBIFS_BLOCK_SIZE - 1)) == 0)
19362306a36Sopenharmony_ci		max_blk -= 1;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	ino = key_inum(c, &r->key);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	data_key_init(c, &min_key, ino, min_blk);
19862306a36Sopenharmony_ci	data_key_init(c, &max_key, ino, max_blk);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	return ubifs_tnc_remove_range(c, &min_key, &max_key);
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci/**
20462306a36Sopenharmony_ci * inode_still_linked - check whether inode in question will be re-linked.
20562306a36Sopenharmony_ci * @c: UBIFS file-system description object
20662306a36Sopenharmony_ci * @rino: replay entry to test
20762306a36Sopenharmony_ci *
20862306a36Sopenharmony_ci * O_TMPFILE files can be re-linked, this means link count goes from 0 to 1.
20962306a36Sopenharmony_ci * This case needs special care, otherwise all references to the inode will
21062306a36Sopenharmony_ci * be removed upon the first replay entry of an inode with link count 0
21162306a36Sopenharmony_ci * is found.
21262306a36Sopenharmony_ci */
21362306a36Sopenharmony_cistatic bool inode_still_linked(struct ubifs_info *c, struct replay_entry *rino)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	struct replay_entry *r;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	ubifs_assert(c, rino->deletion);
21862306a36Sopenharmony_ci	ubifs_assert(c, key_type(c, &rino->key) == UBIFS_INO_KEY);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	/*
22162306a36Sopenharmony_ci	 * Find the most recent entry for the inode behind @rino and check
22262306a36Sopenharmony_ci	 * whether it is a deletion.
22362306a36Sopenharmony_ci	 */
22462306a36Sopenharmony_ci	list_for_each_entry_reverse(r, &c->replay_list, list) {
22562306a36Sopenharmony_ci		ubifs_assert(c, r->sqnum >= rino->sqnum);
22662306a36Sopenharmony_ci		if (key_inum(c, &r->key) == key_inum(c, &rino->key) &&
22762306a36Sopenharmony_ci		    key_type(c, &r->key) == UBIFS_INO_KEY)
22862306a36Sopenharmony_ci			return r->deletion == 0;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	ubifs_assert(c, 0);
23362306a36Sopenharmony_ci	return false;
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci/**
23762306a36Sopenharmony_ci * apply_replay_entry - apply a replay entry to the TNC.
23862306a36Sopenharmony_ci * @c: UBIFS file-system description object
23962306a36Sopenharmony_ci * @r: replay entry to apply
24062306a36Sopenharmony_ci *
24162306a36Sopenharmony_ci * Apply a replay entry to the TNC.
24262306a36Sopenharmony_ci */
24362306a36Sopenharmony_cistatic int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	int err;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	dbg_mntk(&r->key, "LEB %d:%d len %d deletion %d sqnum %llu key ",
24862306a36Sopenharmony_ci		 r->lnum, r->offs, r->len, r->deletion, r->sqnum);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	if (is_hash_key(c, &r->key)) {
25162306a36Sopenharmony_ci		if (r->deletion)
25262306a36Sopenharmony_ci			err = ubifs_tnc_remove_nm(c, &r->key, &r->nm);
25362306a36Sopenharmony_ci		else
25462306a36Sopenharmony_ci			err = ubifs_tnc_add_nm(c, &r->key, r->lnum, r->offs,
25562306a36Sopenharmony_ci					       r->len, r->hash, &r->nm);
25662306a36Sopenharmony_ci	} else {
25762306a36Sopenharmony_ci		if (r->deletion)
25862306a36Sopenharmony_ci			switch (key_type(c, &r->key)) {
25962306a36Sopenharmony_ci			case UBIFS_INO_KEY:
26062306a36Sopenharmony_ci			{
26162306a36Sopenharmony_ci				ino_t inum = key_inum(c, &r->key);
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci				if (inode_still_linked(c, r)) {
26462306a36Sopenharmony_ci					err = 0;
26562306a36Sopenharmony_ci					break;
26662306a36Sopenharmony_ci				}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci				err = ubifs_tnc_remove_ino(c, inum);
26962306a36Sopenharmony_ci				break;
27062306a36Sopenharmony_ci			}
27162306a36Sopenharmony_ci			case UBIFS_TRUN_KEY:
27262306a36Sopenharmony_ci				err = trun_remove_range(c, r);
27362306a36Sopenharmony_ci				break;
27462306a36Sopenharmony_ci			default:
27562306a36Sopenharmony_ci				err = ubifs_tnc_remove(c, &r->key);
27662306a36Sopenharmony_ci				break;
27762306a36Sopenharmony_ci			}
27862306a36Sopenharmony_ci		else
27962306a36Sopenharmony_ci			err = ubifs_tnc_add(c, &r->key, r->lnum, r->offs,
28062306a36Sopenharmony_ci					    r->len, r->hash);
28162306a36Sopenharmony_ci		if (err)
28262306a36Sopenharmony_ci			return err;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci		if (c->need_recovery)
28562306a36Sopenharmony_ci			err = ubifs_recover_size_accum(c, &r->key, r->deletion,
28662306a36Sopenharmony_ci						       r->new_size);
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	return err;
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci/**
29362306a36Sopenharmony_ci * replay_entries_cmp - compare 2 replay entries.
29462306a36Sopenharmony_ci * @priv: UBIFS file-system description object
29562306a36Sopenharmony_ci * @a: first replay entry
29662306a36Sopenharmony_ci * @b: second replay entry
29762306a36Sopenharmony_ci *
29862306a36Sopenharmony_ci * This is a comparios function for 'list_sort()' which compares 2 replay
29962306a36Sopenharmony_ci * entries @a and @b by comparing their sequence number.  Returns %1 if @a has
30062306a36Sopenharmony_ci * greater sequence number and %-1 otherwise.
30162306a36Sopenharmony_ci */
30262306a36Sopenharmony_cistatic int replay_entries_cmp(void *priv, const struct list_head *a,
30362306a36Sopenharmony_ci			      const struct list_head *b)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	struct ubifs_info *c = priv;
30662306a36Sopenharmony_ci	struct replay_entry *ra, *rb;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	cond_resched();
30962306a36Sopenharmony_ci	if (a == b)
31062306a36Sopenharmony_ci		return 0;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	ra = list_entry(a, struct replay_entry, list);
31362306a36Sopenharmony_ci	rb = list_entry(b, struct replay_entry, list);
31462306a36Sopenharmony_ci	ubifs_assert(c, ra->sqnum != rb->sqnum);
31562306a36Sopenharmony_ci	if (ra->sqnum > rb->sqnum)
31662306a36Sopenharmony_ci		return 1;
31762306a36Sopenharmony_ci	return -1;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci/**
32162306a36Sopenharmony_ci * apply_replay_list - apply the replay list to the TNC.
32262306a36Sopenharmony_ci * @c: UBIFS file-system description object
32362306a36Sopenharmony_ci *
32462306a36Sopenharmony_ci * Apply all entries in the replay list to the TNC. Returns zero in case of
32562306a36Sopenharmony_ci * success and a negative error code in case of failure.
32662306a36Sopenharmony_ci */
32762306a36Sopenharmony_cistatic int apply_replay_list(struct ubifs_info *c)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	struct replay_entry *r;
33062306a36Sopenharmony_ci	int err;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	list_sort(c, &c->replay_list, &replay_entries_cmp);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	list_for_each_entry(r, &c->replay_list, list) {
33562306a36Sopenharmony_ci		cond_resched();
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci		err = apply_replay_entry(c, r);
33862306a36Sopenharmony_ci		if (err)
33962306a36Sopenharmony_ci			return err;
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	return 0;
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci/**
34662306a36Sopenharmony_ci * destroy_replay_list - destroy the replay.
34762306a36Sopenharmony_ci * @c: UBIFS file-system description object
34862306a36Sopenharmony_ci *
34962306a36Sopenharmony_ci * Destroy the replay list.
35062306a36Sopenharmony_ci */
35162306a36Sopenharmony_cistatic void destroy_replay_list(struct ubifs_info *c)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	struct replay_entry *r, *tmp;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	list_for_each_entry_safe(r, tmp, &c->replay_list, list) {
35662306a36Sopenharmony_ci		if (is_hash_key(c, &r->key))
35762306a36Sopenharmony_ci			kfree(fname_name(&r->nm));
35862306a36Sopenharmony_ci		list_del(&r->list);
35962306a36Sopenharmony_ci		kfree(r);
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci/**
36462306a36Sopenharmony_ci * insert_node - insert a node to the replay list
36562306a36Sopenharmony_ci * @c: UBIFS file-system description object
36662306a36Sopenharmony_ci * @lnum: node logical eraseblock number
36762306a36Sopenharmony_ci * @offs: node offset
36862306a36Sopenharmony_ci * @len: node length
36962306a36Sopenharmony_ci * @key: node key
37062306a36Sopenharmony_ci * @sqnum: sequence number
37162306a36Sopenharmony_ci * @deletion: non-zero if this is a deletion
37262306a36Sopenharmony_ci * @used: number of bytes in use in a LEB
37362306a36Sopenharmony_ci * @old_size: truncation old size
37462306a36Sopenharmony_ci * @new_size: truncation new size
37562306a36Sopenharmony_ci *
37662306a36Sopenharmony_ci * This function inserts a scanned non-direntry node to the replay list. The
37762306a36Sopenharmony_ci * replay list contains @struct replay_entry elements, and we sort this list in
37862306a36Sopenharmony_ci * sequence number order before applying it. The replay list is applied at the
37962306a36Sopenharmony_ci * very end of the replay process. Since the list is sorted in sequence number
38062306a36Sopenharmony_ci * order, the older modifications are applied first. This function returns zero
38162306a36Sopenharmony_ci * in case of success and a negative error code in case of failure.
38262306a36Sopenharmony_ci */
38362306a36Sopenharmony_cistatic int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
38462306a36Sopenharmony_ci		       const u8 *hash, union ubifs_key *key,
38562306a36Sopenharmony_ci		       unsigned long long sqnum, int deletion, int *used,
38662306a36Sopenharmony_ci		       loff_t old_size, loff_t new_size)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	struct replay_entry *r;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	dbg_mntk(key, "add LEB %d:%d, key ", lnum, offs);
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	if (key_inum(c, key) >= c->highest_inum)
39362306a36Sopenharmony_ci		c->highest_inum = key_inum(c, key);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
39662306a36Sopenharmony_ci	if (!r)
39762306a36Sopenharmony_ci		return -ENOMEM;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	if (!deletion)
40062306a36Sopenharmony_ci		*used += ALIGN(len, 8);
40162306a36Sopenharmony_ci	r->lnum = lnum;
40262306a36Sopenharmony_ci	r->offs = offs;
40362306a36Sopenharmony_ci	r->len = len;
40462306a36Sopenharmony_ci	ubifs_copy_hash(c, hash, r->hash);
40562306a36Sopenharmony_ci	r->deletion = !!deletion;
40662306a36Sopenharmony_ci	r->sqnum = sqnum;
40762306a36Sopenharmony_ci	key_copy(c, key, &r->key);
40862306a36Sopenharmony_ci	r->old_size = old_size;
40962306a36Sopenharmony_ci	r->new_size = new_size;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	list_add_tail(&r->list, &c->replay_list);
41262306a36Sopenharmony_ci	return 0;
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci/**
41662306a36Sopenharmony_ci * insert_dent - insert a directory entry node into the replay list.
41762306a36Sopenharmony_ci * @c: UBIFS file-system description object
41862306a36Sopenharmony_ci * @lnum: node logical eraseblock number
41962306a36Sopenharmony_ci * @offs: node offset
42062306a36Sopenharmony_ci * @len: node length
42162306a36Sopenharmony_ci * @key: node key
42262306a36Sopenharmony_ci * @name: directory entry name
42362306a36Sopenharmony_ci * @nlen: directory entry name length
42462306a36Sopenharmony_ci * @sqnum: sequence number
42562306a36Sopenharmony_ci * @deletion: non-zero if this is a deletion
42662306a36Sopenharmony_ci * @used: number of bytes in use in a LEB
42762306a36Sopenharmony_ci *
42862306a36Sopenharmony_ci * This function inserts a scanned directory entry node or an extended
42962306a36Sopenharmony_ci * attribute entry to the replay list. Returns zero in case of success and a
43062306a36Sopenharmony_ci * negative error code in case of failure.
43162306a36Sopenharmony_ci */
43262306a36Sopenharmony_cistatic int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
43362306a36Sopenharmony_ci		       const u8 *hash, union ubifs_key *key,
43462306a36Sopenharmony_ci		       const char *name, int nlen, unsigned long long sqnum,
43562306a36Sopenharmony_ci		       int deletion, int *used)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	struct replay_entry *r;
43862306a36Sopenharmony_ci	char *nbuf;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	dbg_mntk(key, "add LEB %d:%d, key ", lnum, offs);
44162306a36Sopenharmony_ci	if (key_inum(c, key) >= c->highest_inum)
44262306a36Sopenharmony_ci		c->highest_inum = key_inum(c, key);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
44562306a36Sopenharmony_ci	if (!r)
44662306a36Sopenharmony_ci		return -ENOMEM;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	nbuf = kmalloc(nlen + 1, GFP_KERNEL);
44962306a36Sopenharmony_ci	if (!nbuf) {
45062306a36Sopenharmony_ci		kfree(r);
45162306a36Sopenharmony_ci		return -ENOMEM;
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	if (!deletion)
45562306a36Sopenharmony_ci		*used += ALIGN(len, 8);
45662306a36Sopenharmony_ci	r->lnum = lnum;
45762306a36Sopenharmony_ci	r->offs = offs;
45862306a36Sopenharmony_ci	r->len = len;
45962306a36Sopenharmony_ci	ubifs_copy_hash(c, hash, r->hash);
46062306a36Sopenharmony_ci	r->deletion = !!deletion;
46162306a36Sopenharmony_ci	r->sqnum = sqnum;
46262306a36Sopenharmony_ci	key_copy(c, key, &r->key);
46362306a36Sopenharmony_ci	fname_len(&r->nm) = nlen;
46462306a36Sopenharmony_ci	memcpy(nbuf, name, nlen);
46562306a36Sopenharmony_ci	nbuf[nlen] = '\0';
46662306a36Sopenharmony_ci	fname_name(&r->nm) = nbuf;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	list_add_tail(&r->list, &c->replay_list);
46962306a36Sopenharmony_ci	return 0;
47062306a36Sopenharmony_ci}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci/**
47362306a36Sopenharmony_ci * ubifs_validate_entry - validate directory or extended attribute entry node.
47462306a36Sopenharmony_ci * @c: UBIFS file-system description object
47562306a36Sopenharmony_ci * @dent: the node to validate
47662306a36Sopenharmony_ci *
47762306a36Sopenharmony_ci * This function validates directory or extended attribute entry node @dent.
47862306a36Sopenharmony_ci * Returns zero if the node is all right and a %-EINVAL if not.
47962306a36Sopenharmony_ci */
48062306a36Sopenharmony_ciint ubifs_validate_entry(struct ubifs_info *c,
48162306a36Sopenharmony_ci			 const struct ubifs_dent_node *dent)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	int key_type = key_type_flash(c, dent->key);
48462306a36Sopenharmony_ci	int nlen = le16_to_cpu(dent->nlen);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	if (le32_to_cpu(dent->ch.len) != nlen + UBIFS_DENT_NODE_SZ + 1 ||
48762306a36Sopenharmony_ci	    dent->type >= UBIFS_ITYPES_CNT ||
48862306a36Sopenharmony_ci	    nlen > UBIFS_MAX_NLEN || dent->name[nlen] != 0 ||
48962306a36Sopenharmony_ci	    (key_type == UBIFS_XENT_KEY && strnlen(dent->name, nlen) != nlen) ||
49062306a36Sopenharmony_ci	    le64_to_cpu(dent->inum) > MAX_INUM) {
49162306a36Sopenharmony_ci		ubifs_err(c, "bad %s node", key_type == UBIFS_DENT_KEY ?
49262306a36Sopenharmony_ci			  "directory entry" : "extended attribute entry");
49362306a36Sopenharmony_ci		return -EINVAL;
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	if (key_type != UBIFS_DENT_KEY && key_type != UBIFS_XENT_KEY) {
49762306a36Sopenharmony_ci		ubifs_err(c, "bad key type %d", key_type);
49862306a36Sopenharmony_ci		return -EINVAL;
49962306a36Sopenharmony_ci	}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	return 0;
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci/**
50562306a36Sopenharmony_ci * is_last_bud - check if the bud is the last in the journal head.
50662306a36Sopenharmony_ci * @c: UBIFS file-system description object
50762306a36Sopenharmony_ci * @bud: bud description object
50862306a36Sopenharmony_ci *
50962306a36Sopenharmony_ci * This function checks if bud @bud is the last bud in its journal head. This
51062306a36Sopenharmony_ci * information is then used by 'replay_bud()' to decide whether the bud can
51162306a36Sopenharmony_ci * have corruptions or not. Indeed, only last buds can be corrupted by power
51262306a36Sopenharmony_ci * cuts. Returns %1 if this is the last bud, and %0 if not.
51362306a36Sopenharmony_ci */
51462306a36Sopenharmony_cistatic int is_last_bud(struct ubifs_info *c, struct ubifs_bud *bud)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	struct ubifs_jhead *jh = &c->jheads[bud->jhead];
51762306a36Sopenharmony_ci	struct ubifs_bud *next;
51862306a36Sopenharmony_ci	uint32_t data;
51962306a36Sopenharmony_ci	int err;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	if (list_is_last(&bud->list, &jh->buds_list))
52262306a36Sopenharmony_ci		return 1;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	/*
52562306a36Sopenharmony_ci	 * The following is a quirk to make sure we work correctly with UBIFS
52662306a36Sopenharmony_ci	 * images used with older UBIFS.
52762306a36Sopenharmony_ci	 *
52862306a36Sopenharmony_ci	 * Normally, the last bud will be the last in the journal head's list
52962306a36Sopenharmony_ci	 * of bud. However, there is one exception if the UBIFS image belongs
53062306a36Sopenharmony_ci	 * to older UBIFS. This is fairly unlikely: one would need to use old
53162306a36Sopenharmony_ci	 * UBIFS, then have a power cut exactly at the right point, and then
53262306a36Sopenharmony_ci	 * try to mount this image with new UBIFS.
53362306a36Sopenharmony_ci	 *
53462306a36Sopenharmony_ci	 * The exception is: it is possible to have 2 buds A and B, A goes
53562306a36Sopenharmony_ci	 * before B, and B is the last, bud B is contains no data, and bud A is
53662306a36Sopenharmony_ci	 * corrupted at the end. The reason is that in older versions when the
53762306a36Sopenharmony_ci	 * journal code switched the next bud (from A to B), it first added a
53862306a36Sopenharmony_ci	 * log reference node for the new bud (B), and only after this it
53962306a36Sopenharmony_ci	 * synchronized the write-buffer of current bud (A). But later this was
54062306a36Sopenharmony_ci	 * changed and UBIFS started to always synchronize the write-buffer of
54162306a36Sopenharmony_ci	 * the bud (A) before writing the log reference for the new bud (B).
54262306a36Sopenharmony_ci	 *
54362306a36Sopenharmony_ci	 * But because older UBIFS always synchronized A's write-buffer before
54462306a36Sopenharmony_ci	 * writing to B, we can recognize this exceptional situation but
54562306a36Sopenharmony_ci	 * checking the contents of bud B - if it is empty, then A can be
54662306a36Sopenharmony_ci	 * treated as the last and we can recover it.
54762306a36Sopenharmony_ci	 *
54862306a36Sopenharmony_ci	 * TODO: remove this piece of code in a couple of years (today it is
54962306a36Sopenharmony_ci	 * 16.05.2011).
55062306a36Sopenharmony_ci	 */
55162306a36Sopenharmony_ci	next = list_entry(bud->list.next, struct ubifs_bud, list);
55262306a36Sopenharmony_ci	if (!list_is_last(&next->list, &jh->buds_list))
55362306a36Sopenharmony_ci		return 0;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	err = ubifs_leb_read(c, next->lnum, (char *)&data, next->start, 4, 1);
55662306a36Sopenharmony_ci	if (err)
55762306a36Sopenharmony_ci		return 0;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	return data == 0xFFFFFFFF;
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci/* authenticate_sleb_hash is split out for stack usage */
56362306a36Sopenharmony_cistatic int noinline_for_stack
56462306a36Sopenharmony_ciauthenticate_sleb_hash(struct ubifs_info *c,
56562306a36Sopenharmony_ci		       struct shash_desc *log_hash, u8 *hash)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	SHASH_DESC_ON_STACK(hash_desc, c->hash_tfm);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	hash_desc->tfm = c->hash_tfm;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	ubifs_shash_copy_state(c, log_hash, hash_desc);
57262306a36Sopenharmony_ci	return crypto_shash_final(hash_desc, hash);
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci/**
57662306a36Sopenharmony_ci * authenticate_sleb - authenticate one scan LEB
57762306a36Sopenharmony_ci * @c: UBIFS file-system description object
57862306a36Sopenharmony_ci * @sleb: the scan LEB to authenticate
57962306a36Sopenharmony_ci * @log_hash:
58062306a36Sopenharmony_ci * @is_last: if true, this is the last LEB
58162306a36Sopenharmony_ci *
58262306a36Sopenharmony_ci * This function iterates over the buds of a single LEB authenticating all buds
58362306a36Sopenharmony_ci * with the authentication nodes on this LEB. Authentication nodes are written
58462306a36Sopenharmony_ci * after some buds and contain a HMAC covering the authentication node itself
58562306a36Sopenharmony_ci * and the buds between the last authentication node and the current
58662306a36Sopenharmony_ci * authentication node. It can happen that the last buds cannot be authenticated
58762306a36Sopenharmony_ci * because a powercut happened when some nodes were written but not the
58862306a36Sopenharmony_ci * corresponding authentication node. This function returns the number of nodes
58962306a36Sopenharmony_ci * that could be authenticated or a negative error code.
59062306a36Sopenharmony_ci */
59162306a36Sopenharmony_cistatic int authenticate_sleb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
59262306a36Sopenharmony_ci			     struct shash_desc *log_hash, int is_last)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	int n_not_auth = 0;
59562306a36Sopenharmony_ci	struct ubifs_scan_node *snod;
59662306a36Sopenharmony_ci	int n_nodes = 0;
59762306a36Sopenharmony_ci	int err;
59862306a36Sopenharmony_ci	u8 hash[UBIFS_HASH_ARR_SZ];
59962306a36Sopenharmony_ci	u8 hmac[UBIFS_HMAC_ARR_SZ];
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	if (!ubifs_authenticated(c))
60262306a36Sopenharmony_ci		return sleb->nodes_cnt;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	list_for_each_entry(snod, &sleb->nodes, list) {
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci		n_nodes++;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci		if (snod->type == UBIFS_AUTH_NODE) {
60962306a36Sopenharmony_ci			struct ubifs_auth_node *auth = snod->node;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci			err = authenticate_sleb_hash(c, log_hash, hash);
61262306a36Sopenharmony_ci			if (err)
61362306a36Sopenharmony_ci				goto out;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci			err = crypto_shash_tfm_digest(c->hmac_tfm, hash,
61662306a36Sopenharmony_ci						      c->hash_len, hmac);
61762306a36Sopenharmony_ci			if (err)
61862306a36Sopenharmony_ci				goto out;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci			err = ubifs_check_hmac(c, auth->hmac, hmac);
62162306a36Sopenharmony_ci			if (err) {
62262306a36Sopenharmony_ci				err = -EPERM;
62362306a36Sopenharmony_ci				goto out;
62462306a36Sopenharmony_ci			}
62562306a36Sopenharmony_ci			n_not_auth = 0;
62662306a36Sopenharmony_ci		} else {
62762306a36Sopenharmony_ci			err = crypto_shash_update(log_hash, snod->node,
62862306a36Sopenharmony_ci						  snod->len);
62962306a36Sopenharmony_ci			if (err)
63062306a36Sopenharmony_ci				goto out;
63162306a36Sopenharmony_ci			n_not_auth++;
63262306a36Sopenharmony_ci		}
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	/*
63662306a36Sopenharmony_ci	 * A powercut can happen when some nodes were written, but not yet
63762306a36Sopenharmony_ci	 * the corresponding authentication node. This may only happen on
63862306a36Sopenharmony_ci	 * the last bud though.
63962306a36Sopenharmony_ci	 */
64062306a36Sopenharmony_ci	if (n_not_auth) {
64162306a36Sopenharmony_ci		if (is_last) {
64262306a36Sopenharmony_ci			dbg_mnt("%d unauthenticated nodes found on LEB %d, Ignoring them",
64362306a36Sopenharmony_ci				n_not_auth, sleb->lnum);
64462306a36Sopenharmony_ci			err = 0;
64562306a36Sopenharmony_ci		} else {
64662306a36Sopenharmony_ci			dbg_mnt("%d unauthenticated nodes found on non-last LEB %d",
64762306a36Sopenharmony_ci				n_not_auth, sleb->lnum);
64862306a36Sopenharmony_ci			err = -EPERM;
64962306a36Sopenharmony_ci		}
65062306a36Sopenharmony_ci	} else {
65162306a36Sopenharmony_ci		err = 0;
65262306a36Sopenharmony_ci	}
65362306a36Sopenharmony_ciout:
65462306a36Sopenharmony_ci	return err ? err : n_nodes - n_not_auth;
65562306a36Sopenharmony_ci}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci/**
65862306a36Sopenharmony_ci * replay_bud - replay a bud logical eraseblock.
65962306a36Sopenharmony_ci * @c: UBIFS file-system description object
66062306a36Sopenharmony_ci * @b: bud entry which describes the bud
66162306a36Sopenharmony_ci *
66262306a36Sopenharmony_ci * This function replays bud @bud, recovers it if needed, and adds all nodes
66362306a36Sopenharmony_ci * from this bud to the replay list. Returns zero in case of success and a
66462306a36Sopenharmony_ci * negative error code in case of failure.
66562306a36Sopenharmony_ci */
66662306a36Sopenharmony_cistatic int replay_bud(struct ubifs_info *c, struct bud_entry *b)
66762306a36Sopenharmony_ci{
66862306a36Sopenharmony_ci	int is_last = is_last_bud(c, b->bud);
66962306a36Sopenharmony_ci	int err = 0, used = 0, lnum = b->bud->lnum, offs = b->bud->start;
67062306a36Sopenharmony_ci	int n_nodes, n = 0;
67162306a36Sopenharmony_ci	struct ubifs_scan_leb *sleb;
67262306a36Sopenharmony_ci	struct ubifs_scan_node *snod;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	dbg_mnt("replay bud LEB %d, head %d, offs %d, is_last %d",
67562306a36Sopenharmony_ci		lnum, b->bud->jhead, offs, is_last);
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	if (c->need_recovery && is_last)
67862306a36Sopenharmony_ci		/*
67962306a36Sopenharmony_ci		 * Recover only last LEBs in the journal heads, because power
68062306a36Sopenharmony_ci		 * cuts may cause corruptions only in these LEBs, because only
68162306a36Sopenharmony_ci		 * these LEBs could possibly be written to at the power cut
68262306a36Sopenharmony_ci		 * time.
68362306a36Sopenharmony_ci		 */
68462306a36Sopenharmony_ci		sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, b->bud->jhead);
68562306a36Sopenharmony_ci	else
68662306a36Sopenharmony_ci		sleb = ubifs_scan(c, lnum, offs, c->sbuf, 0);
68762306a36Sopenharmony_ci	if (IS_ERR(sleb))
68862306a36Sopenharmony_ci		return PTR_ERR(sleb);
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	n_nodes = authenticate_sleb(c, sleb, b->bud->log_hash, is_last);
69162306a36Sopenharmony_ci	if (n_nodes < 0) {
69262306a36Sopenharmony_ci		err = n_nodes;
69362306a36Sopenharmony_ci		goto out;
69462306a36Sopenharmony_ci	}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	ubifs_shash_copy_state(c, b->bud->log_hash,
69762306a36Sopenharmony_ci			       c->jheads[b->bud->jhead].log_hash);
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	/*
70062306a36Sopenharmony_ci	 * The bud does not have to start from offset zero - the beginning of
70162306a36Sopenharmony_ci	 * the 'lnum' LEB may contain previously committed data. One of the
70262306a36Sopenharmony_ci	 * things we have to do in replay is to correctly update lprops with
70362306a36Sopenharmony_ci	 * newer information about this LEB.
70462306a36Sopenharmony_ci	 *
70562306a36Sopenharmony_ci	 * At this point lprops thinks that this LEB has 'c->leb_size - offs'
70662306a36Sopenharmony_ci	 * bytes of free space because it only contain information about
70762306a36Sopenharmony_ci	 * committed data.
70862306a36Sopenharmony_ci	 *
70962306a36Sopenharmony_ci	 * But we know that real amount of free space is 'c->leb_size -
71062306a36Sopenharmony_ci	 * sleb->endpt', and the space in the 'lnum' LEB between 'offs' and
71162306a36Sopenharmony_ci	 * 'sleb->endpt' is used by bud data. We have to correctly calculate
71262306a36Sopenharmony_ci	 * how much of these data are dirty and update lprops with this
71362306a36Sopenharmony_ci	 * information.
71462306a36Sopenharmony_ci	 *
71562306a36Sopenharmony_ci	 * The dirt in that LEB region is comprised of padding nodes, deletion
71662306a36Sopenharmony_ci	 * nodes, truncation nodes and nodes which are obsoleted by subsequent
71762306a36Sopenharmony_ci	 * nodes in this LEB. So instead of calculating clean space, we
71862306a36Sopenharmony_ci	 * calculate used space ('used' variable).
71962306a36Sopenharmony_ci	 */
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	list_for_each_entry(snod, &sleb->nodes, list) {
72262306a36Sopenharmony_ci		u8 hash[UBIFS_HASH_ARR_SZ];
72362306a36Sopenharmony_ci		int deletion = 0;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci		cond_resched();
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci		if (snod->sqnum >= SQNUM_WATERMARK) {
72862306a36Sopenharmony_ci			ubifs_err(c, "file system's life ended");
72962306a36Sopenharmony_ci			goto out_dump;
73062306a36Sopenharmony_ci		}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci		ubifs_node_calc_hash(c, snod->node, hash);
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci		if (snod->sqnum > c->max_sqnum)
73562306a36Sopenharmony_ci			c->max_sqnum = snod->sqnum;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci		switch (snod->type) {
73862306a36Sopenharmony_ci		case UBIFS_INO_NODE:
73962306a36Sopenharmony_ci		{
74062306a36Sopenharmony_ci			struct ubifs_ino_node *ino = snod->node;
74162306a36Sopenharmony_ci			loff_t new_size = le64_to_cpu(ino->size);
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci			if (le32_to_cpu(ino->nlink) == 0)
74462306a36Sopenharmony_ci				deletion = 1;
74562306a36Sopenharmony_ci			err = insert_node(c, lnum, snod->offs, snod->len, hash,
74662306a36Sopenharmony_ci					  &snod->key, snod->sqnum, deletion,
74762306a36Sopenharmony_ci					  &used, 0, new_size);
74862306a36Sopenharmony_ci			break;
74962306a36Sopenharmony_ci		}
75062306a36Sopenharmony_ci		case UBIFS_DATA_NODE:
75162306a36Sopenharmony_ci		{
75262306a36Sopenharmony_ci			struct ubifs_data_node *dn = snod->node;
75362306a36Sopenharmony_ci			loff_t new_size = le32_to_cpu(dn->size) +
75462306a36Sopenharmony_ci					  key_block(c, &snod->key) *
75562306a36Sopenharmony_ci					  UBIFS_BLOCK_SIZE;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci			err = insert_node(c, lnum, snod->offs, snod->len, hash,
75862306a36Sopenharmony_ci					  &snod->key, snod->sqnum, deletion,
75962306a36Sopenharmony_ci					  &used, 0, new_size);
76062306a36Sopenharmony_ci			break;
76162306a36Sopenharmony_ci		}
76262306a36Sopenharmony_ci		case UBIFS_DENT_NODE:
76362306a36Sopenharmony_ci		case UBIFS_XENT_NODE:
76462306a36Sopenharmony_ci		{
76562306a36Sopenharmony_ci			struct ubifs_dent_node *dent = snod->node;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci			err = ubifs_validate_entry(c, dent);
76862306a36Sopenharmony_ci			if (err)
76962306a36Sopenharmony_ci				goto out_dump;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci			err = insert_dent(c, lnum, snod->offs, snod->len, hash,
77262306a36Sopenharmony_ci					  &snod->key, dent->name,
77362306a36Sopenharmony_ci					  le16_to_cpu(dent->nlen), snod->sqnum,
77462306a36Sopenharmony_ci					  !le64_to_cpu(dent->inum), &used);
77562306a36Sopenharmony_ci			break;
77662306a36Sopenharmony_ci		}
77762306a36Sopenharmony_ci		case UBIFS_TRUN_NODE:
77862306a36Sopenharmony_ci		{
77962306a36Sopenharmony_ci			struct ubifs_trun_node *trun = snod->node;
78062306a36Sopenharmony_ci			loff_t old_size = le64_to_cpu(trun->old_size);
78162306a36Sopenharmony_ci			loff_t new_size = le64_to_cpu(trun->new_size);
78262306a36Sopenharmony_ci			union ubifs_key key;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci			/* Validate truncation node */
78562306a36Sopenharmony_ci			if (old_size < 0 || old_size > c->max_inode_sz ||
78662306a36Sopenharmony_ci			    new_size < 0 || new_size > c->max_inode_sz ||
78762306a36Sopenharmony_ci			    old_size <= new_size) {
78862306a36Sopenharmony_ci				ubifs_err(c, "bad truncation node");
78962306a36Sopenharmony_ci				goto out_dump;
79062306a36Sopenharmony_ci			}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci			/*
79362306a36Sopenharmony_ci			 * Create a fake truncation key just to use the same
79462306a36Sopenharmony_ci			 * functions which expect nodes to have keys.
79562306a36Sopenharmony_ci			 */
79662306a36Sopenharmony_ci			trun_key_init(c, &key, le32_to_cpu(trun->inum));
79762306a36Sopenharmony_ci			err = insert_node(c, lnum, snod->offs, snod->len, hash,
79862306a36Sopenharmony_ci					  &key, snod->sqnum, 1, &used,
79962306a36Sopenharmony_ci					  old_size, new_size);
80062306a36Sopenharmony_ci			break;
80162306a36Sopenharmony_ci		}
80262306a36Sopenharmony_ci		case UBIFS_AUTH_NODE:
80362306a36Sopenharmony_ci			break;
80462306a36Sopenharmony_ci		default:
80562306a36Sopenharmony_ci			ubifs_err(c, "unexpected node type %d in bud LEB %d:%d",
80662306a36Sopenharmony_ci				  snod->type, lnum, snod->offs);
80762306a36Sopenharmony_ci			err = -EINVAL;
80862306a36Sopenharmony_ci			goto out_dump;
80962306a36Sopenharmony_ci		}
81062306a36Sopenharmony_ci		if (err)
81162306a36Sopenharmony_ci			goto out;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci		n++;
81462306a36Sopenharmony_ci		if (n == n_nodes)
81562306a36Sopenharmony_ci			break;
81662306a36Sopenharmony_ci	}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	ubifs_assert(c, ubifs_search_bud(c, lnum));
81962306a36Sopenharmony_ci	ubifs_assert(c, sleb->endpt - offs >= used);
82062306a36Sopenharmony_ci	ubifs_assert(c, sleb->endpt % c->min_io_size == 0);
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	b->dirty = sleb->endpt - offs - used;
82362306a36Sopenharmony_ci	b->free = c->leb_size - sleb->endpt;
82462306a36Sopenharmony_ci	dbg_mnt("bud LEB %d replied: dirty %d, free %d",
82562306a36Sopenharmony_ci		lnum, b->dirty, b->free);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ciout:
82862306a36Sopenharmony_ci	ubifs_scan_destroy(sleb);
82962306a36Sopenharmony_ci	return err;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ciout_dump:
83262306a36Sopenharmony_ci	ubifs_err(c, "bad node is at LEB %d:%d", lnum, snod->offs);
83362306a36Sopenharmony_ci	ubifs_dump_node(c, snod->node, c->leb_size - snod->offs);
83462306a36Sopenharmony_ci	ubifs_scan_destroy(sleb);
83562306a36Sopenharmony_ci	return -EINVAL;
83662306a36Sopenharmony_ci}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci/**
83962306a36Sopenharmony_ci * replay_buds - replay all buds.
84062306a36Sopenharmony_ci * @c: UBIFS file-system description object
84162306a36Sopenharmony_ci *
84262306a36Sopenharmony_ci * This function returns zero in case of success and a negative error code in
84362306a36Sopenharmony_ci * case of failure.
84462306a36Sopenharmony_ci */
84562306a36Sopenharmony_cistatic int replay_buds(struct ubifs_info *c)
84662306a36Sopenharmony_ci{
84762306a36Sopenharmony_ci	struct bud_entry *b;
84862306a36Sopenharmony_ci	int err;
84962306a36Sopenharmony_ci	unsigned long long prev_sqnum = 0;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	list_for_each_entry(b, &c->replay_buds, list) {
85262306a36Sopenharmony_ci		err = replay_bud(c, b);
85362306a36Sopenharmony_ci		if (err)
85462306a36Sopenharmony_ci			return err;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci		ubifs_assert(c, b->sqnum > prev_sqnum);
85762306a36Sopenharmony_ci		prev_sqnum = b->sqnum;
85862306a36Sopenharmony_ci	}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	return 0;
86162306a36Sopenharmony_ci}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci/**
86462306a36Sopenharmony_ci * destroy_bud_list - destroy the list of buds to replay.
86562306a36Sopenharmony_ci * @c: UBIFS file-system description object
86662306a36Sopenharmony_ci */
86762306a36Sopenharmony_cistatic void destroy_bud_list(struct ubifs_info *c)
86862306a36Sopenharmony_ci{
86962306a36Sopenharmony_ci	struct bud_entry *b;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	while (!list_empty(&c->replay_buds)) {
87262306a36Sopenharmony_ci		b = list_entry(c->replay_buds.next, struct bud_entry, list);
87362306a36Sopenharmony_ci		list_del(&b->list);
87462306a36Sopenharmony_ci		kfree(b);
87562306a36Sopenharmony_ci	}
87662306a36Sopenharmony_ci}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci/**
87962306a36Sopenharmony_ci * add_replay_bud - add a bud to the list of buds to replay.
88062306a36Sopenharmony_ci * @c: UBIFS file-system description object
88162306a36Sopenharmony_ci * @lnum: bud logical eraseblock number to replay
88262306a36Sopenharmony_ci * @offs: bud start offset
88362306a36Sopenharmony_ci * @jhead: journal head to which this bud belongs
88462306a36Sopenharmony_ci * @sqnum: reference node sequence number
88562306a36Sopenharmony_ci *
88662306a36Sopenharmony_ci * This function returns zero in case of success and a negative error code in
88762306a36Sopenharmony_ci * case of failure.
88862306a36Sopenharmony_ci */
88962306a36Sopenharmony_cistatic int add_replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
89062306a36Sopenharmony_ci			  unsigned long long sqnum)
89162306a36Sopenharmony_ci{
89262306a36Sopenharmony_ci	struct ubifs_bud *bud;
89362306a36Sopenharmony_ci	struct bud_entry *b;
89462306a36Sopenharmony_ci	int err;
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	dbg_mnt("add replay bud LEB %d:%d, head %d", lnum, offs, jhead);
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	bud = kmalloc(sizeof(struct ubifs_bud), GFP_KERNEL);
89962306a36Sopenharmony_ci	if (!bud)
90062306a36Sopenharmony_ci		return -ENOMEM;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	b = kmalloc(sizeof(struct bud_entry), GFP_KERNEL);
90362306a36Sopenharmony_ci	if (!b) {
90462306a36Sopenharmony_ci		err = -ENOMEM;
90562306a36Sopenharmony_ci		goto out;
90662306a36Sopenharmony_ci	}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	bud->lnum = lnum;
90962306a36Sopenharmony_ci	bud->start = offs;
91062306a36Sopenharmony_ci	bud->jhead = jhead;
91162306a36Sopenharmony_ci	bud->log_hash = ubifs_hash_get_desc(c);
91262306a36Sopenharmony_ci	if (IS_ERR(bud->log_hash)) {
91362306a36Sopenharmony_ci		err = PTR_ERR(bud->log_hash);
91462306a36Sopenharmony_ci		goto out;
91562306a36Sopenharmony_ci	}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	ubifs_shash_copy_state(c, c->log_hash, bud->log_hash);
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	ubifs_add_bud(c, bud);
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	b->bud = bud;
92262306a36Sopenharmony_ci	b->sqnum = sqnum;
92362306a36Sopenharmony_ci	list_add_tail(&b->list, &c->replay_buds);
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	return 0;
92662306a36Sopenharmony_ciout:
92762306a36Sopenharmony_ci	kfree(bud);
92862306a36Sopenharmony_ci	kfree(b);
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	return err;
93162306a36Sopenharmony_ci}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci/**
93462306a36Sopenharmony_ci * validate_ref - validate a reference node.
93562306a36Sopenharmony_ci * @c: UBIFS file-system description object
93662306a36Sopenharmony_ci * @ref: the reference node to validate
93762306a36Sopenharmony_ci *
93862306a36Sopenharmony_ci * This function returns %1 if a bud reference already exists for the LEB. %0 is
93962306a36Sopenharmony_ci * returned if the reference node is new, otherwise %-EINVAL is returned if
94062306a36Sopenharmony_ci * validation failed.
94162306a36Sopenharmony_ci */
94262306a36Sopenharmony_cistatic int validate_ref(struct ubifs_info *c, const struct ubifs_ref_node *ref)
94362306a36Sopenharmony_ci{
94462306a36Sopenharmony_ci	struct ubifs_bud *bud;
94562306a36Sopenharmony_ci	int lnum = le32_to_cpu(ref->lnum);
94662306a36Sopenharmony_ci	unsigned int offs = le32_to_cpu(ref->offs);
94762306a36Sopenharmony_ci	unsigned int jhead = le32_to_cpu(ref->jhead);
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	/*
95062306a36Sopenharmony_ci	 * ref->offs may point to the end of LEB when the journal head points
95162306a36Sopenharmony_ci	 * to the end of LEB and we write reference node for it during commit.
95262306a36Sopenharmony_ci	 * So this is why we require 'offs > c->leb_size'.
95362306a36Sopenharmony_ci	 */
95462306a36Sopenharmony_ci	if (jhead >= c->jhead_cnt || lnum >= c->leb_cnt ||
95562306a36Sopenharmony_ci	    lnum < c->main_first || offs > c->leb_size ||
95662306a36Sopenharmony_ci	    offs & (c->min_io_size - 1))
95762306a36Sopenharmony_ci		return -EINVAL;
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	/* Make sure we have not already looked at this bud */
96062306a36Sopenharmony_ci	bud = ubifs_search_bud(c, lnum);
96162306a36Sopenharmony_ci	if (bud) {
96262306a36Sopenharmony_ci		if (bud->jhead == jhead && bud->start <= offs)
96362306a36Sopenharmony_ci			return 1;
96462306a36Sopenharmony_ci		ubifs_err(c, "bud at LEB %d:%d was already referred", lnum, offs);
96562306a36Sopenharmony_ci		return -EINVAL;
96662306a36Sopenharmony_ci	}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	return 0;
96962306a36Sopenharmony_ci}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci/**
97262306a36Sopenharmony_ci * replay_log_leb - replay a log logical eraseblock.
97362306a36Sopenharmony_ci * @c: UBIFS file-system description object
97462306a36Sopenharmony_ci * @lnum: log logical eraseblock to replay
97562306a36Sopenharmony_ci * @offs: offset to start replaying from
97662306a36Sopenharmony_ci * @sbuf: scan buffer
97762306a36Sopenharmony_ci *
97862306a36Sopenharmony_ci * This function replays a log LEB and returns zero in case of success, %1 if
97962306a36Sopenharmony_ci * this is the last LEB in the log, and a negative error code in case of
98062306a36Sopenharmony_ci * failure.
98162306a36Sopenharmony_ci */
98262306a36Sopenharmony_cistatic int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf)
98362306a36Sopenharmony_ci{
98462306a36Sopenharmony_ci	int err;
98562306a36Sopenharmony_ci	struct ubifs_scan_leb *sleb;
98662306a36Sopenharmony_ci	struct ubifs_scan_node *snod;
98762306a36Sopenharmony_ci	const struct ubifs_cs_node *node;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	dbg_mnt("replay log LEB %d:%d", lnum, offs);
99062306a36Sopenharmony_ci	sleb = ubifs_scan(c, lnum, offs, sbuf, c->need_recovery);
99162306a36Sopenharmony_ci	if (IS_ERR(sleb)) {
99262306a36Sopenharmony_ci		if (PTR_ERR(sleb) != -EUCLEAN || !c->need_recovery)
99362306a36Sopenharmony_ci			return PTR_ERR(sleb);
99462306a36Sopenharmony_ci		/*
99562306a36Sopenharmony_ci		 * Note, the below function will recover this log LEB only if
99662306a36Sopenharmony_ci		 * it is the last, because unclean reboots can possibly corrupt
99762306a36Sopenharmony_ci		 * only the tail of the log.
99862306a36Sopenharmony_ci		 */
99962306a36Sopenharmony_ci		sleb = ubifs_recover_log_leb(c, lnum, offs, sbuf);
100062306a36Sopenharmony_ci		if (IS_ERR(sleb))
100162306a36Sopenharmony_ci			return PTR_ERR(sleb);
100262306a36Sopenharmony_ci	}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	if (sleb->nodes_cnt == 0) {
100562306a36Sopenharmony_ci		err = 1;
100662306a36Sopenharmony_ci		goto out;
100762306a36Sopenharmony_ci	}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	node = sleb->buf;
101062306a36Sopenharmony_ci	snod = list_entry(sleb->nodes.next, struct ubifs_scan_node, list);
101162306a36Sopenharmony_ci	if (c->cs_sqnum == 0) {
101262306a36Sopenharmony_ci		/*
101362306a36Sopenharmony_ci		 * This is the first log LEB we are looking at, make sure that
101462306a36Sopenharmony_ci		 * the first node is a commit start node. Also record its
101562306a36Sopenharmony_ci		 * sequence number so that UBIFS can determine where the log
101662306a36Sopenharmony_ci		 * ends, because all nodes which were have higher sequence
101762306a36Sopenharmony_ci		 * numbers.
101862306a36Sopenharmony_ci		 */
101962306a36Sopenharmony_ci		if (snod->type != UBIFS_CS_NODE) {
102062306a36Sopenharmony_ci			ubifs_err(c, "first log node at LEB %d:%d is not CS node",
102162306a36Sopenharmony_ci				  lnum, offs);
102262306a36Sopenharmony_ci			goto out_dump;
102362306a36Sopenharmony_ci		}
102462306a36Sopenharmony_ci		if (le64_to_cpu(node->cmt_no) != c->cmt_no) {
102562306a36Sopenharmony_ci			ubifs_err(c, "first CS node at LEB %d:%d has wrong commit number %llu expected %llu",
102662306a36Sopenharmony_ci				  lnum, offs,
102762306a36Sopenharmony_ci				  (unsigned long long)le64_to_cpu(node->cmt_no),
102862306a36Sopenharmony_ci				  c->cmt_no);
102962306a36Sopenharmony_ci			goto out_dump;
103062306a36Sopenharmony_ci		}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci		c->cs_sqnum = le64_to_cpu(node->ch.sqnum);
103362306a36Sopenharmony_ci		dbg_mnt("commit start sqnum %llu", c->cs_sqnum);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci		err = ubifs_shash_init(c, c->log_hash);
103662306a36Sopenharmony_ci		if (err)
103762306a36Sopenharmony_ci			goto out;
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci		err = ubifs_shash_update(c, c->log_hash, node, UBIFS_CS_NODE_SZ);
104062306a36Sopenharmony_ci		if (err < 0)
104162306a36Sopenharmony_ci			goto out;
104262306a36Sopenharmony_ci	}
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	if (snod->sqnum < c->cs_sqnum) {
104562306a36Sopenharmony_ci		/*
104662306a36Sopenharmony_ci		 * This means that we reached end of log and now
104762306a36Sopenharmony_ci		 * look to the older log data, which was already
104862306a36Sopenharmony_ci		 * committed but the eraseblock was not erased (UBIFS
104962306a36Sopenharmony_ci		 * only un-maps it). So this basically means we have to
105062306a36Sopenharmony_ci		 * exit with "end of log" code.
105162306a36Sopenharmony_ci		 */
105262306a36Sopenharmony_ci		err = 1;
105362306a36Sopenharmony_ci		goto out;
105462306a36Sopenharmony_ci	}
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	/* Make sure the first node sits at offset zero of the LEB */
105762306a36Sopenharmony_ci	if (snod->offs != 0) {
105862306a36Sopenharmony_ci		ubifs_err(c, "first node is not at zero offset");
105962306a36Sopenharmony_ci		goto out_dump;
106062306a36Sopenharmony_ci	}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	list_for_each_entry(snod, &sleb->nodes, list) {
106362306a36Sopenharmony_ci		cond_resched();
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci		if (snod->sqnum >= SQNUM_WATERMARK) {
106662306a36Sopenharmony_ci			ubifs_err(c, "file system's life ended");
106762306a36Sopenharmony_ci			goto out_dump;
106862306a36Sopenharmony_ci		}
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci		if (snod->sqnum < c->cs_sqnum) {
107162306a36Sopenharmony_ci			ubifs_err(c, "bad sqnum %llu, commit sqnum %llu",
107262306a36Sopenharmony_ci				  snod->sqnum, c->cs_sqnum);
107362306a36Sopenharmony_ci			goto out_dump;
107462306a36Sopenharmony_ci		}
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci		if (snod->sqnum > c->max_sqnum)
107762306a36Sopenharmony_ci			c->max_sqnum = snod->sqnum;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci		switch (snod->type) {
108062306a36Sopenharmony_ci		case UBIFS_REF_NODE: {
108162306a36Sopenharmony_ci			const struct ubifs_ref_node *ref = snod->node;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci			err = validate_ref(c, ref);
108462306a36Sopenharmony_ci			if (err == 1)
108562306a36Sopenharmony_ci				break; /* Already have this bud */
108662306a36Sopenharmony_ci			if (err)
108762306a36Sopenharmony_ci				goto out_dump;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci			err = ubifs_shash_update(c, c->log_hash, ref,
109062306a36Sopenharmony_ci						 UBIFS_REF_NODE_SZ);
109162306a36Sopenharmony_ci			if (err)
109262306a36Sopenharmony_ci				goto out;
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci			err = add_replay_bud(c, le32_to_cpu(ref->lnum),
109562306a36Sopenharmony_ci					     le32_to_cpu(ref->offs),
109662306a36Sopenharmony_ci					     le32_to_cpu(ref->jhead),
109762306a36Sopenharmony_ci					     snod->sqnum);
109862306a36Sopenharmony_ci			if (err)
109962306a36Sopenharmony_ci				goto out;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci			break;
110262306a36Sopenharmony_ci		}
110362306a36Sopenharmony_ci		case UBIFS_CS_NODE:
110462306a36Sopenharmony_ci			/* Make sure it sits at the beginning of LEB */
110562306a36Sopenharmony_ci			if (snod->offs != 0) {
110662306a36Sopenharmony_ci				ubifs_err(c, "unexpected node in log");
110762306a36Sopenharmony_ci				goto out_dump;
110862306a36Sopenharmony_ci			}
110962306a36Sopenharmony_ci			break;
111062306a36Sopenharmony_ci		default:
111162306a36Sopenharmony_ci			ubifs_err(c, "unexpected node in log");
111262306a36Sopenharmony_ci			goto out_dump;
111362306a36Sopenharmony_ci		}
111462306a36Sopenharmony_ci	}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	if (sleb->endpt || c->lhead_offs >= c->leb_size) {
111762306a36Sopenharmony_ci		c->lhead_lnum = lnum;
111862306a36Sopenharmony_ci		c->lhead_offs = sleb->endpt;
111962306a36Sopenharmony_ci	}
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	err = !sleb->endpt;
112262306a36Sopenharmony_ciout:
112362306a36Sopenharmony_ci	ubifs_scan_destroy(sleb);
112462306a36Sopenharmony_ci	return err;
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ciout_dump:
112762306a36Sopenharmony_ci	ubifs_err(c, "log error detected while replaying the log at LEB %d:%d",
112862306a36Sopenharmony_ci		  lnum, offs + snod->offs);
112962306a36Sopenharmony_ci	ubifs_dump_node(c, snod->node, c->leb_size - snod->offs);
113062306a36Sopenharmony_ci	ubifs_scan_destroy(sleb);
113162306a36Sopenharmony_ci	return -EINVAL;
113262306a36Sopenharmony_ci}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci/**
113562306a36Sopenharmony_ci * take_ihead - update the status of the index head in lprops to 'taken'.
113662306a36Sopenharmony_ci * @c: UBIFS file-system description object
113762306a36Sopenharmony_ci *
113862306a36Sopenharmony_ci * This function returns the amount of free space in the index head LEB or a
113962306a36Sopenharmony_ci * negative error code.
114062306a36Sopenharmony_ci */
114162306a36Sopenharmony_cistatic int take_ihead(struct ubifs_info *c)
114262306a36Sopenharmony_ci{
114362306a36Sopenharmony_ci	const struct ubifs_lprops *lp;
114462306a36Sopenharmony_ci	int err, free;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	ubifs_get_lprops(c);
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	lp = ubifs_lpt_lookup_dirty(c, c->ihead_lnum);
114962306a36Sopenharmony_ci	if (IS_ERR(lp)) {
115062306a36Sopenharmony_ci		err = PTR_ERR(lp);
115162306a36Sopenharmony_ci		goto out;
115262306a36Sopenharmony_ci	}
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	free = lp->free;
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	lp = ubifs_change_lp(c, lp, LPROPS_NC, LPROPS_NC,
115762306a36Sopenharmony_ci			     lp->flags | LPROPS_TAKEN, 0);
115862306a36Sopenharmony_ci	if (IS_ERR(lp)) {
115962306a36Sopenharmony_ci		err = PTR_ERR(lp);
116062306a36Sopenharmony_ci		goto out;
116162306a36Sopenharmony_ci	}
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	err = free;
116462306a36Sopenharmony_ciout:
116562306a36Sopenharmony_ci	ubifs_release_lprops(c);
116662306a36Sopenharmony_ci	return err;
116762306a36Sopenharmony_ci}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci/**
117062306a36Sopenharmony_ci * ubifs_replay_journal - replay journal.
117162306a36Sopenharmony_ci * @c: UBIFS file-system description object
117262306a36Sopenharmony_ci *
117362306a36Sopenharmony_ci * This function scans the journal, replays and cleans it up. It makes sure all
117462306a36Sopenharmony_ci * memory data structures related to uncommitted journal are built (dirty TNC
117562306a36Sopenharmony_ci * tree, tree of buds, modified lprops, etc).
117662306a36Sopenharmony_ci */
117762306a36Sopenharmony_ciint ubifs_replay_journal(struct ubifs_info *c)
117862306a36Sopenharmony_ci{
117962306a36Sopenharmony_ci	int err, lnum, free;
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	BUILD_BUG_ON(UBIFS_TRUN_KEY > 5);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	/* Update the status of the index head in lprops to 'taken' */
118462306a36Sopenharmony_ci	free = take_ihead(c);
118562306a36Sopenharmony_ci	if (free < 0)
118662306a36Sopenharmony_ci		return free; /* Error code */
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	if (c->ihead_offs != c->leb_size - free) {
118962306a36Sopenharmony_ci		ubifs_err(c, "bad index head LEB %d:%d", c->ihead_lnum,
119062306a36Sopenharmony_ci			  c->ihead_offs);
119162306a36Sopenharmony_ci		return -EINVAL;
119262306a36Sopenharmony_ci	}
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	dbg_mnt("start replaying the journal");
119562306a36Sopenharmony_ci	c->replaying = 1;
119662306a36Sopenharmony_ci	lnum = c->ltail_lnum = c->lhead_lnum;
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	do {
119962306a36Sopenharmony_ci		err = replay_log_leb(c, lnum, 0, c->sbuf);
120062306a36Sopenharmony_ci		if (err == 1) {
120162306a36Sopenharmony_ci			if (lnum != c->lhead_lnum)
120262306a36Sopenharmony_ci				/* We hit the end of the log */
120362306a36Sopenharmony_ci				break;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci			/*
120662306a36Sopenharmony_ci			 * The head of the log must always start with the
120762306a36Sopenharmony_ci			 * "commit start" node on a properly formatted UBIFS.
120862306a36Sopenharmony_ci			 * But we found no nodes at all, which means that
120962306a36Sopenharmony_ci			 * something went wrong and we cannot proceed mounting
121062306a36Sopenharmony_ci			 * the file-system.
121162306a36Sopenharmony_ci			 */
121262306a36Sopenharmony_ci			ubifs_err(c, "no UBIFS nodes found at the log head LEB %d:%d, possibly corrupted",
121362306a36Sopenharmony_ci				  lnum, 0);
121462306a36Sopenharmony_ci			err = -EINVAL;
121562306a36Sopenharmony_ci		}
121662306a36Sopenharmony_ci		if (err)
121762306a36Sopenharmony_ci			goto out;
121862306a36Sopenharmony_ci		lnum = ubifs_next_log_lnum(c, lnum);
121962306a36Sopenharmony_ci	} while (lnum != c->ltail_lnum);
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	err = replay_buds(c);
122262306a36Sopenharmony_ci	if (err)
122362306a36Sopenharmony_ci		goto out;
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	err = apply_replay_list(c);
122662306a36Sopenharmony_ci	if (err)
122762306a36Sopenharmony_ci		goto out;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	err = set_buds_lprops(c);
123062306a36Sopenharmony_ci	if (err)
123162306a36Sopenharmony_ci		goto out;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	/*
123462306a36Sopenharmony_ci	 * UBIFS budgeting calculations use @c->bi.uncommitted_idx variable
123562306a36Sopenharmony_ci	 * to roughly estimate index growth. Things like @c->bi.min_idx_lebs
123662306a36Sopenharmony_ci	 * depend on it. This means we have to initialize it to make sure
123762306a36Sopenharmony_ci	 * budgeting works properly.
123862306a36Sopenharmony_ci	 */
123962306a36Sopenharmony_ci	c->bi.uncommitted_idx = atomic_long_read(&c->dirty_zn_cnt);
124062306a36Sopenharmony_ci	c->bi.uncommitted_idx *= c->max_idx_node_sz;
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	ubifs_assert(c, c->bud_bytes <= c->max_bud_bytes || c->need_recovery);
124362306a36Sopenharmony_ci	dbg_mnt("finished, log head LEB %d:%d, max_sqnum %llu, highest_inum %lu",
124462306a36Sopenharmony_ci		c->lhead_lnum, c->lhead_offs, c->max_sqnum,
124562306a36Sopenharmony_ci		(unsigned long)c->highest_inum);
124662306a36Sopenharmony_ciout:
124762306a36Sopenharmony_ci	destroy_replay_list(c);
124862306a36Sopenharmony_ci	destroy_bud_list(c);
124962306a36Sopenharmony_ci	c->replaying = 0;
125062306a36Sopenharmony_ci	return err;
125162306a36Sopenharmony_ci}
1252