// SPDX-License-Identifier: GPL-2.0-only /* * This file is part of UBIFS. * * Copyright (C) 2006-2008 Nokia Corporation. * * Authors: Adrian Hunter * Artem Bityutskiy (Битюцкий Артём) */ /* * This file contains journal replay code. It runs when the file-system is being * mounted and requires no locking. * * The larger is the journal, the longer it takes to scan it, so the longer it * takes to mount UBIFS. This is why the journal has limited size which may be * changed depending on the system requirements. But a larger journal gives * faster I/O speed because it writes the index less frequently. So this is a * trade-off. Also, the journal is indexed by the in-memory index (TNC), so the * larger is the journal, the more memory its index may consume. */ #include "ubifs.h" #include <linux/list_sort.h> #include <crypto/hash.h> /** * struct replay_entry - replay list entry. * @lnum: logical eraseblock number of the node * @offs: node offset * @len: node length * @hash: node hash * @deletion: non-zero if this entry corresponds to a node deletion * @sqnum: node sequence number * @list: links the replay list * @key: node key * @nm: directory entry name * @old_size: truncation old size * @new_size: truncation new size * * The replay process first scans all buds and builds the replay list, then * sorts the replay list in nodes sequence number order, and then inserts all * the replay entries to the TNC. */ struct replay_entry { … }; /** * struct bud_entry - entry in the list of buds to replay. * @list: next bud in the list * @bud: bud description object * @sqnum: reference node sequence number * @free: free bytes in the bud * @dirty: dirty bytes in the bud */ struct bud_entry { … }; /** * set_bud_lprops - set free and dirty space used by a bud. * @c: UBIFS file-system description object * @b: bud entry which describes the bud * * This function makes sure the LEB properties of bud @b are set correctly * after the replay. Returns zero in case of success and a negative error code * in case of failure. */ static int set_bud_lprops(struct ubifs_info *c, struct bud_entry *b) { … } /** * set_buds_lprops - set free and dirty space for all replayed buds. * @c: UBIFS file-system description object * * This function sets LEB properties for all replayed buds. Returns zero in * case of success and a negative error code in case of failure. */ static int set_buds_lprops(struct ubifs_info *c) { … } /** * trun_remove_range - apply a replay entry for a truncation to the TNC. * @c: UBIFS file-system description object * @r: replay entry of truncation */ static int trun_remove_range(struct ubifs_info *c, struct replay_entry *r) { … } /** * inode_still_linked - check whether inode in question will be re-linked. * @c: UBIFS file-system description object * @rino: replay entry to test * * O_TMPFILE files can be re-linked, this means link count goes from 0 to 1. * This case needs special care, otherwise all references to the inode will * be removed upon the first replay entry of an inode with link count 0 * is found. */ static bool inode_still_linked(struct ubifs_info *c, struct replay_entry *rino) { … } /** * apply_replay_entry - apply a replay entry to the TNC. * @c: UBIFS file-system description object * @r: replay entry to apply * * Apply a replay entry to the TNC. */ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r) { … } /** * replay_entries_cmp - compare 2 replay entries. * @priv: UBIFS file-system description object * @a: first replay entry * @b: second replay entry * * This is a comparios function for 'list_sort()' which compares 2 replay * entries @a and @b by comparing their sequence number. Returns %1 if @a has * greater sequence number and %-1 otherwise. */ static int replay_entries_cmp(void *priv, const struct list_head *a, const struct list_head *b) { … } /** * apply_replay_list - apply the replay list to the TNC. * @c: UBIFS file-system description object * * Apply all entries in the replay list to the TNC. Returns zero in case of * success and a negative error code in case of failure. */ static int apply_replay_list(struct ubifs_info *c) { … } /** * destroy_replay_list - destroy the replay. * @c: UBIFS file-system description object * * Destroy the replay list. */ static void destroy_replay_list(struct ubifs_info *c) { … } /** * insert_node - insert a node to the replay list * @c: UBIFS file-system description object * @lnum: node logical eraseblock number * @offs: node offset * @len: node length * @hash: node hash * @key: node key * @sqnum: sequence number * @deletion: non-zero if this is a deletion * @used: number of bytes in use in a LEB * @old_size: truncation old size * @new_size: truncation new size * * This function inserts a scanned non-direntry node to the replay list. The * replay list contains @struct replay_entry elements, and we sort this list in * sequence number order before applying it. The replay list is applied at the * very end of the replay process. Since the list is sorted in sequence number * order, the older modifications are applied first. This function returns zero * in case of success and a negative error code in case of failure. */ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len, const u8 *hash, union ubifs_key *key, unsigned long long sqnum, int deletion, int *used, loff_t old_size, loff_t new_size) { … } /** * insert_dent - insert a directory entry node into the replay list. * @c: UBIFS file-system description object * @lnum: node logical eraseblock number * @offs: node offset * @len: node length * @hash: node hash * @key: node key * @name: directory entry name * @nlen: directory entry name length * @sqnum: sequence number * @deletion: non-zero if this is a deletion * @used: number of bytes in use in a LEB * * This function inserts a scanned directory entry node or an extended * attribute entry to the replay list. Returns zero in case of success and a * negative error code in case of failure. */ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len, const u8 *hash, union ubifs_key *key, const char *name, int nlen, unsigned long long sqnum, int deletion, int *used) { … } /** * ubifs_validate_entry - validate directory or extended attribute entry node. * @c: UBIFS file-system description object * @dent: the node to validate * * This function validates directory or extended attribute entry node @dent. * Returns zero if the node is all right and a %-EINVAL if not. */ int ubifs_validate_entry(struct ubifs_info *c, const struct ubifs_dent_node *dent) { … } /** * is_last_bud - check if the bud is the last in the journal head. * @c: UBIFS file-system description object * @bud: bud description object * * This function checks if bud @bud is the last bud in its journal head. This * information is then used by 'replay_bud()' to decide whether the bud can * have corruptions or not. Indeed, only last buds can be corrupted by power * cuts. Returns %1 if this is the last bud, and %0 if not. */ static int is_last_bud(struct ubifs_info *c, struct ubifs_bud *bud) { … } /* authenticate_sleb_hash is split out for stack usage */ static int noinline_for_stack authenticate_sleb_hash(struct ubifs_info *c, struct shash_desc *log_hash, u8 *hash) { … } /** * authenticate_sleb - authenticate one scan LEB * @c: UBIFS file-system description object * @sleb: the scan LEB to authenticate * @log_hash: * @is_last: if true, this is the last LEB * * This function iterates over the buds of a single LEB authenticating all buds * with the authentication nodes on this LEB. Authentication nodes are written * after some buds and contain a HMAC covering the authentication node itself * and the buds between the last authentication node and the current * authentication node. It can happen that the last buds cannot be authenticated * because a powercut happened when some nodes were written but not the * corresponding authentication node. This function returns the number of nodes * that could be authenticated or a negative error code. */ static int authenticate_sleb(struct ubifs_info *c, struct ubifs_scan_leb *sleb, struct shash_desc *log_hash, int is_last) { … } /** * replay_bud - replay a bud logical eraseblock. * @c: UBIFS file-system description object * @b: bud entry which describes the bud * * This function replays bud @bud, recovers it if needed, and adds all nodes * from this bud to the replay list. Returns zero in case of success and a * negative error code in case of failure. */ static int replay_bud(struct ubifs_info *c, struct bud_entry *b) { … } /** * replay_buds - replay all buds. * @c: UBIFS file-system description object * * This function returns zero in case of success and a negative error code in * case of failure. */ static int replay_buds(struct ubifs_info *c) { … } /** * destroy_bud_list - destroy the list of buds to replay. * @c: UBIFS file-system description object */ static void destroy_bud_list(struct ubifs_info *c) { … } /** * add_replay_bud - add a bud to the list of buds to replay. * @c: UBIFS file-system description object * @lnum: bud logical eraseblock number to replay * @offs: bud start offset * @jhead: journal head to which this bud belongs * @sqnum: reference node sequence number * * This function returns zero in case of success and a negative error code in * case of failure. */ static int add_replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead, unsigned long long sqnum) { … } /** * validate_ref - validate a reference node. * @c: UBIFS file-system description object * @ref: the reference node to validate * * This function returns %1 if a bud reference already exists for the LEB. %0 is * returned if the reference node is new, otherwise %-EINVAL is returned if * validation failed. */ static int validate_ref(struct ubifs_info *c, const struct ubifs_ref_node *ref) { … } /** * replay_log_leb - replay a log logical eraseblock. * @c: UBIFS file-system description object * @lnum: log logical eraseblock to replay * @offs: offset to start replaying from * @sbuf: scan buffer * * This function replays a log LEB and returns zero in case of success, %1 if * this is the last LEB in the log, and a negative error code in case of * failure. */ static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf) { … } /** * take_ihead - update the status of the index head in lprops to 'taken'. * @c: UBIFS file-system description object * * This function returns the amount of free space in the index head LEB or a * negative error code. */ static int take_ihead(struct ubifs_info *c) { … } /** * ubifs_replay_journal - replay journal. * @c: UBIFS file-system description object * * This function scans the journal, replays and cleans it up. It makes sure all * memory data structures related to uncommitted journal are built (dirty TNC * tree, tree of buds, modified lprops, etc). */ int ubifs_replay_journal(struct ubifs_info *c) { … }