/* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <[email protected]> * * For licensing information, see the file 'LICENCE' in this directory. * */ #define pr_fmt(fmt) … #include <linux/kernel.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/fs.h> #include <linux/crc32.h> #include <linux/pagemap.h> #include <linux/mtd/mtd.h> #include <linux/compiler.h> #include "nodelist.h" /* * Check the data CRC of the node. * * Returns: 0 if the data CRC is correct; * 1 - if incorrect; * error code if an error occurred. */ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn) { … } /* * Helper function for jffs2_add_older_frag_to_fragtree(). * * Checks the node if we are in the checking stage. */ static int check_tn_node(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn) { … } static struct jffs2_tmp_dnode_info *jffs2_lookup_tn(struct rb_root *tn_root, uint32_t offset) { … } static void jffs2_kill_tn(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn) { … } /* * This function is used when we read an inode. Data nodes arrive in * arbitrary order -- they may be older or newer than the nodes which * are already in the tree. Where overlaps occur, the older node can * be discarded as long as the newer passes the CRC check. We don't * bother to keep track of holes in this rbtree, and neither do we deal * with frags -- we can have multiple entries starting at the same * offset, and the one with the smallest length will come first in the * ordering. * * Returns 0 if the node was handled (including marking it obsolete) * < 0 an if error occurred */ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, struct jffs2_readinode_info *rii, struct jffs2_tmp_dnode_info *tn) { … } /* Trivial function to remove the last node in the tree. Which by definition has no right-hand child — so can be removed just by making its left-hand child (if any) take its place under its parent. Since this is only done when we're consuming the whole tree, there's no need to use rb_erase() and let it worry about adjusting colours and balancing the tree. That would just be a waste of time. */ static void eat_last(struct rb_root *root, struct rb_node *node) { … } /* We put the version tree in reverse order, so we can use the same eat_last() function that we use to consume the tmpnode tree (tn_root). */ static void ver_insert(struct rb_root *ver_root, struct jffs2_tmp_dnode_info *tn) { … } /* Build final, normal fragtree from tn tree. It doesn't matter which order we add nodes to the real fragtree, as long as they don't overlap. And having thrown away the majority of overlapped nodes as we went, there really shouldn't be many sets of nodes which do overlap. If we start at the end, we can use the overlap markers -- we can just eat nodes which aren't overlapped, and when we encounter nodes which _do_ overlap we sort them all into a temporary tree in version order before replaying them. */ static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_readinode_info *rii) { … } static void jffs2_free_tmp_dnode_info_list(struct rb_root *list) { … } static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd) { … } /* Returns first valid node after 'ref'. May return 'ref' */ static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_ref *ref) { … } /* * Helper function for jffs2_get_inode_nodes(). * It is called every time an directory entry node is found. * * Returns: 0 on success; * negative error code on failure. */ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, struct jffs2_raw_dirent *rd, size_t read, struct jffs2_readinode_info *rii) { … } /* * Helper function for jffs2_get_inode_nodes(). * It is called every time an inode node is found. * * Returns: 0 on success (possibly after marking a bad node obsolete); * negative error code on failure. */ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, struct jffs2_raw_inode *rd, int rdlen, struct jffs2_readinode_info *rii) { … } /* * Helper function for jffs2_get_inode_nodes(). * It is called every time an unknown node is found. * * Returns: 0 on success; * negative error code on failure. */ static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, struct jffs2_unknown_node *un) { … } /* * Helper function for jffs2_get_inode_nodes(). * The function detects whether more data should be read and reads it if yes. * * Returns: 0 on success; * negative error code on failure. */ static int read_more(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, int needed_len, int *rdlen, unsigned char *buf) { … } /* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated with this ino. Perform a preliminary ordering on data nodes, throwing away those which are completely obsoleted by newer ones. The naïve approach we use to take of just returning them _all_ in version order will cause us to run out of memory in certain degenerate cases. */ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_readinode_info *rii) { … } static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *latest_node) { … } /* Scan the list of all nodes present for this ino, build map of versions, etc. */ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t ino, struct jffs2_raw_inode *latest_node) { … } int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) { … } void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) { … }