2005-09-07 12:35:26 +04:00
/*
* JFFS2 - - Journalling Flash File System , Version 2.
*
2007-04-25 17:16:47 +04:00
* Copyright © 2004 Ferenc Havasi < havasi @ inf . u - szeged . hu > ,
2007-07-10 13:01:22 +04:00
* Zoltan Sogor < weth @ inf . u - szeged . hu > ,
* Patrik Kluba < pajko @ halom . u - szeged . hu > ,
* University of Szeged , Hungary
* 2006 KaiGai Kohei < kaigai @ ak . jp . nec . com >
2005-09-07 12:35:26 +04:00
*
* For licensing information , see the file ' LICENCE ' in this directory .
*
*/
2012-02-16 03:56:45 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2005-09-07 12:35:26 +04:00
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/mtd/mtd.h>
# include <linux/pagemap.h>
# include <linux/crc32.h>
# include <linux/compiler.h>
# include <linux/vmalloc.h>
# include "nodelist.h"
# include "debug.h"
int jffs2_sum_init ( struct jffs2_sb_info * c )
{
2009-11-21 18:34:36 +03:00
uint32_t sum_size = min_t ( uint32_t , c - > sector_size , MAX_SUMMARY_SIZE ) ;
2008-08-01 13:07:51 +04:00
2006-12-05 02:03:01 +03:00
c - > summary = kzalloc ( sizeof ( struct jffs2_summary ) , GFP_KERNEL ) ;
2005-09-07 12:35:26 +04:00
if ( ! c - > summary ) {
JFFS2_WARNING ( " Can't allocate memory for summary information! \n " ) ;
return - ENOMEM ;
}
2008-08-01 13:07:51 +04:00
c - > summary - > sum_buf = kmalloc ( sum_size , GFP_KERNEL ) ;
2005-09-07 12:35:26 +04:00
if ( ! c - > summary - > sum_buf ) {
JFFS2_WARNING ( " Can't allocate buffer for writing out summary information! \n " ) ;
2005-09-22 15:25:00 +04:00
kfree ( c - > summary ) ;
2005-09-07 12:35:26 +04:00
return - ENOMEM ;
}
2006-06-26 20:35:02 +04:00
dbg_summary ( " returned successfully \n " ) ;
2005-09-07 12:35:26 +04:00
return 0 ;
}
void jffs2_sum_exit ( struct jffs2_sb_info * c )
{
2005-09-22 15:25:00 +04:00
dbg_summary ( " called \n " ) ;
2005-09-07 12:35:26 +04:00
jffs2_sum_disable_collecting ( c - > summary ) ;
2008-08-01 13:07:51 +04:00
kfree ( c - > summary - > sum_buf ) ;
2005-09-07 12:35:26 +04:00
c - > summary - > sum_buf = NULL ;
kfree ( c - > summary ) ;
c - > summary = NULL ;
}
static int jffs2_sum_add_mem ( struct jffs2_summary * s , union jffs2_sum_mem * item )
{
if ( ! s - > sum_list_head )
s - > sum_list_head = ( union jffs2_sum_mem * ) item ;
if ( s - > sum_list_tail )
s - > sum_list_tail - > u . next = ( union jffs2_sum_mem * ) item ;
s - > sum_list_tail = ( union jffs2_sum_mem * ) item ;
switch ( je16_to_cpu ( item - > u . nodetype ) ) {
case JFFS2_NODETYPE_INODE :
s - > sum_size + = JFFS2_SUMMARY_INODE_SIZE ;
s - > sum_num + + ;
2005-09-22 15:25:00 +04:00
dbg_summary ( " inode (%u) added to summary \n " ,
2005-09-07 12:35:26 +04:00
je32_to_cpu ( item - > i . inode ) ) ;
break ;
case JFFS2_NODETYPE_DIRENT :
s - > sum_size + = JFFS2_SUMMARY_DIRENT_SIZE ( item - > d . nsize ) ;
s - > sum_num + + ;
2005-09-22 15:25:00 +04:00
dbg_summary ( " dirent (%u) added to summary \n " ,
2005-09-07 12:35:26 +04:00
je32_to_cpu ( item - > d . ino ) ) ;
break ;
2006-05-13 10:09:47 +04:00
# ifdef CONFIG_JFFS2_FS_XATTR
case JFFS2_NODETYPE_XATTR :
s - > sum_size + = JFFS2_SUMMARY_XATTR_SIZE ;
s - > sum_num + + ;
dbg_summary ( " xattr (xid=%u, version=%u) added to summary \n " ,
je32_to_cpu ( item - > x . xid ) , je32_to_cpu ( item - > x . version ) ) ;
break ;
case JFFS2_NODETYPE_XREF :
s - > sum_size + = JFFS2_SUMMARY_XREF_SIZE ;
s - > sum_num + + ;
dbg_summary ( " xref added to summary \n " ) ;
break ;
# endif
2005-09-07 12:35:26 +04:00
default :
2005-11-07 14:16:07 +03:00
JFFS2_WARNING ( " UNKNOWN node type %u \n " ,
2005-09-07 12:35:26 +04:00
je16_to_cpu ( item - > u . nodetype ) ) ;
return 1 ;
}
return 0 ;
}
/* The following 3 functions are called from scan.c to collect summary info for not closed jeb */
int jffs2_sum_add_padding_mem ( struct jffs2_summary * s , uint32_t size )
{
2005-09-22 15:25:00 +04:00
dbg_summary ( " called with %u \n " , size ) ;
2005-09-07 12:35:26 +04:00
s - > sum_padded + = size ;
return 0 ;
}
int jffs2_sum_add_inode_mem ( struct jffs2_summary * s , struct jffs2_raw_inode * ri ,
uint32_t ofs )
{
struct jffs2_sum_inode_mem * temp = kmalloc ( sizeof ( struct jffs2_sum_inode_mem ) , GFP_KERNEL ) ;
if ( ! temp )
return - ENOMEM ;
temp - > nodetype = ri - > nodetype ;
temp - > inode = ri - > ino ;
temp - > version = ri - > version ;
2011-03-31 05:57:33 +04:00
temp - > offset = cpu_to_je32 ( ofs ) ; /* relative offset from the beginning of the jeb */
2005-09-07 12:35:26 +04:00
temp - > totlen = ri - > totlen ;
temp - > next = NULL ;
return jffs2_sum_add_mem ( s , ( union jffs2_sum_mem * ) temp ) ;
}
int jffs2_sum_add_dirent_mem ( struct jffs2_summary * s , struct jffs2_raw_dirent * rd ,
uint32_t ofs )
{
struct jffs2_sum_dirent_mem * temp =
kmalloc ( sizeof ( struct jffs2_sum_dirent_mem ) + rd - > nsize , GFP_KERNEL ) ;
if ( ! temp )
return - ENOMEM ;
temp - > nodetype = rd - > nodetype ;
temp - > totlen = rd - > totlen ;
2011-03-31 05:57:33 +04:00
temp - > offset = cpu_to_je32 ( ofs ) ; /* relative from the beginning of the jeb */
2005-09-07 12:35:26 +04:00
temp - > pino = rd - > pino ;
temp - > version = rd - > version ;
temp - > ino = rd - > ino ;
temp - > nsize = rd - > nsize ;
temp - > type = rd - > type ;
temp - > next = NULL ;
memcpy ( temp - > name , rd - > name , rd - > nsize ) ;
return jffs2_sum_add_mem ( s , ( union jffs2_sum_mem * ) temp ) ;
}
2006-05-13 10:09:47 +04:00
# ifdef CONFIG_JFFS2_FS_XATTR
int jffs2_sum_add_xattr_mem ( struct jffs2_summary * s , struct jffs2_raw_xattr * rx , uint32_t ofs )
{
struct jffs2_sum_xattr_mem * temp ;
temp = kmalloc ( sizeof ( struct jffs2_sum_xattr_mem ) , GFP_KERNEL ) ;
if ( ! temp )
return - ENOMEM ;
temp - > nodetype = rx - > nodetype ;
temp - > xid = rx - > xid ;
temp - > version = rx - > version ;
temp - > offset = cpu_to_je32 ( ofs ) ;
temp - > totlen = rx - > totlen ;
temp - > next = NULL ;
return jffs2_sum_add_mem ( s , ( union jffs2_sum_mem * ) temp ) ;
}
int jffs2_sum_add_xref_mem ( struct jffs2_summary * s , struct jffs2_raw_xref * rr , uint32_t ofs )
{
struct jffs2_sum_xref_mem * temp ;
temp = kmalloc ( sizeof ( struct jffs2_sum_xref_mem ) , GFP_KERNEL ) ;
if ( ! temp )
return - ENOMEM ;
temp - > nodetype = rr - > nodetype ;
temp - > offset = cpu_to_je32 ( ofs ) ;
temp - > next = NULL ;
return jffs2_sum_add_mem ( s , ( union jffs2_sum_mem * ) temp ) ;
}
# endif
2005-09-07 12:35:26 +04:00
/* Cleanup every collected summary information */
static void jffs2_sum_clean_collected ( struct jffs2_summary * s )
{
union jffs2_sum_mem * temp ;
if ( ! s - > sum_list_head ) {
2005-09-22 15:25:00 +04:00
dbg_summary ( " already empty \n " ) ;
2005-09-07 12:35:26 +04:00
}
while ( s - > sum_list_head ) {
temp = s - > sum_list_head ;
s - > sum_list_head = s - > sum_list_head - > u . next ;
kfree ( temp ) ;
}
s - > sum_list_tail = NULL ;
s - > sum_padded = 0 ;
s - > sum_num = 0 ;
}
void jffs2_sum_reset_collected ( struct jffs2_summary * s )
{
2005-09-22 15:25:00 +04:00
dbg_summary ( " called \n " ) ;
2005-09-07 12:35:26 +04:00
jffs2_sum_clean_collected ( s ) ;
s - > sum_size = 0 ;
}
void jffs2_sum_disable_collecting ( struct jffs2_summary * s )
{
2005-09-22 15:25:00 +04:00
dbg_summary ( " called \n " ) ;
2005-09-07 12:35:26 +04:00
jffs2_sum_clean_collected ( s ) ;
s - > sum_size = JFFS2_SUMMARY_NOSUM_SIZE ;
}
2005-11-07 14:16:07 +03:00
int jffs2_sum_is_disabled ( struct jffs2_summary * s )
2005-09-07 12:35:26 +04:00
{
return ( s - > sum_size = = JFFS2_SUMMARY_NOSUM_SIZE ) ;
}
/* Move the collected summary information into sb (called from scan.c) */
void jffs2_sum_move_collected ( struct jffs2_sb_info * c , struct jffs2_summary * s )
{
2005-09-22 15:25:00 +04:00
dbg_summary ( " oldsize=0x%x oldnum=%u => newsize=0x%x newnum=%u \n " ,
2005-09-07 12:35:26 +04:00
c - > summary - > sum_size , c - > summary - > sum_num ,
s - > sum_size , s - > sum_num ) ;
c - > summary - > sum_size = s - > sum_size ;
c - > summary - > sum_num = s - > sum_num ;
c - > summary - > sum_padded = s - > sum_padded ;
c - > summary - > sum_list_head = s - > sum_list_head ;
c - > summary - > sum_list_tail = s - > sum_list_tail ;
s - > sum_list_head = s - > sum_list_tail = NULL ;
}
/* Called from wbuf.c to collect writed node info */
int jffs2_sum_add_kvec ( struct jffs2_sb_info * c , const struct kvec * invecs ,
unsigned long count , uint32_t ofs )
{
union jffs2_node_union * node ;
struct jffs2_eraseblock * jeb ;
2006-09-16 23:15:59 +04:00
if ( c - > summary - > sum_size = = JFFS2_SUMMARY_NOSUM_SIZE ) {
dbg_summary ( " Summary is disabled for this jeb! Skipping summary info! \n " ) ;
return 0 ;
}
2005-09-07 12:35:26 +04:00
node = invecs [ 0 ] . iov_base ;
jeb = & c - > blocks [ ofs / c - > sector_size ] ;
ofs - = jeb - > offset ;
switch ( je16_to_cpu ( node - > u . nodetype ) ) {
case JFFS2_NODETYPE_INODE : {
struct jffs2_sum_inode_mem * temp =
kmalloc ( sizeof ( struct jffs2_sum_inode_mem ) , GFP_KERNEL ) ;
if ( ! temp )
goto no_mem ;
temp - > nodetype = node - > i . nodetype ;
temp - > inode = node - > i . ino ;
temp - > version = node - > i . version ;
temp - > offset = cpu_to_je32 ( ofs ) ;
temp - > totlen = node - > i . totlen ;
temp - > next = NULL ;
return jffs2_sum_add_mem ( c - > summary , ( union jffs2_sum_mem * ) temp ) ;
}
case JFFS2_NODETYPE_DIRENT : {
struct jffs2_sum_dirent_mem * temp =
kmalloc ( sizeof ( struct jffs2_sum_dirent_mem ) + node - > d . nsize , GFP_KERNEL ) ;
if ( ! temp )
goto no_mem ;
temp - > nodetype = node - > d . nodetype ;
temp - > totlen = node - > d . totlen ;
temp - > offset = cpu_to_je32 ( ofs ) ;
temp - > pino = node - > d . pino ;
temp - > version = node - > d . version ;
temp - > ino = node - > d . ino ;
temp - > nsize = node - > d . nsize ;
temp - > type = node - > d . type ;
temp - > next = NULL ;
switch ( count ) {
case 1 :
memcpy ( temp - > name , node - > d . name , node - > d . nsize ) ;
break ;
case 2 :
memcpy ( temp - > name , invecs [ 1 ] . iov_base , node - > d . nsize ) ;
break ;
default :
BUG ( ) ; /* impossible count value */
break ;
}
return jffs2_sum_add_mem ( c - > summary , ( union jffs2_sum_mem * ) temp ) ;
}
2006-05-13 10:09:47 +04:00
# ifdef CONFIG_JFFS2_FS_XATTR
case JFFS2_NODETYPE_XATTR : {
struct jffs2_sum_xattr_mem * temp ;
temp = kmalloc ( sizeof ( struct jffs2_sum_xattr_mem ) , GFP_KERNEL ) ;
if ( ! temp )
goto no_mem ;
2005-09-07 12:35:26 +04:00
2006-05-13 10:09:47 +04:00
temp - > nodetype = node - > x . nodetype ;
temp - > xid = node - > x . xid ;
temp - > version = node - > x . version ;
temp - > totlen = node - > x . totlen ;
temp - > offset = cpu_to_je32 ( ofs ) ;
temp - > next = NULL ;
return jffs2_sum_add_mem ( c - > summary , ( union jffs2_sum_mem * ) temp ) ;
}
case JFFS2_NODETYPE_XREF : {
struct jffs2_sum_xref_mem * temp ;
temp = kmalloc ( sizeof ( struct jffs2_sum_xref_mem ) , GFP_KERNEL ) ;
if ( ! temp )
goto no_mem ;
temp - > nodetype = node - > r . nodetype ;
temp - > offset = cpu_to_je32 ( ofs ) ;
temp - > next = NULL ;
return jffs2_sum_add_mem ( c - > summary , ( union jffs2_sum_mem * ) temp ) ;
}
# endif
2005-09-07 12:35:26 +04:00
case JFFS2_NODETYPE_PADDING :
2005-09-22 15:25:00 +04:00
dbg_summary ( " node PADDING \n " ) ;
2005-09-07 12:35:26 +04:00
c - > summary - > sum_padded + = je32_to_cpu ( node - > u . totlen ) ;
break ;
case JFFS2_NODETYPE_CLEANMARKER :
2005-09-22 15:25:00 +04:00
dbg_summary ( " node CLEANMARKER \n " ) ;
2005-09-07 12:35:26 +04:00
break ;
case JFFS2_NODETYPE_SUMMARY :
2005-09-22 15:25:00 +04:00
dbg_summary ( " node SUMMARY \n " ) ;
2005-09-07 12:35:26 +04:00
break ;
default :
/* If you implement a new node type you should also implement
summary support for it or disable summary .
*/
BUG ( ) ;
break ;
}
return 0 ;
no_mem :
JFFS2_WARNING ( " MEMORY ALLOCATION ERROR! " ) ;
return - ENOMEM ;
}
2006-05-24 05:04:45 +04:00
static struct jffs2_raw_node_ref * sum_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-21 07:00:01 +04:00
{
/* If there was a gap, mark it dirty */
2006-05-24 05:04:45 +04:00
if ( ( ofs & ~ 3 ) > c - > sector_size - jeb - > free_size ) {
/* Ew. Summary doesn't actually tell us explicitly about dirty space */
jffs2_scan_dirty_space ( c , jeb , ( ofs & ~ 3 ) - ( c - > sector_size - jeb - > free_size ) ) ;
2006-05-21 07:00:01 +04:00
}
2006-05-24 05:04:45 +04:00
return jffs2_link_node_ref ( c , jeb , jeb - > offset + ofs , len , ic ) ;
2006-05-21 07:00:01 +04:00
}
2005-09-07 12:35:26 +04:00
/* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */
static int jffs2_sum_process_sum_data ( struct jffs2_sb_info * c , struct jffs2_eraseblock * jeb ,
2005-09-26 15:37:25 +04:00
struct jffs2_raw_summary * summary , uint32_t * pseudo_random )
2005-09-07 12:35:26 +04:00
{
struct jffs2_inode_cache * ic ;
struct jffs2_full_dirent * fd ;
void * sp ;
int i , ino ;
2006-05-21 06:46:05 +04:00
int err ;
2005-09-07 12:35:26 +04:00
sp = summary - > sum ;
for ( i = 0 ; i < je32_to_cpu ( summary - > sum_num ) ; i + + ) {
2005-09-22 15:25:00 +04:00
dbg_summary ( " processing summary index %d \n " , i ) ;
2005-09-07 12:35:26 +04:00
2006-12-28 13:01:41 +03:00
cond_resched ( ) ;
2006-05-24 05:04:45 +04:00
/* Make sure there's a spare ref for dirty space */
2006-05-25 04:50:35 +04:00
err = jffs2_prealloc_raw_node_refs ( c , jeb , 2 ) ;
2006-05-24 05:04:45 +04:00
if ( err )
return err ;
2005-09-07 12:35:26 +04:00
switch ( je16_to_cpu ( ( ( struct jffs2_sum_unknown_flash * ) sp ) - > nodetype ) ) {
case JFFS2_NODETYPE_INODE : {
struct jffs2_sum_inode_flash * spi ;
spi = sp ;
ino = je32_to_cpu ( spi - > inode ) ;
2006-05-21 16:13:45 +04:00
dbg_summary ( " Inode at 0x%08x-0x%08x \n " ,
jeb - > offset + je32_to_cpu ( spi - > offset ) ,
2006-05-25 04:53:09 +04:00
jeb - > offset + je32_to_cpu ( spi - > offset ) + je32_to_cpu ( spi - > totlen ) ) ;
2005-09-07 12:35:26 +04:00
ic = jffs2_scan_make_ino_cache ( c , ino ) ;
if ( ! ic ) {
JFFS2_NOTICE ( " scan_make_ino_cache failed \n " ) ;
return - ENOMEM ;
}
2006-05-24 05:04:45 +04:00
sum_link_node_ref ( c , jeb , je32_to_cpu ( spi - > offset ) | REF_UNCHECKED ,
PAD ( je32_to_cpu ( spi - > totlen ) ) , ic ) ;
2006-05-20 22:45:26 +04:00
* pseudo_random + = je32_to_cpu ( spi - > version ) ;
2005-09-07 12:35:26 +04:00
sp + = JFFS2_SUMMARY_INODE_SIZE ;
break ;
}
case JFFS2_NODETYPE_DIRENT : {
struct jffs2_sum_dirent_flash * spd ;
2007-10-13 14:35:58 +04:00
int checkedlen ;
2005-09-07 12:35:26 +04:00
spd = sp ;
2006-05-25 04:53:09 +04:00
dbg_summary ( " Dirent at 0x%08x-0x%08x \n " ,
2006-05-21 16:13:45 +04:00
jeb - > offset + je32_to_cpu ( spd - > offset ) ,
jeb - > offset + je32_to_cpu ( spd - > offset ) + je32_to_cpu ( spd - > totlen ) ) ;
2005-09-07 12:35:26 +04:00
2007-10-13 14:35:58 +04:00
/* This should never happen, but https://dev.laptop.org/ticket/4184 */
checkedlen = strnlen ( spd - > name , spd - > nsize ) ;
if ( ! checkedlen ) {
2012-02-16 03:56:44 +04:00
pr_err ( " Dirent at %08x has zero at start of name. Aborting mount. \n " ,
jeb - > offset +
je32_to_cpu ( spd - > offset ) ) ;
2007-10-13 14:35:58 +04:00
return - EIO ;
}
if ( checkedlen < spd - > nsize ) {
2012-02-16 03:56:44 +04:00
pr_err ( " Dirent at %08x has zeroes in name. Truncating to %d chars \n " ,
jeb - > offset +
je32_to_cpu ( spd - > offset ) ,
checkedlen ) ;
2007-10-13 14:35:58 +04:00
}
fd = jffs2_alloc_full_dirent ( checkedlen + 1 ) ;
2006-05-20 19:13:34 +04:00
if ( ! fd )
2005-09-07 12:35:26 +04:00
return - ENOMEM ;
2007-10-13 14:35:58 +04:00
memcpy ( & fd - > name , spd - > name , checkedlen ) ;
fd - > name [ checkedlen ] = 0 ;
2005-09-07 12:35:26 +04:00
ic = jffs2_scan_make_ino_cache ( c , je32_to_cpu ( spd - > pino ) ) ;
if ( ! ic ) {
jffs2_free_full_dirent ( fd ) ;
return - ENOMEM ;
}
2006-06-19 01:44:21 +04:00
fd - > raw = sum_link_node_ref ( c , jeb , je32_to_cpu ( spd - > offset ) | REF_UNCHECKED ,
2006-05-24 05:04:45 +04:00
PAD ( je32_to_cpu ( spd - > totlen ) ) , ic ) ;
2005-09-07 12:35:26 +04:00
fd - > next = NULL ;
fd - > version = je32_to_cpu ( spd - > version ) ;
fd - > ino = je32_to_cpu ( spd - > ino ) ;
2016-06-10 17:51:30 +03:00
fd - > nhash = full_name_hash ( NULL , fd - > name , checkedlen ) ;
2005-09-07 12:35:26 +04:00
fd - > type = spd - > type ;
2006-05-20 22:45:26 +04:00
2005-09-07 12:35:26 +04:00
jffs2_add_fd_to_list ( c , fd , & ic - > scan_dents ) ;
* pseudo_random + = je32_to_cpu ( spd - > version ) ;
sp + = JFFS2_SUMMARY_DIRENT_SIZE ( spd - > nsize ) ;
break ;
}
2006-05-13 10:09:47 +04:00
# ifdef CONFIG_JFFS2_FS_XATTR
case JFFS2_NODETYPE_XATTR : {
struct jffs2_xattr_datum * xd ;
struct jffs2_sum_xattr_flash * spx ;
spx = ( struct jffs2_sum_xattr_flash * ) sp ;
2006-05-21 16:13:45 +04:00
dbg_summary ( " xattr at %#08x-%#08x (xid=%u, version=%u) \n " ,
2006-05-21 07:00:01 +04:00
jeb - > offset + je32_to_cpu ( spx - > offset ) ,
2006-05-21 16:13:45 +04:00
jeb - > offset + je32_to_cpu ( spx - > offset ) + je32_to_cpu ( spx - > totlen ) ,
2006-05-13 10:09:47 +04:00
je32_to_cpu ( spx - > xid ) , je32_to_cpu ( spx - > version ) ) ;
2006-05-24 05:04:45 +04:00
2006-05-13 10:09:47 +04:00
xd = jffs2_setup_xattr_datum ( c , je32_to_cpu ( spx - > xid ) ,
je32_to_cpu ( spx - > version ) ) ;
2006-06-11 05:35:15 +04:00
if ( IS_ERR ( xd ) )
2006-05-13 10:09:47 +04:00
return PTR_ERR ( xd ) ;
2006-06-11 05:35:15 +04:00
if ( xd - > version > je32_to_cpu ( spx - > version ) ) {
/* node is not the newest one */
struct jffs2_raw_node_ref * raw
= sum_link_node_ref ( c , jeb , je32_to_cpu ( spx - > offset ) | REF_UNCHECKED ,
PAD ( je32_to_cpu ( spx - > totlen ) ) , NULL ) ;
raw - > next_in_ino = xd - > node - > next_in_ino ;
xd - > node - > next_in_ino = raw ;
} else {
xd - > version = je32_to_cpu ( spx - > version ) ;
sum_link_node_ref ( c , jeb , je32_to_cpu ( spx - > offset ) | REF_UNCHECKED ,
PAD ( je32_to_cpu ( spx - > totlen ) ) , ( void * ) xd ) ;
2006-05-13 10:09:47 +04:00
}
* pseudo_random + = je32_to_cpu ( spx - > xid ) ;
sp + = JFFS2_SUMMARY_XATTR_SIZE ;
break ;
}
case JFFS2_NODETYPE_XREF : {
struct jffs2_xattr_ref * ref ;
struct jffs2_sum_xref_flash * spr ;
spr = ( struct jffs2_sum_xref_flash * ) sp ;
2006-05-21 16:13:45 +04:00
dbg_summary ( " xref at %#08x-%#08x \n " ,
2006-05-21 07:00:01 +04:00
jeb - > offset + je32_to_cpu ( spr - > offset ) ,
2006-05-27 00:19:05 +04:00
jeb - > offset + je32_to_cpu ( spr - > offset ) +
( uint32_t ) PAD ( sizeof ( struct jffs2_raw_xref ) ) ) ;
2006-05-21 16:13:45 +04:00
2006-05-13 10:09:47 +04:00
ref = jffs2_alloc_xattr_ref ( ) ;
if ( ! ref ) {
JFFS2_NOTICE ( " allocation of xattr_datum failed \n " ) ;
return - ENOMEM ;
}
2006-05-13 10:15:07 +04:00
ref - > next = c - > xref_temp ;
c - > xref_temp = ref ;
2006-05-13 10:09:47 +04:00
2006-06-11 05:35:15 +04:00
sum_link_node_ref ( c , jeb , je32_to_cpu ( spr - > offset ) | REF_UNCHECKED ,
PAD ( sizeof ( struct jffs2_raw_xref ) ) , ( void * ) ref ) ;
2006-05-13 10:09:47 +04:00
2006-05-24 05:04:45 +04:00
* pseudo_random + = ref - > node - > flash_offset ;
2006-05-13 10:09:47 +04:00
sp + = JFFS2_SUMMARY_XREF_SIZE ;
2005-09-07 12:35:26 +04:00
2006-05-13 10:09:47 +04:00
break ;
}
# endif
2005-09-07 12:35:26 +04:00
default : {
2006-05-21 06:45:27 +04:00
uint16_t nodetype = je16_to_cpu ( ( ( struct jffs2_sum_unknown_flash * ) sp ) - > nodetype ) ;
JFFS2_WARNING ( " Unsupported node type %x found in summary! Exiting... \n " , nodetype ) ;
if ( ( nodetype & JFFS2_COMPAT_MASK ) = = JFFS2_FEATURE_INCOMPAT )
return - EIO ;
/* For compatible node types, just fall back to the full scan */
c - > wasted_size - = jeb - > wasted_size ;
c - > free_size + = c - > sector_size - jeb - > free_size ;
c - > used_size - = jeb - > used_size ;
c - > dirty_size - = jeb - > dirty_size ;
jeb - > wasted_size = jeb - > used_size = jeb - > dirty_size = 0 ;
jeb - > free_size = c - > sector_size ;
2006-05-25 04:38:27 +04:00
jffs2_free_jeb_node_refs ( c , jeb ) ;
2006-05-21 06:45:27 +04:00
return - ENOTRECOVERABLE ;
2005-09-07 12:35:26 +04:00
}
}
}
return 0 ;
}
/* Process the summary node - called from jffs2_scan_eraseblock() */
int jffs2_sum_scan_sumnode ( struct jffs2_sb_info * c , struct jffs2_eraseblock * jeb ,
2006-05-20 19:13:34 +04:00
struct jffs2_raw_summary * summary , uint32_t sumsize ,
uint32_t * pseudo_random )
2005-09-07 12:35:26 +04:00
{
struct jffs2_unknown_node crcnode ;
2006-05-20 19:13:34 +04:00
int ret , ofs ;
2005-09-07 12:35:26 +04:00
uint32_t crc ;
2006-05-21 07:00:01 +04:00
ofs = c - > sector_size - sumsize ;
2005-09-07 12:35:26 +04:00
2005-09-22 15:25:00 +04:00
dbg_summary ( " summary found for 0x%08x at 0x%08x (0x%x bytes) \n " ,
2006-05-21 07:00:01 +04:00
jeb - > offset , jeb - > offset + ofs , sumsize ) ;
2005-09-07 12:35:26 +04:00
/* OK, now check for node validity and CRC */
crcnode . magic = cpu_to_je16 ( JFFS2_MAGIC_BITMASK ) ;
crcnode . nodetype = cpu_to_je16 ( JFFS2_NODETYPE_SUMMARY ) ;
crcnode . totlen = summary - > totlen ;
crc = crc32 ( 0 , & crcnode , sizeof ( crcnode ) - 4 ) ;
if ( je32_to_cpu ( summary - > hdr_crc ) ! = crc ) {
2005-09-22 15:25:00 +04:00
dbg_summary ( " Summary node header is corrupt (bad CRC or "
2005-09-07 12:35:26 +04:00
" no summary at all) \n " ) ;
goto crc_err ;
}
if ( je32_to_cpu ( summary - > totlen ) ! = sumsize ) {
2005-09-22 15:25:00 +04:00
dbg_summary ( " Summary node is corrupt (wrong erasesize?) \n " ) ;
2005-09-07 12:35:26 +04:00
goto crc_err ;
}
2005-09-26 15:37:25 +04:00
crc = crc32 ( 0 , summary , sizeof ( struct jffs2_raw_summary ) - 8 ) ;
2005-09-07 12:35:26 +04:00
if ( je32_to_cpu ( summary - > node_crc ) ! = crc ) {
2005-09-22 15:25:00 +04:00
dbg_summary ( " Summary node is corrupt (bad CRC) \n " ) ;
2005-09-07 12:35:26 +04:00
goto crc_err ;
}
2005-09-26 15:37:25 +04:00
crc = crc32 ( 0 , summary - > sum , sumsize - sizeof ( struct jffs2_raw_summary ) ) ;
2005-09-07 12:35:26 +04:00
if ( je32_to_cpu ( summary - > sum_crc ) ! = crc ) {
2005-09-22 15:25:00 +04:00
dbg_summary ( " Summary node data is corrupt (bad CRC) \n " ) ;
2005-09-07 12:35:26 +04:00
goto crc_err ;
}
if ( je32_to_cpu ( summary - > cln_mkr ) ) {
2005-09-22 15:25:00 +04:00
dbg_summary ( " Summary : CLEANMARKER node \n " ) ;
2005-09-07 12:35:26 +04:00
2006-05-30 12:00:14 +04:00
ret = jffs2_prealloc_raw_node_refs ( c , jeb , 1 ) ;
if ( ret )
return ret ;
2005-09-07 12:35:26 +04:00
if ( je32_to_cpu ( summary - > cln_mkr ) ! = c - > cleanmarker_size ) {
2005-09-22 15:25:00 +04:00
dbg_summary ( " CLEANMARKER node has totlen 0x%x != normal 0x%x \n " ,
2005-09-07 12:35:26 +04:00
je32_to_cpu ( summary - > cln_mkr ) , c - > cleanmarker_size ) ;
2006-05-30 12:00:14 +04:00
if ( ( ret = jffs2_scan_dirty_space ( c , jeb , PAD ( je32_to_cpu ( summary - > cln_mkr ) ) ) ) )
return ret ;
2005-09-07 12:35:26 +04:00
} else if ( jeb - > first_node ) {
2005-09-22 15:25:00 +04:00
dbg_summary ( " CLEANMARKER node not first node in block "
2005-09-07 12:35:26 +04:00
" (0x%08x) \n " , jeb - > offset ) ;
2006-05-30 12:00:14 +04:00
if ( ( ret = jffs2_scan_dirty_space ( c , jeb , PAD ( je32_to_cpu ( summary - > cln_mkr ) ) ) ) )
return ret ;
2005-09-07 12:35:26 +04:00
} else {
2006-05-24 05:04:45 +04:00
jffs2_link_node_ref ( c , jeb , jeb - > offset | REF_NORMAL ,
je32_to_cpu ( summary - > cln_mkr ) , NULL ) ;
2005-09-07 12:35:26 +04:00
}
}
ret = jffs2_sum_process_sum_data ( c , jeb , summary , pseudo_random ) ;
2006-05-21 06:45:27 +04:00
/* -ENOTRECOVERABLE isn't a fatal error -- it means we should do a full
scan of this eraseblock . So return zero */
if ( ret = = - ENOTRECOVERABLE )
return 0 ;
2005-09-07 12:35:26 +04:00
if ( ret )
2006-05-21 06:45:27 +04:00
return ret ; /* real error */
2005-09-07 12:35:26 +04:00
/* for PARANOIA_CHECK */
2006-05-25 04:50:35 +04:00
ret = jffs2_prealloc_raw_node_refs ( c , jeb , 2 ) ;
2006-05-24 05:04:45 +04:00
if ( ret )
return ret ;
2005-09-07 12:35:26 +04:00
2006-05-25 04:42:40 +04:00
sum_link_node_ref ( c , jeb , ofs | REF_NORMAL , sumsize , NULL ) ;
2005-09-07 12:35:26 +04:00
2006-05-21 07:00:01 +04:00
if ( unlikely ( jeb - > free_size ) ) {
JFFS2_WARNING ( " Free size 0x%x bytes in eraseblock @0x%08x with summary? \n " ,
jeb - > free_size , jeb - > offset ) ;
jeb - > wasted_size + = jeb - > free_size ;
c - > wasted_size + = jeb - > free_size ;
c - > free_size - = jeb - > free_size ;
jeb - > free_size = 0 ;
}
2005-09-07 12:35:26 +04:00
return jffs2_scan_classify_jeb ( c , jeb ) ;
crc_err :
JFFS2_WARNING ( " Summary node crc error, skipping summary information. \n " ) ;
return 0 ;
}
/* Write summary data to flash - helper function for jffs2_sum_write_sumnode() */
static int jffs2_sum_write_data ( struct jffs2_sb_info * c , struct jffs2_eraseblock * jeb ,
2008-08-01 13:07:51 +04:00
uint32_t infosize , uint32_t datasize , int padsize )
2005-09-07 12:35:26 +04:00
{
2005-09-26 15:37:25 +04:00
struct jffs2_raw_summary isum ;
2005-09-07 12:35:26 +04:00
union jffs2_sum_mem * temp ;
struct jffs2_sum_marker * sm ;
struct kvec vecs [ 2 ] ;
2006-05-24 05:04:45 +04:00
uint32_t sum_ofs ;
2005-09-07 12:35:26 +04:00
void * wpage ;
int ret ;
size_t retlen ;
2008-08-01 13:07:51 +04:00
if ( padsize + datasize > MAX_SUMMARY_SIZE ) {
/* It won't fit in the buffer. Abort summary for this jeb */
jffs2_sum_disable_collecting ( c - > summary ) ;
JFFS2_WARNING ( " Summary too big (%d data, %d pad) in eraseblock at %08x \n " ,
datasize , padsize , jeb - > offset ) ;
/* Non-fatal */
return 0 ;
}
/* Is there enough space for summary? */
if ( padsize < 0 ) {
/* don't try to write out summary for this jeb */
jffs2_sum_disable_collecting ( c - > summary ) ;
JFFS2_WARNING ( " Not enough space for summary, padsize = %d \n " ,
padsize ) ;
/* Non-fatal */
return 0 ;
}
2005-09-07 12:35:26 +04:00
memset ( c - > summary - > sum_buf , 0xff , datasize ) ;
memset ( & isum , 0 , sizeof ( isum ) ) ;
isum . magic = cpu_to_je16 ( JFFS2_MAGIC_BITMASK ) ;
isum . nodetype = cpu_to_je16 ( JFFS2_NODETYPE_SUMMARY ) ;
isum . totlen = cpu_to_je32 ( infosize ) ;
isum . hdr_crc = cpu_to_je32 ( crc32 ( 0 , & isum , sizeof ( struct jffs2_unknown_node ) - 4 ) ) ;
isum . padded = cpu_to_je32 ( c - > summary - > sum_padded ) ;
isum . cln_mkr = cpu_to_je32 ( c - > cleanmarker_size ) ;
isum . sum_num = cpu_to_je32 ( c - > summary - > sum_num ) ;
wpage = c - > summary - > sum_buf ;
while ( c - > summary - > sum_num ) {
2006-05-12 14:55:51 +04:00
temp = c - > summary - > sum_list_head ;
2005-09-07 12:35:26 +04:00
2006-05-12 14:55:51 +04:00
switch ( je16_to_cpu ( temp - > u . nodetype ) ) {
2005-09-07 12:35:26 +04:00
case JFFS2_NODETYPE_INODE : {
struct jffs2_sum_inode_flash * sino_ptr = wpage ;
2006-05-12 14:55:51 +04:00
sino_ptr - > nodetype = temp - > i . nodetype ;
sino_ptr - > inode = temp - > i . inode ;
sino_ptr - > version = temp - > i . version ;
sino_ptr - > offset = temp - > i . offset ;
sino_ptr - > totlen = temp - > i . totlen ;
2005-09-07 12:35:26 +04:00
wpage + = JFFS2_SUMMARY_INODE_SIZE ;
break ;
}
case JFFS2_NODETYPE_DIRENT : {
struct jffs2_sum_dirent_flash * sdrnt_ptr = wpage ;
2006-05-12 14:55:51 +04:00
sdrnt_ptr - > nodetype = temp - > d . nodetype ;
sdrnt_ptr - > totlen = temp - > d . totlen ;
sdrnt_ptr - > offset = temp - > d . offset ;
sdrnt_ptr - > pino = temp - > d . pino ;
sdrnt_ptr - > version = temp - > d . version ;
sdrnt_ptr - > ino = temp - > d . ino ;
sdrnt_ptr - > nsize = temp - > d . nsize ;
sdrnt_ptr - > type = temp - > d . type ;
2005-09-07 12:35:26 +04:00
2006-05-12 14:55:51 +04:00
memcpy ( sdrnt_ptr - > name , temp - > d . name ,
temp - > d . nsize ) ;
2005-09-07 12:35:26 +04:00
2006-05-12 14:55:51 +04:00
wpage + = JFFS2_SUMMARY_DIRENT_SIZE ( temp - > d . nsize ) ;
2005-09-07 12:35:26 +04:00
break ;
}
2006-05-13 10:09:47 +04:00
# ifdef CONFIG_JFFS2_FS_XATTR
case JFFS2_NODETYPE_XATTR : {
struct jffs2_sum_xattr_flash * sxattr_ptr = wpage ;
temp = c - > summary - > sum_list_head ;
sxattr_ptr - > nodetype = temp - > x . nodetype ;
sxattr_ptr - > xid = temp - > x . xid ;
sxattr_ptr - > version = temp - > x . version ;
sxattr_ptr - > offset = temp - > x . offset ;
sxattr_ptr - > totlen = temp - > x . totlen ;
wpage + = JFFS2_SUMMARY_XATTR_SIZE ;
break ;
}
case JFFS2_NODETYPE_XREF : {
struct jffs2_sum_xref_flash * sxref_ptr = wpage ;
temp = c - > summary - > sum_list_head ;
sxref_ptr - > nodetype = temp - > r . nodetype ;
sxref_ptr - > offset = temp - > r . offset ;
2005-09-07 12:35:26 +04:00
2006-05-13 10:09:47 +04:00
wpage + = JFFS2_SUMMARY_XREF_SIZE ;
break ;
}
# endif
2005-09-07 12:35:26 +04:00
default : {
2006-05-21 03:02:06 +04:00
if ( ( je16_to_cpu ( temp - > u . nodetype ) & JFFS2_COMPAT_MASK )
= = JFFS2_FEATURE_RWCOMPAT_COPY ) {
dbg_summary ( " Writing unknown RWCOMPAT_COPY node type %x \n " ,
je16_to_cpu ( temp - > u . nodetype ) ) ;
jffs2_sum_disable_collecting ( c - > summary ) ;
} else {
BUG ( ) ; /* unknown node in summary information */
}
2005-09-07 12:35:26 +04:00
}
}
2006-05-12 14:55:51 +04:00
c - > summary - > sum_list_head = temp - > u . next ;
2005-09-07 12:35:26 +04:00
kfree ( temp ) ;
c - > summary - > sum_num - - ;
}
jffs2_sum_reset_collected ( c - > summary ) ;
wpage + = padsize ;
sm = wpage ;
sm - > offset = cpu_to_je32 ( c - > sector_size - jeb - > free_size ) ;
sm - > magic = cpu_to_je32 ( JFFS2_SUM_MAGIC ) ;
isum . sum_crc = cpu_to_je32 ( crc32 ( 0 , c - > summary - > sum_buf , datasize ) ) ;
isum . node_crc = cpu_to_je32 ( crc32 ( 0 , & isum , sizeof ( isum ) - 8 ) ) ;
vecs [ 0 ] . iov_base = & isum ;
vecs [ 0 ] . iov_len = sizeof ( isum ) ;
vecs [ 1 ] . iov_base = c - > summary - > sum_buf ;
vecs [ 1 ] . iov_len = datasize ;
2006-05-24 05:04:45 +04:00
sum_ofs = jeb - > offset + c - > sector_size - jeb - > free_size ;
2012-02-16 03:56:45 +04:00
dbg_summary ( " writing out data to flash to pos : 0x%08x \n " , sum_ofs ) ;
2005-09-07 12:35:26 +04:00
2006-05-24 05:04:45 +04:00
ret = jffs2_flash_writev ( c , vecs , 2 , sum_ofs , & retlen , 0 ) ;
2005-09-07 12:35:26 +04:00
if ( ret | | ( retlen ! = infosize ) ) {
2006-05-21 16:15:59 +04:00
2006-05-16 20:05:33 +04:00
JFFS2_WARNING ( " Write of %u bytes at 0x%08x failed. returned %d, retlen %zd \n " ,
2006-05-24 05:04:45 +04:00
infosize , sum_ofs , ret , retlen ) ;
2005-09-07 12:35:26 +04:00
2006-05-27 00:19:05 +04:00
if ( retlen ) {
/* Waste remaining space */
spin_lock ( & c - > erase_completion_lock ) ;
jffs2_link_node_ref ( c , jeb , sum_ofs | REF_OBSOLETE , infosize , NULL ) ;
spin_unlock ( & c - > erase_completion_lock ) ;
}
2006-05-21 16:15:59 +04:00
2005-09-07 12:35:26 +04:00
c - > summary - > sum_size = JFFS2_SUMMARY_NOSUM_SIZE ;
2006-05-24 05:04:45 +04:00
return 0 ;
2005-09-07 12:35:26 +04:00
}
2006-05-21 16:15:59 +04:00
spin_lock ( & c - > erase_completion_lock ) ;
2006-05-24 05:04:45 +04:00
jffs2_link_node_ref ( c , jeb , sum_ofs | REF_NORMAL , infosize , NULL ) ;
spin_unlock ( & c - > erase_completion_lock ) ;
2006-05-21 16:15:59 +04:00
2005-09-07 12:35:26 +04:00
return 0 ;
}
/* Write out summary information - called from jffs2_do_reserve_space */
int jffs2_sum_write_sumnode ( struct jffs2_sb_info * c )
2014-09-28 23:26:32 +04:00
__must_hold ( & c - > erase_completion_block )
2005-09-07 12:35:26 +04:00
{
2006-05-24 05:04:45 +04:00
int datasize , infosize , padsize ;
2005-09-07 12:35:26 +04:00
struct jffs2_eraseblock * jeb ;
2008-08-01 13:07:51 +04:00
int ret = 0 ;
2005-09-07 12:35:26 +04:00
2005-09-22 15:25:00 +04:00
dbg_summary ( " called \n " ) ;
2005-09-07 12:35:26 +04:00
2006-05-24 05:04:45 +04:00
spin_unlock ( & c - > erase_completion_lock ) ;
2005-09-07 12:35:26 +04:00
jeb = c - > nextblock ;
2006-05-25 04:50:35 +04:00
jffs2_prealloc_raw_node_refs ( c , jeb , 1 ) ;
2005-09-07 12:35:26 +04:00
if ( ! c - > summary - > sum_num | | ! c - > summary - > sum_list_head ) {
JFFS2_WARNING ( " Empty summary info!!! \n " ) ;
BUG ( ) ;
}
datasize = c - > summary - > sum_size + sizeof ( struct jffs2_sum_marker ) ;
2005-09-26 15:37:25 +04:00
infosize = sizeof ( struct jffs2_raw_summary ) + datasize ;
2005-09-07 12:35:26 +04:00
padsize = jeb - > free_size - infosize ;
2005-11-07 14:16:07 +03:00
infosize + = padsize ;
2005-09-07 12:35:26 +04:00
datasize + = padsize ;
ret = jffs2_sum_write_data ( c , jeb , infosize , datasize , padsize ) ;
2006-05-21 16:15:59 +04:00
spin_lock ( & c - > erase_completion_lock ) ;
2006-05-24 05:04:45 +04:00
return ret ;
2005-09-07 12:35:26 +04:00
}