// 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 implements functions needed to recover from unclean un-mounts. * When UBIFS is mounted, it checks a flag on the master node to determine if * an un-mount was completed successfully. If not, the process of mounting * incorporates additional checking and fixing of on-flash data structures. * UBIFS always cleans away all remnants of an unclean un-mount, so that * errors do not accumulate. However UBIFS defers recovery if it is mounted * read-only, and the flash is not modified in that case. * * The general UBIFS approach to the recovery is that it recovers from * corruptions which could be caused by power cuts, but it refuses to recover * from corruption caused by other reasons. And UBIFS tries to distinguish * between these 2 reasons of corruptions and silently recover in the former * case and loudly complain in the latter case. * * UBIFS writes only to erased LEBs, so it writes only to the flash space * containing only 0xFFs. UBIFS also always writes strictly from the beginning * of the LEB to the end. And UBIFS assumes that the underlying flash media * writes in @c->max_write_size bytes at a time. * * Hence, if UBIFS finds a corrupted node at offset X, it expects only the min. * I/O unit corresponding to offset X to contain corrupted data, all the * following min. I/O units have to contain empty space (all 0xFFs). If this is * not true, the corruption cannot be the result of a power cut, and UBIFS * refuses to mount. */ #include <linux/crc32.h> #include <linux/slab.h> #include "ubifs.h" /** * is_empty - determine whether a buffer is empty (contains all 0xff). * @buf: buffer to clean * @len: length of buffer * * This function returns %1 if the buffer is empty (contains all 0xff) otherwise * %0 is returned. */ static int is_empty(void *buf, int len) { … } /** * first_non_ff - find offset of the first non-0xff byte. * @buf: buffer to search in * @len: length of buffer * * This function returns offset of the first non-0xff byte in @buf or %-1 if * the buffer contains only 0xff bytes. */ static int first_non_ff(void *buf, int len) { … } /** * get_master_node - get the last valid master node allowing for corruption. * @c: UBIFS file-system description object * @lnum: LEB number * @pbuf: buffer containing the LEB read, is returned here * @mst: master node, if found, is returned here * @cor: corruption, if found, is returned here * * This function allocates a buffer, reads the LEB into it, and finds and * returns the last valid master node allowing for one area of corruption. * The corrupt area, if there is one, must be consistent with the assumption * that it is the result of an unclean unmount while the master node was being * written. Under those circumstances, it is valid to use the previously written * master node. * * This function returns %0 on success and a negative error code on failure. */ static int get_master_node(const struct ubifs_info *c, int lnum, void **pbuf, struct ubifs_mst_node **mst, void **cor) { … } /** * write_rcvrd_mst_node - write recovered master node. * @c: UBIFS file-system description object * @mst: master node * * This function returns %0 on success and a negative error code on failure. */ static int write_rcvrd_mst_node(struct ubifs_info *c, struct ubifs_mst_node *mst) { … } /** * ubifs_recover_master_node - recover the master node. * @c: UBIFS file-system description object * * This function recovers the master node from corruption that may occur due to * an unclean unmount. * * This function returns %0 on success and a negative error code on failure. */ int ubifs_recover_master_node(struct ubifs_info *c) { … } /** * ubifs_write_rcvrd_mst_node - write the recovered master node. * @c: UBIFS file-system description object * * This function writes the master node that was recovered during mounting in * read-only mode and must now be written because we are remounting rw. * * This function returns %0 on success and a negative error code on failure. */ int ubifs_write_rcvrd_mst_node(struct ubifs_info *c) { … } /** * is_last_write - determine if an offset was in the last write to a LEB. * @c: UBIFS file-system description object * @buf: buffer to check * @offs: offset to check * * This function returns %1 if @offs was in the last write to the LEB whose data * is in @buf, otherwise %0 is returned. The determination is made by checking * for subsequent empty space starting from the next @c->max_write_size * boundary. */ static int is_last_write(const struct ubifs_info *c, void *buf, int offs) { … } /** * clean_buf - clean the data from an LEB sitting in a buffer. * @c: UBIFS file-system description object * @buf: buffer to clean * @lnum: LEB number to clean * @offs: offset from which to clean * @len: length of buffer * * This function pads up to the next min_io_size boundary (if there is one) and * sets empty space to all 0xff. @buf, @offs and @len are updated to the next * @c->min_io_size boundary. */ static void clean_buf(const struct ubifs_info *c, void **buf, int lnum, int *offs, int *len) { … } /** * no_more_nodes - determine if there are no more nodes in a buffer. * @c: UBIFS file-system description object * @buf: buffer to check * @len: length of buffer * @lnum: LEB number of the LEB from which @buf was read * @offs: offset from which @buf was read * * This function ensures that the corrupted node at @offs is the last thing * written to a LEB. This function returns %1 if more data is not found and * %0 if more data is found. */ static int no_more_nodes(const struct ubifs_info *c, void *buf, int len, int lnum, int offs) { … } /** * fix_unclean_leb - fix an unclean LEB. * @c: UBIFS file-system description object * @sleb: scanned LEB information * @start: offset where scan started */ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb, int start) { … } /** * drop_last_group - drop the last group of nodes. * @sleb: scanned LEB information * @offs: offset of dropped nodes is returned here * * This is a helper function for 'ubifs_recover_leb()' which drops the last * group of nodes of the scanned LEB. */ static void drop_last_group(struct ubifs_scan_leb *sleb, int *offs) { … } /** * drop_last_node - drop the last node. * @sleb: scanned LEB information * @offs: offset of dropped nodes is returned here * * This is a helper function for 'ubifs_recover_leb()' which drops the last * node of the scanned LEB. */ static void drop_last_node(struct ubifs_scan_leb *sleb, int *offs) { … } /** * ubifs_recover_leb - scan and recover a LEB. * @c: UBIFS file-system description object * @lnum: LEB number * @offs: offset * @sbuf: LEB-sized buffer to use * @jhead: journal head number this LEB belongs to (%-1 if the LEB does not * belong to any journal head) * * This function does a scan of a LEB, but caters for errors that might have * been caused by the unclean unmount from which we are attempting to recover. * Returns the scanned information on success and a negative error code on * failure. */ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf, int jhead) { … } /** * get_cs_sqnum - get commit start sequence number. * @c: UBIFS file-system description object * @lnum: LEB number of commit start node * @offs: offset of commit start node * @cs_sqnum: commit start sequence number is returned here * * This function returns %0 on success and a negative error code on failure. */ static int get_cs_sqnum(struct ubifs_info *c, int lnum, int offs, unsigned long long *cs_sqnum) { … } /** * ubifs_recover_log_leb - scan and recover a log LEB. * @c: UBIFS file-system description object * @lnum: LEB number * @offs: offset * @sbuf: LEB-sized buffer to use * * This function does a scan of a LEB, but caters for errors that might have * been caused by unclean reboots from which we are attempting to recover * (assume that only the last log LEB can be corrupted by an unclean reboot). * * This function returns %0 on success and a negative error code on failure. */ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf) { … } /** * recover_head - recover a head. * @c: UBIFS file-system description object * @lnum: LEB number of head to recover * @offs: offset of head to recover * @sbuf: LEB-sized buffer to use * * This function ensures that there is no data on the flash at a head location. * * This function returns %0 on success and a negative error code on failure. */ static int recover_head(struct ubifs_info *c, int lnum, int offs, void *sbuf) { … } /** * ubifs_recover_inl_heads - recover index and LPT heads. * @c: UBIFS file-system description object * @sbuf: LEB-sized buffer to use * * This function ensures that there is no data on the flash at the index and * LPT head locations. * * This deals with the recovery of a half-completed journal commit. UBIFS is * careful never to overwrite the last version of the index or the LPT. Because * the index and LPT are wandering trees, data from a half-completed commit will * not be referenced anywhere in UBIFS. The data will be either in LEBs that are * assumed to be empty and will be unmapped anyway before use, or in the index * and LPT heads. * * This function returns %0 on success and a negative error code on failure. */ int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf) { … } /** * clean_an_unclean_leb - read and write a LEB to remove corruption. * @c: UBIFS file-system description object * @ucleb: unclean LEB information * @sbuf: LEB-sized buffer to use * * This function reads a LEB up to a point pre-determined by the mount recovery, * checks the nodes, and writes the result back to the flash, thereby cleaning * off any following corruption, or non-fatal ECC errors. * * This function returns %0 on success and a negative error code on failure. */ static int clean_an_unclean_leb(struct ubifs_info *c, struct ubifs_unclean_leb *ucleb, void *sbuf) { … } /** * ubifs_clean_lebs - clean LEBs recovered during read-only mount. * @c: UBIFS file-system description object * @sbuf: LEB-sized buffer to use * * This function cleans a LEB identified during recovery that needs to be * written but was not because UBIFS was mounted read-only. This happens when * remounting to read-write mode. * * This function returns %0 on success and a negative error code on failure. */ int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf) { … } /** * grab_empty_leb - grab an empty LEB to use as GC LEB and run commit. * @c: UBIFS file-system description object * * This is a helper function for 'ubifs_rcvry_gc_commit()' which grabs an empty * LEB to be used as GC LEB (@c->gc_lnum), and then runs the commit. Returns * zero in case of success and a negative error code in case of failure. */ static int grab_empty_leb(struct ubifs_info *c) { … } /** * ubifs_rcvry_gc_commit - recover the GC LEB number and run the commit. * @c: UBIFS file-system description object * * Out-of-place garbage collection requires always one empty LEB with which to * start garbage collection. The LEB number is recorded in c->gc_lnum and is * written to the master node on unmounting. In the case of an unclean unmount * the value of gc_lnum recorded in the master node is out of date and cannot * be used. Instead, recovery must allocate an empty LEB for this purpose. * However, there may not be enough empty space, in which case it must be * possible to GC the dirtiest LEB into the GC head LEB. * * This function also runs the commit which causes the TNC updates from * size-recovery and orphans to be written to the flash. That is important to * ensure correct replay order for subsequent mounts. * * This function returns %0 on success and a negative error code on failure. */ int ubifs_rcvry_gc_commit(struct ubifs_info *c) { … } /** * struct size_entry - inode size information for recovery. * @rb: link in the RB-tree of sizes * @inum: inode number * @i_size: size on inode * @d_size: maximum size based on data nodes * @exists: indicates whether the inode exists * @inode: inode if pinned in memory awaiting rw mode to fix it */ struct size_entry { … }; /** * add_ino - add an entry to the size tree. * @c: UBIFS file-system description object * @inum: inode number * @i_size: size on inode * @d_size: maximum size based on data nodes * @exists: indicates whether the inode exists */ static int add_ino(struct ubifs_info *c, ino_t inum, loff_t i_size, loff_t d_size, int exists) { … } /** * find_ino - find an entry on the size tree. * @c: UBIFS file-system description object * @inum: inode number */ static struct size_entry *find_ino(struct ubifs_info *c, ino_t inum) { … } /** * remove_ino - remove an entry from the size tree. * @c: UBIFS file-system description object * @inum: inode number */ static void remove_ino(struct ubifs_info *c, ino_t inum) { … } /** * ubifs_destroy_size_tree - free resources related to the size tree. * @c: UBIFS file-system description object */ void ubifs_destroy_size_tree(struct ubifs_info *c) { … } /** * ubifs_recover_size_accum - accumulate inode sizes for recovery. * @c: UBIFS file-system description object * @key: node key * @deletion: node is for a deletion * @new_size: inode size * * This function has two purposes: * 1) to ensure there are no data nodes that fall outside the inode size * 2) to ensure there are no data nodes for inodes that do not exist * To accomplish those purposes, a rb-tree is constructed containing an entry * for each inode number in the journal that has not been deleted, and recording * the size from the inode node, the maximum size of any data node (also altered * by truncations) and a flag indicating a inode number for which no inode node * was present in the journal. * * Note that there is still the possibility that there are data nodes that have * been committed that are beyond the inode size, however the only way to find * them would be to scan the entire index. Alternatively, some provision could * be made to record the size of inodes at the start of commit, which would seem * very cumbersome for a scenario that is quite unlikely and the only negative * consequence of which is wasted space. * * This functions returns %0 on success and a negative error code on failure. */ int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key, int deletion, loff_t new_size) { … } /** * fix_size_in_place - fix inode size in place on flash. * @c: UBIFS file-system description object * @e: inode size information for recovery */ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e) { … } /** * inode_fix_size - fix inode size * @c: UBIFS file-system description object * @e: inode size information for recovery */ static int inode_fix_size(struct ubifs_info *c, struct size_entry *e) { … } /** * ubifs_recover_size - recover inode size. * @c: UBIFS file-system description object * @in_place: If true, do a in-place size fixup * * This function attempts to fix inode size discrepancies identified by the * 'ubifs_recover_size_accum()' function. * * This functions returns %0 on success and a negative error code on failure. */ int ubifs_recover_size(struct ubifs_info *c, bool in_place) { … }