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