18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * JFFS2 -- Journalling Flash File System, Version 2. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright © 2001-2007 Red Hat, Inc. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Created by David Woodhouse <dwmw2@infradead.org> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * For licensing information, see the file 'LICENCE' in this directory. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/sched.h> 168c2ecf20Sopenharmony_ci#include <linux/fs.h> 178c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h> 188c2ecf20Sopenharmony_ci#include <linux/rbtree.h> 198c2ecf20Sopenharmony_ci#include <linux/crc32.h> 208c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 218c2ecf20Sopenharmony_ci#include "nodelist.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, 248c2ecf20Sopenharmony_ci struct jffs2_node_frag *this); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_civoid jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci struct jffs2_full_dirent **prev = list; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci dbg_dentlist("add dirent \"%s\", ino #%u\n", new->name, new->ino); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci while ((*prev) && (*prev)->nhash <= new->nhash) { 338c2ecf20Sopenharmony_ci if ((*prev)->nhash == new->nhash && !strcmp((*prev)->name, new->name)) { 348c2ecf20Sopenharmony_ci /* Duplicate. Free one */ 358c2ecf20Sopenharmony_ci if (new->version < (*prev)->version) { 368c2ecf20Sopenharmony_ci dbg_dentlist("Eep! Marking new dirent node obsolete, old is \"%s\", ino #%u\n", 378c2ecf20Sopenharmony_ci (*prev)->name, (*prev)->ino); 388c2ecf20Sopenharmony_ci jffs2_mark_node_obsolete(c, new->raw); 398c2ecf20Sopenharmony_ci jffs2_free_full_dirent(new); 408c2ecf20Sopenharmony_ci } else { 418c2ecf20Sopenharmony_ci dbg_dentlist("marking old dirent \"%s\", ino #%u obsolete\n", 428c2ecf20Sopenharmony_ci (*prev)->name, (*prev)->ino); 438c2ecf20Sopenharmony_ci new->next = (*prev)->next; 448c2ecf20Sopenharmony_ci /* It may have been a 'placeholder' deletion dirent, 458c2ecf20Sopenharmony_ci if jffs2_can_mark_obsolete() (see jffs2_do_unlink()) */ 468c2ecf20Sopenharmony_ci if ((*prev)->raw) 478c2ecf20Sopenharmony_ci jffs2_mark_node_obsolete(c, ((*prev)->raw)); 488c2ecf20Sopenharmony_ci jffs2_free_full_dirent(*prev); 498c2ecf20Sopenharmony_ci *prev = new; 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci return; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci prev = &((*prev)->next); 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci new->next = *prev; 568c2ecf20Sopenharmony_ci *prev = new; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ciuint32_t jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint32_t size) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci dbg_fragtree("truncating fragtree to 0x%08x bytes\n", size); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* We know frag->ofs <= size. That's what lookup does for us */ 668c2ecf20Sopenharmony_ci if (frag && frag->ofs != size) { 678c2ecf20Sopenharmony_ci if (frag->ofs+frag->size > size) { 688c2ecf20Sopenharmony_ci frag->size = size - frag->ofs; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci frag = frag_next(frag); 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci while (frag && frag->ofs >= size) { 738c2ecf20Sopenharmony_ci struct jffs2_node_frag *next = frag_next(frag); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci frag_erase(frag, list); 768c2ecf20Sopenharmony_ci jffs2_obsolete_node_frag(c, frag); 778c2ecf20Sopenharmony_ci frag = next; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (size == 0) 818c2ecf20Sopenharmony_ci return 0; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci frag = frag_last(list); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* Sanity check for truncation to longer than we started with... */ 868c2ecf20Sopenharmony_ci if (!frag) 878c2ecf20Sopenharmony_ci return 0; 888c2ecf20Sopenharmony_ci if (frag->ofs + frag->size < size) 898c2ecf20Sopenharmony_ci return frag->ofs + frag->size; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* If the last fragment starts at the RAM page boundary, it is 928c2ecf20Sopenharmony_ci * REF_PRISTINE irrespective of its size. */ 938c2ecf20Sopenharmony_ci if (frag->node && (frag->ofs & (PAGE_SIZE - 1)) == 0) { 948c2ecf20Sopenharmony_ci dbg_fragtree2("marking the last fragment 0x%08x-0x%08x REF_PRISTINE.\n", 958c2ecf20Sopenharmony_ci frag->ofs, frag->ofs + frag->size); 968c2ecf20Sopenharmony_ci frag->node->raw->flash_offset = ref_offset(frag->node->raw) | REF_PRISTINE; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci return size; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, 1028c2ecf20Sopenharmony_ci struct jffs2_node_frag *this) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci if (this->node) { 1058c2ecf20Sopenharmony_ci this->node->frags--; 1068c2ecf20Sopenharmony_ci if (!this->node->frags) { 1078c2ecf20Sopenharmony_ci /* The node has no valid frags left. It's totally obsoleted */ 1088c2ecf20Sopenharmony_ci dbg_fragtree2("marking old node @0x%08x (0x%04x-0x%04x) obsolete\n", 1098c2ecf20Sopenharmony_ci ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size); 1108c2ecf20Sopenharmony_ci jffs2_mark_node_obsolete(c, this->node->raw); 1118c2ecf20Sopenharmony_ci jffs2_free_full_dnode(this->node); 1128c2ecf20Sopenharmony_ci } else { 1138c2ecf20Sopenharmony_ci dbg_fragtree2("marking old node @0x%08x (0x%04x-0x%04x) REF_NORMAL. frags is %d\n", 1148c2ecf20Sopenharmony_ci ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size, this->node->frags); 1158c2ecf20Sopenharmony_ci mark_ref_normal(this->node->raw); 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci jffs2_free_node_frag(this); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct rb_node *parent = &base->rb; 1258c2ecf20Sopenharmony_ci struct rb_node **link = &parent; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci dbg_fragtree2("insert frag (0x%04x-0x%04x)\n", newfrag->ofs, newfrag->ofs + newfrag->size); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci while (*link) { 1308c2ecf20Sopenharmony_ci parent = *link; 1318c2ecf20Sopenharmony_ci base = rb_entry(parent, struct jffs2_node_frag, rb); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (newfrag->ofs > base->ofs) 1348c2ecf20Sopenharmony_ci link = &base->rb.rb_right; 1358c2ecf20Sopenharmony_ci else if (newfrag->ofs < base->ofs) 1368c2ecf20Sopenharmony_ci link = &base->rb.rb_left; 1378c2ecf20Sopenharmony_ci else { 1388c2ecf20Sopenharmony_ci JFFS2_ERROR("duplicate frag at %08x (%p,%p)\n", newfrag->ofs, newfrag, base); 1398c2ecf20Sopenharmony_ci BUG(); 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci rb_link_node(&newfrag->rb, &base->rb, link); 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* 1478c2ecf20Sopenharmony_ci * Allocate and initializes a new fragment. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_cistatic struct jffs2_node_frag * new_fragment(struct jffs2_full_dnode *fn, uint32_t ofs, uint32_t size) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci struct jffs2_node_frag *newfrag; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci newfrag = jffs2_alloc_node_frag(); 1548c2ecf20Sopenharmony_ci if (likely(newfrag)) { 1558c2ecf20Sopenharmony_ci newfrag->ofs = ofs; 1568c2ecf20Sopenharmony_ci newfrag->size = size; 1578c2ecf20Sopenharmony_ci newfrag->node = fn; 1588c2ecf20Sopenharmony_ci } else { 1598c2ecf20Sopenharmony_ci JFFS2_ERROR("cannot allocate a jffs2_node_frag object\n"); 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return newfrag; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* 1668c2ecf20Sopenharmony_ci * Called when there is no overlapping fragment exist. Inserts a hole before the new 1678c2ecf20Sopenharmony_ci * fragment and inserts the new fragment to the fragtree. 1688c2ecf20Sopenharmony_ci */ 1698c2ecf20Sopenharmony_cistatic int no_overlapping_node(struct jffs2_sb_info *c, struct rb_root *root, 1708c2ecf20Sopenharmony_ci struct jffs2_node_frag *newfrag, 1718c2ecf20Sopenharmony_ci struct jffs2_node_frag *this, uint32_t lastend) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci if (lastend < newfrag->node->ofs) { 1748c2ecf20Sopenharmony_ci /* put a hole in before the new fragment */ 1758c2ecf20Sopenharmony_ci struct jffs2_node_frag *holefrag; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci holefrag= new_fragment(NULL, lastend, newfrag->node->ofs - lastend); 1788c2ecf20Sopenharmony_ci if (unlikely(!holefrag)) { 1798c2ecf20Sopenharmony_ci jffs2_free_node_frag(newfrag); 1808c2ecf20Sopenharmony_ci return -ENOMEM; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (this) { 1848c2ecf20Sopenharmony_ci /* By definition, the 'this' node has no right-hand child, 1858c2ecf20Sopenharmony_ci because there are no frags with offset greater than it. 1868c2ecf20Sopenharmony_ci So that's where we want to put the hole */ 1878c2ecf20Sopenharmony_ci dbg_fragtree2("add hole frag %#04x-%#04x on the right of the new frag.\n", 1888c2ecf20Sopenharmony_ci holefrag->ofs, holefrag->ofs + holefrag->size); 1898c2ecf20Sopenharmony_ci rb_link_node(&holefrag->rb, &this->rb, &this->rb.rb_right); 1908c2ecf20Sopenharmony_ci } else { 1918c2ecf20Sopenharmony_ci dbg_fragtree2("Add hole frag %#04x-%#04x to the root of the tree.\n", 1928c2ecf20Sopenharmony_ci holefrag->ofs, holefrag->ofs + holefrag->size); 1938c2ecf20Sopenharmony_ci rb_link_node(&holefrag->rb, NULL, &root->rb_node); 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci rb_insert_color(&holefrag->rb, root); 1968c2ecf20Sopenharmony_ci this = holefrag; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (this) { 2008c2ecf20Sopenharmony_ci /* By definition, the 'this' node has no right-hand child, 2018c2ecf20Sopenharmony_ci because there are no frags with offset greater than it. 2028c2ecf20Sopenharmony_ci So that's where we want to put new fragment */ 2038c2ecf20Sopenharmony_ci dbg_fragtree2("add the new node at the right\n"); 2048c2ecf20Sopenharmony_ci rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right); 2058c2ecf20Sopenharmony_ci } else { 2068c2ecf20Sopenharmony_ci dbg_fragtree2("insert the new node at the root of the tree\n"); 2078c2ecf20Sopenharmony_ci rb_link_node(&newfrag->rb, NULL, &root->rb_node); 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci rb_insert_color(&newfrag->rb, root); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci return 0; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/* Doesn't set inode->i_size */ 2158c2ecf20Sopenharmony_cistatic int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *root, struct jffs2_node_frag *newfrag) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci struct jffs2_node_frag *this; 2188c2ecf20Sopenharmony_ci uint32_t lastend; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* Skip all the nodes which are completed before this one starts */ 2218c2ecf20Sopenharmony_ci this = jffs2_lookup_node_frag(root, newfrag->node->ofs); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (this) { 2248c2ecf20Sopenharmony_ci dbg_fragtree2("lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", 2258c2ecf20Sopenharmony_ci this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this); 2268c2ecf20Sopenharmony_ci lastend = this->ofs + this->size; 2278c2ecf20Sopenharmony_ci } else { 2288c2ecf20Sopenharmony_ci dbg_fragtree2("lookup gave no frag\n"); 2298c2ecf20Sopenharmony_ci lastend = 0; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* See if we ran off the end of the fragtree */ 2338c2ecf20Sopenharmony_ci if (lastend <= newfrag->ofs) { 2348c2ecf20Sopenharmony_ci /* We did */ 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* Check if 'this' node was on the same page as the new node. 2378c2ecf20Sopenharmony_ci If so, both 'this' and the new node get marked REF_NORMAL so 2388c2ecf20Sopenharmony_ci the GC can take a look. 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_ci if (lastend && (lastend-1) >> PAGE_SHIFT == newfrag->ofs >> PAGE_SHIFT) { 2418c2ecf20Sopenharmony_ci if (this->node) 2428c2ecf20Sopenharmony_ci mark_ref_normal(this->node->raw); 2438c2ecf20Sopenharmony_ci mark_ref_normal(newfrag->node->raw); 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return no_overlapping_node(c, root, newfrag, this, lastend); 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (this->node) 2508c2ecf20Sopenharmony_ci dbg_fragtree2("dealing with frag %u-%u, phys %#08x(%d).\n", 2518c2ecf20Sopenharmony_ci this->ofs, this->ofs + this->size, 2528c2ecf20Sopenharmony_ci ref_offset(this->node->raw), ref_flags(this->node->raw)); 2538c2ecf20Sopenharmony_ci else 2548c2ecf20Sopenharmony_ci dbg_fragtree2("dealing with hole frag %u-%u.\n", 2558c2ecf20Sopenharmony_ci this->ofs, this->ofs + this->size); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* OK. 'this' is pointing at the first frag that newfrag->ofs at least partially obsoletes, 2588c2ecf20Sopenharmony_ci * - i.e. newfrag->ofs < this->ofs+this->size && newfrag->ofs >= this->ofs 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_ci if (newfrag->ofs > this->ofs) { 2618c2ecf20Sopenharmony_ci /* This node isn't completely obsoleted. The start of it remains valid */ 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* Mark the new node and the partially covered node REF_NORMAL -- let 2648c2ecf20Sopenharmony_ci the GC take a look at them */ 2658c2ecf20Sopenharmony_ci mark_ref_normal(newfrag->node->raw); 2668c2ecf20Sopenharmony_ci if (this->node) 2678c2ecf20Sopenharmony_ci mark_ref_normal(this->node->raw); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (this->ofs + this->size > newfrag->ofs + newfrag->size) { 2708c2ecf20Sopenharmony_ci /* The new node splits 'this' frag into two */ 2718c2ecf20Sopenharmony_ci struct jffs2_node_frag *newfrag2; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (this->node) 2748c2ecf20Sopenharmony_ci dbg_fragtree2("split old frag 0x%04x-0x%04x, phys 0x%08x\n", 2758c2ecf20Sopenharmony_ci this->ofs, this->ofs+this->size, ref_offset(this->node->raw)); 2768c2ecf20Sopenharmony_ci else 2778c2ecf20Sopenharmony_ci dbg_fragtree2("split old hole frag 0x%04x-0x%04x\n", 2788c2ecf20Sopenharmony_ci this->ofs, this->ofs+this->size); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* New second frag pointing to this's node */ 2818c2ecf20Sopenharmony_ci newfrag2 = new_fragment(this->node, newfrag->ofs + newfrag->size, 2828c2ecf20Sopenharmony_ci this->ofs + this->size - newfrag->ofs - newfrag->size); 2838c2ecf20Sopenharmony_ci if (unlikely(!newfrag2)) 2848c2ecf20Sopenharmony_ci return -ENOMEM; 2858c2ecf20Sopenharmony_ci if (this->node) 2868c2ecf20Sopenharmony_ci this->node->frags++; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* Adjust size of original 'this' */ 2898c2ecf20Sopenharmony_ci this->size = newfrag->ofs - this->ofs; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* Now, we know there's no node with offset 2928c2ecf20Sopenharmony_ci greater than this->ofs but smaller than 2938c2ecf20Sopenharmony_ci newfrag2->ofs or newfrag->ofs, for obvious 2948c2ecf20Sopenharmony_ci reasons. So we can do a tree insert from 2958c2ecf20Sopenharmony_ci 'this' to insert newfrag, and a tree insert 2968c2ecf20Sopenharmony_ci from newfrag to insert newfrag2. */ 2978c2ecf20Sopenharmony_ci jffs2_fragtree_insert(newfrag, this); 2988c2ecf20Sopenharmony_ci rb_insert_color(&newfrag->rb, root); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci jffs2_fragtree_insert(newfrag2, newfrag); 3018c2ecf20Sopenharmony_ci rb_insert_color(&newfrag2->rb, root); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci return 0; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci /* New node just reduces 'this' frag in size, doesn't split it */ 3068c2ecf20Sopenharmony_ci this->size = newfrag->ofs - this->ofs; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* Again, we know it lives down here in the tree */ 3098c2ecf20Sopenharmony_ci jffs2_fragtree_insert(newfrag, this); 3108c2ecf20Sopenharmony_ci rb_insert_color(&newfrag->rb, root); 3118c2ecf20Sopenharmony_ci } else { 3128c2ecf20Sopenharmony_ci /* New frag starts at the same point as 'this' used to. Replace 3138c2ecf20Sopenharmony_ci it in the tree without doing a delete and insertion */ 3148c2ecf20Sopenharmony_ci dbg_fragtree2("inserting newfrag (*%p),%d-%d in before 'this' (*%p),%d-%d\n", 3158c2ecf20Sopenharmony_ci newfrag, newfrag->ofs, newfrag->ofs+newfrag->size, this, this->ofs, this->ofs+this->size); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci rb_replace_node(&this->rb, &newfrag->rb, root); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (newfrag->ofs + newfrag->size >= this->ofs+this->size) { 3208c2ecf20Sopenharmony_ci dbg_fragtree2("obsoleting node frag %p (%x-%x)\n", this, this->ofs, this->ofs+this->size); 3218c2ecf20Sopenharmony_ci jffs2_obsolete_node_frag(c, this); 3228c2ecf20Sopenharmony_ci } else { 3238c2ecf20Sopenharmony_ci this->ofs += newfrag->size; 3248c2ecf20Sopenharmony_ci this->size -= newfrag->size; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci jffs2_fragtree_insert(this, newfrag); 3278c2ecf20Sopenharmony_ci rb_insert_color(&this->rb, root); 3288c2ecf20Sopenharmony_ci return 0; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci /* OK, now we have newfrag added in the correct place in the tree, but 3328c2ecf20Sopenharmony_ci frag_next(newfrag) may be a fragment which is overlapped by it 3338c2ecf20Sopenharmony_ci */ 3348c2ecf20Sopenharmony_ci while ((this = frag_next(newfrag)) && newfrag->ofs + newfrag->size >= this->ofs + this->size) { 3358c2ecf20Sopenharmony_ci /* 'this' frag is obsoleted completely. */ 3368c2ecf20Sopenharmony_ci dbg_fragtree2("obsoleting node frag %p (%x-%x) and removing from tree\n", 3378c2ecf20Sopenharmony_ci this, this->ofs, this->ofs+this->size); 3388c2ecf20Sopenharmony_ci rb_erase(&this->rb, root); 3398c2ecf20Sopenharmony_ci jffs2_obsolete_node_frag(c, this); 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci /* Now we're pointing at the first frag which isn't totally obsoleted by 3428c2ecf20Sopenharmony_ci the new frag */ 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (!this || newfrag->ofs + newfrag->size == this->ofs) 3458c2ecf20Sopenharmony_ci return 0; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* Still some overlap but we don't need to move it in the tree */ 3488c2ecf20Sopenharmony_ci this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size); 3498c2ecf20Sopenharmony_ci this->ofs = newfrag->ofs + newfrag->size; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* And mark them REF_NORMAL so the GC takes a look at them */ 3528c2ecf20Sopenharmony_ci if (this->node) 3538c2ecf20Sopenharmony_ci mark_ref_normal(this->node->raw); 3548c2ecf20Sopenharmony_ci mark_ref_normal(newfrag->node->raw); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci return 0; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci/* 3608c2ecf20Sopenharmony_ci * Given an inode, probably with existing tree of fragments, add the new node 3618c2ecf20Sopenharmony_ci * to the fragment tree. 3628c2ecf20Sopenharmony_ci */ 3638c2ecf20Sopenharmony_ciint jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci int ret; 3668c2ecf20Sopenharmony_ci struct jffs2_node_frag *newfrag; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (unlikely(!fn->size)) 3698c2ecf20Sopenharmony_ci return 0; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci newfrag = new_fragment(fn, fn->ofs, fn->size); 3728c2ecf20Sopenharmony_ci if (unlikely(!newfrag)) 3738c2ecf20Sopenharmony_ci return -ENOMEM; 3748c2ecf20Sopenharmony_ci newfrag->node->frags = 1; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci dbg_fragtree("adding node %#04x-%#04x @0x%08x on flash, newfrag *%p\n", 3778c2ecf20Sopenharmony_ci fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci ret = jffs2_add_frag_to_fragtree(c, &f->fragtree, newfrag); 3808c2ecf20Sopenharmony_ci if (unlikely(ret)) 3818c2ecf20Sopenharmony_ci return ret; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* If we now share a page with other nodes, mark either previous 3848c2ecf20Sopenharmony_ci or next node REF_NORMAL, as appropriate. */ 3858c2ecf20Sopenharmony_ci if (newfrag->ofs & (PAGE_SIZE-1)) { 3868c2ecf20Sopenharmony_ci struct jffs2_node_frag *prev = frag_prev(newfrag); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci mark_ref_normal(fn->raw); 3898c2ecf20Sopenharmony_ci /* If we don't start at zero there's _always_ a previous */ 3908c2ecf20Sopenharmony_ci if (prev->node) 3918c2ecf20Sopenharmony_ci mark_ref_normal(prev->node->raw); 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if ((newfrag->ofs+newfrag->size) & (PAGE_SIZE-1)) { 3958c2ecf20Sopenharmony_ci struct jffs2_node_frag *next = frag_next(newfrag); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (next) { 3988c2ecf20Sopenharmony_ci mark_ref_normal(fn->raw); 3998c2ecf20Sopenharmony_ci if (next->node) 4008c2ecf20Sopenharmony_ci mark_ref_normal(next->node->raw); 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci jffs2_dbg_fragtree_paranoia_check_nolock(f); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci return 0; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_civoid jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci spin_lock(&c->inocache_lock); 4118c2ecf20Sopenharmony_ci ic->state = state; 4128c2ecf20Sopenharmony_ci wake_up(&c->inocache_wq); 4138c2ecf20Sopenharmony_ci spin_unlock(&c->inocache_lock); 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci/* During mount, this needs no locking. During normal operation, its 4178c2ecf20Sopenharmony_ci callers want to do other stuff while still holding the inocache_lock. 4188c2ecf20Sopenharmony_ci Rather than introducing special case get_ino_cache functions or 4198c2ecf20Sopenharmony_ci callbacks, we just let the caller do the locking itself. */ 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistruct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci struct jffs2_inode_cache *ret; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci ret = c->inocache_list[ino % c->inocache_hashsize]; 4268c2ecf20Sopenharmony_ci while (ret && ret->ino < ino) { 4278c2ecf20Sopenharmony_ci ret = ret->next; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (ret && ret->ino != ino) 4318c2ecf20Sopenharmony_ci ret = NULL; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci return ret; 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_civoid jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct jffs2_inode_cache **prev; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci spin_lock(&c->inocache_lock); 4418c2ecf20Sopenharmony_ci if (!new->ino) 4428c2ecf20Sopenharmony_ci new->ino = ++c->highest_ino; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci dbg_inocache("add %p (ino #%u)\n", new, new->ino); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci prev = &c->inocache_list[new->ino % c->inocache_hashsize]; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci while ((*prev) && (*prev)->ino < new->ino) { 4498c2ecf20Sopenharmony_ci prev = &(*prev)->next; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci new->next = *prev; 4528c2ecf20Sopenharmony_ci *prev = new; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci spin_unlock(&c->inocache_lock); 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_civoid jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci struct jffs2_inode_cache **prev; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_XATTR 4628c2ecf20Sopenharmony_ci BUG_ON(old->xref); 4638c2ecf20Sopenharmony_ci#endif 4648c2ecf20Sopenharmony_ci dbg_inocache("del %p (ino #%u)\n", old, old->ino); 4658c2ecf20Sopenharmony_ci spin_lock(&c->inocache_lock); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci prev = &c->inocache_list[old->ino % c->inocache_hashsize]; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci while ((*prev) && (*prev)->ino < old->ino) { 4708c2ecf20Sopenharmony_ci prev = &(*prev)->next; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci if ((*prev) == old) { 4738c2ecf20Sopenharmony_ci *prev = old->next; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* Free it now unless it's in READING or CLEARING state, which 4778c2ecf20Sopenharmony_ci are the transitions upon read_inode() and clear_inode(). The 4788c2ecf20Sopenharmony_ci rest of the time we know nobody else is looking at it, and 4798c2ecf20Sopenharmony_ci if it's held by read_inode() or clear_inode() they'll free it 4808c2ecf20Sopenharmony_ci for themselves. */ 4818c2ecf20Sopenharmony_ci if (old->state != INO_STATE_READING && old->state != INO_STATE_CLEARING) 4828c2ecf20Sopenharmony_ci jffs2_free_inode_cache(old); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci spin_unlock(&c->inocache_lock); 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_civoid jffs2_free_ino_caches(struct jffs2_sb_info *c) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci int i; 4908c2ecf20Sopenharmony_ci struct jffs2_inode_cache *this, *next; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci for (i=0; i < c->inocache_hashsize; i++) { 4938c2ecf20Sopenharmony_ci this = c->inocache_list[i]; 4948c2ecf20Sopenharmony_ci while (this) { 4958c2ecf20Sopenharmony_ci next = this->next; 4968c2ecf20Sopenharmony_ci jffs2_xattr_free_inode(c, this); 4978c2ecf20Sopenharmony_ci jffs2_free_inode_cache(this); 4988c2ecf20Sopenharmony_ci this = next; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci c->inocache_list[i] = NULL; 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_civoid jffs2_free_raw_node_refs(struct jffs2_sb_info *c) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci int i; 5078c2ecf20Sopenharmony_ci struct jffs2_raw_node_ref *this, *next; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci for (i=0; i<c->nr_blocks; i++) { 5108c2ecf20Sopenharmony_ci this = c->blocks[i].first_node; 5118c2ecf20Sopenharmony_ci while (this) { 5128c2ecf20Sopenharmony_ci if (this[REFS_PER_BLOCK].flash_offset == REF_LINK_NODE) 5138c2ecf20Sopenharmony_ci next = this[REFS_PER_BLOCK].next_in_ino; 5148c2ecf20Sopenharmony_ci else 5158c2ecf20Sopenharmony_ci next = NULL; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci jffs2_free_refblock(this); 5188c2ecf20Sopenharmony_ci this = next; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci c->blocks[i].first_node = c->blocks[i].last_node = NULL; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistruct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci /* The common case in lookup is that there will be a node 5278c2ecf20Sopenharmony_ci which precisely matches. So we go looking for that first */ 5288c2ecf20Sopenharmony_ci struct rb_node *next; 5298c2ecf20Sopenharmony_ci struct jffs2_node_frag *prev = NULL; 5308c2ecf20Sopenharmony_ci struct jffs2_node_frag *frag = NULL; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci dbg_fragtree2("root %p, offset %d\n", fragtree, offset); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci next = fragtree->rb_node; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci while(next) { 5378c2ecf20Sopenharmony_ci frag = rb_entry(next, struct jffs2_node_frag, rb); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (frag->ofs + frag->size <= offset) { 5408c2ecf20Sopenharmony_ci /* Remember the closest smaller match on the way down */ 5418c2ecf20Sopenharmony_ci if (!prev || frag->ofs > prev->ofs) 5428c2ecf20Sopenharmony_ci prev = frag; 5438c2ecf20Sopenharmony_ci next = frag->rb.rb_right; 5448c2ecf20Sopenharmony_ci } else if (frag->ofs > offset) { 5458c2ecf20Sopenharmony_ci next = frag->rb.rb_left; 5468c2ecf20Sopenharmony_ci } else { 5478c2ecf20Sopenharmony_ci return frag; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci /* Exact match not found. Go back up looking at each parent, 5528c2ecf20Sopenharmony_ci and return the closest smaller one */ 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (prev) 5558c2ecf20Sopenharmony_ci dbg_fragtree2("no match. Returning frag %#04x-%#04x, closest previous\n", 5568c2ecf20Sopenharmony_ci prev->ofs, prev->ofs+prev->size); 5578c2ecf20Sopenharmony_ci else 5588c2ecf20Sopenharmony_ci dbg_fragtree2("returning NULL, empty fragtree\n"); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci return prev; 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci/* Pass 'c' argument to indicate that nodes should be marked obsolete as 5648c2ecf20Sopenharmony_ci they're killed. */ 5658c2ecf20Sopenharmony_civoid jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci struct jffs2_node_frag *frag, *next; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci dbg_fragtree("killing\n"); 5708c2ecf20Sopenharmony_ci rbtree_postorder_for_each_entry_safe(frag, next, root, rb) { 5718c2ecf20Sopenharmony_ci if (frag->node && !(--frag->node->frags)) { 5728c2ecf20Sopenharmony_ci /* Not a hole, and it's the final remaining frag 5738c2ecf20Sopenharmony_ci of this node. Free the node */ 5748c2ecf20Sopenharmony_ci if (c) 5758c2ecf20Sopenharmony_ci jffs2_mark_node_obsolete(c, frag->node->raw); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci jffs2_free_full_dnode(frag->node); 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci jffs2_free_node_frag(frag); 5818c2ecf20Sopenharmony_ci cond_resched(); 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci} 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_cistruct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c, 5868c2ecf20Sopenharmony_ci struct jffs2_eraseblock *jeb, 5878c2ecf20Sopenharmony_ci uint32_t ofs, uint32_t len, 5888c2ecf20Sopenharmony_ci struct jffs2_inode_cache *ic) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci struct jffs2_raw_node_ref *ref; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci BUG_ON(!jeb->allocated_refs); 5938c2ecf20Sopenharmony_ci jeb->allocated_refs--; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci ref = jeb->last_node; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci dbg_noderef("Last node at %p is (%08x,%p)\n", ref, ref->flash_offset, 5988c2ecf20Sopenharmony_ci ref->next_in_ino); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci while (ref->flash_offset != REF_EMPTY_NODE) { 6018c2ecf20Sopenharmony_ci if (ref->flash_offset == REF_LINK_NODE) 6028c2ecf20Sopenharmony_ci ref = ref->next_in_ino; 6038c2ecf20Sopenharmony_ci else 6048c2ecf20Sopenharmony_ci ref++; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci dbg_noderef("New ref is %p (%08x becomes %08x,%p) len 0x%x\n", ref, 6088c2ecf20Sopenharmony_ci ref->flash_offset, ofs, ref->next_in_ino, len); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci ref->flash_offset = ofs; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (!jeb->first_node) { 6138c2ecf20Sopenharmony_ci jeb->first_node = ref; 6148c2ecf20Sopenharmony_ci BUG_ON(ref_offset(ref) != jeb->offset); 6158c2ecf20Sopenharmony_ci } else if (unlikely(ref_offset(ref) != jeb->offset + c->sector_size - jeb->free_size)) { 6168c2ecf20Sopenharmony_ci uint32_t last_len = ref_totlen(c, jeb, jeb->last_node); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci JFFS2_ERROR("Adding new ref %p at (0x%08x-0x%08x) not immediately after previous (0x%08x-0x%08x)\n", 6198c2ecf20Sopenharmony_ci ref, ref_offset(ref), ref_offset(ref)+len, 6208c2ecf20Sopenharmony_ci ref_offset(jeb->last_node), 6218c2ecf20Sopenharmony_ci ref_offset(jeb->last_node)+last_len); 6228c2ecf20Sopenharmony_ci BUG(); 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci jeb->last_node = ref; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (ic) { 6278c2ecf20Sopenharmony_ci ref->next_in_ino = ic->nodes; 6288c2ecf20Sopenharmony_ci ic->nodes = ref; 6298c2ecf20Sopenharmony_ci } else { 6308c2ecf20Sopenharmony_ci ref->next_in_ino = NULL; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci switch(ref_flags(ref)) { 6348c2ecf20Sopenharmony_ci case REF_UNCHECKED: 6358c2ecf20Sopenharmony_ci c->unchecked_size += len; 6368c2ecf20Sopenharmony_ci jeb->unchecked_size += len; 6378c2ecf20Sopenharmony_ci break; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci case REF_NORMAL: 6408c2ecf20Sopenharmony_ci case REF_PRISTINE: 6418c2ecf20Sopenharmony_ci c->used_size += len; 6428c2ecf20Sopenharmony_ci jeb->used_size += len; 6438c2ecf20Sopenharmony_ci break; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci case REF_OBSOLETE: 6468c2ecf20Sopenharmony_ci c->dirty_size += len; 6478c2ecf20Sopenharmony_ci jeb->dirty_size += len; 6488c2ecf20Sopenharmony_ci break; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci c->free_size -= len; 6518c2ecf20Sopenharmony_ci jeb->free_size -= len; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci#ifdef TEST_TOTLEN 6548c2ecf20Sopenharmony_ci /* Set (and test) __totlen field... for now */ 6558c2ecf20Sopenharmony_ci ref->__totlen = len; 6568c2ecf20Sopenharmony_ci ref_totlen(c, jeb, ref); 6578c2ecf20Sopenharmony_ci#endif 6588c2ecf20Sopenharmony_ci return ref; 6598c2ecf20Sopenharmony_ci} 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci/* No locking, no reservation of 'ref'. Do not use on a live file system */ 6628c2ecf20Sopenharmony_ciint jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 6638c2ecf20Sopenharmony_ci uint32_t size) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci if (!size) 6668c2ecf20Sopenharmony_ci return 0; 6678c2ecf20Sopenharmony_ci if (unlikely(size > jeb->free_size)) { 6688c2ecf20Sopenharmony_ci pr_crit("Dirty space 0x%x larger then free_size 0x%x (wasted 0x%x)\n", 6698c2ecf20Sopenharmony_ci size, jeb->free_size, jeb->wasted_size); 6708c2ecf20Sopenharmony_ci BUG(); 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci /* REF_EMPTY_NODE is !obsolete, so that works OK */ 6738c2ecf20Sopenharmony_ci if (jeb->last_node && ref_obsolete(jeb->last_node)) { 6748c2ecf20Sopenharmony_ci#ifdef TEST_TOTLEN 6758c2ecf20Sopenharmony_ci jeb->last_node->__totlen += size; 6768c2ecf20Sopenharmony_ci#endif 6778c2ecf20Sopenharmony_ci c->dirty_size += size; 6788c2ecf20Sopenharmony_ci c->free_size -= size; 6798c2ecf20Sopenharmony_ci jeb->dirty_size += size; 6808c2ecf20Sopenharmony_ci jeb->free_size -= size; 6818c2ecf20Sopenharmony_ci } else { 6828c2ecf20Sopenharmony_ci uint32_t ofs = jeb->offset + c->sector_size - jeb->free_size; 6838c2ecf20Sopenharmony_ci ofs |= REF_OBSOLETE; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci jffs2_link_node_ref(c, jeb, ofs, size, NULL); 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci return 0; 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci/* Calculate totlen from surrounding nodes or eraseblock */ 6928c2ecf20Sopenharmony_cistatic inline uint32_t __ref_totlen(struct jffs2_sb_info *c, 6938c2ecf20Sopenharmony_ci struct jffs2_eraseblock *jeb, 6948c2ecf20Sopenharmony_ci struct jffs2_raw_node_ref *ref) 6958c2ecf20Sopenharmony_ci{ 6968c2ecf20Sopenharmony_ci uint32_t ref_end; 6978c2ecf20Sopenharmony_ci struct jffs2_raw_node_ref *next_ref = ref_next(ref); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci if (next_ref) 7008c2ecf20Sopenharmony_ci ref_end = ref_offset(next_ref); 7018c2ecf20Sopenharmony_ci else { 7028c2ecf20Sopenharmony_ci if (!jeb) 7038c2ecf20Sopenharmony_ci jeb = &c->blocks[ref->flash_offset / c->sector_size]; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci /* Last node in block. Use free_space */ 7068c2ecf20Sopenharmony_ci if (unlikely(ref != jeb->last_node)) { 7078c2ecf20Sopenharmony_ci pr_crit("ref %p @0x%08x is not jeb->last_node (%p @0x%08x)\n", 7088c2ecf20Sopenharmony_ci ref, ref_offset(ref), jeb->last_node, 7098c2ecf20Sopenharmony_ci jeb->last_node ? 7108c2ecf20Sopenharmony_ci ref_offset(jeb->last_node) : 0); 7118c2ecf20Sopenharmony_ci BUG(); 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci ref_end = jeb->offset + c->sector_size - jeb->free_size; 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci return ref_end - ref_offset(ref); 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ciuint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 7198c2ecf20Sopenharmony_ci struct jffs2_raw_node_ref *ref) 7208c2ecf20Sopenharmony_ci{ 7218c2ecf20Sopenharmony_ci uint32_t ret; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci ret = __ref_totlen(c, jeb, ref); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci#ifdef TEST_TOTLEN 7268c2ecf20Sopenharmony_ci if (unlikely(ret != ref->__totlen)) { 7278c2ecf20Sopenharmony_ci if (!jeb) 7288c2ecf20Sopenharmony_ci jeb = &c->blocks[ref->flash_offset / c->sector_size]; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci pr_crit("Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x\n", 7318c2ecf20Sopenharmony_ci ref, ref_offset(ref), ref_offset(ref) + ref->__totlen, 7328c2ecf20Sopenharmony_ci ret, ref->__totlen); 7338c2ecf20Sopenharmony_ci if (ref_next(ref)) { 7348c2ecf20Sopenharmony_ci pr_crit("next %p (0x%08x-0x%08x)\n", 7358c2ecf20Sopenharmony_ci ref_next(ref), ref_offset(ref_next(ref)), 7368c2ecf20Sopenharmony_ci ref_offset(ref_next(ref)) + ref->__totlen); 7378c2ecf20Sopenharmony_ci } else 7388c2ecf20Sopenharmony_ci pr_crit("No next ref. jeb->last_node is %p\n", 7398c2ecf20Sopenharmony_ci jeb->last_node); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci pr_crit("jeb->wasted_size %x, dirty_size %x, used_size %x, free_size %x\n", 7428c2ecf20Sopenharmony_ci jeb->wasted_size, jeb->dirty_size, jeb->used_size, 7438c2ecf20Sopenharmony_ci jeb->free_size); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci#if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS) 7468c2ecf20Sopenharmony_ci __jffs2_dbg_dump_node_refs_nolock(c, jeb); 7478c2ecf20Sopenharmony_ci#endif 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci WARN_ON(1); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci ret = ref->__totlen; 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci#endif /* TEST_TOTLEN */ 7548c2ecf20Sopenharmony_ci return ret; 7558c2ecf20Sopenharmony_ci} 756