2005-04-17 02:20:36 +04:00
/*
* JFFS2 - - Journalling Flash File System , Version 2.
*
2007-04-25 17:16:47 +04:00
* Copyright © 2001 - 2007 Red Hat , Inc .
2005-04-17 02:20:36 +04:00
*
* Created by David Woodhouse < dwmw2 @ infradead . org >
*
* For licensing information , see the file ' LICENCE ' in this directory .
*
*/
# include <linux/kernel.h>
# include <linux/sched.h>
# include <linux/fs.h>
# include <linux/mtd/mtd.h>
# include <linux/rbtree.h>
# include <linux/crc32.h>
# include <linux/pagemap.h>
# include "nodelist.h"
2006-07-07 00:37:43 +04:00
static void jffs2_obsolete_node_frag ( struct jffs2_sb_info * c ,
struct jffs2_node_frag * this ) ;
2005-04-17 02:20:36 +04:00
void jffs2_add_fd_to_list ( struct jffs2_sb_info * c , struct jffs2_full_dirent * new , struct jffs2_full_dirent * * list )
{
struct jffs2_full_dirent * * prev = list ;
2005-11-07 14:16:07 +03:00
2005-09-22 15:25:00 +04:00
dbg_dentlist ( " add dirent \" %s \" , ino #%u \n " , new - > name , new - > ino ) ;
2005-04-17 02:20:36 +04:00
while ( ( * prev ) & & ( * prev ) - > nhash < = new - > nhash ) {
if ( ( * prev ) - > nhash = = new - > nhash & & ! strcmp ( ( * prev ) - > name , new - > name ) ) {
/* Duplicate. Free one */
if ( new - > version < ( * prev ) - > version ) {
2007-11-01 23:25:56 +03:00
dbg_dentlist ( " Eep! Marking new dirent node obsolete, old is \" %s \" , ino #%u \n " ,
2005-07-28 18:46:43 +04:00
( * prev ) - > name , ( * prev ) - > ino ) ;
2005-04-17 02:20:36 +04:00
jffs2_mark_node_obsolete ( c , new - > raw ) ;
jffs2_free_full_dirent ( new ) ;
} else {
2007-11-01 23:25:56 +03:00
dbg_dentlist ( " marking old dirent \" %s \" , ino #%u obsolete \n " ,
2005-07-28 18:46:43 +04:00
( * prev ) - > name , ( * prev ) - > ino ) ;
2005-04-17 02:20:36 +04:00
new - > next = ( * prev ) - > next ;
2007-11-01 23:25:56 +03:00
/* It may have been a 'placeholder' deletion dirent,
if jffs2_can_mark_obsolete ( ) ( see jffs2_do_unlink ( ) ) */
if ( ( * prev ) - > raw )
jffs2_mark_node_obsolete ( c , ( ( * prev ) - > raw ) ) ;
2005-04-17 02:20:36 +04:00
jffs2_free_full_dirent ( * prev ) ;
* prev = new ;
}
2005-07-28 18:46:43 +04:00
return ;
2005-04-17 02:20:36 +04:00
}
prev = & ( ( * prev ) - > next ) ;
}
new - > next = * prev ;
* prev = new ;
}
2007-04-25 20:04:23 +04:00
uint32_t jffs2_truncate_fragtree ( struct jffs2_sb_info * c , struct rb_root * list , uint32_t size )
2005-07-31 12:20:48 +04:00
{
struct jffs2_node_frag * frag = jffs2_lookup_node_frag ( list , size ) ;
2005-09-22 15:25:00 +04:00
dbg_fragtree ( " truncating fragtree to 0x%08x bytes \n " , size ) ;
2005-07-31 12:20:48 +04:00
/* We know frag->ofs <= size. That's what lookup does for us */
if ( frag & & frag - > ofs ! = size ) {
2005-08-01 16:05:22 +04:00
if ( frag - > ofs + frag - > size > size ) {
2005-07-31 12:20:48 +04:00
frag - > size = size - frag - > ofs ;
}
frag = frag_next ( frag ) ;
}
while ( frag & & frag - > ofs > = size ) {
struct jffs2_node_frag * next = frag_next ( frag ) ;
frag_erase ( frag , list ) ;
jffs2_obsolete_node_frag ( c , frag ) ;
frag = next ;
}
2005-08-01 16:05:22 +04:00
if ( size = = 0 )
2007-04-25 20:04:23 +04:00
return 0 ;
2005-08-01 16:05:22 +04:00
frag = frag_last ( list ) ;
2007-04-25 20:04:23 +04:00
/* Sanity check for truncation to longer than we started with... */
if ( ! frag )
return 0 ;
if ( frag - > ofs + frag - > size < size )
return frag - > ofs + frag - > size ;
/* If the last fragment starts at the RAM page boundary, it is
* REF_PRISTINE irrespective of its size . */
2005-08-22 13:07:12 +04:00
if ( frag - > node & & ( frag - > ofs & ( PAGE_CACHE_SIZE - 1 ) ) = = 0 ) {
2005-09-22 15:25:00 +04:00
dbg_fragtree2 ( " marking the last fragment 0x%08x-0x%08x REF_PRISTINE. \n " ,
2005-11-07 14:16:07 +03:00
frag - > ofs , frag - > ofs + frag - > size ) ;
2005-08-01 16:05:22 +04:00
frag - > node - > raw - > flash_offset = ref_offset ( frag - > node - > raw ) | REF_PRISTINE ;
}
2007-04-25 20:04:23 +04:00
return size ;
2005-07-31 12:20:48 +04:00
}
2006-07-07 00:37:43 +04:00
static void jffs2_obsolete_node_frag ( struct jffs2_sb_info * c ,
struct jffs2_node_frag * this )
2005-04-17 02:20:36 +04:00
{
2005-07-27 18:46:14 +04:00
if ( this - > node ) {
this - > node - > frags - - ;
if ( ! this - > node - > frags ) {
/* The node has no valid frags left. It's totally obsoleted */
2005-09-22 15:25:00 +04:00
dbg_fragtree2 ( " marking old node @0x%08x (0x%04x-0x%04x) obsolete \n " ,
2005-07-28 18:46:43 +04:00
ref_offset ( this - > node - > raw ) , this - > node - > ofs , this - > node - > ofs + this - > node - > size ) ;
2005-07-27 18:46:14 +04:00
jffs2_mark_node_obsolete ( c , this - > node - > raw ) ;
jffs2_free_full_dnode ( this - > node ) ;
} else {
2005-09-22 15:25:00 +04:00
dbg_fragtree2 ( " marking old node @0x%08x (0x%04x-0x%04x) REF_NORMAL. frags is %d \n " ,
2005-07-28 18:46:43 +04:00
ref_offset ( this - > node - > raw ) , this - > node - > ofs , this - > node - > ofs + this - > node - > size , this - > node - > frags ) ;
2005-07-27 18:46:14 +04:00
mark_ref_normal ( this - > node - > raw ) ;
}
2005-11-07 14:16:07 +03:00
2005-07-27 18:46:14 +04:00
}
jffs2_free_node_frag ( this ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-27 18:46:14 +04:00
static void jffs2_fragtree_insert ( struct jffs2_node_frag * newfrag , struct jffs2_node_frag * base )
2005-04-17 02:20:36 +04:00
{
2005-07-27 18:46:14 +04:00
struct rb_node * parent = & base - > rb ;
struct rb_node * * link = & parent ;
2005-07-06 01:03:10 +04:00
2005-09-22 15:25:00 +04:00
dbg_fragtree2 ( " insert frag (0x%04x-0x%04x) \n " , newfrag - > ofs , newfrag - > ofs + newfrag - > size ) ;
2005-07-06 01:03:10 +04:00
2005-07-27 18:46:14 +04:00
while ( * link ) {
parent = * link ;
base = rb_entry ( parent , struct jffs2_node_frag , rb ) ;
2005-11-07 14:16:07 +03:00
2005-07-27 18:46:14 +04:00
if ( newfrag - > ofs > base - > ofs )
link = & base - > rb . rb_right ;
else if ( newfrag - > ofs < base - > ofs )
link = & base - > rb . rb_left ;
2005-07-06 01:03:10 +04:00
else {
2005-07-28 18:46:43 +04:00
JFFS2_ERROR ( " duplicate frag at %08x (%p,%p) \n " , newfrag - > ofs , newfrag , base ) ;
2005-07-27 18:46:14 +04:00
BUG ( ) ;
2005-07-06 01:03:10 +04:00
}
2005-04-17 02:20:36 +04:00
}
2005-07-27 18:46:14 +04:00
rb_link_node ( & newfrag - > rb , & base - > rb , link ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-01 16:05:22 +04:00
/*
* Allocate and initializes a new fragment .
*/
2006-01-15 00:20:43 +03:00
static struct jffs2_node_frag * new_fragment ( struct jffs2_full_dnode * fn , uint32_t ofs , uint32_t size )
2005-08-01 16:05:22 +04:00
{
struct jffs2_node_frag * newfrag ;
2005-11-07 14:16:07 +03:00
2005-08-01 16:05:22 +04:00
newfrag = jffs2_alloc_node_frag ( ) ;
if ( likely ( newfrag ) ) {
newfrag - > ofs = ofs ;
newfrag - > size = size ;
newfrag - > node = fn ;
} else {
JFFS2_ERROR ( " cannot allocate a jffs2_node_frag object \n " ) ;
}
return newfrag ;
}
/*
* Called when there is no overlapping fragment exist . Inserts a hole before the new
* fragment and inserts the new fragment to the fragtree .
*/
static int no_overlapping_node ( struct jffs2_sb_info * c , struct rb_root * root ,
struct jffs2_node_frag * newfrag ,
struct jffs2_node_frag * this , uint32_t lastend )
{
if ( lastend < newfrag - > node - > ofs ) {
/* put a hole in before the new fragment */
struct jffs2_node_frag * holefrag ;
holefrag = new_fragment ( NULL , lastend , newfrag - > node - > ofs - lastend ) ;
if ( unlikely ( ! holefrag ) ) {
jffs2_free_node_frag ( newfrag ) ;
return - ENOMEM ;
}
if ( this ) {
2005-11-07 14:16:07 +03:00
/* By definition, the 'this' node has no right-hand child,
2005-08-01 16:05:22 +04:00
because there are no frags with offset greater than it .
So that ' s where we want to put the hole */
2005-09-22 15:25:00 +04:00
dbg_fragtree2 ( " add hole frag %#04x-%#04x on the right of the new frag. \n " ,
2005-08-01 16:05:22 +04:00
holefrag - > ofs , holefrag - > ofs + holefrag - > size ) ;
rb_link_node ( & holefrag - > rb , & this - > rb , & this - > rb . rb_right ) ;
} else {
2005-09-22 15:25:00 +04:00
dbg_fragtree2 ( " Add hole frag %#04x-%#04x to the root of the tree. \n " ,
2005-08-01 16:05:22 +04:00
holefrag - > ofs , holefrag - > ofs + holefrag - > size ) ;
rb_link_node ( & holefrag - > rb , NULL , & root - > rb_node ) ;
}
rb_insert_color ( & holefrag - > rb , root ) ;
this = holefrag ;
}
2005-11-07 14:16:07 +03:00
2005-08-01 16:05:22 +04:00
if ( this ) {
2005-11-07 14:16:07 +03:00
/* By definition, the 'this' node has no right-hand child,
2005-08-01 16:05:22 +04:00
because there are no frags with offset greater than it .
So that ' s where we want to put new fragment */
2005-09-22 15:25:00 +04:00
dbg_fragtree2 ( " add the new node at the right \n " ) ;
2005-11-07 14:16:07 +03:00
rb_link_node ( & newfrag - > rb , & this - > rb , & this - > rb . rb_right ) ;
2005-08-01 16:05:22 +04:00
} else {
2005-09-22 15:25:00 +04:00
dbg_fragtree2 ( " insert the new node at the root of the tree \n " ) ;
2005-08-01 16:05:22 +04:00
rb_link_node ( & newfrag - > rb , NULL , & root - > rb_node ) ;
}
rb_insert_color ( & newfrag - > rb , root ) ;
return 0 ;
}
2005-07-27 18:46:14 +04:00
/* Doesn't set inode->i_size */
2005-08-01 16:05:22 +04:00
static int jffs2_add_frag_to_fragtree ( struct jffs2_sb_info * c , struct rb_root * root , struct jffs2_node_frag * newfrag )
2005-04-17 02:20:36 +04:00
{
2005-07-27 18:46:14 +04:00
struct jffs2_node_frag * this ;
uint32_t lastend ;
2005-04-17 02:20:36 +04:00
2005-07-27 18:46:14 +04:00
/* Skip all the nodes which are completed before this one starts */
2005-08-01 16:05:22 +04:00
this = jffs2_lookup_node_frag ( root , newfrag - > node - > ofs ) ;
2005-04-17 02:20:36 +04:00
2005-07-27 18:46:14 +04:00
if ( this ) {
2005-09-22 15:25:00 +04:00
dbg_fragtree2 ( " lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p) \n " ,
2005-07-28 18:46:43 +04:00
this - > ofs , this - > ofs + this - > size , this - > node ? ( ref_offset ( this - > node - > raw ) ) : 0xffffffff , this ) ;
2005-07-27 18:46:14 +04:00
lastend = this - > ofs + this - > size ;
} else {
2005-09-22 15:25:00 +04:00
dbg_fragtree2 ( " lookup gave no frag \n " ) ;
2005-07-27 18:46:14 +04:00
lastend = 0 ;
2005-04-17 02:20:36 +04:00
}
2005-11-07 14:16:07 +03:00
2005-08-01 16:05:22 +04:00
/* See if we ran off the end of the fragtree */
2005-07-27 18:46:14 +04:00
if ( lastend < = newfrag - > ofs ) {
/* We did */
/* Check if 'this' node was on the same page as the new node.
If so , both ' this ' and the new node get marked REF_NORMAL so
the GC can take a look .
*/
if ( lastend & & ( lastend - 1 ) > > PAGE_CACHE_SHIFT = = newfrag - > ofs > > PAGE_CACHE_SHIFT ) {
if ( this - > node )
mark_ref_normal ( this - > node - > raw ) ;
mark_ref_normal ( newfrag - > node - > raw ) ;
}
2005-04-17 02:20:36 +04:00
2005-08-01 16:05:22 +04:00
return no_overlapping_node ( c , root , newfrag , this , lastend ) ;
2005-07-15 14:13:57 +04:00
}
2005-08-01 16:05:22 +04:00
if ( this - > node )
2005-09-22 15:25:00 +04:00
dbg_fragtree2 ( " dealing with frag %u-%u, phys %#08x(%d). \n " ,
2005-08-01 16:05:22 +04:00
this - > ofs , this - > ofs + this - > size ,
ref_offset ( this - > node - > raw ) , ref_flags ( this - > node - > raw ) ) ;
else
2005-09-22 15:25:00 +04:00
dbg_fragtree2 ( " dealing with hole frag %u-%u. \n " ,
2005-08-01 16:05:22 +04:00
this - > ofs , this - > ofs + this - > size ) ;
2005-07-15 14:13:57 +04:00
2005-07-27 18:46:14 +04:00
/* OK. 'this' is pointing at the first frag that newfrag->ofs at least partially obsoletes,
2005-11-07 14:16:07 +03:00
* - i . e . newfrag - > ofs < this - > ofs + this - > size & & newfrag - > ofs > = this - > ofs
2005-07-15 14:13:57 +04:00
*/
2005-07-27 18:46:14 +04:00
if ( newfrag - > ofs > this - > ofs ) {
/* This node isn't completely obsoleted. The start of it remains valid */
/* Mark the new node and the partially covered node REF_NORMAL -- let
the GC take a look at them */
mark_ref_normal ( newfrag - > node - > raw ) ;
if ( this - > node )
mark_ref_normal ( this - > node - > raw ) ;
if ( this - > ofs + this - > size > newfrag - > ofs + newfrag - > size ) {
/* The new node splits 'this' frag into two */
2005-08-01 16:05:22 +04:00
struct jffs2_node_frag * newfrag2 ;
2005-07-27 18:46:14 +04:00
if ( this - > node )
2005-09-22 15:25:00 +04:00
dbg_fragtree2 ( " split old frag 0x%04x-0x%04x, phys 0x%08x \n " ,
2005-07-28 18:46:43 +04:00
this - > ofs , this - > ofs + this - > size , ref_offset ( this - > node - > raw ) ) ;
2005-11-07 14:16:07 +03:00
else
2005-09-22 15:25:00 +04:00
dbg_fragtree2 ( " split old hole frag 0x%04x-0x%04x \n " ,
2005-08-17 18:13:48 +04:00
this - > ofs , this - > ofs + this - > size ) ;
2005-11-07 14:16:07 +03:00
2005-07-27 18:46:14 +04:00
/* New second frag pointing to this's node */
2005-08-01 16:05:22 +04:00
newfrag2 = new_fragment ( this - > node , newfrag - > ofs + newfrag - > size ,
this - > ofs + this - > size - newfrag - > ofs - newfrag - > size ) ;
if ( unlikely ( ! newfrag2 ) )
return - ENOMEM ;
2005-07-27 18:46:14 +04:00
if ( this - > node )
this - > node - > frags + + ;
/* Adjust size of original 'this' */
this - > size = newfrag - > ofs - this - > ofs ;
/* Now, we know there's no node with offset
greater than this - > ofs but smaller than
newfrag2 - > ofs or newfrag - > ofs , for obvious
reasons . So we can do a tree insert from
' this ' to insert newfrag , and a tree insert
from newfrag to insert newfrag2 . */
jffs2_fragtree_insert ( newfrag , this ) ;
2005-08-01 16:05:22 +04:00
rb_insert_color ( & newfrag - > rb , root ) ;
2005-11-07 14:16:07 +03:00
2005-07-27 18:46:14 +04:00
jffs2_fragtree_insert ( newfrag2 , newfrag ) ;
2005-08-01 16:05:22 +04:00
rb_insert_color ( & newfrag2 - > rb , root ) ;
2005-11-07 14:16:07 +03:00
2005-07-27 18:46:14 +04:00
return 0 ;
2005-07-15 14:13:57 +04:00
}
2005-07-27 18:46:14 +04:00
/* New node just reduces 'this' frag in size, doesn't split it */
this - > size = newfrag - > ofs - this - > ofs ;
2005-07-15 14:13:57 +04:00
2005-07-27 18:46:14 +04:00
/* Again, we know it lives down here in the tree */
jffs2_fragtree_insert ( newfrag , this ) ;
2005-08-01 16:05:22 +04:00
rb_insert_color ( & newfrag - > rb , root ) ;
2005-07-27 18:46:14 +04:00
} else {
2005-11-07 14:16:07 +03:00
/* New frag starts at the same point as 'this' used to. Replace
2005-07-27 18:46:14 +04:00
it in the tree without doing a delete and insertion */
2005-09-22 15:25:00 +04:00
dbg_fragtree2 ( " inserting newfrag (*%p),%d-%d in before 'this' (*%p),%d-%d \n " ,
2005-07-28 18:46:43 +04:00
newfrag , newfrag - > ofs , newfrag - > ofs + newfrag - > size , this , this - > ofs , this - > ofs + this - > size ) ;
2005-11-07 14:16:07 +03:00
2005-08-01 16:05:22 +04:00
rb_replace_node ( & this - > rb , & newfrag - > rb , root ) ;
2005-11-07 14:16:07 +03:00
2005-07-27 18:46:14 +04:00
if ( newfrag - > ofs + newfrag - > size > = this - > ofs + this - > size ) {
2005-09-22 15:25:00 +04:00
dbg_fragtree2 ( " obsoleting node frag %p (%x-%x) \n " , this , this - > ofs , this - > ofs + this - > size ) ;
2005-07-27 18:46:14 +04:00
jffs2_obsolete_node_frag ( c , this ) ;
2005-07-15 14:13:57 +04:00
} else {
2005-07-27 18:46:14 +04:00
this - > ofs + = newfrag - > size ;
this - > size - = newfrag - > size ;
jffs2_fragtree_insert ( this , newfrag ) ;
2005-08-01 16:05:22 +04:00
rb_insert_color ( & this - > rb , root ) ;
2005-07-27 18:46:14 +04:00
return 0 ;
2005-07-15 14:13:57 +04:00
}
}
2005-07-27 18:46:14 +04:00
/* OK, now we have newfrag added in the correct place in the tree, but
2005-11-07 14:16:07 +03:00
frag_next ( newfrag ) may be a fragment which is overlapped by it
2005-07-27 18:46:14 +04:00
*/
while ( ( this = frag_next ( newfrag ) ) & & newfrag - > ofs + newfrag - > size > = this - > ofs + this - > size ) {
/* 'this' frag is obsoleted completely. */
2005-09-22 15:25:00 +04:00
dbg_fragtree2 ( " obsoleting node frag %p (%x-%x) and removing from tree \n " ,
2005-07-28 18:46:43 +04:00
this , this - > ofs , this - > ofs + this - > size ) ;
2005-08-01 16:05:22 +04:00
rb_erase ( & this - > rb , root ) ;
2005-07-27 18:46:14 +04:00
jffs2_obsolete_node_frag ( c , this ) ;
2005-07-15 14:13:57 +04:00
}
2005-11-07 14:16:07 +03:00
/* Now we're pointing at the first frag which isn't totally obsoleted by
2005-07-27 18:46:14 +04:00
the new frag */
2005-07-15 14:13:57 +04:00
2005-08-01 16:05:22 +04:00
if ( ! this | | newfrag - > ofs + newfrag - > size = = this - > ofs )
2005-07-27 18:46:14 +04:00
return 0 ;
2005-08-01 16:05:22 +04:00
2005-07-27 18:46:14 +04:00
/* Still some overlap but we don't need to move it in the tree */
this - > size = ( this - > ofs + this - > size ) - ( newfrag - > ofs + newfrag - > size ) ;
this - > ofs = newfrag - > ofs + newfrag - > size ;
/* And mark them REF_NORMAL so the GC takes a look at them */
if ( this - > node )
mark_ref_normal ( this - > node - > raw ) ;
mark_ref_normal ( newfrag - > node - > raw ) ;
2005-07-15 14:13:57 +04:00
return 0 ;
}
2005-11-07 14:16:07 +03:00
/*
2005-08-01 16:05:22 +04:00
* Given an inode , probably with existing tree of fragments , add the new node
* to the fragment tree .
2005-07-15 14:13:57 +04:00
*/
2005-07-27 18:46:14 +04:00
int jffs2_add_full_dnode_to_inode ( struct jffs2_sb_info * c , struct jffs2_inode_info * f , struct jffs2_full_dnode * fn )
2005-07-15 14:13:57 +04:00
{
2005-07-27 18:46:14 +04:00
int ret ;
struct jffs2_node_frag * newfrag ;
2005-07-15 14:13:57 +04:00
2005-07-27 18:46:14 +04:00
if ( unlikely ( ! fn - > size ) )
return 0 ;
2005-07-15 14:13:57 +04:00
2005-08-01 16:05:22 +04:00
newfrag = new_fragment ( fn , fn - > ofs , fn - > size ) ;
2005-07-27 18:46:14 +04:00
if ( unlikely ( ! newfrag ) )
return - ENOMEM ;
2005-08-01 16:05:22 +04:00
newfrag - > node - > frags = 1 ;
2005-04-17 02:20:36 +04:00
2005-09-22 15:25:00 +04:00
dbg_fragtree ( " adding node %#04x-%#04x @0x%08x on flash, newfrag *%p \n " ,
2005-07-28 18:46:43 +04:00
fn - > ofs , fn - > ofs + fn - > size , ref_offset ( fn - > raw ) , newfrag ) ;
2005-11-07 14:16:07 +03:00
2005-07-27 18:46:14 +04:00
ret = jffs2_add_frag_to_fragtree ( c , & f - > fragtree , newfrag ) ;
if ( unlikely ( ret ) )
return ret ;
/* If we now share a page with other nodes, mark either previous
or next node REF_NORMAL , as appropriate . */
if ( newfrag - > ofs & ( PAGE_CACHE_SIZE - 1 ) ) {
struct jffs2_node_frag * prev = frag_prev ( newfrag ) ;
mark_ref_normal ( fn - > raw ) ;
2005-11-07 14:16:07 +03:00
/* If we don't start at zero there's _always_ a previous */
2005-07-27 18:46:14 +04:00
if ( prev - > node )
mark_ref_normal ( prev - > node - > raw ) ;
}
2005-04-17 02:20:36 +04:00
2005-07-27 18:46:14 +04:00
if ( ( newfrag - > ofs + newfrag - > size ) & ( PAGE_CACHE_SIZE - 1 ) ) {
struct jffs2_node_frag * next = frag_next ( newfrag ) ;
2005-11-07 14:16:07 +03:00
2005-07-27 18:46:14 +04:00
if ( next ) {
mark_ref_normal ( fn - > raw ) ;
if ( next - > node )
mark_ref_normal ( next - > node - > raw ) ;
2005-04-17 02:20:36 +04:00
}
}
2005-07-27 18:46:14 +04:00
jffs2_dbg_fragtree_paranoia_check_nolock ( f ) ;
2005-08-01 16:05:22 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
void jffs2_set_inocache_state ( struct jffs2_sb_info * c , struct jffs2_inode_cache * ic , int state )
{
spin_lock ( & c - > inocache_lock ) ;
ic - > state = state ;
wake_up ( & c - > inocache_wq ) ;
spin_unlock ( & c - > inocache_lock ) ;
}
/* During mount, this needs no locking. During normal operation, its
callers want to do other stuff while still holding the inocache_lock .
2005-11-07 14:16:07 +03:00
Rather than introducing special case get_ino_cache functions or
2005-04-17 02:20:36 +04:00
callbacks , we just let the caller do the locking itself . */
2005-11-07 14:16:07 +03:00
2005-04-17 02:20:36 +04:00
struct jffs2_inode_cache * jffs2_get_ino_cache ( struct jffs2_sb_info * c , uint32_t ino )
{
struct jffs2_inode_cache * ret ;
2010-10-07 22:14:02 +04:00
ret = c - > inocache_list [ ino % c - > inocache_hashsize ] ;
2005-04-17 02:20:36 +04:00
while ( ret & & ret - > ino < ino ) {
ret = ret - > next ;
}
2005-11-07 14:16:07 +03:00
2005-04-17 02:20:36 +04:00
if ( ret & & ret - > ino ! = ino )
ret = NULL ;
return ret ;
}
void jffs2_add_ino_cache ( struct jffs2_sb_info * c , struct jffs2_inode_cache * new )
{
struct jffs2_inode_cache * * prev ;
2005-05-22 23:47:19 +04:00
2005-04-17 02:20:36 +04:00
spin_lock ( & c - > inocache_lock ) ;
2005-05-22 23:47:19 +04:00
if ( ! new - > ino )
new - > ino = + + c - > highest_ino ;
2005-09-22 15:25:00 +04:00
dbg_inocache ( " add %p (ino #%u) \n " , new , new - > ino ) ;
2005-05-22 23:47:19 +04:00
2010-10-07 22:14:02 +04:00
prev = & c - > inocache_list [ new - > ino % c - > inocache_hashsize ] ;
2005-04-17 02:20:36 +04:00
while ( ( * prev ) & & ( * prev ) - > ino < new - > ino ) {
prev = & ( * prev ) - > next ;
}
new - > next = * prev ;
* prev = new ;
spin_unlock ( & c - > inocache_lock ) ;
}
void jffs2_del_ino_cache ( struct jffs2_sb_info * c , struct jffs2_inode_cache * old )
{
struct jffs2_inode_cache * * prev ;
2005-07-28 18:46:43 +04:00
2006-06-24 04:15:36 +04:00
# ifdef CONFIG_JFFS2_FS_XATTR
BUG_ON ( old - > xref ) ;
# endif
2005-09-22 15:25:00 +04:00
dbg_inocache ( " del %p (ino #%u) \n " , old , old - > ino ) ;
2005-04-17 02:20:36 +04:00
spin_lock ( & c - > inocache_lock ) ;
2005-11-07 14:16:07 +03:00
2010-10-07 22:14:02 +04:00
prev = & c - > inocache_list [ old - > ino % c - > inocache_hashsize ] ;
2005-11-07 14:16:07 +03:00
2005-04-17 02:20:36 +04:00
while ( ( * prev ) & & ( * prev ) - > ino < old - > ino ) {
prev = & ( * prev ) - > next ;
}
if ( ( * prev ) = = old ) {
* prev = old - > next ;
}
2005-02-28 02:01:36 +03:00
/* Free it now unless it's in READING or CLEARING state, which
are the transitions upon read_inode ( ) and clear_inode ( ) . The
2005-11-07 14:16:07 +03:00
rest of the time we know nobody else is looking at it , and
2005-02-28 02:01:36 +03:00
if it ' s held by read_inode ( ) or clear_inode ( ) they ' ll free it
for themselves . */
if ( old - > state ! = INO_STATE_READING & & old - > state ! = INO_STATE_CLEARING )
jffs2_free_inode_cache ( old ) ;
2005-04-17 02:20:36 +04:00
spin_unlock ( & c - > inocache_lock ) ;
}
void jffs2_free_ino_caches ( struct jffs2_sb_info * c )
{
int i ;
struct jffs2_inode_cache * this , * next ;
2005-11-07 14:16:07 +03:00
2010-10-07 22:14:02 +04:00
for ( i = 0 ; i < c - > inocache_hashsize ; i + + ) {
2005-04-17 02:20:36 +04:00
this = c - > inocache_list [ i ] ;
while ( this ) {
next = this - > next ;
2006-05-13 10:09:47 +04:00
jffs2_xattr_free_inode ( c , this ) ;
2005-04-17 02:20:36 +04:00
jffs2_free_inode_cache ( this ) ;
this = next ;
}
c - > inocache_list [ i ] = NULL ;
}
}
void jffs2_free_raw_node_refs ( struct jffs2_sb_info * c )
{
int i ;
struct jffs2_raw_node_ref * this , * next ;
for ( i = 0 ; i < c - > nr_blocks ; i + + ) {
this = c - > blocks [ i ] . first_node ;
2006-05-24 05:04:45 +04:00
while ( this ) {
2006-05-27 00:19:05 +04:00
if ( this [ REFS_PER_BLOCK ] . flash_offset = = REF_LINK_NODE )
next = this [ REFS_PER_BLOCK ] . next_in_ino ;
else
next = NULL ;
jffs2_free_refblock ( this ) ;
2005-04-17 02:20:36 +04:00
this = next ;
}
c - > blocks [ i ] . first_node = c - > blocks [ i ] . last_node = NULL ;
}
}
2005-11-07 14:16:07 +03:00
2005-04-17 02:20:36 +04:00
struct jffs2_node_frag * jffs2_lookup_node_frag ( struct rb_root * fragtree , uint32_t offset )
{
2005-11-07 14:16:07 +03:00
/* The common case in lookup is that there will be a node
2005-04-17 02:20:36 +04:00
which precisely matches . So we go looking for that first */
struct rb_node * next ;
struct jffs2_node_frag * prev = NULL ;
struct jffs2_node_frag * frag = NULL ;
2005-09-22 15:25:00 +04:00
dbg_fragtree2 ( " root %p, offset %d \n " , fragtree , offset ) ;
2005-04-17 02:20:36 +04:00
next = fragtree - > rb_node ;
while ( next ) {
frag = rb_entry ( next , struct jffs2_node_frag , rb ) ;
if ( frag - > ofs + frag - > size < = offset ) {
/* Remember the closest smaller match on the way down */
if ( ! prev | | frag - > ofs > prev - > ofs )
prev = frag ;
next = frag - > rb . rb_right ;
} else if ( frag - > ofs > offset ) {
next = frag - > rb . rb_left ;
} else {
return frag ;
}
}
/* Exact match not found. Go back up looking at each parent,
and return the closest smaller one */
if ( prev )
2005-09-22 15:25:00 +04:00
dbg_fragtree2 ( " no match. Returning frag %#04x-%#04x, closest previous \n " ,
2005-07-28 18:46:43 +04:00
prev - > ofs , prev - > ofs + prev - > size ) ;
2005-11-07 14:16:07 +03:00
else
2005-09-22 15:25:00 +04:00
dbg_fragtree2 ( " returning NULL, empty fragtree \n " ) ;
2005-11-07 14:16:07 +03:00
2005-04-17 02:20:36 +04:00
return prev ;
}
/* Pass 'c' argument to indicate that nodes should be marked obsolete as
they ' re killed . */
void jffs2_kill_fragtree ( struct rb_root * root , struct jffs2_sb_info * c )
{
struct jffs2_node_frag * frag ;
struct jffs2_node_frag * parent ;
if ( ! root - > rb_node )
return ;
2005-09-22 15:25:00 +04:00
dbg_fragtree ( " killing \n " ) ;
2005-11-07 14:16:07 +03:00
2005-04-17 02:20:36 +04:00
frag = ( rb_entry ( root - > rb_node , struct jffs2_node_frag , rb ) ) ;
while ( frag ) {
if ( frag - > rb . rb_left ) {
frag = frag_left ( frag ) ;
continue ;
}
if ( frag - > rb . rb_right ) {
frag = frag_right ( frag ) ;
continue ;
}
if ( frag - > node & & ! ( - - frag - > node - > frags ) ) {
2005-11-07 14:16:07 +03:00
/* Not a hole, and it's the final remaining frag
2005-04-17 02:20:36 +04:00
of this node . Free the node */
if ( c )
jffs2_mark_node_obsolete ( c , frag - > node - > raw ) ;
2005-11-07 14:16:07 +03:00
2005-04-17 02:20:36 +04:00
jffs2_free_full_dnode ( frag - > node ) ;
}
parent = frag_parent ( frag ) ;
if ( parent ) {
if ( frag_left ( parent ) = = frag )
parent - > rb . rb_left = NULL ;
2005-11-07 14:16:07 +03:00
else
2005-04-17 02:20:36 +04:00
parent - > rb . rb_right = NULL ;
}
jffs2_free_node_frag ( frag ) ;
frag = parent ;
cond_resched ( ) ;
}
}
2006-05-20 22:45:26 +04:00
2006-05-24 05:04:45 +04:00
struct jffs2_raw_node_ref * jffs2_link_node_ref ( struct jffs2_sb_info * c ,
struct jffs2_eraseblock * jeb ,
uint32_t ofs , uint32_t len ,
struct jffs2_inode_cache * ic )
2006-05-20 22:45:26 +04:00
{
2006-05-24 05:04:45 +04:00
struct jffs2_raw_node_ref * ref ;
2006-05-27 00:19:05 +04:00
BUG_ON ( ! jeb - > allocated_refs ) ;
jeb - > allocated_refs - - ;
ref = jeb - > last_node ;
dbg_noderef ( " Last node at %p is (%08x,%p) \n " , ref , ref - > flash_offset ,
ref - > next_in_ino ) ;
while ( ref - > flash_offset ! = REF_EMPTY_NODE ) {
if ( ref - > flash_offset = = REF_LINK_NODE )
ref = ref - > next_in_ino ;
else
ref + + ;
2006-05-24 05:04:45 +04:00
}
2006-05-27 00:19:05 +04:00
dbg_noderef ( " New ref is %p (%08x becomes %08x,%p) len 0x%x \n " , ref ,
ref - > flash_offset , ofs , ref - > next_in_ino , len ) ;
2006-05-24 05:04:45 +04:00
ref - > flash_offset = ofs ;
2006-05-27 00:19:05 +04:00
if ( ! jeb - > first_node ) {
2006-05-20 22:45:26 +04:00
jeb - > first_node = ref ;
2006-05-27 00:19:05 +04:00
BUG_ON ( ref_offset ( ref ) ! = jeb - > offset ) ;
} else if ( unlikely ( ref_offset ( ref ) ! = jeb - > offset + c - > sector_size - jeb - > free_size ) ) {
uint32_t last_len = ref_totlen ( c , jeb , jeb - > last_node ) ;
JFFS2_ERROR ( " Adding new ref %p at (0x%08x-0x%08x) not immediately after previous (0x%08x-0x%08x) \n " ,
ref , ref_offset ( ref ) , ref_offset ( ref ) + len ,
ref_offset ( jeb - > last_node ) ,
ref_offset ( jeb - > last_node ) + last_len ) ;
BUG ( ) ;
2006-05-21 16:29:11 +04:00
}
2006-05-20 22:45:26 +04:00
jeb - > last_node = ref ;
2006-05-22 18:23:10 +04:00
if ( ic ) {
ref - > next_in_ino = ic - > nodes ;
ic - > nodes = ref ;
} else {
ref - > next_in_ino = NULL ;
}
2006-05-20 22:45:26 +04:00
switch ( ref_flags ( ref ) ) {
case REF_UNCHECKED :
c - > unchecked_size + = len ;
jeb - > unchecked_size + = len ;
break ;
case REF_NORMAL :
case REF_PRISTINE :
c - > used_size + = len ;
jeb - > used_size + = len ;
break ;
case REF_OBSOLETE :
c - > dirty_size + = len ;
2006-05-22 15:15:47 +04:00
jeb - > dirty_size + = len ;
2006-05-20 22:45:26 +04:00
break ;
}
c - > free_size - = len ;
jeb - > free_size - = len ;
2006-05-21 16:29:11 +04:00
# ifdef TEST_TOTLEN
/* Set (and test) __totlen field... for now */
ref - > __totlen = len ;
ref_totlen ( c , jeb , ref ) ;
# endif
2006-05-24 05:04:45 +04:00
return ref ;
2006-05-20 22:45:26 +04:00
}
2006-05-21 06:46:05 +04:00
2006-05-24 05:04:45 +04:00
/* No locking, no reservation of 'ref'. Do not use on a live file system */
2006-05-21 06:46:05 +04:00
int jffs2_scan_dirty_space ( struct jffs2_sb_info * c , struct jffs2_eraseblock * jeb ,
uint32_t size )
{
2006-05-21 16:29:11 +04:00
if ( ! size )
return 0 ;
2006-05-27 00:19:05 +04:00
if ( unlikely ( size > jeb - > free_size ) ) {
printk ( KERN_CRIT " Dirty space 0x%x larger then free_size 0x%x (wasted 0x%x) \n " ,
size , jeb - > free_size , jeb - > wasted_size ) ;
2006-05-21 16:29:11 +04:00
BUG ( ) ;
}
2006-05-27 00:19:05 +04:00
/* REF_EMPTY_NODE is !obsolete, so that works OK */
2006-05-29 01:13:25 +04:00
if ( jeb - > last_node & & ref_obsolete ( jeb - > last_node ) ) {
2006-05-21 16:29:11 +04:00
# ifdef TEST_TOTLEN
jeb - > last_node - > __totlen + = size ;
# endif
c - > dirty_size + = size ;
c - > free_size - = size ;
jeb - > dirty_size + = size ;
jeb - > free_size - = size ;
} else {
2006-05-24 05:04:45 +04:00
uint32_t ofs = jeb - > offset + c - > sector_size - jeb - > free_size ;
ofs | = REF_OBSOLETE ;
2006-05-21 16:29:11 +04:00
2006-05-24 05:04:45 +04:00
jffs2_link_node_ref ( c , jeb , ofs , size , NULL ) ;
2006-05-21 16:29:11 +04:00
}
2006-05-21 06:46:05 +04:00
return 0 ;
}
2006-05-21 16:29:11 +04:00
/* Calculate totlen from surrounding nodes or eraseblock */
static inline uint32_t __ref_totlen ( struct jffs2_sb_info * c ,
struct jffs2_eraseblock * jeb ,
struct jffs2_raw_node_ref * ref )
{
uint32_t ref_end ;
2006-05-24 12:04:17 +04:00
struct jffs2_raw_node_ref * next_ref = ref_next ( ref ) ;
2006-05-21 16:29:11 +04:00
2006-05-24 12:04:17 +04:00
if ( next_ref )
ref_end = ref_offset ( next_ref ) ;
2006-05-21 16:29:11 +04:00
else {
if ( ! jeb )
jeb = & c - > blocks [ ref - > flash_offset / c - > sector_size ] ;
/* Last node in block. Use free_space */
2006-05-27 00:19:05 +04:00
if ( unlikely ( ref ! = jeb - > last_node ) ) {
2006-05-21 16:29:11 +04:00
printk ( KERN_CRIT " ref %p @0x%08x is not jeb->last_node (%p @0x%08x) \n " ,
ref , ref_offset ( ref ) , jeb - > last_node , jeb - > last_node ? ref_offset ( jeb - > last_node ) : 0 ) ;
BUG ( ) ;
}
ref_end = jeb - > offset + c - > sector_size - jeb - > free_size ;
}
return ref_end - ref_offset ( ref ) ;
}
uint32_t __jffs2_ref_totlen ( struct jffs2_sb_info * c , struct jffs2_eraseblock * jeb ,
struct jffs2_raw_node_ref * ref )
{
uint32_t ret ;
ret = __ref_totlen ( c , jeb , ref ) ;
2006-05-27 00:19:05 +04:00
2006-05-21 16:29:11 +04:00
# ifdef TEST_TOTLEN
2006-05-27 00:19:05 +04:00
if ( unlikely ( ret ! = ref - > __totlen ) ) {
if ( ! jeb )
jeb = & c - > blocks [ ref - > flash_offset / c - > sector_size ] ;
2006-05-21 16:29:11 +04:00
printk ( KERN_CRIT " Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x \n " ,
ref , ref_offset ( ref ) , ref_offset ( ref ) + ref - > __totlen ,
ret , ref - > __totlen ) ;
2006-05-24 12:04:17 +04:00
if ( ref_next ( ref ) ) {
printk ( KERN_CRIT " next %p (0x%08x-0x%08x) \n " , ref_next ( ref ) , ref_offset ( ref_next ( ref ) ) ,
ref_offset ( ref_next ( ref ) ) + ref - > __totlen ) ;
2006-05-21 16:29:11 +04:00
} else
2006-05-24 12:04:17 +04:00
printk ( KERN_CRIT " No next ref. jeb->last_node is %p \n " , jeb - > last_node ) ;
2006-05-21 16:29:11 +04:00
printk ( KERN_CRIT " jeb->wasted_size %x, dirty_size %x, used_size %x, free_size %x \n " , jeb - > wasted_size , jeb - > dirty_size , jeb - > used_size , jeb - > free_size ) ;
2006-05-27 00:19:05 +04:00
2006-05-21 16:29:11 +04:00
# if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS)
__jffs2_dbg_dump_node_refs_nolock ( c , jeb ) ;
# endif
2006-05-27 00:19:05 +04:00
2006-05-21 16:29:11 +04:00
WARN_ON ( 1 ) ;
2006-05-27 00:19:05 +04:00
ret = ref - > __totlen ;
2006-05-21 16:29:11 +04:00
}
# endif /* TEST_TOTLEN */
return ret ;
}