11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * JFFS2 -- Journalling Flash File System, Version 2. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2001-2003 Red Hat, Inc. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Created by David Woodhouse <dwmw2@infradead.org> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * For licensing information, see the file 'LICENCE' in this directory. 91da177e4SLinus Torvalds * 10336d2ff7SArtem B. Bityuckiy * $Id: readinode.c,v 1.124 2005/07/07 15:45:29 dedekind Exp $ 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds */ 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #include <linux/kernel.h> 151da177e4SLinus Torvalds #include <linux/slab.h> 161da177e4SLinus Torvalds #include <linux/fs.h> 171da177e4SLinus Torvalds #include <linux/crc32.h> 181da177e4SLinus Torvalds #include <linux/pagemap.h> 191da177e4SLinus Torvalds #include <linux/mtd/mtd.h> 201da177e4SLinus Torvalds #include <linux/compiler.h> 211da177e4SLinus Torvalds #include "nodelist.h" 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag); 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #if CONFIG_JFFS2_FS_DEBUG >= 2 261da177e4SLinus Torvalds static void jffs2_print_fragtree(struct rb_root *list, int permitbug) 271da177e4SLinus Torvalds { 281da177e4SLinus Torvalds struct jffs2_node_frag *this = frag_first(list); 291da177e4SLinus Torvalds uint32_t lastofs = 0; 301da177e4SLinus Torvalds int buggy = 0; 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds while(this) { 331da177e4SLinus Torvalds if (this->node) 341da177e4SLinus Torvalds printk(KERN_DEBUG "frag %04x-%04x: 0x%08x(%d) on flash (*%p). left (%p), right (%p), parent (%p)\n", 351da177e4SLinus Torvalds this->ofs, this->ofs+this->size, ref_offset(this->node->raw), ref_flags(this->node->raw), 361da177e4SLinus Torvalds this, frag_left(this), frag_right(this), frag_parent(this)); 371da177e4SLinus Torvalds else 381da177e4SLinus Torvalds printk(KERN_DEBUG "frag %04x-%04x: hole (*%p). left (%p} right (%p), parent (%p)\n", this->ofs, 391da177e4SLinus Torvalds this->ofs+this->size, this, frag_left(this), frag_right(this), frag_parent(this)); 401da177e4SLinus Torvalds if (this->ofs != lastofs) 411da177e4SLinus Torvalds buggy = 1; 421da177e4SLinus Torvalds lastofs = this->ofs+this->size; 431da177e4SLinus Torvalds this = frag_next(this); 441da177e4SLinus Torvalds } 451da177e4SLinus Torvalds if (buggy && !permitbug) { 461da177e4SLinus Torvalds printk(KERN_CRIT "Frag tree got a hole in it\n"); 471da177e4SLinus Torvalds BUG(); 481da177e4SLinus Torvalds } 491da177e4SLinus Torvalds } 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds void jffs2_print_frag_list(struct jffs2_inode_info *f) 521da177e4SLinus Torvalds { 531da177e4SLinus Torvalds jffs2_print_fragtree(&f->fragtree, 0); 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds if (f->metadata) { 561da177e4SLinus Torvalds printk(KERN_DEBUG "metadata at 0x%08x\n", ref_offset(f->metadata->raw)); 571da177e4SLinus Torvalds } 581da177e4SLinus Torvalds } 591da177e4SLinus Torvalds #endif 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds #if CONFIG_JFFS2_FS_DEBUG >= 1 621da177e4SLinus Torvalds static int jffs2_sanitycheck_fragtree(struct jffs2_inode_info *f) 631da177e4SLinus Torvalds { 641da177e4SLinus Torvalds struct jffs2_node_frag *frag; 651da177e4SLinus Torvalds int bitched = 0; 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) { 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds struct jffs2_full_dnode *fn = frag->node; 701da177e4SLinus Torvalds if (!fn || !fn->raw) 711da177e4SLinus Torvalds continue; 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds if (ref_flags(fn->raw) == REF_PRISTINE) { 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds if (fn->frags > 1) { 761da177e4SLinus Torvalds printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2\n", ref_offset(fn->raw), fn->frags); 771da177e4SLinus Torvalds bitched = 1; 781da177e4SLinus Torvalds } 791da177e4SLinus Torvalds /* A hole node which isn't multi-page should be garbage-collected 801da177e4SLinus Torvalds and merged anyway, so we just check for the frag size here, 811da177e4SLinus Torvalds rather than mucking around with actually reading the node 821da177e4SLinus Torvalds and checking the compression type, which is the real way 831da177e4SLinus Torvalds to tell a hole node. */ 841da177e4SLinus Torvalds if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) { 851da177e4SLinus Torvalds printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2\n", 861da177e4SLinus Torvalds ref_offset(fn->raw)); 871da177e4SLinus Torvalds bitched = 1; 881da177e4SLinus Torvalds } 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) { 911da177e4SLinus Torvalds printk(KERN_WARNING "REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2\n", 921da177e4SLinus Torvalds ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size); 931da177e4SLinus Torvalds bitched = 1; 941da177e4SLinus Torvalds } 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds if (bitched) { 991da177e4SLinus Torvalds struct jffs2_node_frag *thisfrag; 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds printk(KERN_WARNING "Inode is #%u\n", f->inocache->ino); 1021da177e4SLinus Torvalds thisfrag = frag_first(&f->fragtree); 1031da177e4SLinus Torvalds while (thisfrag) { 1041da177e4SLinus Torvalds if (!thisfrag->node) { 1051da177e4SLinus Torvalds printk("Frag @0x%x-0x%x; node-less hole\n", 1061da177e4SLinus Torvalds thisfrag->ofs, thisfrag->size + thisfrag->ofs); 1071da177e4SLinus Torvalds } else if (!thisfrag->node->raw) { 1081da177e4SLinus Torvalds printk("Frag @0x%x-0x%x; raw-less hole\n", 1091da177e4SLinus Torvalds thisfrag->ofs, thisfrag->size + thisfrag->ofs); 1101da177e4SLinus Torvalds } else { 1111da177e4SLinus Torvalds printk("Frag @0x%x-0x%x; raw at 0x%08x(%d) (0x%x-0x%x)\n", 1121da177e4SLinus Torvalds thisfrag->ofs, thisfrag->size + thisfrag->ofs, 1131da177e4SLinus Torvalds ref_offset(thisfrag->node->raw), ref_flags(thisfrag->node->raw), 1141da177e4SLinus Torvalds thisfrag->node->ofs, thisfrag->node->ofs+thisfrag->node->size); 1151da177e4SLinus Torvalds } 1161da177e4SLinus Torvalds thisfrag = frag_next(thisfrag); 1171da177e4SLinus Torvalds } 1181da177e4SLinus Torvalds } 1191da177e4SLinus Torvalds return bitched; 1201da177e4SLinus Torvalds } 1211da177e4SLinus Torvalds #endif /* D1 */ 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this) 1241da177e4SLinus Torvalds { 1251da177e4SLinus Torvalds if (this->node) { 1261da177e4SLinus Torvalds this->node->frags--; 1271da177e4SLinus Torvalds if (!this->node->frags) { 1281da177e4SLinus Torvalds /* The node has no valid frags left. It's totally obsoleted */ 1291da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) obsolete\n", 1301da177e4SLinus Torvalds ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size)); 1311da177e4SLinus Torvalds jffs2_mark_node_obsolete(c, this->node->raw); 1321da177e4SLinus Torvalds jffs2_free_full_dnode(this->node); 1331da177e4SLinus Torvalds } else { 1341da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) REF_NORMAL. frags is %d\n", 1351da177e4SLinus Torvalds ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size, 1361da177e4SLinus Torvalds this->node->frags)); 1371da177e4SLinus Torvalds mark_ref_normal(this->node->raw); 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds } 1411da177e4SLinus Torvalds jffs2_free_node_frag(this); 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds /* Given an inode, probably with existing list of fragments, add the new node 1451da177e4SLinus Torvalds * to the fragment list. 1461da177e4SLinus Torvalds */ 1471da177e4SLinus Torvalds int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) 1481da177e4SLinus Torvalds { 1491da177e4SLinus Torvalds int ret; 1501da177e4SLinus Torvalds struct jffs2_node_frag *newfrag; 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn)); 1531da177e4SLinus Torvalds 154336d2ff7SArtem B. Bityuckiy if (unlikely(!fn->size)) 155336d2ff7SArtem B. Bityuckiy return 0; 156336d2ff7SArtem B. Bityuckiy 1571da177e4SLinus Torvalds newfrag = jffs2_alloc_node_frag(); 1581da177e4SLinus Torvalds if (unlikely(!newfrag)) 1591da177e4SLinus Torvalds return -ENOMEM; 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds D2(printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n", 1621da177e4SLinus Torvalds fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag)); 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds newfrag->ofs = fn->ofs; 1651da177e4SLinus Torvalds newfrag->size = fn->size; 1661da177e4SLinus Torvalds newfrag->node = fn; 1671da177e4SLinus Torvalds newfrag->node->frags = 1; 1681da177e4SLinus Torvalds 1691da177e4SLinus Torvalds ret = jffs2_add_frag_to_fragtree(c, &f->fragtree, newfrag); 1701da177e4SLinus Torvalds if (ret) 1711da177e4SLinus Torvalds return ret; 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds /* If we now share a page with other nodes, mark either previous 1741da177e4SLinus Torvalds or next node REF_NORMAL, as appropriate. */ 1751da177e4SLinus Torvalds if (newfrag->ofs & (PAGE_CACHE_SIZE-1)) { 1761da177e4SLinus Torvalds struct jffs2_node_frag *prev = frag_prev(newfrag); 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds mark_ref_normal(fn->raw); 1791da177e4SLinus Torvalds /* If we don't start at zero there's _always_ a previous */ 1801da177e4SLinus Torvalds if (prev->node) 1811da177e4SLinus Torvalds mark_ref_normal(prev->node->raw); 1821da177e4SLinus Torvalds } 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds if ((newfrag->ofs+newfrag->size) & (PAGE_CACHE_SIZE-1)) { 1851da177e4SLinus Torvalds struct jffs2_node_frag *next = frag_next(newfrag); 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds if (next) { 1881da177e4SLinus Torvalds mark_ref_normal(fn->raw); 1891da177e4SLinus Torvalds if (next->node) 1901da177e4SLinus Torvalds mark_ref_normal(next->node->raw); 1911da177e4SLinus Torvalds } 1921da177e4SLinus Torvalds } 1931da177e4SLinus Torvalds D2(if (jffs2_sanitycheck_fragtree(f)) { 1941da177e4SLinus Torvalds printk(KERN_WARNING "Just added node %04x-%04x @0x%08x on flash, newfrag *%p\n", 1951da177e4SLinus Torvalds fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag); 1961da177e4SLinus Torvalds return 0; 1971da177e4SLinus Torvalds }) 1981da177e4SLinus Torvalds D2(jffs2_print_frag_list(f)); 1991da177e4SLinus Torvalds return 0; 2001da177e4SLinus Torvalds } 2011da177e4SLinus Torvalds 2021da177e4SLinus Torvalds /* Doesn't set inode->i_size */ 2031da177e4SLinus Torvalds static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag) 2041da177e4SLinus Torvalds { 2051da177e4SLinus Torvalds struct jffs2_node_frag *this; 2061da177e4SLinus Torvalds uint32_t lastend; 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds /* Skip all the nodes which are completed before this one starts */ 2091da177e4SLinus Torvalds this = jffs2_lookup_node_frag(list, newfrag->node->ofs); 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds if (this) { 2121da177e4SLinus Torvalds D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", 2131da177e4SLinus Torvalds this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this)); 2141da177e4SLinus Torvalds lastend = this->ofs + this->size; 2151da177e4SLinus Torvalds } else { 2161da177e4SLinus Torvalds D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave no frag\n")); 2171da177e4SLinus Torvalds lastend = 0; 2181da177e4SLinus Torvalds } 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds /* See if we ran off the end of the list */ 2211da177e4SLinus Torvalds if (lastend <= newfrag->ofs) { 2221da177e4SLinus Torvalds /* We did */ 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds /* Check if 'this' node was on the same page as the new node. 2251da177e4SLinus Torvalds If so, both 'this' and the new node get marked REF_NORMAL so 2261da177e4SLinus Torvalds the GC can take a look. 2271da177e4SLinus Torvalds */ 2281da177e4SLinus Torvalds if (lastend && (lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) { 2291da177e4SLinus Torvalds if (this->node) 2301da177e4SLinus Torvalds mark_ref_normal(this->node->raw); 2311da177e4SLinus Torvalds mark_ref_normal(newfrag->node->raw); 2321da177e4SLinus Torvalds } 2331da177e4SLinus Torvalds 2341da177e4SLinus Torvalds if (lastend < newfrag->node->ofs) { 2351da177e4SLinus Torvalds /* ... and we need to put a hole in before the new node */ 2361da177e4SLinus Torvalds struct jffs2_node_frag *holefrag = jffs2_alloc_node_frag(); 2371da177e4SLinus Torvalds if (!holefrag) { 2381da177e4SLinus Torvalds jffs2_free_node_frag(newfrag); 2391da177e4SLinus Torvalds return -ENOMEM; 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds holefrag->ofs = lastend; 2421da177e4SLinus Torvalds holefrag->size = newfrag->node->ofs - lastend; 2431da177e4SLinus Torvalds holefrag->node = NULL; 2441da177e4SLinus Torvalds if (this) { 2451da177e4SLinus Torvalds /* By definition, the 'this' node has no right-hand child, 2461da177e4SLinus Torvalds because there are no frags with offset greater than it. 2471da177e4SLinus Torvalds So that's where we want to put the hole */ 2481da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Adding hole frag (%p) on right of node at (%p)\n", holefrag, this)); 2491da177e4SLinus Torvalds rb_link_node(&holefrag->rb, &this->rb, &this->rb.rb_right); 2501da177e4SLinus Torvalds } else { 2511da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Adding hole frag (%p) at root of tree\n", holefrag)); 2521da177e4SLinus Torvalds rb_link_node(&holefrag->rb, NULL, &list->rb_node); 2531da177e4SLinus Torvalds } 2541da177e4SLinus Torvalds rb_insert_color(&holefrag->rb, list); 2551da177e4SLinus Torvalds this = holefrag; 2561da177e4SLinus Torvalds } 2571da177e4SLinus Torvalds if (this) { 2581da177e4SLinus Torvalds /* By definition, the 'this' node has no right-hand child, 2591da177e4SLinus Torvalds because there are no frags with offset greater than it. 2601da177e4SLinus Torvalds So that's where we want to put the hole */ 2611da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Adding new frag (%p) on right of node at (%p)\n", newfrag, this)); 2621da177e4SLinus Torvalds rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right); 2631da177e4SLinus Torvalds } else { 2641da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Adding new frag (%p) at root of tree\n", newfrag)); 2651da177e4SLinus Torvalds rb_link_node(&newfrag->rb, NULL, &list->rb_node); 2661da177e4SLinus Torvalds } 2671da177e4SLinus Torvalds rb_insert_color(&newfrag->rb, list); 2681da177e4SLinus Torvalds return 0; 2691da177e4SLinus Torvalds } 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds D2(printk(KERN_DEBUG "j_a_f_d_t_f: dealing with frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", 2721da177e4SLinus Torvalds this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this)); 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds /* OK. 'this' is pointing at the first frag that newfrag->ofs at least partially obsoletes, 2751da177e4SLinus Torvalds * - i.e. newfrag->ofs < this->ofs+this->size && newfrag->ofs >= this->ofs 2761da177e4SLinus Torvalds */ 2771da177e4SLinus Torvalds if (newfrag->ofs > this->ofs) { 2781da177e4SLinus Torvalds /* This node isn't completely obsoleted. The start of it remains valid */ 2791da177e4SLinus Torvalds 2801da177e4SLinus Torvalds /* Mark the new node and the partially covered node REF_NORMAL -- let 2811da177e4SLinus Torvalds the GC take a look at them */ 2821da177e4SLinus Torvalds mark_ref_normal(newfrag->node->raw); 2831da177e4SLinus Torvalds if (this->node) 2841da177e4SLinus Torvalds mark_ref_normal(this->node->raw); 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds if (this->ofs + this->size > newfrag->ofs + newfrag->size) { 2871da177e4SLinus Torvalds /* The new node splits 'this' frag into two */ 2881da177e4SLinus Torvalds struct jffs2_node_frag *newfrag2 = jffs2_alloc_node_frag(); 2891da177e4SLinus Torvalds if (!newfrag2) { 2901da177e4SLinus Torvalds jffs2_free_node_frag(newfrag); 2911da177e4SLinus Torvalds return -ENOMEM; 2921da177e4SLinus Torvalds } 2931da177e4SLinus Torvalds D2(printk(KERN_DEBUG "split old frag 0x%04x-0x%04x -->", this->ofs, this->ofs+this->size); 2941da177e4SLinus Torvalds if (this->node) 2951da177e4SLinus Torvalds printk("phys 0x%08x\n", ref_offset(this->node->raw)); 2961da177e4SLinus Torvalds else 2971da177e4SLinus Torvalds printk("hole\n"); 2981da177e4SLinus Torvalds ) 2991da177e4SLinus Torvalds 3001da177e4SLinus Torvalds /* New second frag pointing to this's node */ 3011da177e4SLinus Torvalds newfrag2->ofs = newfrag->ofs + newfrag->size; 3021da177e4SLinus Torvalds newfrag2->size = (this->ofs+this->size) - newfrag2->ofs; 3031da177e4SLinus Torvalds newfrag2->node = this->node; 3041da177e4SLinus Torvalds if (this->node) 3051da177e4SLinus Torvalds this->node->frags++; 3061da177e4SLinus Torvalds 3071da177e4SLinus Torvalds /* Adjust size of original 'this' */ 3081da177e4SLinus Torvalds this->size = newfrag->ofs - this->ofs; 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds /* Now, we know there's no node with offset 3111da177e4SLinus Torvalds greater than this->ofs but smaller than 3121da177e4SLinus Torvalds newfrag2->ofs or newfrag->ofs, for obvious 3131da177e4SLinus Torvalds reasons. So we can do a tree insert from 3141da177e4SLinus Torvalds 'this' to insert newfrag, and a tree insert 3151da177e4SLinus Torvalds from newfrag to insert newfrag2. */ 3161da177e4SLinus Torvalds jffs2_fragtree_insert(newfrag, this); 3171da177e4SLinus Torvalds rb_insert_color(&newfrag->rb, list); 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds jffs2_fragtree_insert(newfrag2, newfrag); 3201da177e4SLinus Torvalds rb_insert_color(&newfrag2->rb, list); 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds return 0; 3231da177e4SLinus Torvalds } 3241da177e4SLinus Torvalds /* New node just reduces 'this' frag in size, doesn't split it */ 3251da177e4SLinus Torvalds this->size = newfrag->ofs - this->ofs; 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds /* Again, we know it lives down here in the tree */ 3281da177e4SLinus Torvalds jffs2_fragtree_insert(newfrag, this); 3291da177e4SLinus Torvalds rb_insert_color(&newfrag->rb, list); 3301da177e4SLinus Torvalds } else { 3311da177e4SLinus Torvalds /* New frag starts at the same point as 'this' used to. Replace 3321da177e4SLinus Torvalds it in the tree without doing a delete and insertion */ 3331da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Inserting newfrag (*%p),%d-%d in before 'this' (*%p),%d-%d\n", 3341da177e4SLinus Torvalds newfrag, newfrag->ofs, newfrag->ofs+newfrag->size, 3351da177e4SLinus Torvalds this, this->ofs, this->ofs+this->size)); 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds rb_replace_node(&this->rb, &newfrag->rb, list); 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds if (newfrag->ofs + newfrag->size >= this->ofs+this->size) { 3401da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Obsoleting node frag %p (%x-%x)\n", this, this->ofs, this->ofs+this->size)); 3411da177e4SLinus Torvalds jffs2_obsolete_node_frag(c, this); 3421da177e4SLinus Torvalds } else { 3431da177e4SLinus Torvalds this->ofs += newfrag->size; 3441da177e4SLinus Torvalds this->size -= newfrag->size; 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds jffs2_fragtree_insert(this, newfrag); 3471da177e4SLinus Torvalds rb_insert_color(&this->rb, list); 3481da177e4SLinus Torvalds return 0; 3491da177e4SLinus Torvalds } 3501da177e4SLinus Torvalds } 3511da177e4SLinus Torvalds /* OK, now we have newfrag added in the correct place in the tree, but 3521da177e4SLinus Torvalds frag_next(newfrag) may be a fragment which is overlapped by it 3531da177e4SLinus Torvalds */ 3541da177e4SLinus Torvalds while ((this = frag_next(newfrag)) && newfrag->ofs + newfrag->size >= this->ofs + this->size) { 3551da177e4SLinus Torvalds /* 'this' frag is obsoleted completely. */ 3561da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Obsoleting node frag %p (%x-%x) and removing from tree\n", this, this->ofs, this->ofs+this->size)); 3571da177e4SLinus Torvalds rb_erase(&this->rb, list); 3581da177e4SLinus Torvalds jffs2_obsolete_node_frag(c, this); 3591da177e4SLinus Torvalds } 3601da177e4SLinus Torvalds /* Now we're pointing at the first frag which isn't totally obsoleted by 3611da177e4SLinus Torvalds the new frag */ 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds if (!this || newfrag->ofs + newfrag->size == this->ofs) { 3641da177e4SLinus Torvalds return 0; 3651da177e4SLinus Torvalds } 3661da177e4SLinus Torvalds /* Still some overlap but we don't need to move it in the tree */ 3671da177e4SLinus Torvalds this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size); 3681da177e4SLinus Torvalds this->ofs = newfrag->ofs + newfrag->size; 3691da177e4SLinus Torvalds 3701da177e4SLinus Torvalds /* And mark them REF_NORMAL so the GC takes a look at them */ 3711da177e4SLinus Torvalds if (this->node) 3721da177e4SLinus Torvalds mark_ref_normal(this->node->raw); 3731da177e4SLinus Torvalds mark_ref_normal(newfrag->node->raw); 3741da177e4SLinus Torvalds 3751da177e4SLinus Torvalds return 0; 3761da177e4SLinus Torvalds } 3771da177e4SLinus Torvalds 3781da177e4SLinus Torvalds void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size) 3791da177e4SLinus Torvalds { 3801da177e4SLinus Torvalds struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size); 3811da177e4SLinus Torvalds 3821da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Truncating fraglist to 0x%08x bytes\n", size)); 3831da177e4SLinus Torvalds 3841da177e4SLinus Torvalds /* We know frag->ofs <= size. That's what lookup does for us */ 3851da177e4SLinus Torvalds if (frag && frag->ofs != size) { 3861da177e4SLinus Torvalds if (frag->ofs+frag->size >= size) { 3871da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Truncating frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size)); 3881da177e4SLinus Torvalds frag->size = size - frag->ofs; 3891da177e4SLinus Torvalds } 3901da177e4SLinus Torvalds frag = frag_next(frag); 3911da177e4SLinus Torvalds } 3921da177e4SLinus Torvalds while (frag && frag->ofs >= size) { 3931da177e4SLinus Torvalds struct jffs2_node_frag *next = frag_next(frag); 3941da177e4SLinus Torvalds 3951da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Removing frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size)); 3961da177e4SLinus Torvalds frag_erase(frag, list); 3971da177e4SLinus Torvalds jffs2_obsolete_node_frag(c, frag); 3981da177e4SLinus Torvalds frag = next; 3991da177e4SLinus Torvalds } 4001da177e4SLinus Torvalds } 4011da177e4SLinus Torvalds 4021da177e4SLinus Torvalds /* Scan the list of all nodes present for this ino, build map of versions, etc. */ 4031da177e4SLinus Torvalds 4041da177e4SLinus Torvalds static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, 4051da177e4SLinus Torvalds struct jffs2_inode_info *f, 4061da177e4SLinus Torvalds struct jffs2_raw_inode *latest_node); 4071da177e4SLinus Torvalds 4081da177e4SLinus Torvalds int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, 4091da177e4SLinus Torvalds uint32_t ino, struct jffs2_raw_inode *latest_node) 4101da177e4SLinus Torvalds { 4111da177e4SLinus Torvalds D2(printk(KERN_DEBUG "jffs2_do_read_inode(): getting inocache\n")); 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds retry_inocache: 4141da177e4SLinus Torvalds spin_lock(&c->inocache_lock); 4151da177e4SLinus Torvalds f->inocache = jffs2_get_ino_cache(c, ino); 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds D2(printk(KERN_DEBUG "jffs2_do_read_inode(): Got inocache at %p\n", f->inocache)); 4181da177e4SLinus Torvalds 4191da177e4SLinus Torvalds if (f->inocache) { 4201da177e4SLinus Torvalds /* Check its state. We may need to wait before we can use it */ 4211da177e4SLinus Torvalds switch(f->inocache->state) { 4221da177e4SLinus Torvalds case INO_STATE_UNCHECKED: 4231da177e4SLinus Torvalds case INO_STATE_CHECKEDABSENT: 4241da177e4SLinus Torvalds f->inocache->state = INO_STATE_READING; 4251da177e4SLinus Torvalds break; 4261da177e4SLinus Torvalds 4271da177e4SLinus Torvalds case INO_STATE_CHECKING: 4281da177e4SLinus Torvalds case INO_STATE_GC: 4291da177e4SLinus Torvalds /* If it's in either of these states, we need 4301da177e4SLinus Torvalds to wait for whoever's got it to finish and 4311da177e4SLinus Torvalds put it back. */ 4321da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_get_ino_cache_read waiting for ino #%u in state %d\n", 4331da177e4SLinus Torvalds ino, f->inocache->state)); 4341da177e4SLinus Torvalds sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); 4351da177e4SLinus Torvalds goto retry_inocache; 4361da177e4SLinus Torvalds 4371da177e4SLinus Torvalds case INO_STATE_READING: 4381da177e4SLinus Torvalds case INO_STATE_PRESENT: 4391da177e4SLinus Torvalds /* Eep. This should never happen. It can 4401da177e4SLinus Torvalds happen if Linux calls read_inode() again 4411da177e4SLinus Torvalds before clear_inode() has finished though. */ 4421da177e4SLinus Torvalds printk(KERN_WARNING "Eep. Trying to read_inode #%u when it's already in state %d!\n", ino, f->inocache->state); 4431da177e4SLinus Torvalds /* Fail. That's probably better than allowing it to succeed */ 4441da177e4SLinus Torvalds f->inocache = NULL; 4451da177e4SLinus Torvalds break; 4461da177e4SLinus Torvalds 4471da177e4SLinus Torvalds default: 4481da177e4SLinus Torvalds BUG(); 4491da177e4SLinus Torvalds } 4501da177e4SLinus Torvalds } 4511da177e4SLinus Torvalds spin_unlock(&c->inocache_lock); 4521da177e4SLinus Torvalds 4531da177e4SLinus Torvalds if (!f->inocache && ino == 1) { 4541da177e4SLinus Torvalds /* Special case - no root inode on medium */ 4551da177e4SLinus Torvalds f->inocache = jffs2_alloc_inode_cache(); 4561da177e4SLinus Torvalds if (!f->inocache) { 4571da177e4SLinus Torvalds printk(KERN_CRIT "jffs2_do_read_inode(): Cannot allocate inocache for root inode\n"); 4581da177e4SLinus Torvalds return -ENOMEM; 4591da177e4SLinus Torvalds } 4601da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_do_read_inode(): Creating inocache for root inode\n")); 4611da177e4SLinus Torvalds memset(f->inocache, 0, sizeof(struct jffs2_inode_cache)); 4621da177e4SLinus Torvalds f->inocache->ino = f->inocache->nlink = 1; 4631da177e4SLinus Torvalds f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; 4641da177e4SLinus Torvalds f->inocache->state = INO_STATE_READING; 4651da177e4SLinus Torvalds jffs2_add_ino_cache(c, f->inocache); 4661da177e4SLinus Torvalds } 4671da177e4SLinus Torvalds if (!f->inocache) { 4681da177e4SLinus Torvalds printk(KERN_WARNING "jffs2_do_read_inode() on nonexistent ino %u\n", ino); 4691da177e4SLinus Torvalds return -ENOENT; 4701da177e4SLinus Torvalds } 4711da177e4SLinus Torvalds 4721da177e4SLinus Torvalds return jffs2_do_read_inode_internal(c, f, latest_node); 4731da177e4SLinus Torvalds } 4741da177e4SLinus Torvalds 4751da177e4SLinus Torvalds int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) 4761da177e4SLinus Torvalds { 4771da177e4SLinus Torvalds struct jffs2_raw_inode n; 4781da177e4SLinus Torvalds struct jffs2_inode_info *f = kmalloc(sizeof(*f), GFP_KERNEL); 4791da177e4SLinus Torvalds int ret; 4801da177e4SLinus Torvalds 4811da177e4SLinus Torvalds if (!f) 4821da177e4SLinus Torvalds return -ENOMEM; 4831da177e4SLinus Torvalds 4841da177e4SLinus Torvalds memset(f, 0, sizeof(*f)); 4851da177e4SLinus Torvalds init_MUTEX_LOCKED(&f->sem); 4861da177e4SLinus Torvalds f->inocache = ic; 4871da177e4SLinus Torvalds 4881da177e4SLinus Torvalds ret = jffs2_do_read_inode_internal(c, f, &n); 4891da177e4SLinus Torvalds if (!ret) { 4901da177e4SLinus Torvalds up(&f->sem); 4911da177e4SLinus Torvalds jffs2_do_clear_inode(c, f); 4921da177e4SLinus Torvalds } 4931da177e4SLinus Torvalds kfree (f); 4941da177e4SLinus Torvalds return ret; 4951da177e4SLinus Torvalds } 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, 4981da177e4SLinus Torvalds struct jffs2_inode_info *f, 4991da177e4SLinus Torvalds struct jffs2_raw_inode *latest_node) 5001da177e4SLinus Torvalds { 5019dee7503SDavid Woodhouse struct jffs2_tmp_dnode_info *tn = NULL; 5029dee7503SDavid Woodhouse struct rb_root tn_list; 5039dee7503SDavid Woodhouse struct rb_node *rb, *repl_rb; 5041da177e4SLinus Torvalds struct jffs2_full_dirent *fd_list; 5051da177e4SLinus Torvalds struct jffs2_full_dnode *fn = NULL; 5061da177e4SLinus Torvalds uint32_t crc; 5071da177e4SLinus Torvalds uint32_t latest_mctime, mctime_ver; 5081da177e4SLinus Torvalds uint32_t mdata_ver = 0; 5091da177e4SLinus Torvalds size_t retlen; 5101da177e4SLinus Torvalds int ret; 5111da177e4SLinus Torvalds 5121da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_do_read_inode_internal(): ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink)); 5131da177e4SLinus Torvalds 5141da177e4SLinus Torvalds /* Grab all nodes relevant to this ino */ 5151da177e4SLinus Torvalds ret = jffs2_get_inode_nodes(c, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver); 5161da177e4SLinus Torvalds 5171da177e4SLinus Torvalds if (ret) { 5181da177e4SLinus Torvalds printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %u returned %d\n", f->inocache->ino, ret); 5191da177e4SLinus Torvalds if (f->inocache->state == INO_STATE_READING) 5201da177e4SLinus Torvalds jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); 5211da177e4SLinus Torvalds return ret; 5221da177e4SLinus Torvalds } 5231da177e4SLinus Torvalds f->dents = fd_list; 5241da177e4SLinus Torvalds 5259dee7503SDavid Woodhouse rb = rb_first(&tn_list); 5261da177e4SLinus Torvalds 5279dee7503SDavid Woodhouse while (rb) { 5289dee7503SDavid Woodhouse tn = rb_entry(rb, struct jffs2_tmp_dnode_info, rb); 5291da177e4SLinus Torvalds fn = tn->fn; 5301da177e4SLinus Torvalds 5311da177e4SLinus Torvalds if (f->metadata) { 5321da177e4SLinus Torvalds if (likely(tn->version >= mdata_ver)) { 5331da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", ref_offset(f->metadata->raw))); 5341da177e4SLinus Torvalds jffs2_mark_node_obsolete(c, f->metadata->raw); 5351da177e4SLinus Torvalds jffs2_free_full_dnode(f->metadata); 5361da177e4SLinus Torvalds f->metadata = NULL; 5371da177e4SLinus Torvalds 5381da177e4SLinus Torvalds mdata_ver = 0; 5391da177e4SLinus Torvalds } else { 5401da177e4SLinus Torvalds /* This should never happen. */ 5411da177e4SLinus Torvalds printk(KERN_WARNING "Er. New metadata at 0x%08x with ver %d is actually older than previous ver %d at 0x%08x\n", 5421da177e4SLinus Torvalds ref_offset(fn->raw), tn->version, mdata_ver, ref_offset(f->metadata->raw)); 5431da177e4SLinus Torvalds jffs2_mark_node_obsolete(c, fn->raw); 5441da177e4SLinus Torvalds jffs2_free_full_dnode(fn); 5451da177e4SLinus Torvalds /* Fill in latest_node from the metadata, not this one we're about to free... */ 5461da177e4SLinus Torvalds fn = f->metadata; 5471da177e4SLinus Torvalds goto next_tn; 5481da177e4SLinus Torvalds } 5491da177e4SLinus Torvalds } 5501da177e4SLinus Torvalds 5511da177e4SLinus Torvalds if (fn->size) { 5521da177e4SLinus Torvalds jffs2_add_full_dnode_to_inode(c, f, fn); 5531da177e4SLinus Torvalds } else { 5541da177e4SLinus Torvalds /* Zero-sized node at end of version list. Just a metadata update */ 5551da177e4SLinus Torvalds D1(printk(KERN_DEBUG "metadata @%08x: ver %d\n", ref_offset(fn->raw), tn->version)); 5561da177e4SLinus Torvalds f->metadata = fn; 5571da177e4SLinus Torvalds mdata_ver = tn->version; 5581da177e4SLinus Torvalds } 5591da177e4SLinus Torvalds next_tn: 5609dee7503SDavid Woodhouse BUG_ON(rb->rb_left); 5619dee7503SDavid Woodhouse repl_rb = NULL; 5629dee7503SDavid Woodhouse if (rb->rb_parent && rb->rb_parent->rb_left == rb) { 5639dee7503SDavid Woodhouse /* We were then left-hand child of our parent. We need 5649dee7503SDavid Woodhouse to move our own right-hand child into our place. */ 5659dee7503SDavid Woodhouse repl_rb = rb->rb_right; 5669dee7503SDavid Woodhouse if (repl_rb) 5679dee7503SDavid Woodhouse repl_rb->rb_parent = rb->rb_parent; 5689dee7503SDavid Woodhouse } else 5699dee7503SDavid Woodhouse repl_rb = NULL; 5709dee7503SDavid Woodhouse 5719dee7503SDavid Woodhouse rb = rb_next(rb); 5729dee7503SDavid Woodhouse 5739dee7503SDavid Woodhouse /* Remove the spent tn from the tree; don't bother rebalancing 5749dee7503SDavid Woodhouse but put our right-hand child in our own place. */ 5759dee7503SDavid Woodhouse if (tn->rb.rb_parent) { 5769dee7503SDavid Woodhouse if (tn->rb.rb_parent->rb_left == &tn->rb) 5779dee7503SDavid Woodhouse tn->rb.rb_parent->rb_left = repl_rb; 5789dee7503SDavid Woodhouse else if (tn->rb.rb_parent->rb_right == &tn->rb) 5799dee7503SDavid Woodhouse tn->rb.rb_parent->rb_right = repl_rb; 5809dee7503SDavid Woodhouse else BUG(); 5819dee7503SDavid Woodhouse } else if (tn->rb.rb_right) 5829dee7503SDavid Woodhouse tn->rb.rb_right->rb_parent = NULL; 5839dee7503SDavid Woodhouse 5841da177e4SLinus Torvalds jffs2_free_tmp_dnode_info(tn); 5851da177e4SLinus Torvalds } 5861da177e4SLinus Torvalds D1(jffs2_sanitycheck_fragtree(f)); 5871da177e4SLinus Torvalds 5881da177e4SLinus Torvalds if (!fn) { 5891da177e4SLinus Torvalds /* No data nodes for this inode. */ 5901da177e4SLinus Torvalds if (f->inocache->ino != 1) { 5911da177e4SLinus Torvalds printk(KERN_WARNING "jffs2_do_read_inode(): No data nodes found for ino #%u\n", f->inocache->ino); 5921da177e4SLinus Torvalds if (!fd_list) { 5931da177e4SLinus Torvalds if (f->inocache->state == INO_STATE_READING) 5941da177e4SLinus Torvalds jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); 5951da177e4SLinus Torvalds return -EIO; 5961da177e4SLinus Torvalds } 5971da177e4SLinus Torvalds printk(KERN_WARNING "jffs2_do_read_inode(): But it has children so we fake some modes for it\n"); 5981da177e4SLinus Torvalds } 5991da177e4SLinus Torvalds latest_node->mode = cpu_to_jemode(S_IFDIR|S_IRUGO|S_IWUSR|S_IXUGO); 6001da177e4SLinus Torvalds latest_node->version = cpu_to_je32(0); 6011da177e4SLinus Torvalds latest_node->atime = latest_node->ctime = latest_node->mtime = cpu_to_je32(0); 6021da177e4SLinus Torvalds latest_node->isize = cpu_to_je32(0); 6031da177e4SLinus Torvalds latest_node->gid = cpu_to_je16(0); 6041da177e4SLinus Torvalds latest_node->uid = cpu_to_je16(0); 6051da177e4SLinus Torvalds if (f->inocache->state == INO_STATE_READING) 6061da177e4SLinus Torvalds jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT); 6071da177e4SLinus Torvalds return 0; 6081da177e4SLinus Torvalds } 6091da177e4SLinus Torvalds 6101da177e4SLinus Torvalds ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(*latest_node), &retlen, (void *)latest_node); 6111da177e4SLinus Torvalds if (ret || retlen != sizeof(*latest_node)) { 6121da177e4SLinus Torvalds printk(KERN_NOTICE "MTD read in jffs2_do_read_inode() failed: Returned %d, %zd of %zd bytes read\n", 6131da177e4SLinus Torvalds ret, retlen, sizeof(*latest_node)); 6141da177e4SLinus Torvalds /* FIXME: If this fails, there seems to be a memory leak. Find it. */ 6151da177e4SLinus Torvalds up(&f->sem); 6161da177e4SLinus Torvalds jffs2_do_clear_inode(c, f); 6171da177e4SLinus Torvalds return ret?ret:-EIO; 6181da177e4SLinus Torvalds } 6191da177e4SLinus Torvalds 6201da177e4SLinus Torvalds crc = crc32(0, latest_node, sizeof(*latest_node)-8); 6211da177e4SLinus Torvalds if (crc != je32_to_cpu(latest_node->node_crc)) { 6221da177e4SLinus Torvalds printk(KERN_NOTICE "CRC failed for read_inode of inode %u at physical location 0x%x\n", f->inocache->ino, ref_offset(fn->raw)); 6231da177e4SLinus Torvalds up(&f->sem); 6241da177e4SLinus Torvalds jffs2_do_clear_inode(c, f); 6251da177e4SLinus Torvalds return -EIO; 6261da177e4SLinus Torvalds } 6271da177e4SLinus Torvalds 6281da177e4SLinus Torvalds switch(jemode_to_cpu(latest_node->mode) & S_IFMT) { 6291da177e4SLinus Torvalds case S_IFDIR: 6301da177e4SLinus Torvalds if (mctime_ver > je32_to_cpu(latest_node->version)) { 6311da177e4SLinus Torvalds /* The times in the latest_node are actually older than 6321da177e4SLinus Torvalds mctime in the latest dirent. Cheat. */ 6331da177e4SLinus Torvalds latest_node->ctime = latest_node->mtime = cpu_to_je32(latest_mctime); 6341da177e4SLinus Torvalds } 6351da177e4SLinus Torvalds break; 6361da177e4SLinus Torvalds 6371da177e4SLinus Torvalds 6381da177e4SLinus Torvalds case S_IFREG: 6391da177e4SLinus Torvalds /* If it was a regular file, truncate it to the latest node's isize */ 6401da177e4SLinus Torvalds jffs2_truncate_fraglist(c, &f->fragtree, je32_to_cpu(latest_node->isize)); 6411da177e4SLinus Torvalds break; 6421da177e4SLinus Torvalds 6431da177e4SLinus Torvalds case S_IFLNK: 6441da177e4SLinus Torvalds /* Hack to work around broken isize in old symlink code. 6451da177e4SLinus Torvalds Remove this when dwmw2 comes to his senses and stops 6461da177e4SLinus Torvalds symlinks from being an entirely gratuitous special 6471da177e4SLinus Torvalds case. */ 6481da177e4SLinus Torvalds if (!je32_to_cpu(latest_node->isize)) 6491da177e4SLinus Torvalds latest_node->isize = latest_node->dsize; 65032f1a95dSArtem B. Bityuckiy 65132f1a95dSArtem B. Bityuckiy if (f->inocache->state != INO_STATE_CHECKING) { 65232f1a95dSArtem B. Bityuckiy /* Symlink's inode data is the target path. Read it and 65332f1a95dSArtem B. Bityuckiy * keep in RAM to facilitate quick follow symlink operation. 65432f1a95dSArtem B. Bityuckiy * We use f->dents field to store the target path, which 65532f1a95dSArtem B. Bityuckiy * is somewhat ugly. */ 65632f1a95dSArtem B. Bityuckiy f->dents = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL); 65732f1a95dSArtem B. Bityuckiy if (!f->dents) { 65832f1a95dSArtem B. Bityuckiy printk(KERN_WARNING "Can't allocate %d bytes of memory " 65932f1a95dSArtem B. Bityuckiy "for the symlink target path cache\n", 66032f1a95dSArtem B. Bityuckiy je32_to_cpu(latest_node->csize)); 66132f1a95dSArtem B. Bityuckiy up(&f->sem); 66232f1a95dSArtem B. Bityuckiy jffs2_do_clear_inode(c, f); 66332f1a95dSArtem B. Bityuckiy return -ENOMEM; 66432f1a95dSArtem B. Bityuckiy } 66532f1a95dSArtem B. Bityuckiy 66632f1a95dSArtem B. Bityuckiy ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node), 66732f1a95dSArtem B. Bityuckiy je32_to_cpu(latest_node->csize), &retlen, (char *)f->dents); 66832f1a95dSArtem B. Bityuckiy 66932f1a95dSArtem B. Bityuckiy if (ret || retlen != je32_to_cpu(latest_node->csize)) { 67032f1a95dSArtem B. Bityuckiy if (retlen != je32_to_cpu(latest_node->csize)) 67132f1a95dSArtem B. Bityuckiy ret = -EIO; 67232f1a95dSArtem B. Bityuckiy kfree(f->dents); 67332f1a95dSArtem B. Bityuckiy f->dents = NULL; 67432f1a95dSArtem B. Bityuckiy up(&f->sem); 67532f1a95dSArtem B. Bityuckiy jffs2_do_clear_inode(c, f); 67632f1a95dSArtem B. Bityuckiy return -ret; 67732f1a95dSArtem B. Bityuckiy } 67832f1a95dSArtem B. Bityuckiy 67932f1a95dSArtem B. Bityuckiy ((char *)f->dents)[je32_to_cpu(latest_node->csize)] = '\0'; 68032f1a95dSArtem B. Bityuckiy D1(printk(KERN_DEBUG "jffs2_do_read_inode(): symlink's target '%s' cached\n", 68132f1a95dSArtem B. Bityuckiy (char *)f->dents)); 68232f1a95dSArtem B. Bityuckiy } 68332f1a95dSArtem B. Bityuckiy 6841da177e4SLinus Torvalds /* fall through... */ 6851da177e4SLinus Torvalds 6861da177e4SLinus Torvalds case S_IFBLK: 6871da177e4SLinus Torvalds case S_IFCHR: 6881da177e4SLinus Torvalds /* Certain inode types should have only one data node, and it's 6891da177e4SLinus Torvalds kept as the metadata node */ 6901da177e4SLinus Torvalds if (f->metadata) { 6911da177e4SLinus Torvalds printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had metadata node\n", 6921da177e4SLinus Torvalds f->inocache->ino, jemode_to_cpu(latest_node->mode)); 6931da177e4SLinus Torvalds up(&f->sem); 6941da177e4SLinus Torvalds jffs2_do_clear_inode(c, f); 6951da177e4SLinus Torvalds return -EIO; 6961da177e4SLinus Torvalds } 6971da177e4SLinus Torvalds if (!frag_first(&f->fragtree)) { 6981da177e4SLinus Torvalds printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o has no fragments\n", 6991da177e4SLinus Torvalds f->inocache->ino, jemode_to_cpu(latest_node->mode)); 7001da177e4SLinus Torvalds up(&f->sem); 7011da177e4SLinus Torvalds jffs2_do_clear_inode(c, f); 7021da177e4SLinus Torvalds return -EIO; 7031da177e4SLinus Torvalds } 7041da177e4SLinus Torvalds /* ASSERT: f->fraglist != NULL */ 7051da177e4SLinus Torvalds if (frag_next(frag_first(&f->fragtree))) { 7061da177e4SLinus Torvalds printk(KERN_WARNING "Argh. Special inode #%u with mode 0x%x had more than one node\n", 7071da177e4SLinus Torvalds f->inocache->ino, jemode_to_cpu(latest_node->mode)); 7081da177e4SLinus Torvalds /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */ 7091da177e4SLinus Torvalds up(&f->sem); 7101da177e4SLinus Torvalds jffs2_do_clear_inode(c, f); 7111da177e4SLinus Torvalds return -EIO; 7121da177e4SLinus Torvalds } 7131da177e4SLinus Torvalds /* OK. We're happy */ 7141da177e4SLinus Torvalds f->metadata = frag_first(&f->fragtree)->node; 7151da177e4SLinus Torvalds jffs2_free_node_frag(frag_first(&f->fragtree)); 7161da177e4SLinus Torvalds f->fragtree = RB_ROOT; 7171da177e4SLinus Torvalds break; 7181da177e4SLinus Torvalds } 7191da177e4SLinus Torvalds if (f->inocache->state == INO_STATE_READING) 7201da177e4SLinus Torvalds jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT); 7211da177e4SLinus Torvalds 7221da177e4SLinus Torvalds return 0; 7231da177e4SLinus Torvalds } 7241da177e4SLinus Torvalds 7251da177e4SLinus Torvalds void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) 7261da177e4SLinus Torvalds { 7271da177e4SLinus Torvalds struct jffs2_full_dirent *fd, *fds; 7281da177e4SLinus Torvalds int deleted; 7291da177e4SLinus Torvalds 7301da177e4SLinus Torvalds down(&f->sem); 7311da177e4SLinus Torvalds deleted = f->inocache && !f->inocache->nlink; 7321da177e4SLinus Torvalds 73367e345d1SDavid Woodhouse if (f->inocache && f->inocache->state != INO_STATE_CHECKING) 73467e345d1SDavid Woodhouse jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING); 73567e345d1SDavid Woodhouse 7361da177e4SLinus Torvalds if (f->metadata) { 7371da177e4SLinus Torvalds if (deleted) 7381da177e4SLinus Torvalds jffs2_mark_node_obsolete(c, f->metadata->raw); 7391da177e4SLinus Torvalds jffs2_free_full_dnode(f->metadata); 7401da177e4SLinus Torvalds } 7411da177e4SLinus Torvalds 7421da177e4SLinus Torvalds jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); 7431da177e4SLinus Torvalds 74432f1a95dSArtem B. Bityuckiy /* For symlink inodes we us f->dents to store the target path name */ 74532f1a95dSArtem B. Bityuckiy if (S_ISLNK(OFNI_EDONI_2SFFJ(f)->i_mode)) { 74632f1a95dSArtem B. Bityuckiy if (f->dents) { 74732f1a95dSArtem B. Bityuckiy kfree(f->dents); 74832f1a95dSArtem B. Bityuckiy f->dents = NULL; 74932f1a95dSArtem B. Bityuckiy } 75032f1a95dSArtem B. Bityuckiy } else { 7511da177e4SLinus Torvalds fds = f->dents; 7521da177e4SLinus Torvalds 7531da177e4SLinus Torvalds while(fds) { 7541da177e4SLinus Torvalds fd = fds; 7551da177e4SLinus Torvalds fds = fd->next; 7561da177e4SLinus Torvalds jffs2_free_full_dirent(fd); 7571da177e4SLinus Torvalds } 75832f1a95dSArtem B. Bityuckiy } 7591da177e4SLinus Torvalds 76067e345d1SDavid Woodhouse if (f->inocache && f->inocache->state != INO_STATE_CHECKING) { 7611da177e4SLinus Torvalds jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); 76267e345d1SDavid Woodhouse if (f->inocache->nodes == (void *)f->inocache) 76367e345d1SDavid Woodhouse jffs2_del_ino_cache(c, f->inocache); 76467e345d1SDavid Woodhouse } 7651da177e4SLinus Torvalds 7661da177e4SLinus Torvalds up(&f->sem); 7671da177e4SLinus Torvalds } 768