18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This file is part of UBIFS. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2006-2008 Nokia Corporation. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: Adrian Hunter 88c2ecf20Sopenharmony_ci * Artem Bityutskiy (Битюцкий Артём) 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci/* 128c2ecf20Sopenharmony_ci * This file contains journal replay code. It runs when the file-system is being 138c2ecf20Sopenharmony_ci * mounted and requires no locking. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * The larger is the journal, the longer it takes to scan it, so the longer it 168c2ecf20Sopenharmony_ci * takes to mount UBIFS. This is why the journal has limited size which may be 178c2ecf20Sopenharmony_ci * changed depending on the system requirements. But a larger journal gives 188c2ecf20Sopenharmony_ci * faster I/O speed because it writes the index less frequently. So this is a 198c2ecf20Sopenharmony_ci * trade-off. Also, the journal is indexed by the in-memory index (TNC), so the 208c2ecf20Sopenharmony_ci * larger is the journal, the more memory its index may consume. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "ubifs.h" 248c2ecf20Sopenharmony_ci#include <linux/list_sort.h> 258c2ecf20Sopenharmony_ci#include <crypto/hash.h> 268c2ecf20Sopenharmony_ci#include <crypto/algapi.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/** 298c2ecf20Sopenharmony_ci * struct replay_entry - replay list entry. 308c2ecf20Sopenharmony_ci * @lnum: logical eraseblock number of the node 318c2ecf20Sopenharmony_ci * @offs: node offset 328c2ecf20Sopenharmony_ci * @len: node length 338c2ecf20Sopenharmony_ci * @deletion: non-zero if this entry corresponds to a node deletion 348c2ecf20Sopenharmony_ci * @sqnum: node sequence number 358c2ecf20Sopenharmony_ci * @list: links the replay list 368c2ecf20Sopenharmony_ci * @key: node key 378c2ecf20Sopenharmony_ci * @nm: directory entry name 388c2ecf20Sopenharmony_ci * @old_size: truncation old size 398c2ecf20Sopenharmony_ci * @new_size: truncation new size 408c2ecf20Sopenharmony_ci * 418c2ecf20Sopenharmony_ci * The replay process first scans all buds and builds the replay list, then 428c2ecf20Sopenharmony_ci * sorts the replay list in nodes sequence number order, and then inserts all 438c2ecf20Sopenharmony_ci * the replay entries to the TNC. 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_cistruct replay_entry { 468c2ecf20Sopenharmony_ci int lnum; 478c2ecf20Sopenharmony_ci int offs; 488c2ecf20Sopenharmony_ci int len; 498c2ecf20Sopenharmony_ci u8 hash[UBIFS_HASH_ARR_SZ]; 508c2ecf20Sopenharmony_ci unsigned int deletion:1; 518c2ecf20Sopenharmony_ci unsigned long long sqnum; 528c2ecf20Sopenharmony_ci struct list_head list; 538c2ecf20Sopenharmony_ci union ubifs_key key; 548c2ecf20Sopenharmony_ci union { 558c2ecf20Sopenharmony_ci struct fscrypt_name nm; 568c2ecf20Sopenharmony_ci struct { 578c2ecf20Sopenharmony_ci loff_t old_size; 588c2ecf20Sopenharmony_ci loff_t new_size; 598c2ecf20Sopenharmony_ci }; 608c2ecf20Sopenharmony_ci }; 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/** 648c2ecf20Sopenharmony_ci * struct bud_entry - entry in the list of buds to replay. 658c2ecf20Sopenharmony_ci * @list: next bud in the list 668c2ecf20Sopenharmony_ci * @bud: bud description object 678c2ecf20Sopenharmony_ci * @sqnum: reference node sequence number 688c2ecf20Sopenharmony_ci * @free: free bytes in the bud 698c2ecf20Sopenharmony_ci * @dirty: dirty bytes in the bud 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_cistruct bud_entry { 728c2ecf20Sopenharmony_ci struct list_head list; 738c2ecf20Sopenharmony_ci struct ubifs_bud *bud; 748c2ecf20Sopenharmony_ci unsigned long long sqnum; 758c2ecf20Sopenharmony_ci int free; 768c2ecf20Sopenharmony_ci int dirty; 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/** 808c2ecf20Sopenharmony_ci * set_bud_lprops - set free and dirty space used by a bud. 818c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 828c2ecf20Sopenharmony_ci * @b: bud entry which describes the bud 838c2ecf20Sopenharmony_ci * 848c2ecf20Sopenharmony_ci * This function makes sure the LEB properties of bud @b are set correctly 858c2ecf20Sopenharmony_ci * after the replay. Returns zero in case of success and a negative error code 868c2ecf20Sopenharmony_ci * in case of failure. 878c2ecf20Sopenharmony_ci */ 888c2ecf20Sopenharmony_cistatic int set_bud_lprops(struct ubifs_info *c, struct bud_entry *b) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci const struct ubifs_lprops *lp; 918c2ecf20Sopenharmony_ci int err = 0, dirty; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci ubifs_get_lprops(c); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci lp = ubifs_lpt_lookup_dirty(c, b->bud->lnum); 968c2ecf20Sopenharmony_ci if (IS_ERR(lp)) { 978c2ecf20Sopenharmony_ci err = PTR_ERR(lp); 988c2ecf20Sopenharmony_ci goto out; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci dirty = lp->dirty; 1028c2ecf20Sopenharmony_ci if (b->bud->start == 0 && (lp->free != c->leb_size || lp->dirty != 0)) { 1038c2ecf20Sopenharmony_ci /* 1048c2ecf20Sopenharmony_ci * The LEB was added to the journal with a starting offset of 1058c2ecf20Sopenharmony_ci * zero which means the LEB must have been empty. The LEB 1068c2ecf20Sopenharmony_ci * property values should be @lp->free == @c->leb_size and 1078c2ecf20Sopenharmony_ci * @lp->dirty == 0, but that is not the case. The reason is that 1088c2ecf20Sopenharmony_ci * the LEB had been garbage collected before it became the bud, 1098c2ecf20Sopenharmony_ci * and there was not commit inbetween. The garbage collector 1108c2ecf20Sopenharmony_ci * resets the free and dirty space without recording it 1118c2ecf20Sopenharmony_ci * anywhere except lprops, so if there was no commit then 1128c2ecf20Sopenharmony_ci * lprops does not have that information. 1138c2ecf20Sopenharmony_ci * 1148c2ecf20Sopenharmony_ci * We do not need to adjust free space because the scan has told 1158c2ecf20Sopenharmony_ci * us the exact value which is recorded in the replay entry as 1168c2ecf20Sopenharmony_ci * @b->free. 1178c2ecf20Sopenharmony_ci * 1188c2ecf20Sopenharmony_ci * However we do need to subtract from the dirty space the 1198c2ecf20Sopenharmony_ci * amount of space that the garbage collector reclaimed, which 1208c2ecf20Sopenharmony_ci * is the whole LEB minus the amount of space that was free. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci dbg_mnt("bud LEB %d was GC'd (%d free, %d dirty)", b->bud->lnum, 1238c2ecf20Sopenharmony_ci lp->free, lp->dirty); 1248c2ecf20Sopenharmony_ci dbg_gc("bud LEB %d was GC'd (%d free, %d dirty)", b->bud->lnum, 1258c2ecf20Sopenharmony_ci lp->free, lp->dirty); 1268c2ecf20Sopenharmony_ci dirty -= c->leb_size - lp->free; 1278c2ecf20Sopenharmony_ci /* 1288c2ecf20Sopenharmony_ci * If the replay order was perfect the dirty space would now be 1298c2ecf20Sopenharmony_ci * zero. The order is not perfect because the journal heads 1308c2ecf20Sopenharmony_ci * race with each other. This is not a problem but is does mean 1318c2ecf20Sopenharmony_ci * that the dirty space may temporarily exceed c->leb_size 1328c2ecf20Sopenharmony_ci * during the replay. 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_ci if (dirty != 0) 1358c2ecf20Sopenharmony_ci dbg_mnt("LEB %d lp: %d free %d dirty replay: %d free %d dirty", 1368c2ecf20Sopenharmony_ci b->bud->lnum, lp->free, lp->dirty, b->free, 1378c2ecf20Sopenharmony_ci b->dirty); 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci lp = ubifs_change_lp(c, lp, b->free, dirty + b->dirty, 1408c2ecf20Sopenharmony_ci lp->flags | LPROPS_TAKEN, 0); 1418c2ecf20Sopenharmony_ci if (IS_ERR(lp)) { 1428c2ecf20Sopenharmony_ci err = PTR_ERR(lp); 1438c2ecf20Sopenharmony_ci goto out; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* Make sure the journal head points to the latest bud */ 1478c2ecf20Sopenharmony_ci err = ubifs_wbuf_seek_nolock(&c->jheads[b->bud->jhead].wbuf, 1488c2ecf20Sopenharmony_ci b->bud->lnum, c->leb_size - b->free); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ciout: 1518c2ecf20Sopenharmony_ci ubifs_release_lprops(c); 1528c2ecf20Sopenharmony_ci return err; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci/** 1568c2ecf20Sopenharmony_ci * set_buds_lprops - set free and dirty space for all replayed buds. 1578c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 1588c2ecf20Sopenharmony_ci * 1598c2ecf20Sopenharmony_ci * This function sets LEB properties for all replayed buds. Returns zero in 1608c2ecf20Sopenharmony_ci * case of success and a negative error code in case of failure. 1618c2ecf20Sopenharmony_ci */ 1628c2ecf20Sopenharmony_cistatic int set_buds_lprops(struct ubifs_info *c) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct bud_entry *b; 1658c2ecf20Sopenharmony_ci int err; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci list_for_each_entry(b, &c->replay_buds, list) { 1688c2ecf20Sopenharmony_ci err = set_bud_lprops(c, b); 1698c2ecf20Sopenharmony_ci if (err) 1708c2ecf20Sopenharmony_ci return err; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return 0; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci/** 1778c2ecf20Sopenharmony_ci * trun_remove_range - apply a replay entry for a truncation to the TNC. 1788c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 1798c2ecf20Sopenharmony_ci * @r: replay entry of truncation 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_cistatic int trun_remove_range(struct ubifs_info *c, struct replay_entry *r) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci unsigned min_blk, max_blk; 1848c2ecf20Sopenharmony_ci union ubifs_key min_key, max_key; 1858c2ecf20Sopenharmony_ci ino_t ino; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci min_blk = r->new_size / UBIFS_BLOCK_SIZE; 1888c2ecf20Sopenharmony_ci if (r->new_size & (UBIFS_BLOCK_SIZE - 1)) 1898c2ecf20Sopenharmony_ci min_blk += 1; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci max_blk = r->old_size / UBIFS_BLOCK_SIZE; 1928c2ecf20Sopenharmony_ci if ((r->old_size & (UBIFS_BLOCK_SIZE - 1)) == 0) 1938c2ecf20Sopenharmony_ci max_blk -= 1; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci ino = key_inum(c, &r->key); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci data_key_init(c, &min_key, ino, min_blk); 1988c2ecf20Sopenharmony_ci data_key_init(c, &max_key, ino, max_blk); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci return ubifs_tnc_remove_range(c, &min_key, &max_key); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci/** 2048c2ecf20Sopenharmony_ci * inode_still_linked - check whether inode in question will be re-linked. 2058c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 2068c2ecf20Sopenharmony_ci * @rino: replay entry to test 2078c2ecf20Sopenharmony_ci * 2088c2ecf20Sopenharmony_ci * O_TMPFILE files can be re-linked, this means link count goes from 0 to 1. 2098c2ecf20Sopenharmony_ci * This case needs special care, otherwise all references to the inode will 2108c2ecf20Sopenharmony_ci * be removed upon the first replay entry of an inode with link count 0 2118c2ecf20Sopenharmony_ci * is found. 2128c2ecf20Sopenharmony_ci */ 2138c2ecf20Sopenharmony_cistatic bool inode_still_linked(struct ubifs_info *c, struct replay_entry *rino) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct replay_entry *r; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci ubifs_assert(c, rino->deletion); 2188c2ecf20Sopenharmony_ci ubifs_assert(c, key_type(c, &rino->key) == UBIFS_INO_KEY); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* 2218c2ecf20Sopenharmony_ci * Find the most recent entry for the inode behind @rino and check 2228c2ecf20Sopenharmony_ci * whether it is a deletion. 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_ci list_for_each_entry_reverse(r, &c->replay_list, list) { 2258c2ecf20Sopenharmony_ci ubifs_assert(c, r->sqnum >= rino->sqnum); 2268c2ecf20Sopenharmony_ci if (key_inum(c, &r->key) == key_inum(c, &rino->key) && 2278c2ecf20Sopenharmony_ci key_type(c, &r->key) == UBIFS_INO_KEY) 2288c2ecf20Sopenharmony_ci return r->deletion == 0; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci ubifs_assert(c, 0); 2338c2ecf20Sopenharmony_ci return false; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci/** 2378c2ecf20Sopenharmony_ci * apply_replay_entry - apply a replay entry to the TNC. 2388c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 2398c2ecf20Sopenharmony_ci * @r: replay entry to apply 2408c2ecf20Sopenharmony_ci * 2418c2ecf20Sopenharmony_ci * Apply a replay entry to the TNC. 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_cistatic int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci int err; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci dbg_mntk(&r->key, "LEB %d:%d len %d deletion %d sqnum %llu key ", 2488c2ecf20Sopenharmony_ci r->lnum, r->offs, r->len, r->deletion, r->sqnum); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (is_hash_key(c, &r->key)) { 2518c2ecf20Sopenharmony_ci if (r->deletion) 2528c2ecf20Sopenharmony_ci err = ubifs_tnc_remove_nm(c, &r->key, &r->nm); 2538c2ecf20Sopenharmony_ci else 2548c2ecf20Sopenharmony_ci err = ubifs_tnc_add_nm(c, &r->key, r->lnum, r->offs, 2558c2ecf20Sopenharmony_ci r->len, r->hash, &r->nm); 2568c2ecf20Sopenharmony_ci } else { 2578c2ecf20Sopenharmony_ci if (r->deletion) 2588c2ecf20Sopenharmony_ci switch (key_type(c, &r->key)) { 2598c2ecf20Sopenharmony_ci case UBIFS_INO_KEY: 2608c2ecf20Sopenharmony_ci { 2618c2ecf20Sopenharmony_ci ino_t inum = key_inum(c, &r->key); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (inode_still_linked(c, r)) { 2648c2ecf20Sopenharmony_ci err = 0; 2658c2ecf20Sopenharmony_ci break; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci err = ubifs_tnc_remove_ino(c, inum); 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci case UBIFS_TRUN_KEY: 2728c2ecf20Sopenharmony_ci err = trun_remove_range(c, r); 2738c2ecf20Sopenharmony_ci break; 2748c2ecf20Sopenharmony_ci default: 2758c2ecf20Sopenharmony_ci err = ubifs_tnc_remove(c, &r->key); 2768c2ecf20Sopenharmony_ci break; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci else 2798c2ecf20Sopenharmony_ci err = ubifs_tnc_add(c, &r->key, r->lnum, r->offs, 2808c2ecf20Sopenharmony_ci r->len, r->hash); 2818c2ecf20Sopenharmony_ci if (err) 2828c2ecf20Sopenharmony_ci return err; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (c->need_recovery) 2858c2ecf20Sopenharmony_ci err = ubifs_recover_size_accum(c, &r->key, r->deletion, 2868c2ecf20Sopenharmony_ci r->new_size); 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return err; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci/** 2938c2ecf20Sopenharmony_ci * replay_entries_cmp - compare 2 replay entries. 2948c2ecf20Sopenharmony_ci * @priv: UBIFS file-system description object 2958c2ecf20Sopenharmony_ci * @a: first replay entry 2968c2ecf20Sopenharmony_ci * @b: second replay entry 2978c2ecf20Sopenharmony_ci * 2988c2ecf20Sopenharmony_ci * This is a comparios function for 'list_sort()' which compares 2 replay 2998c2ecf20Sopenharmony_ci * entries @a and @b by comparing their sequence numer. Returns %1 if @a has 3008c2ecf20Sopenharmony_ci * greater sequence number and %-1 otherwise. 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_cistatic int replay_entries_cmp(void *priv, const struct list_head *a, 3038c2ecf20Sopenharmony_ci const struct list_head *b) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci struct ubifs_info *c = priv; 3068c2ecf20Sopenharmony_ci struct replay_entry *ra, *rb; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci cond_resched(); 3098c2ecf20Sopenharmony_ci if (a == b) 3108c2ecf20Sopenharmony_ci return 0; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci ra = list_entry(a, struct replay_entry, list); 3138c2ecf20Sopenharmony_ci rb = list_entry(b, struct replay_entry, list); 3148c2ecf20Sopenharmony_ci ubifs_assert(c, ra->sqnum != rb->sqnum); 3158c2ecf20Sopenharmony_ci if (ra->sqnum > rb->sqnum) 3168c2ecf20Sopenharmony_ci return 1; 3178c2ecf20Sopenharmony_ci return -1; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci/** 3218c2ecf20Sopenharmony_ci * apply_replay_list - apply the replay list to the TNC. 3228c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 3238c2ecf20Sopenharmony_ci * 3248c2ecf20Sopenharmony_ci * Apply all entries in the replay list to the TNC. Returns zero in case of 3258c2ecf20Sopenharmony_ci * success and a negative error code in case of failure. 3268c2ecf20Sopenharmony_ci */ 3278c2ecf20Sopenharmony_cistatic int apply_replay_list(struct ubifs_info *c) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci struct replay_entry *r; 3308c2ecf20Sopenharmony_ci int err; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci list_sort(c, &c->replay_list, &replay_entries_cmp); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci list_for_each_entry(r, &c->replay_list, list) { 3358c2ecf20Sopenharmony_ci cond_resched(); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci err = apply_replay_entry(c, r); 3388c2ecf20Sopenharmony_ci if (err) 3398c2ecf20Sopenharmony_ci return err; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci return 0; 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci/** 3468c2ecf20Sopenharmony_ci * destroy_replay_list - destroy the replay. 3478c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 3488c2ecf20Sopenharmony_ci * 3498c2ecf20Sopenharmony_ci * Destroy the replay list. 3508c2ecf20Sopenharmony_ci */ 3518c2ecf20Sopenharmony_cistatic void destroy_replay_list(struct ubifs_info *c) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci struct replay_entry *r, *tmp; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci list_for_each_entry_safe(r, tmp, &c->replay_list, list) { 3568c2ecf20Sopenharmony_ci if (is_hash_key(c, &r->key)) 3578c2ecf20Sopenharmony_ci kfree(fname_name(&r->nm)); 3588c2ecf20Sopenharmony_ci list_del(&r->list); 3598c2ecf20Sopenharmony_ci kfree(r); 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci/** 3648c2ecf20Sopenharmony_ci * insert_node - insert a node to the replay list 3658c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 3668c2ecf20Sopenharmony_ci * @lnum: node logical eraseblock number 3678c2ecf20Sopenharmony_ci * @offs: node offset 3688c2ecf20Sopenharmony_ci * @len: node length 3698c2ecf20Sopenharmony_ci * @key: node key 3708c2ecf20Sopenharmony_ci * @sqnum: sequence number 3718c2ecf20Sopenharmony_ci * @deletion: non-zero if this is a deletion 3728c2ecf20Sopenharmony_ci * @used: number of bytes in use in a LEB 3738c2ecf20Sopenharmony_ci * @old_size: truncation old size 3748c2ecf20Sopenharmony_ci * @new_size: truncation new size 3758c2ecf20Sopenharmony_ci * 3768c2ecf20Sopenharmony_ci * This function inserts a scanned non-direntry node to the replay list. The 3778c2ecf20Sopenharmony_ci * replay list contains @struct replay_entry elements, and we sort this list in 3788c2ecf20Sopenharmony_ci * sequence number order before applying it. The replay list is applied at the 3798c2ecf20Sopenharmony_ci * very end of the replay process. Since the list is sorted in sequence number 3808c2ecf20Sopenharmony_ci * order, the older modifications are applied first. This function returns zero 3818c2ecf20Sopenharmony_ci * in case of success and a negative error code in case of failure. 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_cistatic int insert_node(struct ubifs_info *c, int lnum, int offs, int len, 3848c2ecf20Sopenharmony_ci const u8 *hash, union ubifs_key *key, 3858c2ecf20Sopenharmony_ci unsigned long long sqnum, int deletion, int *used, 3868c2ecf20Sopenharmony_ci loff_t old_size, loff_t new_size) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci struct replay_entry *r; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci dbg_mntk(key, "add LEB %d:%d, key ", lnum, offs); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (key_inum(c, key) >= c->highest_inum) 3938c2ecf20Sopenharmony_ci c->highest_inum = key_inum(c, key); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL); 3968c2ecf20Sopenharmony_ci if (!r) 3978c2ecf20Sopenharmony_ci return -ENOMEM; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (!deletion) 4008c2ecf20Sopenharmony_ci *used += ALIGN(len, 8); 4018c2ecf20Sopenharmony_ci r->lnum = lnum; 4028c2ecf20Sopenharmony_ci r->offs = offs; 4038c2ecf20Sopenharmony_ci r->len = len; 4048c2ecf20Sopenharmony_ci ubifs_copy_hash(c, hash, r->hash); 4058c2ecf20Sopenharmony_ci r->deletion = !!deletion; 4068c2ecf20Sopenharmony_ci r->sqnum = sqnum; 4078c2ecf20Sopenharmony_ci key_copy(c, key, &r->key); 4088c2ecf20Sopenharmony_ci r->old_size = old_size; 4098c2ecf20Sopenharmony_ci r->new_size = new_size; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci list_add_tail(&r->list, &c->replay_list); 4128c2ecf20Sopenharmony_ci return 0; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci/** 4168c2ecf20Sopenharmony_ci * insert_dent - insert a directory entry node into the replay list. 4178c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 4188c2ecf20Sopenharmony_ci * @lnum: node logical eraseblock number 4198c2ecf20Sopenharmony_ci * @offs: node offset 4208c2ecf20Sopenharmony_ci * @len: node length 4218c2ecf20Sopenharmony_ci * @key: node key 4228c2ecf20Sopenharmony_ci * @name: directory entry name 4238c2ecf20Sopenharmony_ci * @nlen: directory entry name length 4248c2ecf20Sopenharmony_ci * @sqnum: sequence number 4258c2ecf20Sopenharmony_ci * @deletion: non-zero if this is a deletion 4268c2ecf20Sopenharmony_ci * @used: number of bytes in use in a LEB 4278c2ecf20Sopenharmony_ci * 4288c2ecf20Sopenharmony_ci * This function inserts a scanned directory entry node or an extended 4298c2ecf20Sopenharmony_ci * attribute entry to the replay list. Returns zero in case of success and a 4308c2ecf20Sopenharmony_ci * negative error code in case of failure. 4318c2ecf20Sopenharmony_ci */ 4328c2ecf20Sopenharmony_cistatic int insert_dent(struct ubifs_info *c, int lnum, int offs, int len, 4338c2ecf20Sopenharmony_ci const u8 *hash, union ubifs_key *key, 4348c2ecf20Sopenharmony_ci const char *name, int nlen, unsigned long long sqnum, 4358c2ecf20Sopenharmony_ci int deletion, int *used) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci struct replay_entry *r; 4388c2ecf20Sopenharmony_ci char *nbuf; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci dbg_mntk(key, "add LEB %d:%d, key ", lnum, offs); 4418c2ecf20Sopenharmony_ci if (key_inum(c, key) >= c->highest_inum) 4428c2ecf20Sopenharmony_ci c->highest_inum = key_inum(c, key); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL); 4458c2ecf20Sopenharmony_ci if (!r) 4468c2ecf20Sopenharmony_ci return -ENOMEM; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci nbuf = kmalloc(nlen + 1, GFP_KERNEL); 4498c2ecf20Sopenharmony_ci if (!nbuf) { 4508c2ecf20Sopenharmony_ci kfree(r); 4518c2ecf20Sopenharmony_ci return -ENOMEM; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (!deletion) 4558c2ecf20Sopenharmony_ci *used += ALIGN(len, 8); 4568c2ecf20Sopenharmony_ci r->lnum = lnum; 4578c2ecf20Sopenharmony_ci r->offs = offs; 4588c2ecf20Sopenharmony_ci r->len = len; 4598c2ecf20Sopenharmony_ci ubifs_copy_hash(c, hash, r->hash); 4608c2ecf20Sopenharmony_ci r->deletion = !!deletion; 4618c2ecf20Sopenharmony_ci r->sqnum = sqnum; 4628c2ecf20Sopenharmony_ci key_copy(c, key, &r->key); 4638c2ecf20Sopenharmony_ci fname_len(&r->nm) = nlen; 4648c2ecf20Sopenharmony_ci memcpy(nbuf, name, nlen); 4658c2ecf20Sopenharmony_ci nbuf[nlen] = '\0'; 4668c2ecf20Sopenharmony_ci fname_name(&r->nm) = nbuf; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci list_add_tail(&r->list, &c->replay_list); 4698c2ecf20Sopenharmony_ci return 0; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci/** 4738c2ecf20Sopenharmony_ci * ubifs_validate_entry - validate directory or extended attribute entry node. 4748c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 4758c2ecf20Sopenharmony_ci * @dent: the node to validate 4768c2ecf20Sopenharmony_ci * 4778c2ecf20Sopenharmony_ci * This function validates directory or extended attribute entry node @dent. 4788c2ecf20Sopenharmony_ci * Returns zero if the node is all right and a %-EINVAL if not. 4798c2ecf20Sopenharmony_ci */ 4808c2ecf20Sopenharmony_ciint ubifs_validate_entry(struct ubifs_info *c, 4818c2ecf20Sopenharmony_ci const struct ubifs_dent_node *dent) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci int key_type = key_type_flash(c, dent->key); 4848c2ecf20Sopenharmony_ci int nlen = le16_to_cpu(dent->nlen); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci if (le32_to_cpu(dent->ch.len) != nlen + UBIFS_DENT_NODE_SZ + 1 || 4878c2ecf20Sopenharmony_ci dent->type >= UBIFS_ITYPES_CNT || 4888c2ecf20Sopenharmony_ci nlen > UBIFS_MAX_NLEN || dent->name[nlen] != 0 || 4898c2ecf20Sopenharmony_ci (key_type == UBIFS_XENT_KEY && strnlen(dent->name, nlen) != nlen) || 4908c2ecf20Sopenharmony_ci le64_to_cpu(dent->inum) > MAX_INUM) { 4918c2ecf20Sopenharmony_ci ubifs_err(c, "bad %s node", key_type == UBIFS_DENT_KEY ? 4928c2ecf20Sopenharmony_ci "directory entry" : "extended attribute entry"); 4938c2ecf20Sopenharmony_ci return -EINVAL; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (key_type != UBIFS_DENT_KEY && key_type != UBIFS_XENT_KEY) { 4978c2ecf20Sopenharmony_ci ubifs_err(c, "bad key type %d", key_type); 4988c2ecf20Sopenharmony_ci return -EINVAL; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci return 0; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci/** 5058c2ecf20Sopenharmony_ci * is_last_bud - check if the bud is the last in the journal head. 5068c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 5078c2ecf20Sopenharmony_ci * @bud: bud description object 5088c2ecf20Sopenharmony_ci * 5098c2ecf20Sopenharmony_ci * This function checks if bud @bud is the last bud in its journal head. This 5108c2ecf20Sopenharmony_ci * information is then used by 'replay_bud()' to decide whether the bud can 5118c2ecf20Sopenharmony_ci * have corruptions or not. Indeed, only last buds can be corrupted by power 5128c2ecf20Sopenharmony_ci * cuts. Returns %1 if this is the last bud, and %0 if not. 5138c2ecf20Sopenharmony_ci */ 5148c2ecf20Sopenharmony_cistatic int is_last_bud(struct ubifs_info *c, struct ubifs_bud *bud) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci struct ubifs_jhead *jh = &c->jheads[bud->jhead]; 5178c2ecf20Sopenharmony_ci struct ubifs_bud *next; 5188c2ecf20Sopenharmony_ci uint32_t data; 5198c2ecf20Sopenharmony_ci int err; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (list_is_last(&bud->list, &jh->buds_list)) 5228c2ecf20Sopenharmony_ci return 1; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci /* 5258c2ecf20Sopenharmony_ci * The following is a quirk to make sure we work correctly with UBIFS 5268c2ecf20Sopenharmony_ci * images used with older UBIFS. 5278c2ecf20Sopenharmony_ci * 5288c2ecf20Sopenharmony_ci * Normally, the last bud will be the last in the journal head's list 5298c2ecf20Sopenharmony_ci * of bud. However, there is one exception if the UBIFS image belongs 5308c2ecf20Sopenharmony_ci * to older UBIFS. This is fairly unlikely: one would need to use old 5318c2ecf20Sopenharmony_ci * UBIFS, then have a power cut exactly at the right point, and then 5328c2ecf20Sopenharmony_ci * try to mount this image with new UBIFS. 5338c2ecf20Sopenharmony_ci * 5348c2ecf20Sopenharmony_ci * The exception is: it is possible to have 2 buds A and B, A goes 5358c2ecf20Sopenharmony_ci * before B, and B is the last, bud B is contains no data, and bud A is 5368c2ecf20Sopenharmony_ci * corrupted at the end. The reason is that in older versions when the 5378c2ecf20Sopenharmony_ci * journal code switched the next bud (from A to B), it first added a 5388c2ecf20Sopenharmony_ci * log reference node for the new bud (B), and only after this it 5398c2ecf20Sopenharmony_ci * synchronized the write-buffer of current bud (A). But later this was 5408c2ecf20Sopenharmony_ci * changed and UBIFS started to always synchronize the write-buffer of 5418c2ecf20Sopenharmony_ci * the bud (A) before writing the log reference for the new bud (B). 5428c2ecf20Sopenharmony_ci * 5438c2ecf20Sopenharmony_ci * But because older UBIFS always synchronized A's write-buffer before 5448c2ecf20Sopenharmony_ci * writing to B, we can recognize this exceptional situation but 5458c2ecf20Sopenharmony_ci * checking the contents of bud B - if it is empty, then A can be 5468c2ecf20Sopenharmony_ci * treated as the last and we can recover it. 5478c2ecf20Sopenharmony_ci * 5488c2ecf20Sopenharmony_ci * TODO: remove this piece of code in a couple of years (today it is 5498c2ecf20Sopenharmony_ci * 16.05.2011). 5508c2ecf20Sopenharmony_ci */ 5518c2ecf20Sopenharmony_ci next = list_entry(bud->list.next, struct ubifs_bud, list); 5528c2ecf20Sopenharmony_ci if (!list_is_last(&next->list, &jh->buds_list)) 5538c2ecf20Sopenharmony_ci return 0; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci err = ubifs_leb_read(c, next->lnum, (char *)&data, next->start, 4, 1); 5568c2ecf20Sopenharmony_ci if (err) 5578c2ecf20Sopenharmony_ci return 0; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci return data == 0xFFFFFFFF; 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci/* authenticate_sleb_hash is split out for stack usage */ 5638c2ecf20Sopenharmony_cistatic int noinline_for_stack 5648c2ecf20Sopenharmony_ciauthenticate_sleb_hash(struct ubifs_info *c, 5658c2ecf20Sopenharmony_ci struct shash_desc *log_hash, u8 *hash) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci SHASH_DESC_ON_STACK(hash_desc, c->hash_tfm); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci hash_desc->tfm = c->hash_tfm; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci ubifs_shash_copy_state(c, log_hash, hash_desc); 5728c2ecf20Sopenharmony_ci return crypto_shash_final(hash_desc, hash); 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci/** 5768c2ecf20Sopenharmony_ci * authenticate_sleb - authenticate one scan LEB 5778c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 5788c2ecf20Sopenharmony_ci * @sleb: the scan LEB to authenticate 5798c2ecf20Sopenharmony_ci * @log_hash: 5808c2ecf20Sopenharmony_ci * @is_last: if true, this is is the last LEB 5818c2ecf20Sopenharmony_ci * 5828c2ecf20Sopenharmony_ci * This function iterates over the buds of a single LEB authenticating all buds 5838c2ecf20Sopenharmony_ci * with the authentication nodes on this LEB. Authentication nodes are written 5848c2ecf20Sopenharmony_ci * after some buds and contain a HMAC covering the authentication node itself 5858c2ecf20Sopenharmony_ci * and the buds between the last authentication node and the current 5868c2ecf20Sopenharmony_ci * authentication node. It can happen that the last buds cannot be authenticated 5878c2ecf20Sopenharmony_ci * because a powercut happened when some nodes were written but not the 5888c2ecf20Sopenharmony_ci * corresponding authentication node. This function returns the number of nodes 5898c2ecf20Sopenharmony_ci * that could be authenticated or a negative error code. 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_cistatic int authenticate_sleb(struct ubifs_info *c, struct ubifs_scan_leb *sleb, 5928c2ecf20Sopenharmony_ci struct shash_desc *log_hash, int is_last) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci int n_not_auth = 0; 5958c2ecf20Sopenharmony_ci struct ubifs_scan_node *snod; 5968c2ecf20Sopenharmony_ci int n_nodes = 0; 5978c2ecf20Sopenharmony_ci int err; 5988c2ecf20Sopenharmony_ci u8 hash[UBIFS_HASH_ARR_SZ]; 5998c2ecf20Sopenharmony_ci u8 hmac[UBIFS_HMAC_ARR_SZ]; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (!ubifs_authenticated(c)) 6028c2ecf20Sopenharmony_ci return sleb->nodes_cnt; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci list_for_each_entry(snod, &sleb->nodes, list) { 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci n_nodes++; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci if (snod->type == UBIFS_AUTH_NODE) { 6098c2ecf20Sopenharmony_ci struct ubifs_auth_node *auth = snod->node; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci err = authenticate_sleb_hash(c, log_hash, hash); 6128c2ecf20Sopenharmony_ci if (err) 6138c2ecf20Sopenharmony_ci goto out; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci err = crypto_shash_tfm_digest(c->hmac_tfm, hash, 6168c2ecf20Sopenharmony_ci c->hash_len, hmac); 6178c2ecf20Sopenharmony_ci if (err) 6188c2ecf20Sopenharmony_ci goto out; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci err = ubifs_check_hmac(c, auth->hmac, hmac); 6218c2ecf20Sopenharmony_ci if (err) { 6228c2ecf20Sopenharmony_ci err = -EPERM; 6238c2ecf20Sopenharmony_ci goto out; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci n_not_auth = 0; 6268c2ecf20Sopenharmony_ci } else { 6278c2ecf20Sopenharmony_ci err = crypto_shash_update(log_hash, snod->node, 6288c2ecf20Sopenharmony_ci snod->len); 6298c2ecf20Sopenharmony_ci if (err) 6308c2ecf20Sopenharmony_ci goto out; 6318c2ecf20Sopenharmony_ci n_not_auth++; 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci /* 6368c2ecf20Sopenharmony_ci * A powercut can happen when some nodes were written, but not yet 6378c2ecf20Sopenharmony_ci * the corresponding authentication node. This may only happen on 6388c2ecf20Sopenharmony_ci * the last bud though. 6398c2ecf20Sopenharmony_ci */ 6408c2ecf20Sopenharmony_ci if (n_not_auth) { 6418c2ecf20Sopenharmony_ci if (is_last) { 6428c2ecf20Sopenharmony_ci dbg_mnt("%d unauthenticated nodes found on LEB %d, Ignoring them", 6438c2ecf20Sopenharmony_ci n_not_auth, sleb->lnum); 6448c2ecf20Sopenharmony_ci err = 0; 6458c2ecf20Sopenharmony_ci } else { 6468c2ecf20Sopenharmony_ci dbg_mnt("%d unauthenticated nodes found on non-last LEB %d", 6478c2ecf20Sopenharmony_ci n_not_auth, sleb->lnum); 6488c2ecf20Sopenharmony_ci err = -EPERM; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci } else { 6518c2ecf20Sopenharmony_ci err = 0; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ciout: 6548c2ecf20Sopenharmony_ci return err ? err : n_nodes - n_not_auth; 6558c2ecf20Sopenharmony_ci} 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci/** 6588c2ecf20Sopenharmony_ci * replay_bud - replay a bud logical eraseblock. 6598c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 6608c2ecf20Sopenharmony_ci * @b: bud entry which describes the bud 6618c2ecf20Sopenharmony_ci * 6628c2ecf20Sopenharmony_ci * This function replays bud @bud, recovers it if needed, and adds all nodes 6638c2ecf20Sopenharmony_ci * from this bud to the replay list. Returns zero in case of success and a 6648c2ecf20Sopenharmony_ci * negative error code in case of failure. 6658c2ecf20Sopenharmony_ci */ 6668c2ecf20Sopenharmony_cistatic int replay_bud(struct ubifs_info *c, struct bud_entry *b) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci int is_last = is_last_bud(c, b->bud); 6698c2ecf20Sopenharmony_ci int err = 0, used = 0, lnum = b->bud->lnum, offs = b->bud->start; 6708c2ecf20Sopenharmony_ci int n_nodes, n = 0; 6718c2ecf20Sopenharmony_ci struct ubifs_scan_leb *sleb; 6728c2ecf20Sopenharmony_ci struct ubifs_scan_node *snod; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci dbg_mnt("replay bud LEB %d, head %d, offs %d, is_last %d", 6758c2ecf20Sopenharmony_ci lnum, b->bud->jhead, offs, is_last); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (c->need_recovery && is_last) 6788c2ecf20Sopenharmony_ci /* 6798c2ecf20Sopenharmony_ci * Recover only last LEBs in the journal heads, because power 6808c2ecf20Sopenharmony_ci * cuts may cause corruptions only in these LEBs, because only 6818c2ecf20Sopenharmony_ci * these LEBs could possibly be written to at the power cut 6828c2ecf20Sopenharmony_ci * time. 6838c2ecf20Sopenharmony_ci */ 6848c2ecf20Sopenharmony_ci sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, b->bud->jhead); 6858c2ecf20Sopenharmony_ci else 6868c2ecf20Sopenharmony_ci sleb = ubifs_scan(c, lnum, offs, c->sbuf, 0); 6878c2ecf20Sopenharmony_ci if (IS_ERR(sleb)) 6888c2ecf20Sopenharmony_ci return PTR_ERR(sleb); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci n_nodes = authenticate_sleb(c, sleb, b->bud->log_hash, is_last); 6918c2ecf20Sopenharmony_ci if (n_nodes < 0) { 6928c2ecf20Sopenharmony_ci err = n_nodes; 6938c2ecf20Sopenharmony_ci goto out; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci ubifs_shash_copy_state(c, b->bud->log_hash, 6978c2ecf20Sopenharmony_ci c->jheads[b->bud->jhead].log_hash); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci /* 7008c2ecf20Sopenharmony_ci * The bud does not have to start from offset zero - the beginning of 7018c2ecf20Sopenharmony_ci * the 'lnum' LEB may contain previously committed data. One of the 7028c2ecf20Sopenharmony_ci * things we have to do in replay is to correctly update lprops with 7038c2ecf20Sopenharmony_ci * newer information about this LEB. 7048c2ecf20Sopenharmony_ci * 7058c2ecf20Sopenharmony_ci * At this point lprops thinks that this LEB has 'c->leb_size - offs' 7068c2ecf20Sopenharmony_ci * bytes of free space because it only contain information about 7078c2ecf20Sopenharmony_ci * committed data. 7088c2ecf20Sopenharmony_ci * 7098c2ecf20Sopenharmony_ci * But we know that real amount of free space is 'c->leb_size - 7108c2ecf20Sopenharmony_ci * sleb->endpt', and the space in the 'lnum' LEB between 'offs' and 7118c2ecf20Sopenharmony_ci * 'sleb->endpt' is used by bud data. We have to correctly calculate 7128c2ecf20Sopenharmony_ci * how much of these data are dirty and update lprops with this 7138c2ecf20Sopenharmony_ci * information. 7148c2ecf20Sopenharmony_ci * 7158c2ecf20Sopenharmony_ci * The dirt in that LEB region is comprised of padding nodes, deletion 7168c2ecf20Sopenharmony_ci * nodes, truncation nodes and nodes which are obsoleted by subsequent 7178c2ecf20Sopenharmony_ci * nodes in this LEB. So instead of calculating clean space, we 7188c2ecf20Sopenharmony_ci * calculate used space ('used' variable). 7198c2ecf20Sopenharmony_ci */ 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci list_for_each_entry(snod, &sleb->nodes, list) { 7228c2ecf20Sopenharmony_ci u8 hash[UBIFS_HASH_ARR_SZ]; 7238c2ecf20Sopenharmony_ci int deletion = 0; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci cond_resched(); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci if (snod->sqnum >= SQNUM_WATERMARK) { 7288c2ecf20Sopenharmony_ci ubifs_err(c, "file system's life ended"); 7298c2ecf20Sopenharmony_ci goto out_dump; 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci ubifs_node_calc_hash(c, snod->node, hash); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci if (snod->sqnum > c->max_sqnum) 7358c2ecf20Sopenharmony_ci c->max_sqnum = snod->sqnum; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci switch (snod->type) { 7388c2ecf20Sopenharmony_ci case UBIFS_INO_NODE: 7398c2ecf20Sopenharmony_ci { 7408c2ecf20Sopenharmony_ci struct ubifs_ino_node *ino = snod->node; 7418c2ecf20Sopenharmony_ci loff_t new_size = le64_to_cpu(ino->size); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci if (le32_to_cpu(ino->nlink) == 0) 7448c2ecf20Sopenharmony_ci deletion = 1; 7458c2ecf20Sopenharmony_ci err = insert_node(c, lnum, snod->offs, snod->len, hash, 7468c2ecf20Sopenharmony_ci &snod->key, snod->sqnum, deletion, 7478c2ecf20Sopenharmony_ci &used, 0, new_size); 7488c2ecf20Sopenharmony_ci break; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci case UBIFS_DATA_NODE: 7518c2ecf20Sopenharmony_ci { 7528c2ecf20Sopenharmony_ci struct ubifs_data_node *dn = snod->node; 7538c2ecf20Sopenharmony_ci loff_t new_size = le32_to_cpu(dn->size) + 7548c2ecf20Sopenharmony_ci key_block(c, &snod->key) * 7558c2ecf20Sopenharmony_ci UBIFS_BLOCK_SIZE; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci err = insert_node(c, lnum, snod->offs, snod->len, hash, 7588c2ecf20Sopenharmony_ci &snod->key, snod->sqnum, deletion, 7598c2ecf20Sopenharmony_ci &used, 0, new_size); 7608c2ecf20Sopenharmony_ci break; 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci case UBIFS_DENT_NODE: 7638c2ecf20Sopenharmony_ci case UBIFS_XENT_NODE: 7648c2ecf20Sopenharmony_ci { 7658c2ecf20Sopenharmony_ci struct ubifs_dent_node *dent = snod->node; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci err = ubifs_validate_entry(c, dent); 7688c2ecf20Sopenharmony_ci if (err) 7698c2ecf20Sopenharmony_ci goto out_dump; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci err = insert_dent(c, lnum, snod->offs, snod->len, hash, 7728c2ecf20Sopenharmony_ci &snod->key, dent->name, 7738c2ecf20Sopenharmony_ci le16_to_cpu(dent->nlen), snod->sqnum, 7748c2ecf20Sopenharmony_ci !le64_to_cpu(dent->inum), &used); 7758c2ecf20Sopenharmony_ci break; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci case UBIFS_TRUN_NODE: 7788c2ecf20Sopenharmony_ci { 7798c2ecf20Sopenharmony_ci struct ubifs_trun_node *trun = snod->node; 7808c2ecf20Sopenharmony_ci loff_t old_size = le64_to_cpu(trun->old_size); 7818c2ecf20Sopenharmony_ci loff_t new_size = le64_to_cpu(trun->new_size); 7828c2ecf20Sopenharmony_ci union ubifs_key key; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci /* Validate truncation node */ 7858c2ecf20Sopenharmony_ci if (old_size < 0 || old_size > c->max_inode_sz || 7868c2ecf20Sopenharmony_ci new_size < 0 || new_size > c->max_inode_sz || 7878c2ecf20Sopenharmony_ci old_size <= new_size) { 7888c2ecf20Sopenharmony_ci ubifs_err(c, "bad truncation node"); 7898c2ecf20Sopenharmony_ci goto out_dump; 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci /* 7938c2ecf20Sopenharmony_ci * Create a fake truncation key just to use the same 7948c2ecf20Sopenharmony_ci * functions which expect nodes to have keys. 7958c2ecf20Sopenharmony_ci */ 7968c2ecf20Sopenharmony_ci trun_key_init(c, &key, le32_to_cpu(trun->inum)); 7978c2ecf20Sopenharmony_ci err = insert_node(c, lnum, snod->offs, snod->len, hash, 7988c2ecf20Sopenharmony_ci &key, snod->sqnum, 1, &used, 7998c2ecf20Sopenharmony_ci old_size, new_size); 8008c2ecf20Sopenharmony_ci break; 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci case UBIFS_AUTH_NODE: 8038c2ecf20Sopenharmony_ci break; 8048c2ecf20Sopenharmony_ci default: 8058c2ecf20Sopenharmony_ci ubifs_err(c, "unexpected node type %d in bud LEB %d:%d", 8068c2ecf20Sopenharmony_ci snod->type, lnum, snod->offs); 8078c2ecf20Sopenharmony_ci err = -EINVAL; 8088c2ecf20Sopenharmony_ci goto out_dump; 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci if (err) 8118c2ecf20Sopenharmony_ci goto out; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci n++; 8148c2ecf20Sopenharmony_ci if (n == n_nodes) 8158c2ecf20Sopenharmony_ci break; 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci ubifs_assert(c, ubifs_search_bud(c, lnum)); 8198c2ecf20Sopenharmony_ci ubifs_assert(c, sleb->endpt - offs >= used); 8208c2ecf20Sopenharmony_ci ubifs_assert(c, sleb->endpt % c->min_io_size == 0); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci b->dirty = sleb->endpt - offs - used; 8238c2ecf20Sopenharmony_ci b->free = c->leb_size - sleb->endpt; 8248c2ecf20Sopenharmony_ci dbg_mnt("bud LEB %d replied: dirty %d, free %d", 8258c2ecf20Sopenharmony_ci lnum, b->dirty, b->free); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ciout: 8288c2ecf20Sopenharmony_ci ubifs_scan_destroy(sleb); 8298c2ecf20Sopenharmony_ci return err; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ciout_dump: 8328c2ecf20Sopenharmony_ci ubifs_err(c, "bad node is at LEB %d:%d", lnum, snod->offs); 8338c2ecf20Sopenharmony_ci ubifs_dump_node(c, snod->node, c->leb_size - snod->offs); 8348c2ecf20Sopenharmony_ci ubifs_scan_destroy(sleb); 8358c2ecf20Sopenharmony_ci return -EINVAL; 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci/** 8398c2ecf20Sopenharmony_ci * replay_buds - replay all buds. 8408c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 8418c2ecf20Sopenharmony_ci * 8428c2ecf20Sopenharmony_ci * This function returns zero in case of success and a negative error code in 8438c2ecf20Sopenharmony_ci * case of failure. 8448c2ecf20Sopenharmony_ci */ 8458c2ecf20Sopenharmony_cistatic int replay_buds(struct ubifs_info *c) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci struct bud_entry *b; 8488c2ecf20Sopenharmony_ci int err; 8498c2ecf20Sopenharmony_ci unsigned long long prev_sqnum = 0; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci list_for_each_entry(b, &c->replay_buds, list) { 8528c2ecf20Sopenharmony_ci err = replay_bud(c, b); 8538c2ecf20Sopenharmony_ci if (err) 8548c2ecf20Sopenharmony_ci return err; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci ubifs_assert(c, b->sqnum > prev_sqnum); 8578c2ecf20Sopenharmony_ci prev_sqnum = b->sqnum; 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci return 0; 8618c2ecf20Sopenharmony_ci} 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci/** 8648c2ecf20Sopenharmony_ci * destroy_bud_list - destroy the list of buds to replay. 8658c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 8668c2ecf20Sopenharmony_ci */ 8678c2ecf20Sopenharmony_cistatic void destroy_bud_list(struct ubifs_info *c) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci struct bud_entry *b; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci while (!list_empty(&c->replay_buds)) { 8728c2ecf20Sopenharmony_ci b = list_entry(c->replay_buds.next, struct bud_entry, list); 8738c2ecf20Sopenharmony_ci list_del(&b->list); 8748c2ecf20Sopenharmony_ci kfree(b); 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci} 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci/** 8798c2ecf20Sopenharmony_ci * add_replay_bud - add a bud to the list of buds to replay. 8808c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 8818c2ecf20Sopenharmony_ci * @lnum: bud logical eraseblock number to replay 8828c2ecf20Sopenharmony_ci * @offs: bud start offset 8838c2ecf20Sopenharmony_ci * @jhead: journal head to which this bud belongs 8848c2ecf20Sopenharmony_ci * @sqnum: reference node sequence number 8858c2ecf20Sopenharmony_ci * 8868c2ecf20Sopenharmony_ci * This function returns zero in case of success and a negative error code in 8878c2ecf20Sopenharmony_ci * case of failure. 8888c2ecf20Sopenharmony_ci */ 8898c2ecf20Sopenharmony_cistatic int add_replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead, 8908c2ecf20Sopenharmony_ci unsigned long long sqnum) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci struct ubifs_bud *bud; 8938c2ecf20Sopenharmony_ci struct bud_entry *b; 8948c2ecf20Sopenharmony_ci int err; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci dbg_mnt("add replay bud LEB %d:%d, head %d", lnum, offs, jhead); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci bud = kmalloc(sizeof(struct ubifs_bud), GFP_KERNEL); 8998c2ecf20Sopenharmony_ci if (!bud) 9008c2ecf20Sopenharmony_ci return -ENOMEM; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci b = kmalloc(sizeof(struct bud_entry), GFP_KERNEL); 9038c2ecf20Sopenharmony_ci if (!b) { 9048c2ecf20Sopenharmony_ci err = -ENOMEM; 9058c2ecf20Sopenharmony_ci goto out; 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci bud->lnum = lnum; 9098c2ecf20Sopenharmony_ci bud->start = offs; 9108c2ecf20Sopenharmony_ci bud->jhead = jhead; 9118c2ecf20Sopenharmony_ci bud->log_hash = ubifs_hash_get_desc(c); 9128c2ecf20Sopenharmony_ci if (IS_ERR(bud->log_hash)) { 9138c2ecf20Sopenharmony_ci err = PTR_ERR(bud->log_hash); 9148c2ecf20Sopenharmony_ci goto out; 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci ubifs_shash_copy_state(c, c->log_hash, bud->log_hash); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci ubifs_add_bud(c, bud); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci b->bud = bud; 9228c2ecf20Sopenharmony_ci b->sqnum = sqnum; 9238c2ecf20Sopenharmony_ci list_add_tail(&b->list, &c->replay_buds); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci return 0; 9268c2ecf20Sopenharmony_ciout: 9278c2ecf20Sopenharmony_ci kfree(bud); 9288c2ecf20Sopenharmony_ci kfree(b); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci return err; 9318c2ecf20Sopenharmony_ci} 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci/** 9348c2ecf20Sopenharmony_ci * validate_ref - validate a reference node. 9358c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 9368c2ecf20Sopenharmony_ci * @ref: the reference node to validate 9378c2ecf20Sopenharmony_ci * 9388c2ecf20Sopenharmony_ci * This function returns %1 if a bud reference already exists for the LEB. %0 is 9398c2ecf20Sopenharmony_ci * returned if the reference node is new, otherwise %-EINVAL is returned if 9408c2ecf20Sopenharmony_ci * validation failed. 9418c2ecf20Sopenharmony_ci */ 9428c2ecf20Sopenharmony_cistatic int validate_ref(struct ubifs_info *c, const struct ubifs_ref_node *ref) 9438c2ecf20Sopenharmony_ci{ 9448c2ecf20Sopenharmony_ci struct ubifs_bud *bud; 9458c2ecf20Sopenharmony_ci int lnum = le32_to_cpu(ref->lnum); 9468c2ecf20Sopenharmony_ci unsigned int offs = le32_to_cpu(ref->offs); 9478c2ecf20Sopenharmony_ci unsigned int jhead = le32_to_cpu(ref->jhead); 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci /* 9508c2ecf20Sopenharmony_ci * ref->offs may point to the end of LEB when the journal head points 9518c2ecf20Sopenharmony_ci * to the end of LEB and we write reference node for it during commit. 9528c2ecf20Sopenharmony_ci * So this is why we require 'offs > c->leb_size'. 9538c2ecf20Sopenharmony_ci */ 9548c2ecf20Sopenharmony_ci if (jhead >= c->jhead_cnt || lnum >= c->leb_cnt || 9558c2ecf20Sopenharmony_ci lnum < c->main_first || offs > c->leb_size || 9568c2ecf20Sopenharmony_ci offs & (c->min_io_size - 1)) 9578c2ecf20Sopenharmony_ci return -EINVAL; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci /* Make sure we have not already looked at this bud */ 9608c2ecf20Sopenharmony_ci bud = ubifs_search_bud(c, lnum); 9618c2ecf20Sopenharmony_ci if (bud) { 9628c2ecf20Sopenharmony_ci if (bud->jhead == jhead && bud->start <= offs) 9638c2ecf20Sopenharmony_ci return 1; 9648c2ecf20Sopenharmony_ci ubifs_err(c, "bud at LEB %d:%d was already referred", lnum, offs); 9658c2ecf20Sopenharmony_ci return -EINVAL; 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci return 0; 9698c2ecf20Sopenharmony_ci} 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci/** 9728c2ecf20Sopenharmony_ci * replay_log_leb - replay a log logical eraseblock. 9738c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 9748c2ecf20Sopenharmony_ci * @lnum: log logical eraseblock to replay 9758c2ecf20Sopenharmony_ci * @offs: offset to start replaying from 9768c2ecf20Sopenharmony_ci * @sbuf: scan buffer 9778c2ecf20Sopenharmony_ci * 9788c2ecf20Sopenharmony_ci * This function replays a log LEB and returns zero in case of success, %1 if 9798c2ecf20Sopenharmony_ci * this is the last LEB in the log, and a negative error code in case of 9808c2ecf20Sopenharmony_ci * failure. 9818c2ecf20Sopenharmony_ci */ 9828c2ecf20Sopenharmony_cistatic int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf) 9838c2ecf20Sopenharmony_ci{ 9848c2ecf20Sopenharmony_ci int err; 9858c2ecf20Sopenharmony_ci struct ubifs_scan_leb *sleb; 9868c2ecf20Sopenharmony_ci struct ubifs_scan_node *snod; 9878c2ecf20Sopenharmony_ci const struct ubifs_cs_node *node; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci dbg_mnt("replay log LEB %d:%d", lnum, offs); 9908c2ecf20Sopenharmony_ci sleb = ubifs_scan(c, lnum, offs, sbuf, c->need_recovery); 9918c2ecf20Sopenharmony_ci if (IS_ERR(sleb)) { 9928c2ecf20Sopenharmony_ci if (PTR_ERR(sleb) != -EUCLEAN || !c->need_recovery) 9938c2ecf20Sopenharmony_ci return PTR_ERR(sleb); 9948c2ecf20Sopenharmony_ci /* 9958c2ecf20Sopenharmony_ci * Note, the below function will recover this log LEB only if 9968c2ecf20Sopenharmony_ci * it is the last, because unclean reboots can possibly corrupt 9978c2ecf20Sopenharmony_ci * only the tail of the log. 9988c2ecf20Sopenharmony_ci */ 9998c2ecf20Sopenharmony_ci sleb = ubifs_recover_log_leb(c, lnum, offs, sbuf); 10008c2ecf20Sopenharmony_ci if (IS_ERR(sleb)) 10018c2ecf20Sopenharmony_ci return PTR_ERR(sleb); 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci if (sleb->nodes_cnt == 0) { 10058c2ecf20Sopenharmony_ci err = 1; 10068c2ecf20Sopenharmony_ci goto out; 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci node = sleb->buf; 10108c2ecf20Sopenharmony_ci snod = list_entry(sleb->nodes.next, struct ubifs_scan_node, list); 10118c2ecf20Sopenharmony_ci if (c->cs_sqnum == 0) { 10128c2ecf20Sopenharmony_ci /* 10138c2ecf20Sopenharmony_ci * This is the first log LEB we are looking at, make sure that 10148c2ecf20Sopenharmony_ci * the first node is a commit start node. Also record its 10158c2ecf20Sopenharmony_ci * sequence number so that UBIFS can determine where the log 10168c2ecf20Sopenharmony_ci * ends, because all nodes which were have higher sequence 10178c2ecf20Sopenharmony_ci * numbers. 10188c2ecf20Sopenharmony_ci */ 10198c2ecf20Sopenharmony_ci if (snod->type != UBIFS_CS_NODE) { 10208c2ecf20Sopenharmony_ci ubifs_err(c, "first log node at LEB %d:%d is not CS node", 10218c2ecf20Sopenharmony_ci lnum, offs); 10228c2ecf20Sopenharmony_ci goto out_dump; 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci if (le64_to_cpu(node->cmt_no) != c->cmt_no) { 10258c2ecf20Sopenharmony_ci ubifs_err(c, "first CS node at LEB %d:%d has wrong commit number %llu expected %llu", 10268c2ecf20Sopenharmony_ci lnum, offs, 10278c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu(node->cmt_no), 10288c2ecf20Sopenharmony_ci c->cmt_no); 10298c2ecf20Sopenharmony_ci goto out_dump; 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci c->cs_sqnum = le64_to_cpu(node->ch.sqnum); 10338c2ecf20Sopenharmony_ci dbg_mnt("commit start sqnum %llu", c->cs_sqnum); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci err = ubifs_shash_init(c, c->log_hash); 10368c2ecf20Sopenharmony_ci if (err) 10378c2ecf20Sopenharmony_ci goto out; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci err = ubifs_shash_update(c, c->log_hash, node, UBIFS_CS_NODE_SZ); 10408c2ecf20Sopenharmony_ci if (err < 0) 10418c2ecf20Sopenharmony_ci goto out; 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci if (snod->sqnum < c->cs_sqnum) { 10458c2ecf20Sopenharmony_ci /* 10468c2ecf20Sopenharmony_ci * This means that we reached end of log and now 10478c2ecf20Sopenharmony_ci * look to the older log data, which was already 10488c2ecf20Sopenharmony_ci * committed but the eraseblock was not erased (UBIFS 10498c2ecf20Sopenharmony_ci * only un-maps it). So this basically means we have to 10508c2ecf20Sopenharmony_ci * exit with "end of log" code. 10518c2ecf20Sopenharmony_ci */ 10528c2ecf20Sopenharmony_ci err = 1; 10538c2ecf20Sopenharmony_ci goto out; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci /* Make sure the first node sits at offset zero of the LEB */ 10578c2ecf20Sopenharmony_ci if (snod->offs != 0) { 10588c2ecf20Sopenharmony_ci ubifs_err(c, "first node is not at zero offset"); 10598c2ecf20Sopenharmony_ci goto out_dump; 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci list_for_each_entry(snod, &sleb->nodes, list) { 10638c2ecf20Sopenharmony_ci cond_resched(); 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci if (snod->sqnum >= SQNUM_WATERMARK) { 10668c2ecf20Sopenharmony_ci ubifs_err(c, "file system's life ended"); 10678c2ecf20Sopenharmony_ci goto out_dump; 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci if (snod->sqnum < c->cs_sqnum) { 10718c2ecf20Sopenharmony_ci ubifs_err(c, "bad sqnum %llu, commit sqnum %llu", 10728c2ecf20Sopenharmony_ci snod->sqnum, c->cs_sqnum); 10738c2ecf20Sopenharmony_ci goto out_dump; 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci if (snod->sqnum > c->max_sqnum) 10778c2ecf20Sopenharmony_ci c->max_sqnum = snod->sqnum; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci switch (snod->type) { 10808c2ecf20Sopenharmony_ci case UBIFS_REF_NODE: { 10818c2ecf20Sopenharmony_ci const struct ubifs_ref_node *ref = snod->node; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci err = validate_ref(c, ref); 10848c2ecf20Sopenharmony_ci if (err == 1) 10858c2ecf20Sopenharmony_ci break; /* Already have this bud */ 10868c2ecf20Sopenharmony_ci if (err) 10878c2ecf20Sopenharmony_ci goto out_dump; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci err = ubifs_shash_update(c, c->log_hash, ref, 10908c2ecf20Sopenharmony_ci UBIFS_REF_NODE_SZ); 10918c2ecf20Sopenharmony_ci if (err) 10928c2ecf20Sopenharmony_ci goto out; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci err = add_replay_bud(c, le32_to_cpu(ref->lnum), 10958c2ecf20Sopenharmony_ci le32_to_cpu(ref->offs), 10968c2ecf20Sopenharmony_ci le32_to_cpu(ref->jhead), 10978c2ecf20Sopenharmony_ci snod->sqnum); 10988c2ecf20Sopenharmony_ci if (err) 10998c2ecf20Sopenharmony_ci goto out; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci break; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci case UBIFS_CS_NODE: 11048c2ecf20Sopenharmony_ci /* Make sure it sits at the beginning of LEB */ 11058c2ecf20Sopenharmony_ci if (snod->offs != 0) { 11068c2ecf20Sopenharmony_ci ubifs_err(c, "unexpected node in log"); 11078c2ecf20Sopenharmony_ci goto out_dump; 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci break; 11108c2ecf20Sopenharmony_ci default: 11118c2ecf20Sopenharmony_ci ubifs_err(c, "unexpected node in log"); 11128c2ecf20Sopenharmony_ci goto out_dump; 11138c2ecf20Sopenharmony_ci } 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci if (sleb->endpt || c->lhead_offs >= c->leb_size) { 11178c2ecf20Sopenharmony_ci c->lhead_lnum = lnum; 11188c2ecf20Sopenharmony_ci c->lhead_offs = sleb->endpt; 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci err = !sleb->endpt; 11228c2ecf20Sopenharmony_ciout: 11238c2ecf20Sopenharmony_ci ubifs_scan_destroy(sleb); 11248c2ecf20Sopenharmony_ci return err; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ciout_dump: 11278c2ecf20Sopenharmony_ci ubifs_err(c, "log error detected while replaying the log at LEB %d:%d", 11288c2ecf20Sopenharmony_ci lnum, offs + snod->offs); 11298c2ecf20Sopenharmony_ci ubifs_dump_node(c, snod->node, c->leb_size - snod->offs); 11308c2ecf20Sopenharmony_ci ubifs_scan_destroy(sleb); 11318c2ecf20Sopenharmony_ci return -EINVAL; 11328c2ecf20Sopenharmony_ci} 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci/** 11358c2ecf20Sopenharmony_ci * take_ihead - update the status of the index head in lprops to 'taken'. 11368c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 11378c2ecf20Sopenharmony_ci * 11388c2ecf20Sopenharmony_ci * This function returns the amount of free space in the index head LEB or a 11398c2ecf20Sopenharmony_ci * negative error code. 11408c2ecf20Sopenharmony_ci */ 11418c2ecf20Sopenharmony_cistatic int take_ihead(struct ubifs_info *c) 11428c2ecf20Sopenharmony_ci{ 11438c2ecf20Sopenharmony_ci const struct ubifs_lprops *lp; 11448c2ecf20Sopenharmony_ci int err, free; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci ubifs_get_lprops(c); 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci lp = ubifs_lpt_lookup_dirty(c, c->ihead_lnum); 11498c2ecf20Sopenharmony_ci if (IS_ERR(lp)) { 11508c2ecf20Sopenharmony_ci err = PTR_ERR(lp); 11518c2ecf20Sopenharmony_ci goto out; 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci free = lp->free; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci lp = ubifs_change_lp(c, lp, LPROPS_NC, LPROPS_NC, 11578c2ecf20Sopenharmony_ci lp->flags | LPROPS_TAKEN, 0); 11588c2ecf20Sopenharmony_ci if (IS_ERR(lp)) { 11598c2ecf20Sopenharmony_ci err = PTR_ERR(lp); 11608c2ecf20Sopenharmony_ci goto out; 11618c2ecf20Sopenharmony_ci } 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci err = free; 11648c2ecf20Sopenharmony_ciout: 11658c2ecf20Sopenharmony_ci ubifs_release_lprops(c); 11668c2ecf20Sopenharmony_ci return err; 11678c2ecf20Sopenharmony_ci} 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci/** 11708c2ecf20Sopenharmony_ci * ubifs_replay_journal - replay journal. 11718c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 11728c2ecf20Sopenharmony_ci * 11738c2ecf20Sopenharmony_ci * This function scans the journal, replays and cleans it up. It makes sure all 11748c2ecf20Sopenharmony_ci * memory data structures related to uncommitted journal are built (dirty TNC 11758c2ecf20Sopenharmony_ci * tree, tree of buds, modified lprops, etc). 11768c2ecf20Sopenharmony_ci */ 11778c2ecf20Sopenharmony_ciint ubifs_replay_journal(struct ubifs_info *c) 11788c2ecf20Sopenharmony_ci{ 11798c2ecf20Sopenharmony_ci int err, lnum, free; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_TRUN_KEY > 5); 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci /* Update the status of the index head in lprops to 'taken' */ 11848c2ecf20Sopenharmony_ci free = take_ihead(c); 11858c2ecf20Sopenharmony_ci if (free < 0) 11868c2ecf20Sopenharmony_ci return free; /* Error code */ 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci if (c->ihead_offs != c->leb_size - free) { 11898c2ecf20Sopenharmony_ci ubifs_err(c, "bad index head LEB %d:%d", c->ihead_lnum, 11908c2ecf20Sopenharmony_ci c->ihead_offs); 11918c2ecf20Sopenharmony_ci return -EINVAL; 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci dbg_mnt("start replaying the journal"); 11958c2ecf20Sopenharmony_ci c->replaying = 1; 11968c2ecf20Sopenharmony_ci lnum = c->ltail_lnum = c->lhead_lnum; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci do { 11998c2ecf20Sopenharmony_ci err = replay_log_leb(c, lnum, 0, c->sbuf); 12008c2ecf20Sopenharmony_ci if (err == 1) { 12018c2ecf20Sopenharmony_ci if (lnum != c->lhead_lnum) 12028c2ecf20Sopenharmony_ci /* We hit the end of the log */ 12038c2ecf20Sopenharmony_ci break; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci /* 12068c2ecf20Sopenharmony_ci * The head of the log must always start with the 12078c2ecf20Sopenharmony_ci * "commit start" node on a properly formatted UBIFS. 12088c2ecf20Sopenharmony_ci * But we found no nodes at all, which means that 12098c2ecf20Sopenharmony_ci * something went wrong and we cannot proceed mounting 12108c2ecf20Sopenharmony_ci * the file-system. 12118c2ecf20Sopenharmony_ci */ 12128c2ecf20Sopenharmony_ci ubifs_err(c, "no UBIFS nodes found at the log head LEB %d:%d, possibly corrupted", 12138c2ecf20Sopenharmony_ci lnum, 0); 12148c2ecf20Sopenharmony_ci err = -EINVAL; 12158c2ecf20Sopenharmony_ci } 12168c2ecf20Sopenharmony_ci if (err) 12178c2ecf20Sopenharmony_ci goto out; 12188c2ecf20Sopenharmony_ci lnum = ubifs_next_log_lnum(c, lnum); 12198c2ecf20Sopenharmony_ci } while (lnum != c->ltail_lnum); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci err = replay_buds(c); 12228c2ecf20Sopenharmony_ci if (err) 12238c2ecf20Sopenharmony_ci goto out; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci err = apply_replay_list(c); 12268c2ecf20Sopenharmony_ci if (err) 12278c2ecf20Sopenharmony_ci goto out; 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci err = set_buds_lprops(c); 12308c2ecf20Sopenharmony_ci if (err) 12318c2ecf20Sopenharmony_ci goto out; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci /* 12348c2ecf20Sopenharmony_ci * UBIFS budgeting calculations use @c->bi.uncommitted_idx variable 12358c2ecf20Sopenharmony_ci * to roughly estimate index growth. Things like @c->bi.min_idx_lebs 12368c2ecf20Sopenharmony_ci * depend on it. This means we have to initialize it to make sure 12378c2ecf20Sopenharmony_ci * budgeting works properly. 12388c2ecf20Sopenharmony_ci */ 12398c2ecf20Sopenharmony_ci c->bi.uncommitted_idx = atomic_long_read(&c->dirty_zn_cnt); 12408c2ecf20Sopenharmony_ci c->bi.uncommitted_idx *= c->max_idx_node_sz; 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci ubifs_assert(c, c->bud_bytes <= c->max_bud_bytes || c->need_recovery); 12438c2ecf20Sopenharmony_ci dbg_mnt("finished, log head LEB %d:%d, max_sqnum %llu, highest_inum %lu", 12448c2ecf20Sopenharmony_ci c->lhead_lnum, c->lhead_offs, c->max_sqnum, 12458c2ecf20Sopenharmony_ci (unsigned long)c->highest_inum); 12468c2ecf20Sopenharmony_ciout: 12478c2ecf20Sopenharmony_ci destroy_replay_list(c); 12488c2ecf20Sopenharmony_ci destroy_bud_list(c); 12498c2ecf20Sopenharmony_ci c->replaying = 0; 12508c2ecf20Sopenharmony_ci return err; 12518c2ecf20Sopenharmony_ci} 1252