diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-04-28 00:34:57 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-04-28 00:34:57 +0200 |
commit | f00546363fff1576ceddc2690d47e5f9c1dd2e05 (patch) | |
tree | f6cb8965b6754fc6ce7570cf1471ebe9874e509a /fs | |
parent | Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6 (diff) | |
parent | [MTD] [MAPS] drivers/mtd/maps/ck804xrom.c: convert pci_module_init() (diff) | |
download | linux-f00546363fff1576ceddc2690d47e5f9c1dd2e05.tar.xz linux-f00546363fff1576ceddc2690d47e5f9c1dd2e05.zip |
Merge git://git.infradead.org/mtd-2.6
* git://git.infradead.org/mtd-2.6: (46 commits)
[MTD] [MAPS] drivers/mtd/maps/ck804xrom.c: convert pci_module_init()
[MTD] [NAND] CM-x270 MTD driver
[MTD] [NAND] Wrong calculation of page number in nand_block_bad()
[MTD] [MAPS] fix plat-ram printk format
[JFFS2] Fix compr_rubin.c build after include file elimination.
[JFFS2] Handle inodes with only a single metadata node with non-zero isize
[JFFS2] Tidy up licensing/copyright boilerplate.
[MTD] [OneNAND] Exit loop only when column start with 0
[MTD] [OneNAND] Fix access the past of the real oobfree array
[MTD] [OneNAND] Update Samsung OneNAND official URL
[JFFS2] Better fix for all-zero node headers
[JFFS2] Improve read_inode memory usage, v2.
[JFFS2] Improve failure mode if inode checking leaves unchecked space.
[JFFS2] Fix cross-endian build.
[MTD] Finish conversion mtd_blkdevs to use the kthread API
[JFFS2] Obsolete dirent nodes immediately on unlink, where possible.
Use menuconfig objects: MTD
[MTD] mtd_blkdevs: Convert to use the kthread API
[MTD] Fix fwh_lock locking
[JFFS2] Speed up mount for directly-mapped NOR flash
...
Diffstat (limited to 'fs')
46 files changed, 880 insertions, 1386 deletions
diff --git a/fs/jffs2/LICENCE b/fs/jffs2/LICENCE index cd81d83e4ad2..562885908135 100644 --- a/fs/jffs2/LICENCE +++ b/fs/jffs2/LICENCE @@ -1,7 +1,7 @@ The files in this directory and elsewhere which refer to this LICENCE file are part of JFFS2, the Journalling Flash File System v2. - Copyright (C) 2001, 2002 Red Hat, Inc. + Copyright © 2001-2007 Red Hat, Inc. and others JFFS2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -28,8 +28,3 @@ of the GNU General Public License. This exception does not invalidate any other reasons why a work based on this file might be covered by the GNU General Public License. -For information on obtaining alternative licences for JFFS2, see -http://sources.redhat.com/jffs2/jffs2-licence.html - - - $Id: LICENCE,v 1.1 2002/05/20 14:56:37 dwmw2 Exp $ diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index 7f28ee0bd132..c32b241e3d91 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile @@ -1,7 +1,6 @@ # # Makefile for the Linux Journalling Flash File System v2 (JFFS2) # -# $Id: Makefile.common,v 1.11 2005/09/07 08:34:53 havasi Exp $ # obj-$(CONFIG_JFFS2_FS) += jffs2.o diff --git a/fs/jffs2/README.Locking b/fs/jffs2/README.Locking index c8f0bd64e53e..d14d5a4dc5ac 100644 --- a/fs/jffs2/README.Locking +++ b/fs/jffs2/README.Locking @@ -1,4 +1,3 @@ - $Id: README.Locking,v 1.12 2005/04/13 13:22:35 dwmw2 Exp $ JFFS2 LOCKING DOCUMENTATION --------------------------- diff --git a/fs/jffs2/TODO b/fs/jffs2/TODO index d0e23b26fa50..5d3ea4070f01 100644 --- a/fs/jffs2/TODO +++ b/fs/jffs2/TODO @@ -1,4 +1,3 @@ -$Id: TODO,v 1.18 2005/09/22 11:24:56 dedekind Exp $ - support asynchronous operation -- add a per-fs 'reserved_space' count, let each outstanding write reserve the _maximum_ amount of physical @@ -30,8 +29,6 @@ $Id: TODO,v 1.18 2005/09/22 11:24:56 dedekind Exp $ the full dirent, we only need to go to the flash in lookup() when we think we've got a match, and in readdir(). - Doubly-linked next_in_ino list to allow us to free obsoleted raw_node_refs immediately? - - Remove totlen from jffs2_raw_node_ref? Need to have totlen passed into - jffs2_mark_node_obsolete(). Can all callers work it out? - Remove size from jffs2_raw_node_frag. dedekind: diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 73f0d60f73a5..a46101ee867a 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c @@ -1,13 +1,14 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2006 NEC Corporation + * Copyright © 2006 NEC Corporation * * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> * * For licensing information, see the file 'LICENCE' in this directory. * */ + #include <linux/kernel.h> #include <linux/slab.h> #include <linux/fs.h> diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h index fa327dbd3171..c84378cee82a 100644 --- a/fs/jffs2/acl.h +++ b/fs/jffs2/acl.h @@ -1,13 +1,14 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2006 NEC Corporation + * Copyright © 2006 NEC Corporation * * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> * * For licensing information, see the file 'LICENCE' in this directory. * */ + struct jffs2_acl_entry { jint16_t e_tag; jint16_t e_perm; diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 888f236e5494..0c82dfcfd246 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c @@ -1,14 +1,12 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: background.c,v 1.54 2005/05/20 21:37:12 gleixner Exp $ - * */ #include <linux/kernel.h> diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index 07119c42a861..0ca2fff2617f 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c @@ -1,14 +1,12 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: build.c,v 1.85 2005/11/07 11:14:38 gleixner Exp $ - * */ #include <linux/kernel.h> diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c index 7001ba26c067..485d065de41f 100644 --- a/fs/jffs2/compr.c +++ b/fs/jffs2/compr.c @@ -1,16 +1,14 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * Created by Arjan van de Ven <arjanv@redhat.com> * - * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, + * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, * University of Szeged, Hungary * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: compr.c,v 1.46 2005/11/07 11:14:38 gleixner Exp $ - * */ #include "compr.h" @@ -268,144 +266,6 @@ int jffs2_unregister_compressor(struct jffs2_compressor *comp) return 0; } -#ifdef CONFIG_JFFS2_PROC - -#define JFFS2_STAT_BUF_SIZE 16000 - -char *jffs2_list_compressors(void) -{ - struct jffs2_compressor *this; - char *buf, *act_buf; - - act_buf = buf = kmalloc(JFFS2_STAT_BUF_SIZE,GFP_KERNEL); - list_for_each_entry(this, &jffs2_compressor_list, list) { - act_buf += sprintf(act_buf, "%10s priority:%d ", this->name, this->priority); - if ((this->disabled)||(!this->compress)) - act_buf += sprintf(act_buf,"disabled"); - else - act_buf += sprintf(act_buf,"enabled"); - act_buf += sprintf(act_buf,"\n"); - } - return buf; -} - -char *jffs2_stats(void) -{ - struct jffs2_compressor *this; - char *buf, *act_buf; - - act_buf = buf = kmalloc(JFFS2_STAT_BUF_SIZE,GFP_KERNEL); - - act_buf += sprintf(act_buf,"JFFS2 compressor statistics:\n"); - act_buf += sprintf(act_buf,"%10s ","none"); - act_buf += sprintf(act_buf,"compr: %d blocks (%d) decompr: %d blocks\n", none_stat_compr_blocks, - none_stat_compr_size, none_stat_decompr_blocks); - spin_lock(&jffs2_compressor_list_lock); - list_for_each_entry(this, &jffs2_compressor_list, list) { - act_buf += sprintf(act_buf,"%10s ",this->name); - if ((this->disabled)||(!this->compress)) - act_buf += sprintf(act_buf,"- "); - else - act_buf += sprintf(act_buf,"+ "); - act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d) decompr: %d blocks ", this->stat_compr_blocks, - this->stat_compr_new_size, this->stat_compr_orig_size, - this->stat_decompr_blocks); - act_buf += sprintf(act_buf,"\n"); - } - spin_unlock(&jffs2_compressor_list_lock); - - return buf; -} - -char *jffs2_get_compression_mode_name(void) -{ - switch (jffs2_compression_mode) { - case JFFS2_COMPR_MODE_NONE: - return "none"; - case JFFS2_COMPR_MODE_PRIORITY: - return "priority"; - case JFFS2_COMPR_MODE_SIZE: - return "size"; - } - return "unkown"; -} - -int jffs2_set_compression_mode_name(const char *name) -{ - if (!strcmp("none",name)) { - jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; - return 0; - } - if (!strcmp("priority",name)) { - jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY; - return 0; - } - if (!strcmp("size",name)) { - jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE; - return 0; - } - return 1; -} - -static int jffs2_compressor_Xable(const char *name, int disabled) -{ - struct jffs2_compressor *this; - spin_lock(&jffs2_compressor_list_lock); - list_for_each_entry(this, &jffs2_compressor_list, list) { - if (!strcmp(this->name, name)) { - this->disabled = disabled; - spin_unlock(&jffs2_compressor_list_lock); - return 0; - } - } - spin_unlock(&jffs2_compressor_list_lock); - printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name); - return 1; -} - -int jffs2_enable_compressor_name(const char *name) -{ - return jffs2_compressor_Xable(name, 0); -} - -int jffs2_disable_compressor_name(const char *name) -{ - return jffs2_compressor_Xable(name, 1); -} - -int jffs2_set_compressor_priority(const char *name, int priority) -{ - struct jffs2_compressor *this,*comp; - spin_lock(&jffs2_compressor_list_lock); - list_for_each_entry(this, &jffs2_compressor_list, list) { - if (!strcmp(this->name, name)) { - this->priority = priority; - comp = this; - goto reinsert; - } - } - spin_unlock(&jffs2_compressor_list_lock); - printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name); - return 1; -reinsert: - /* list is sorted in the order of priority, so if - we change it we have to reinsert it into the - good place */ - list_del(&comp->list); - list_for_each_entry(this, &jffs2_compressor_list, list) { - if (this->priority < comp->priority) { - list_add(&comp->list, this->list.prev); - spin_unlock(&jffs2_compressor_list_lock); - return 0; - } - } - list_add_tail(&comp->list, &jffs2_compressor_list); - spin_unlock(&jffs2_compressor_list_lock); - return 0; -} - -#endif - void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig) { if (orig != comprbuf) diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h index 509b8b1c0811..68cc7010dbdf 100644 --- a/fs/jffs2/compr.h +++ b/fs/jffs2/compr.h @@ -1,13 +1,10 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, + * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, * University of Szeged, Hungary * - * For licensing information, see the file 'LICENCE' in the - * jffs2 directory. - * - * $Id: compr.h,v 1.9 2005/11/07 11:14:38 gleixner Exp $ + * For licensing information, see the file 'LICENCE' in this directory. * */ @@ -76,16 +73,6 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig); -#ifdef CONFIG_JFFS2_PROC -int jffs2_enable_compressor_name(const char *name); -int jffs2_disable_compressor_name(const char *name); -int jffs2_set_compression_mode_name(const char *mode_name); -char *jffs2_get_compression_mode_name(void); -int jffs2_set_compressor_priority(const char *mode_name, int priority); -char *jffs2_list_compressors(void); -char *jffs2_stats(void); -#endif - /* Compressor modules */ /* These functions will be called by jffs2_compressors_init/exit */ diff --git a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c index 2eb1b7428d16..0d0bfd2e4e0d 100644 --- a/fs/jffs2/compr_rtime.c +++ b/fs/jffs2/compr_rtime.c @@ -1,13 +1,12 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by Arjan van de Ven <arjanv@redhat.com> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: compr_rtime.c,v 1.14 2004/06/23 16:34:40 havasi Exp $ * * * Very simple lz77-ish encoder. diff --git a/fs/jffs2/compr_rubin.c b/fs/jffs2/compr_rubin.c index e792e675d624..ea0431e047d5 100644 --- a/fs/jffs2/compr_rubin.c +++ b/fs/jffs2/compr_rubin.c @@ -1,23 +1,94 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001, 2002 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by Arjan van de Ven <arjanv@redhat.com> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: compr_rubin.c,v 1.20 2004/06/23 16:34:40 havasi Exp $ - * */ #include <linux/string.h> #include <linux/types.h> #include <linux/jffs2.h> -#include "compr_rubin.h" -#include "histo_mips.h" +#include <linux/errno.h> #include "compr.h" + +#define RUBIN_REG_SIZE 16 +#define UPPER_BIT_RUBIN (((long) 1)<<(RUBIN_REG_SIZE-1)) +#define LOWER_BITS_RUBIN ((((long) 1)<<(RUBIN_REG_SIZE-1))-1) + + +#define BIT_DIVIDER_MIPS 1043 +static int bits_mips[8] = { 277,249,290,267,229,341,212,241}; /* mips32 */ + +#include <linux/errno.h> + +struct pushpull { + unsigned char *buf; + unsigned int buflen; + unsigned int ofs; + unsigned int reserve; +}; + +struct rubin_state { + unsigned long p; + unsigned long q; + unsigned long rec_q; + long bit_number; + struct pushpull pp; + int bit_divider; + int bits[8]; +}; + +static inline void init_pushpull(struct pushpull *pp, char *buf, unsigned buflen, unsigned ofs, unsigned reserve) +{ + pp->buf = buf; + pp->buflen = buflen; + pp->ofs = ofs; + pp->reserve = reserve; +} + +static inline int pushbit(struct pushpull *pp, int bit, int use_reserved) +{ + if (pp->ofs >= pp->buflen - (use_reserved?0:pp->reserve)) { + return -ENOSPC; + } + + if (bit) { + pp->buf[pp->ofs >> 3] |= (1<<(7-(pp->ofs &7))); + } + else { + pp->buf[pp->ofs >> 3] &= ~(1<<(7-(pp->ofs &7))); + } + pp->ofs++; + + return 0; +} + +static inline int pushedbits(struct pushpull *pp) +{ + return pp->ofs; +} + +static inline int pullbit(struct pushpull *pp) +{ + int bit; + + bit = (pp->buf[pp->ofs >> 3] >> (7-(pp->ofs & 7))) & 1; + + pp->ofs++; + return bit; +} + +static inline int pulledbits(struct pushpull *pp) +{ + return pp->ofs; +} + + static void init_rubin(struct rubin_state *rs, int div, int *bits) { int c; diff --git a/fs/jffs2/compr_rubin.h b/fs/jffs2/compr_rubin.h deleted file mode 100644 index bf1a93451621..000000000000 --- a/fs/jffs2/compr_rubin.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Rubin encoder/decoder header */ -/* work started at : aug 3, 1994 */ -/* last modification : aug 15, 1994 */ -/* $Id: compr_rubin.h,v 1.7 2005/11/07 11:14:38 gleixner Exp $ */ - -#include "pushpull.h" - -#define RUBIN_REG_SIZE 16 -#define UPPER_BIT_RUBIN (((long) 1)<<(RUBIN_REG_SIZE-1)) -#define LOWER_BITS_RUBIN ((((long) 1)<<(RUBIN_REG_SIZE-1))-1) - - -struct rubin_state { - unsigned long p; - unsigned long q; - unsigned long rec_q; - long bit_number; - struct pushpull pp; - int bit_divider; - int bits[8]; -}; diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c index 0c1fc6e20b43..2b87fccc1557 100644 --- a/fs/jffs2/compr_zlib.c +++ b/fs/jffs2/compr_zlib.c @@ -1,14 +1,12 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: compr_zlib.c,v 1.32 2005/11/07 11:14:38 gleixner Exp $ - * */ #if !defined(__KERNEL__) && !defined(__ECOS) diff --git a/fs/jffs2/comprtest.c b/fs/jffs2/comprtest.c deleted file mode 100644 index f0fb8be7740c..000000000000 --- a/fs/jffs2/comprtest.c +++ /dev/null @@ -1,307 +0,0 @@ -/* $Id: comprtest.c,v 1.6 2005/11/07 11:14:38 gleixner Exp $ */ - -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/module.h> -#include <asm/types.h> -#if 0 -#define TESTDATA_LEN 512 -static unsigned char testdata[TESTDATA_LEN] = { - 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x83, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00, - 0xb0, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x20, 0x00, 0x06, 0x00, 0x28, 0x00, - 0x1e, 0x00, 0x1b, 0x00, 0x06, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x34, 0x80, 0x04, 0x08, - 0x34, 0x80, 0x04, 0x08, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0xf4, 0x80, 0x04, 0x08, - 0xf4, 0x80, 0x04, 0x08, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x08, - 0x00, 0x80, 0x04, 0x08, 0x0d, 0x05, 0x00, 0x00, 0x0d, 0x05, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x10, 0x95, 0x04, 0x08, - 0x10, 0x95, 0x04, 0x08, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x58, 0x05, 0x00, 0x00, 0x58, 0x95, 0x04, 0x08, - 0x58, 0x95, 0x04, 0x08, 0xa0, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x81, 0x04, 0x08, - 0x08, 0x81, 0x04, 0x08, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x6c, 0x64, 0x2d, 0x6c, 0x69, 0x6e, 0x75, - 0x78, 0x2e, 0x73, 0x6f, 0x2e, 0x32, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, - 0x0c, 0x83, 0x04, 0x08, 0x81, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x1c, 0x83, 0x04, 0x08, 0xac, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, - 0x2c, 0x83, 0x04, 0x08, 0xdd, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x3c, 0x83, 0x04, 0x08, 0x2e, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x4c, 0x83, 0x04, 0x08, 0x7d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, - 0x00, 0x85, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x67, - 0x6d, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x5f, 0x00, 0x6c, 0x69, 0x62, 0x63, - 0x2e, 0x73, 0x6f, 0x2e, 0x36, 0x00, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x00, 0x5f, 0x5f, 0x63}; -#else -#define TESTDATA_LEN 3481 -static unsigned char testdata[TESTDATA_LEN] = { - 0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x22, 0x64, 0x62, 0x65, 0x6e, 0x63, 0x68, - 0x2e, 0x68, 0x22, 0x0a, 0x0a, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x4d, 0x41, 0x58, - 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x20, 0x31, 0x30, 0x30, 0x30, 0x0a, 0x0a, 0x73, 0x74, 0x61, - 0x74, 0x69, 0x63, 0x20, 0x63, 0x68, 0x61, 0x72, 0x20, 0x62, 0x75, 0x66, 0x5b, 0x37, 0x30, 0x30, - 0x30, 0x30, 0x5d, 0x3b, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x69, 0x6e, 0x74, 0x20, - 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x61, - 0x74, 0x69, 0x63, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x7b, 0x0a, 0x09, 0x69, 0x6e, - 0x74, 0x20, 0x66, 0x64, 0x3b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, - 0x65, 0x3b, 0x0a, 0x7d, 0x20, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x4d, 0x41, 0x58, 0x5f, - 0x46, 0x49, 0x4c, 0x45, 0x53, 0x5d, 0x3b, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, - 0x5f, 0x75, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, - 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, - 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x75, - 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x20, 0x21, 0x3d, 0x20, - 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, - 0x25, 0x64, 0x29, 0x20, 0x75, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x25, 0x73, 0x20, 0x66, 0x61, - 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, - 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, - 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x5f, 0x66, - 0x69, 0x6c, 0x65, 0x28, 0x69, 0x6e, 0x74, 0x20, 0x66, 0x64, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, - 0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x73, 0x3b, 0x0a, - 0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, - 0x09, 0x09, 0x73, 0x20, 0x3d, 0x20, 0x4d, 0x49, 0x4e, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x6f, 0x66, - 0x28, 0x62, 0x75, 0x66, 0x29, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x09, - 0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x66, 0x64, 0x2c, 0x20, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x73, - 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x2d, 0x3d, 0x20, 0x73, 0x3b, 0x0a, - 0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x6f, 0x70, - 0x65, 0x6e, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, - 0x69, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, - 0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x66, 0x64, 0x2c, - 0x20, 0x69, 0x3b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x20, 0x3d, - 0x20, 0x4f, 0x5f, 0x52, 0x44, 0x57, 0x52, 0x7c, 0x4f, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x3b, - 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x73, 0x74, 0x61, 0x74, 0x20, 0x73, 0x74, - 0x3b, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x3b, 0x0a, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, - 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x73, 0x69, - 0x7a, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x20, 0x7c, - 0x3d, 0x20, 0x4f, 0x5f, 0x54, 0x52, 0x55, 0x4e, 0x43, 0x3b, 0x0a, 0x0a, 0x09, 0x66, 0x64, 0x20, - 0x3d, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x66, 0x6c, - 0x61, 0x67, 0x73, 0x2c, 0x20, 0x30, 0x36, 0x30, 0x30, 0x29, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20, - 0x28, 0x66, 0x64, 0x20, 0x3d, 0x3d, 0x20, 0x2d, 0x31, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, - 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x6f, 0x70, 0x65, 0x6e, - 0x20, 0x25, 0x73, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x68, - 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, 0x22, - 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, - 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x68, - 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, - 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, - 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x66, 0x73, 0x74, 0x61, 0x74, 0x28, 0x66, 0x64, 0x2c, - 0x20, 0x26, 0x73, 0x74, 0x29, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x73, 0x69, 0x7a, 0x65, - 0x20, 0x3e, 0x20, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, - 0x0a, 0x23, 0x69, 0x66, 0x20, 0x44, 0x45, 0x42, 0x55, 0x47, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, - 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x20, 0x25, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x25, 0x64, 0x20, 0x66, 0x72, 0x6f, - 0x6d, 0x20, 0x25, 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66, - 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x28, 0x69, 0x6e, 0x74, - 0x29, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x23, 0x65, - 0x6e, 0x64, 0x69, 0x66, 0x0a, 0x09, 0x09, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x5f, 0x66, 0x69, - 0x6c, 0x65, 0x28, 0x66, 0x64, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x2d, 0x20, 0x73, 0x74, - 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x20, 0x65, 0x6c, - 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3c, 0x20, 0x73, 0x74, - 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, - 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x69, 0x6e, 0x67, - 0x20, 0x25, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x25, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x25, - 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x28, 0x69, 0x6e, - 0x74, 0x29, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, - 0x09, 0x66, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x28, 0x66, 0x64, 0x2c, 0x20, 0x73, - 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x69, - 0x3d, 0x30, 0x3b, 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x3b, 0x69, - 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, 0x61, 0x62, - 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x3d, 0x20, - 0x30, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, - 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, - 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x66, 0x69, - 0x6c, 0x65, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x66, 0x6f, - 0x72, 0x20, 0x25, 0x73, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, - 0x0a, 0x09, 0x09, 0x65, 0x78, 0x69, 0x74, 0x28, 0x31, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, - 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, - 0x20, 0x3d, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x3b, 0x0a, 0x09, 0x66, 0x74, 0x61, 0x62, - 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x64, 0x3b, 0x0a, 0x09, - 0x69, 0x66, 0x20, 0x28, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2b, 0x2b, 0x20, 0x25, 0x20, 0x31, 0x30, - 0x30, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, - 0x74, 0x66, 0x28, 0x22, 0x2e, 0x22, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, - 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x69, 0x6e, 0x74, - 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x7a, - 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x0a, 0x7b, - 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x69, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x62, - 0x75, 0x66, 0x5b, 0x30, 0x5d, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x6d, 0x65, 0x6d, 0x73, - 0x65, 0x74, 0x28, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x6f, - 0x66, 0x28, 0x62, 0x75, 0x66, 0x29, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x28, - 0x69, 0x3d, 0x30, 0x3b, 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x3b, - 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, 0x61, - 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x3d, - 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, - 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, 0x58, - 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x29, 0x20, 0x7b, 0x0a, 0x23, 0x69, 0x66, 0x20, 0x31, 0x0a, - 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, - 0x6f, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x3a, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, - 0x25, 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x20, - 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x25, 0x64, 0x20, 0x6f, 0x66, 0x73, 0x3d, 0x25, 0x64, 0x5c, 0x6e, - 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, - 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, - 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x3b, 0x0a, - 0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, - 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x6c, 0x73, 0x65, 0x65, 0x6b, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, - 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x2c, - 0x20, 0x53, 0x45, 0x45, 0x4b, 0x5f, 0x53, 0x45, 0x54, 0x29, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20, - 0x28, 0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, - 0x2e, 0x66, 0x64, 0x2c, 0x20, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, - 0x21, 0x3d, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, - 0x6e, 0x74, 0x66, 0x28, 0x22, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, - 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x5c, 0x6e, - 0x22, 0x2c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, - 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x28, 0x69, - 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x73, - 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, - 0x0a, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x69, 0x3b, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, - 0x28, 0x69, 0x3d, 0x30, 0x3b, 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, - 0x3b, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, - 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, - 0x3d, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, - 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, - 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, - 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x72, 0x65, 0x61, - 0x64, 0x3a, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x20, 0x77, 0x61, 0x73, - 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x25, - 0x64, 0x20, 0x6f, 0x66, 0x73, 0x3d, 0x25, 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x2c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, - 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, - 0x72, 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x6c, 0x73, 0x65, 0x65, 0x6b, 0x28, 0x66, 0x74, - 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, - 0x65, 0x74, 0x2c, 0x20, 0x53, 0x45, 0x45, 0x4b, 0x5f, 0x53, 0x45, 0x54, 0x29, 0x3b, 0x0a, 0x09, - 0x72, 0x65, 0x61, 0x64, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, - 0x64, 0x2c, 0x20, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x7d, - 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, - 0x69, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x69, - 0x6e, 0x74, 0x20, 0x69, 0x3b, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x69, 0x3d, 0x30, 0x3b, - 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x3b, 0x69, 0x2b, 0x2b, 0x29, - 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, - 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x68, 0x61, 0x6e, - 0x64, 0x6c, 0x65, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, - 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, - 0x45, 0x53, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, - 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x3a, 0x20, 0x68, - 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x74, - 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, - 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, - 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x66, 0x74, 0x61, - 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x29, 0x3b, 0x0a, 0x09, 0x66, 0x74, 0x61, - 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x20, - 0x30, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x6d, 0x6b, - 0x64, 0x69, 0x72, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, - 0x0a, 0x7b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x66, 0x6e, 0x61, - 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x6d, 0x6b, 0x64, 0x69, 0x72, - 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x30, 0x37, 0x30, 0x30, 0x29, 0x20, 0x21, 0x3d, - 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x23, 0x69, 0x66, 0x20, 0x44, 0x45, 0x42, 0x55, 0x47, 0x0a, - 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x6d, 0x6b, 0x64, 0x69, 0x72, 0x20, - 0x25, 0x73, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, - 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6e, 0x61, - 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, - 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a, 0x09, 0x7d, 0x0a, - 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x72, 0x6d, 0x64, 0x69, 0x72, - 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x7b, 0x0a, - 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, - 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x72, 0x6d, 0x64, 0x69, 0x72, 0x28, 0x66, 0x6e, - 0x61, 0x6d, 0x65, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, - 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x72, 0x6d, 0x64, 0x69, 0x72, 0x20, 0x25, 0x73, 0x20, - 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, 0x22, 0x2c, 0x20, - 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, - 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, - 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, - 0x5f, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x6f, 0x6c, - 0x64, 0x2c, 0x20, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x6e, 0x65, 0x77, 0x29, 0x0a, 0x7b, 0x0a, - 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x6f, 0x6c, 0x64, 0x29, 0x3b, 0x0a, - 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x6e, 0x65, 0x77, 0x29, 0x3b, 0x0a, - 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x6f, 0x6c, 0x64, - 0x2c, 0x20, 0x6e, 0x65, 0x77, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, - 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x20, - 0x25, 0x73, 0x20, 0x25, 0x73, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73, - 0x29, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x6f, 0x6c, 0x64, 0x2c, 0x20, 0x6e, 0x65, 0x77, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, - 0x0a, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x28, - 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, - 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, - 0x20, 0x73, 0x74, 0x61, 0x74, 0x20, 0x73, 0x74, 0x3b, 0x0a, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, - 0x70, 0x70, 0x65, 0x72, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, - 0x66, 0x20, 0x28, 0x73, 0x74, 0x61, 0x74, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x26, - 0x73, 0x74, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, - 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x73, 0x74, - 0x61, 0x74, 0x3a, 0x20, 0x25, 0x73, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x25, 0x64, 0x20, 0x25, - 0x73, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, - 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, - 0x75, 0x72, 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x53, 0x5f, 0x49, - 0x53, 0x44, 0x49, 0x52, 0x28, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x29, - 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, - 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x21, 0x3d, 0x20, 0x73, 0x69, - 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, - 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x3a, 0x20, 0x25, 0x73, - 0x20, 0x77, 0x72, 0x6f, 0x6e, 0x67, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x25, 0x64, 0x20, 0x25, - 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, - 0x65, 0x2c, 0x20, 0x28, 0x69, 0x6e, 0x74, 0x29, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, - 0x7a, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a, - 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x28, - 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, - 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x64, 0x6f, 0x5f, 0x6f, 0x70, 0x65, - 0x6e, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x35, 0x30, 0x30, 0x30, 0x2c, 0x20, 0x73, - 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x64, 0x6f, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, - 0x35, 0x30, 0x30, 0x30, 0x29, 0x3b, 0x0a, 0x7d, 0x0a -}; -#endif -static unsigned char comprbuf[TESTDATA_LEN]; -static unsigned char decomprbuf[TESTDATA_LEN]; - -int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in, - unsigned char *data_out, uint32_t cdatalen, uint32_t datalen); -unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out, - uint32_t *datalen, uint32_t *cdatalen); - -int init_module(void ) { - unsigned char comprtype; - uint32_t c, d; - int ret; - - printk("Original data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - testdata[0],testdata[1],testdata[2],testdata[3], - testdata[4],testdata[5],testdata[6],testdata[7], - testdata[8],testdata[9],testdata[10],testdata[11], - testdata[12],testdata[13],testdata[14],testdata[15]); - d = TESTDATA_LEN; - c = TESTDATA_LEN; - comprtype = jffs2_compress(testdata, comprbuf, &d, &c); - - printk("jffs2_compress used compression type %d. Compressed size %d, uncompressed size %d\n", - comprtype, c, d); - printk("Compressed data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - comprbuf[0],comprbuf[1],comprbuf[2],comprbuf[3], - comprbuf[4],comprbuf[5],comprbuf[6],comprbuf[7], - comprbuf[8],comprbuf[9],comprbuf[10],comprbuf[11], - comprbuf[12],comprbuf[13],comprbuf[14],comprbuf[15]); - - ret = jffs2_decompress(comprtype, comprbuf, decomprbuf, c, d); - printk("jffs2_decompress returned %d\n", ret); - printk("Decompressed data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - decomprbuf[0],decomprbuf[1],decomprbuf[2],decomprbuf[3], - decomprbuf[4],decomprbuf[5],decomprbuf[6],decomprbuf[7], - decomprbuf[8],decomprbuf[9],decomprbuf[10],decomprbuf[11], - decomprbuf[12],decomprbuf[13],decomprbuf[14],decomprbuf[15]); - if (memcmp(decomprbuf, testdata, d)) - printk("Compression and decompression corrupted data\n"); - else - printk("Compression good for %d bytes\n", d); - return 1; -} diff --git a/fs/jffs2/debug.c b/fs/jffs2/debug.c index 4189e4a36050..3a32c64ed497 100644 --- a/fs/jffs2/debug.c +++ b/fs/jffs2/debug.c @@ -1,15 +1,14 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: debug.c,v 1.12 2005/11/07 11:14:39 gleixner Exp $ - * */ + #include <linux/kernel.h> #include <linux/types.h> #include <linux/pagemap.h> diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h index f89c85d5a3f8..2a49f2c51a9f 100644 --- a/fs/jffs2/debug.h +++ b/fs/jffs2/debug.h @@ -1,15 +1,14 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: debug.h,v 1.21 2005/11/07 11:14:39 gleixner Exp $ - * */ + #ifndef _JFFS2_DEBUG_H_ #define _JFFS2_DEBUG_H_ diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 9fa2e27f0641..c1dfca310dd6 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -1,14 +1,12 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: dir.c,v 1.90 2005/11/07 11:14:39 gleixner Exp $ - * */ #include <linux/kernel.h> diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index ad0121088dde..66e7c2f1e644 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -1,14 +1,12 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: erase.c,v 1.85 2005/09/20 14:53:15 dedekind Exp $ - * */ #include <linux/kernel.h> @@ -333,7 +331,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl *bad_offset = ofs; - ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf); + ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf); if (ret) { printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret); goto fail; diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index e82eeaf7590d..99871279a1ed 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -1,14 +1,12 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: file.c,v 1.104 2005/10/18 23:29:35 tpoynor Exp $ - * */ #include <linux/kernel.h> diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 8a649f602767..1d3b7a9fc828 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -1,14 +1,12 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: fs.c,v 1.66 2005/09/27 13:17:29 dedekind Exp $ - * */ #include <linux/capability.h> diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 3a3cf225981f..2d99e06ab223 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -1,14 +1,12 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: gc.c,v 1.155 2005/11/07 11:14:39 gleixner Exp $ - * */ #include <linux/kernel.h> @@ -144,7 +142,8 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) c->unchecked_size); jffs2_dbg_dump_block_lists_nolock(c); spin_unlock(&c->erase_completion_lock); - BUG(); + up(&c->alloc_sem); + return -ENOSPC; } spin_unlock(&c->erase_completion_lock); diff --git a/fs/jffs2/ioctl.c b/fs/jffs2/ioctl.c index 69099835de1c..f4d525b0ea53 100644 --- a/fs/jffs2/ioctl.c +++ b/fs/jffs2/ioctl.c @@ -1,14 +1,12 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: ioctl.c,v 1.10 2005/11/07 11:14:40 gleixner Exp $ - * */ #include <linux/fs.h> diff --git a/fs/jffs2/jffs2_fs_i.h b/fs/jffs2/jffs2_fs_i.h index 3a566077ac95..0b78fdc9773b 100644 --- a/fs/jffs2/jffs2_fs_i.h +++ b/fs/jffs2/jffs2_fs_i.h @@ -1,4 +1,13 @@ -/* $Id: jffs2_fs_i.h,v 1.19 2005/11/07 11:14:52 gleixner Exp $ */ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright © 2001-2007 Red Hat, Inc. + * + * Created by David Woodhouse <dwmw2@infradead.org> + * + * For licensing information, see the file 'LICENCE' in this directory. + * + */ #ifndef _JFFS2_FS_I #define _JFFS2_FS_I diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index ea88f69af130..b13298a824ed 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h @@ -1,4 +1,13 @@ -/* $Id: jffs2_fs_sb.h,v 1.54 2005/09/21 13:37:34 dedekind Exp $ */ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright © 2001-2007 Red Hat, Inc. + * + * Created by David Woodhouse <dwmw2@infradead.org> + * + * For licensing information, see the file 'LICENCE' in this directory. + * + */ #ifndef _JFFS2_FS_SB #define _JFFS2_FS_SB diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index 83f9881ec4cc..35c1a5e30ba1 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c @@ -1,14 +1,12 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: malloc.c,v 1.31 2005/11/07 11:14:40 gleixner Exp $ - * */ #include <linux/kernel.h> diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 5a6b4d64206c..4bf86088b3ae 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -1,14 +1,12 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodelist.c,v 1.115 2005/11/07 11:14:40 gleixner Exp $ - * */ #include <linux/kernel.h> @@ -54,7 +52,7 @@ void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new *prev = new; } -void jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint32_t size) +uint32_t jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint32_t size) { struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size); @@ -76,18 +74,24 @@ void jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint } if (size == 0) - return; + return 0; - /* - * If the last fragment starts at the RAM page boundary, it is - * REF_PRISTINE irrespective of its size. - */ frag = frag_last(list); + + /* 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. */ if (frag->node && (frag->ofs & (PAGE_CACHE_SIZE - 1)) == 0) { dbg_fragtree2("marking the last fragment 0x%08x-0x%08x REF_PRISTINE.\n", frag->ofs, frag->ofs + frag->size); frag->node->raw->flash_offset = ref_offset(frag->node->raw) | REF_PRISTINE; } + return size; } static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, @@ -397,466 +401,6 @@ int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_in return 0; } -/* - * Check the data CRC of the node. - * - * Returns: 0 if the data CRC is correct; - * 1 - if incorrect; - * error code if an error occured. - */ -static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn) -{ - struct jffs2_raw_node_ref *ref = tn->fn->raw; - int err = 0, pointed = 0; - struct jffs2_eraseblock *jeb; - unsigned char *buffer; - uint32_t crc, ofs, len; - size_t retlen; - - BUG_ON(tn->csize == 0); - - if (!jffs2_is_writebuffered(c)) - goto adj_acc; - - /* Calculate how many bytes were already checked */ - ofs = ref_offset(ref) + sizeof(struct jffs2_raw_inode); - len = ofs % c->wbuf_pagesize; - if (likely(len)) - len = c->wbuf_pagesize - len; - - if (len >= tn->csize) { - dbg_readinode("no need to check node at %#08x, data length %u, data starts at %#08x - it has already been checked.\n", - ref_offset(ref), tn->csize, ofs); - goto adj_acc; - } - - ofs += len; - len = tn->csize - len; - - dbg_readinode("check node at %#08x, data length %u, partial CRC %#08x, correct CRC %#08x, data starts at %#08x, start checking from %#08x - %u bytes.\n", - ref_offset(ref), tn->csize, tn->partial_crc, tn->data_crc, ofs - len, ofs, len); - -#ifndef __ECOS - /* TODO: instead, incapsulate point() stuff to jffs2_flash_read(), - * adding and jffs2_flash_read_end() interface. */ - if (c->mtd->point) { - err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer); - if (!err && retlen < tn->csize) { - JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize); - c->mtd->unpoint(c->mtd, buffer, ofs, len); - } else if (err) - JFFS2_WARNING("MTD point failed: error code %d.\n", err); - else - pointed = 1; /* succefully pointed to device */ - } -#endif - - if (!pointed) { - buffer = kmalloc(len, GFP_KERNEL); - if (unlikely(!buffer)) - return -ENOMEM; - - /* TODO: this is very frequent pattern, make it a separate - * routine */ - err = jffs2_flash_read(c, ofs, len, &retlen, buffer); - if (err) { - JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ofs, err); - goto free_out; - } - - if (retlen != len) { - JFFS2_ERROR("short read at %#08x: %zd instead of %d.\n", ofs, retlen, len); - err = -EIO; - goto free_out; - } - } - - /* Continue calculating CRC */ - crc = crc32(tn->partial_crc, buffer, len); - if(!pointed) - kfree(buffer); -#ifndef __ECOS - else - c->mtd->unpoint(c->mtd, buffer, ofs, len); -#endif - - if (crc != tn->data_crc) { - JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n", - ofs, tn->data_crc, crc); - return 1; - } - -adj_acc: - jeb = &c->blocks[ref->flash_offset / c->sector_size]; - len = ref_totlen(c, jeb, ref); - - /* - * Mark the node as having been checked and fix the - * accounting accordingly. - */ - spin_lock(&c->erase_completion_lock); - jeb->used_size += len; - jeb->unchecked_size -= len; - c->used_size += len; - c->unchecked_size -= len; - spin_unlock(&c->erase_completion_lock); - - return 0; - -free_out: - if(!pointed) - kfree(buffer); -#ifndef __ECOS - else - c->mtd->unpoint(c->mtd, buffer, ofs, len); -#endif - return err; -} - -/* - * Helper function for jffs2_add_older_frag_to_fragtree(). - * - * Checks the node if we are in the checking stage. - */ -static int check_node(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn) -{ - int ret; - - BUG_ON(ref_obsolete(tn->fn->raw)); - - /* We only check the data CRC of unchecked nodes */ - if (ref_flags(tn->fn->raw) != REF_UNCHECKED) - return 0; - - dbg_fragtree2("check node %#04x-%#04x, phys offs %#08x.\n", - tn->fn->ofs, tn->fn->ofs + tn->fn->size, ref_offset(tn->fn->raw)); - - ret = check_node_data(c, tn); - if (unlikely(ret < 0)) { - JFFS2_ERROR("check_node_data() returned error: %d.\n", - ret); - } else if (unlikely(ret > 0)) { - dbg_fragtree2("CRC error, mark it obsolete.\n"); - jffs2_mark_node_obsolete(c, tn->fn->raw); - } - - return ret; -} - -/* - * Helper function for jffs2_add_older_frag_to_fragtree(). - * - * Called when the new fragment that is being inserted - * splits a hole fragment. - */ -static int split_hole(struct jffs2_sb_info *c, struct rb_root *root, - struct jffs2_node_frag *newfrag, struct jffs2_node_frag *hole) -{ - dbg_fragtree2("fragment %#04x-%#04x splits the hole %#04x-%#04x\n", - newfrag->ofs, newfrag->ofs + newfrag->size, hole->ofs, hole->ofs + hole->size); - - if (hole->ofs == newfrag->ofs) { - /* - * Well, the new fragment actually starts at the same offset as - * the hole. - */ - if (hole->ofs + hole->size > newfrag->ofs + newfrag->size) { - /* - * We replace the overlapped left part of the hole by - * the new node. - */ - - dbg_fragtree2("insert fragment %#04x-%#04x and cut the left part of the hole\n", - newfrag->ofs, newfrag->ofs + newfrag->size); - rb_replace_node(&hole->rb, &newfrag->rb, root); - - hole->ofs += newfrag->size; - hole->size -= newfrag->size; - - /* - * We know that 'hole' should be the right hand - * fragment. - */ - jffs2_fragtree_insert(hole, newfrag); - rb_insert_color(&hole->rb, root); - } else { - /* - * Ah, the new fragment is of the same size as the hole. - * Relace the hole by it. - */ - dbg_fragtree2("insert fragment %#04x-%#04x and overwrite hole\n", - newfrag->ofs, newfrag->ofs + newfrag->size); - rb_replace_node(&hole->rb, &newfrag->rb, root); - jffs2_free_node_frag(hole); - } - } else { - /* The new fragment lefts some hole space at the left */ - - struct jffs2_node_frag * newfrag2 = NULL; - - if (hole->ofs + hole->size > newfrag->ofs + newfrag->size) { - /* The new frag also lefts some space at the right */ - newfrag2 = new_fragment(NULL, newfrag->ofs + - newfrag->size, hole->ofs + hole->size - - newfrag->ofs - newfrag->size); - if (unlikely(!newfrag2)) { - jffs2_free_node_frag(newfrag); - return -ENOMEM; - } - } - - hole->size = newfrag->ofs - hole->ofs; - dbg_fragtree2("left the hole %#04x-%#04x at the left and inserd fragment %#04x-%#04x\n", - hole->ofs, hole->ofs + hole->size, newfrag->ofs, newfrag->ofs + newfrag->size); - - jffs2_fragtree_insert(newfrag, hole); - rb_insert_color(&newfrag->rb, root); - - if (newfrag2) { - dbg_fragtree2("left the hole %#04x-%#04x at the right\n", - newfrag2->ofs, newfrag2->ofs + newfrag2->size); - jffs2_fragtree_insert(newfrag2, newfrag); - rb_insert_color(&newfrag2->rb, root); - } - } - - return 0; -} - -/* - * This function is used when we build inode. It expects the nodes are passed - * in the decreasing version order. The whole point of this is to improve the - * inodes checking on NAND: we check the nodes' data CRC only when they are not - * obsoleted. Previously, add_frag_to_fragtree() function was used and - * nodes were passed to it in the increasing version ordes and CRCs of all - * nodes were checked. - * - * Note: tn->fn->size shouldn't be zero. - * - * Returns 0 if the node was inserted - * 1 if it wasn't inserted (since it is obsolete) - * < 0 an if error occured - */ -int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f, - struct jffs2_tmp_dnode_info *tn) -{ - struct jffs2_node_frag *this, *newfrag; - uint32_t lastend; - struct jffs2_full_dnode *fn = tn->fn; - struct rb_root *root = &f->fragtree; - uint32_t fn_size = fn->size, fn_ofs = fn->ofs; - int err, checked = 0; - int ref_flag; - - dbg_fragtree("insert fragment %#04x-%#04x, ver %u\n", fn_ofs, fn_ofs + fn_size, tn->version); - - /* Skip all the nodes which are completed before this one starts */ - this = jffs2_lookup_node_frag(root, fn_ofs); - if (this) - dbg_fragtree2("'this' found %#04x-%#04x (%s)\n", this->ofs, this->ofs + this->size, this->node ? "data" : "hole"); - - if (this) - lastend = this->ofs + this->size; - else - lastend = 0; - - /* Detect the preliminary type of node */ - if (fn->size >= PAGE_CACHE_SIZE) - ref_flag = REF_PRISTINE; - else - ref_flag = REF_NORMAL; - - /* See if we ran off the end of the root */ - if (lastend <= fn_ofs) { - /* We did */ - - /* - * We are going to insert the new node into the - * fragment tree, so check it. - */ - err = check_node(c, f, tn); - if (err != 0) - return err; - - fn->frags = 1; - - newfrag = new_fragment(fn, fn_ofs, fn_size); - if (unlikely(!newfrag)) - return -ENOMEM; - - err = no_overlapping_node(c, root, newfrag, this, lastend); - if (unlikely(err != 0)) { - jffs2_free_node_frag(newfrag); - return err; - } - - goto out_ok; - } - - fn->frags = 0; - - while (1) { - /* - * Here we have: - * fn_ofs < this->ofs + this->size && fn_ofs >= this->ofs. - * - * Remember, 'this' has higher version, any non-hole node - * which is already in the fragtree is newer then the newly - * inserted. - */ - if (!this->node) { - /* - * 'this' is the hole fragment, so at least the - * beginning of the new fragment is valid. - */ - - /* - * We are going to insert the new node into the - * fragment tree, so check it. - */ - if (!checked) { - err = check_node(c, f, tn); - if (unlikely(err != 0)) - return err; - checked = 1; - } - - if (this->ofs + this->size >= fn_ofs + fn_size) { - /* We split the hole on two parts */ - - fn->frags += 1; - newfrag = new_fragment(fn, fn_ofs, fn_size); - if (unlikely(!newfrag)) - return -ENOMEM; - - err = split_hole(c, root, newfrag, this); - if (unlikely(err)) - return err; - goto out_ok; - } - - /* - * The beginning of the new fragment is valid since it - * overlaps the hole node. - */ - - ref_flag = REF_NORMAL; - - fn->frags += 1; - newfrag = new_fragment(fn, fn_ofs, - this->ofs + this->size - fn_ofs); - if (unlikely(!newfrag)) - return -ENOMEM; - - if (fn_ofs == this->ofs) { - /* - * The new node starts at the same offset as - * the hole and supersieds the hole. - */ - dbg_fragtree2("add the new fragment instead of hole %#04x-%#04x, refcnt %d\n", - fn_ofs, fn_ofs + this->ofs + this->size - fn_ofs, fn->frags); - - rb_replace_node(&this->rb, &newfrag->rb, root); - jffs2_free_node_frag(this); - } else { - /* - * The hole becomes shorter as its right part - * is supersieded by the new fragment. - */ - dbg_fragtree2("reduce size of hole %#04x-%#04x to %#04x-%#04x\n", - this->ofs, this->ofs + this->size, this->ofs, this->ofs + this->size - newfrag->size); - - dbg_fragtree2("add new fragment %#04x-%#04x, refcnt %d\n", fn_ofs, - fn_ofs + this->ofs + this->size - fn_ofs, fn->frags); - - this->size -= newfrag->size; - jffs2_fragtree_insert(newfrag, this); - rb_insert_color(&newfrag->rb, root); - } - - fn_ofs += newfrag->size; - fn_size -= newfrag->size; - this = rb_entry(rb_next(&newfrag->rb), - struct jffs2_node_frag, rb); - - dbg_fragtree2("switch to the next 'this' fragment: %#04x-%#04x %s\n", - this->ofs, this->ofs + this->size, this->node ? "(data)" : "(hole)"); - } - - /* - * 'This' node is not the hole so it obsoletes the new fragment - * either fully or partially. - */ - if (this->ofs + this->size >= fn_ofs + fn_size) { - /* The new node is obsolete, drop it */ - if (fn->frags == 0) { - dbg_fragtree2("%#04x-%#04x is obsolete, mark it obsolete\n", fn_ofs, fn_ofs + fn_size); - ref_flag = REF_OBSOLETE; - } - goto out_ok; - } else { - struct jffs2_node_frag *new_this; - - /* 'This' node obsoletes the beginning of the new node */ - dbg_fragtree2("the beginning %#04x-%#04x is obsolete\n", fn_ofs, this->ofs + this->size); - - ref_flag = REF_NORMAL; - - fn_size -= this->ofs + this->size - fn_ofs; - fn_ofs = this->ofs + this->size; - dbg_fragtree2("now considering %#04x-%#04x\n", fn_ofs, fn_ofs + fn_size); - - new_this = rb_entry(rb_next(&this->rb), struct jffs2_node_frag, rb); - if (!new_this) { - /* - * There is no next fragment. Add the rest of - * the new node as the right-hand child. - */ - if (!checked) { - err = check_node(c, f, tn); - if (unlikely(err != 0)) - return err; - checked = 1; - } - - fn->frags += 1; - newfrag = new_fragment(fn, fn_ofs, fn_size); - if (unlikely(!newfrag)) - return -ENOMEM; - - dbg_fragtree2("there are no more fragments, insert %#04x-%#04x\n", - newfrag->ofs, newfrag->ofs + newfrag->size); - rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right); - rb_insert_color(&newfrag->rb, root); - goto out_ok; - } else { - this = new_this; - dbg_fragtree2("switch to the next 'this' fragment: %#04x-%#04x %s\n", - this->ofs, this->ofs + this->size, this->node ? "(data)" : "(hole)"); - } - } - } - -out_ok: - BUG_ON(fn->size < PAGE_CACHE_SIZE && ref_flag == REF_PRISTINE); - - if (ref_flag == REF_OBSOLETE) { - dbg_fragtree2("the node is obsolete now\n"); - /* jffs2_mark_node_obsolete() will adjust space accounting */ - jffs2_mark_node_obsolete(c, fn->raw); - return 1; - } - - dbg_fragtree2("the node is \"%s\" now\n", ref_flag == REF_NORMAL ? "REF_NORMAL" : "REF_PRISTINE"); - - /* Space accounting was adjusted at check_node_data() */ - spin_lock(&c->erase_completion_lock); - fn->raw->flash_offset = ref_offset(fn->raw) | ref_flag; - spin_unlock(&c->erase_completion_lock); - - return 0; -} - void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state) { spin_lock(&c->inocache_lock); diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 4178b4b55948..25126a062cae 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -1,14 +1,12 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodelist.h,v 1.140 2005/09/07 08:34:54 havasi Exp $ - * */ #ifndef __JFFS2_NODELIST_H__ @@ -40,6 +38,9 @@ #define cpu_to_je32(x) ((jint32_t){x}) #define cpu_to_jemode(x) ((jmode_t){os_to_jffs2_mode(x)}) +#define constant_cpu_to_je16(x) ((jint16_t){x}) +#define constant_cpu_to_je32(x) ((jint32_t){x}) + #define je16_to_cpu(x) ((x).v16) #define je32_to_cpu(x) ((x).v32) #define jemode_to_cpu(x) (jffs2_to_os_mode((x).m)) @@ -48,6 +49,9 @@ #define cpu_to_je32(x) ((jint32_t){cpu_to_be32(x)}) #define cpu_to_jemode(x) ((jmode_t){cpu_to_be32(os_to_jffs2_mode(x))}) +#define constant_cpu_to_je16(x) ((jint16_t){__constant_cpu_to_be16(x)}) +#define constant_cpu_to_je32(x) ((jint32_t){__constant_cpu_to_be32(x)}) + #define je16_to_cpu(x) (be16_to_cpu(x.v16)) #define je32_to_cpu(x) (be32_to_cpu(x.v32)) #define jemode_to_cpu(x) (be32_to_cpu(jffs2_to_os_mode((x).m))) @@ -56,6 +60,9 @@ #define cpu_to_je32(x) ((jint32_t){cpu_to_le32(x)}) #define cpu_to_jemode(x) ((jmode_t){cpu_to_le32(os_to_jffs2_mode(x))}) +#define constant_cpu_to_je16(x) ((jint16_t){__constant_cpu_to_le16(x)}) +#define constant_cpu_to_je32(x) ((jint32_t){__constant_cpu_to_le32(x)}) + #define je16_to_cpu(x) (le16_to_cpu(x.v16)) #define je32_to_cpu(x) (le32_to_cpu(x.v32)) #define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m))) @@ -216,7 +223,20 @@ struct jffs2_tmp_dnode_info uint32_t version; uint32_t data_crc; uint32_t partial_crc; - uint32_t csize; + uint16_t csize; + uint16_t overlapped; +}; + +/* Temporary data structure used during readinode. */ +struct jffs2_readinode_info +{ + struct rb_root tn_root; + struct jffs2_tmp_dnode_info *mdata_tn; + uint32_t highest_version; + uint32_t latest_mctime; + uint32_t mctime_ver; + struct jffs2_full_dirent *fds; + struct jffs2_raw_node_ref *latest_ref; }; struct jffs2_full_dirent @@ -319,6 +339,15 @@ static inline struct jffs2_node_frag *frag_last(struct rb_root *root) #define frag_right(frag) rb_entry((frag)->rb.rb_right, struct jffs2_node_frag, rb) #define frag_erase(frag, list) rb_erase(&frag->rb, list); +#define tn_next(tn) rb_entry(rb_next(&(tn)->rb), struct jffs2_tmp_dnode_info, rb) +#define tn_prev(tn) rb_entry(rb_prev(&(tn)->rb), struct jffs2_tmp_dnode_info, rb) +#define tn_parent(tn) rb_entry(rb_parent(&(tn)->rb), struct jffs2_tmp_dnode_info, rb) +#define tn_left(tn) rb_entry((tn)->rb.rb_left, struct jffs2_tmp_dnode_info, rb) +#define tn_right(tn) rb_entry((tn)->rb.rb_right, struct jffs2_tmp_dnode_info, rb) +#define tn_erase(tn, list) rb_erase(&tn->rb, list); +#define tn_last(list) rb_entry(rb_last(list), struct jffs2_tmp_dnode_info, rb) +#define tn_first(list) rb_entry(rb_first(list), struct jffs2_tmp_dnode_info, rb) + /* nodelist.c */ void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list); void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state); @@ -333,8 +362,7 @@ struct rb_node *rb_next(struct rb_node *); struct rb_node *rb_prev(struct rb_node *); void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root); int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn); -void jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size); -int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn); +uint32_t jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size); struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t ofs, uint32_t len, diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index d88376992ed9..dbc908ad622b 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -1,14 +1,12 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodemgmt.c,v 1.127 2005/09/20 15:49:12 dedekind Exp $ - * */ #include <linux/kernel.h> @@ -172,6 +170,11 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, static void jffs2_close_nextblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { + if (c->nextblock == NULL) { + D1(printk(KERN_DEBUG "jffs2_close_nextblock: Erase block at 0x%08x has already been placed in a list\n", + jeb->offset)); + return; + } /* Check, if we have a dirty block now, or if it was dirty already */ if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) { c->dirty_size += jeb->wasted_size; diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 8d92e45168ca..80daea96bbc2 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -1,14 +1,12 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2002-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: os-linux.h,v 1.64 2005/09/30 13:59:13 dedekind Exp $ - * */ #ifndef __JFFS2_OS_LINUX_H__ diff --git a/fs/jffs2/pushpull.h b/fs/jffs2/pushpull.h deleted file mode 100644 index c0c2a9158dff..000000000000 --- a/fs/jffs2/pushpull.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * JFFS2 -- Journalling Flash File System, Version 2. - * - * Copyright (C) 2001, 2002 Red Hat, Inc. - * - * Created by David Woodhouse <dwmw2@infradead.org> - * - * For licensing information, see the file 'LICENCE' in this directory. - * - * $Id: pushpull.h,v 1.10 2004/11/16 20:36:11 dwmw2 Exp $ - * - */ - -#ifndef __PUSHPULL_H__ -#define __PUSHPULL_H__ - -#include <linux/errno.h> - -struct pushpull { - unsigned char *buf; - unsigned int buflen; - unsigned int ofs; - unsigned int reserve; -}; - - -static inline void init_pushpull(struct pushpull *pp, char *buf, unsigned buflen, unsigned ofs, unsigned reserve) -{ - pp->buf = buf; - pp->buflen = buflen; - pp->ofs = ofs; - pp->reserve = reserve; -} - -static inline int pushbit(struct pushpull *pp, int bit, int use_reserved) -{ - if (pp->ofs >= pp->buflen - (use_reserved?0:pp->reserve)) { - return -ENOSPC; - } - - if (bit) { - pp->buf[pp->ofs >> 3] |= (1<<(7-(pp->ofs &7))); - } - else { - pp->buf[pp->ofs >> 3] &= ~(1<<(7-(pp->ofs &7))); - } - pp->ofs++; - - return 0; -} - -static inline int pushedbits(struct pushpull *pp) -{ - return pp->ofs; -} - -static inline int pullbit(struct pushpull *pp) -{ - int bit; - - bit = (pp->buf[pp->ofs >> 3] >> (7-(pp->ofs & 7))) & 1; - - pp->ofs++; - return bit; -} - -static inline int pulledbits(struct pushpull *pp) -{ - return pp->ofs; -} - -#endif /* __PUSHPULL_H__ */ diff --git a/fs/jffs2/read.c b/fs/jffs2/read.c index f3b86da833ba..cfe05c1966a5 100644 --- a/fs/jffs2/read.c +++ b/fs/jffs2/read.c @@ -1,14 +1,12 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: read.c,v 1.42 2005/11/07 11:14:41 gleixner Exp $ - * */ #include <linux/kernel.h> diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 717a48cf7df2..6aff38930b50 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -1,14 +1,12 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: readinode.c,v 1.143 2005/11/07 11:14:41 gleixner Exp $ - * */ #include <linux/kernel.h> @@ -22,30 +20,510 @@ #include "nodelist.h" /* - * Put a new tmp_dnode_info into the temporaty RB-tree, keeping the list in - * order of increasing version. + * Check the data CRC of the node. + * + * Returns: 0 if the data CRC is correct; + * 1 - if incorrect; + * error code if an error occured. */ -static void jffs2_add_tn_to_tree(struct jffs2_tmp_dnode_info *tn, struct rb_root *list) +static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn) { - struct rb_node **p = &list->rb_node; - struct rb_node * parent = NULL; - struct jffs2_tmp_dnode_info *this; - - while (*p) { - parent = *p; - this = rb_entry(parent, struct jffs2_tmp_dnode_info, rb); - - /* There may actually be a collision here, but it doesn't - actually matter. As long as the two nodes with the same - version are together, it's all fine. */ - if (tn->version > this->version) - p = &(*p)->rb_left; + struct jffs2_raw_node_ref *ref = tn->fn->raw; + int err = 0, pointed = 0; + struct jffs2_eraseblock *jeb; + unsigned char *buffer; + uint32_t crc, ofs, len; + size_t retlen; + + BUG_ON(tn->csize == 0); + + if (!jffs2_is_writebuffered(c)) + goto adj_acc; + + /* Calculate how many bytes were already checked */ + ofs = ref_offset(ref) + sizeof(struct jffs2_raw_inode); + len = ofs % c->wbuf_pagesize; + if (likely(len)) + len = c->wbuf_pagesize - len; + + if (len >= tn->csize) { + dbg_readinode("no need to check node at %#08x, data length %u, data starts at %#08x - it has already been checked.\n", + ref_offset(ref), tn->csize, ofs); + goto adj_acc; + } + + ofs += len; + len = tn->csize - len; + + dbg_readinode("check node at %#08x, data length %u, partial CRC %#08x, correct CRC %#08x, data starts at %#08x, start checking from %#08x - %u bytes.\n", + ref_offset(ref), tn->csize, tn->partial_crc, tn->data_crc, ofs - len, ofs, len); + +#ifndef __ECOS + /* TODO: instead, incapsulate point() stuff to jffs2_flash_read(), + * adding and jffs2_flash_read_end() interface. */ + if (c->mtd->point) { + err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer); + if (!err && retlen < tn->csize) { + JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize); + c->mtd->unpoint(c->mtd, buffer, ofs, len); + } else if (err) + JFFS2_WARNING("MTD point failed: error code %d.\n", err); else - p = &(*p)->rb_right; + pointed = 1; /* succefully pointed to device */ + } +#endif + + if (!pointed) { + buffer = kmalloc(len, GFP_KERNEL); + if (unlikely(!buffer)) + return -ENOMEM; + + /* TODO: this is very frequent pattern, make it a separate + * routine */ + err = jffs2_flash_read(c, ofs, len, &retlen, buffer); + if (err) { + JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ofs, err); + goto free_out; + } + + if (retlen != len) { + JFFS2_ERROR("short read at %#08x: %zd instead of %d.\n", ofs, retlen, len); + err = -EIO; + goto free_out; + } + } + + /* Continue calculating CRC */ + crc = crc32(tn->partial_crc, buffer, len); + if(!pointed) + kfree(buffer); +#ifndef __ECOS + else + c->mtd->unpoint(c->mtd, buffer, ofs, len); +#endif + + if (crc != tn->data_crc) { + JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n", + ofs, tn->data_crc, crc); + return 1; } - rb_link_node(&tn->rb, parent, p); - rb_insert_color(&tn->rb, list); +adj_acc: + jeb = &c->blocks[ref->flash_offset / c->sector_size]; + len = ref_totlen(c, jeb, ref); + /* If it should be REF_NORMAL, it'll get marked as such when + we build the fragtree, shortly. No need to worry about GC + moving it while it's marked REF_PRISTINE -- GC won't happen + till we've finished checking every inode anyway. */ + ref->flash_offset |= REF_PRISTINE; + /* + * Mark the node as having been checked and fix the + * accounting accordingly. + */ + spin_lock(&c->erase_completion_lock); + jeb->used_size += len; + jeb->unchecked_size -= len; + c->used_size += len; + c->unchecked_size -= len; + jffs2_dbg_acct_paranoia_check_nolock(c, jeb); + spin_unlock(&c->erase_completion_lock); + + return 0; + +free_out: + if(!pointed) + kfree(buffer); +#ifndef __ECOS + else + c->mtd->unpoint(c->mtd, buffer, ofs, len); +#endif + return err; +} + +/* + * Helper function for jffs2_add_older_frag_to_fragtree(). + * + * Checks the node if we are in the checking stage. + */ +static int check_tn_node(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn) +{ + int ret; + + BUG_ON(ref_obsolete(tn->fn->raw)); + + /* We only check the data CRC of unchecked nodes */ + if (ref_flags(tn->fn->raw) != REF_UNCHECKED) + return 0; + + dbg_readinode("check node %#04x-%#04x, phys offs %#08x\n", + tn->fn->ofs, tn->fn->ofs + tn->fn->size, ref_offset(tn->fn->raw)); + + ret = check_node_data(c, tn); + if (unlikely(ret < 0)) { + JFFS2_ERROR("check_node_data() returned error: %d.\n", + ret); + } else if (unlikely(ret > 0)) { + dbg_readinode("CRC error, mark it obsolete.\n"); + jffs2_mark_node_obsolete(c, tn->fn->raw); + } + + return ret; +} + +static struct jffs2_tmp_dnode_info *jffs2_lookup_tn(struct rb_root *tn_root, uint32_t offset) +{ + struct rb_node *next; + struct jffs2_tmp_dnode_info *tn = NULL; + + dbg_readinode("root %p, offset %d\n", tn_root, offset); + + next = tn_root->rb_node; + + while (next) { + tn = rb_entry(next, struct jffs2_tmp_dnode_info, rb); + + if (tn->fn->ofs < offset) + next = tn->rb.rb_right; + else if (tn->fn->ofs >= offset) + next = tn->rb.rb_left; + else + break; + } + + return tn; +} + + +static void jffs2_kill_tn(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn) +{ + jffs2_mark_node_obsolete(c, tn->fn->raw); + jffs2_free_full_dnode(tn->fn); + jffs2_free_tmp_dnode_info(tn); +} +/* + * This function is used when we read an inode. Data nodes arrive in + * arbitrary order -- they may be older or newer than the nodes which + * are already in the tree. Where overlaps occur, the older node can + * be discarded as long as the newer passes the CRC check. We don't + * bother to keep track of holes in this rbtree, and neither do we deal + * with frags -- we can have multiple entries starting at the same + * offset, and the one with the smallest length will come first in the + * ordering. + * + * Returns 0 if the node was inserted + * 1 if the node is obsolete (because we can't mark it so yet) + * < 0 an if error occurred + */ +static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, + struct jffs2_readinode_info *rii, + struct jffs2_tmp_dnode_info *tn) +{ + uint32_t fn_end = tn->fn->ofs + tn->fn->size; + struct jffs2_tmp_dnode_info *insert_point = NULL, *this; + + dbg_readinode("insert fragment %#04x-%#04x, ver %u\n", tn->fn->ofs, fn_end, tn->version); + + /* If a node has zero dsize, we only have to keep if it if it might be the + node with highest version -- i.e. the one which will end up as f->metadata. + Note that such nodes won't be REF_UNCHECKED since there are no data to + check anyway. */ + if (!tn->fn->size) { + if (rii->mdata_tn) { + /* We had a candidate mdata node already */ + dbg_readinode("kill old mdata with ver %d\n", rii->mdata_tn->version); + jffs2_kill_tn(c, rii->mdata_tn); + } + rii->mdata_tn = tn; + dbg_readinode("keep new mdata with ver %d\n", tn->version); + return 0; + } + + /* Find the earliest node which _may_ be relevant to this one */ + this = jffs2_lookup_tn(&rii->tn_root, tn->fn->ofs); + if (!this) { + /* First addition to empty tree. $DEITY how I love the easy cases */ + rb_link_node(&tn->rb, NULL, &rii->tn_root.rb_node); + rb_insert_color(&tn->rb, &rii->tn_root); + dbg_readinode("keep new frag\n"); + return 0; + } + + /* If we add a new node it'll be somewhere under here. */ + insert_point = this; + + /* If the node is coincident with another at a lower address, + back up until the other node is found. It may be relevant */ + while (tn->overlapped) + tn = tn_prev(tn); + + dbg_readinode("'this' found %#04x-%#04x (%s)\n", this->fn->ofs, this->fn->ofs + this->fn->size, this->fn ? "data" : "hole"); + + while (this) { + if (this->fn->ofs > fn_end) + break; + dbg_readinode("Ponder this ver %d, 0x%x-0x%x\n", + this->version, this->fn->ofs, this->fn->size); + + if (this->version == tn->version) { + /* Version number collision means REF_PRISTINE GC. Accept either of them + as long as the CRC is correct. Check the one we have already... */ + if (!check_tn_node(c, this)) { + /* The one we already had was OK. Keep it and throw away the new one */ + dbg_readinode("Like old node. Throw away new\n"); + jffs2_kill_tn(c, tn); + return 0; + } else { + /* Who cares if the new one is good; keep it for now anyway. */ + rb_replace_node(&this->rb, &tn->rb, &rii->tn_root); + /* Same overlapping from in front and behind */ + tn->overlapped = this->overlapped; + jffs2_kill_tn(c, this); + dbg_readinode("Like new node. Throw away old\n"); + return 0; + } + } + if (this->version < tn->version && + this->fn->ofs >= tn->fn->ofs && + this->fn->ofs + this->fn->size <= fn_end) { + /* New node entirely overlaps 'this' */ + if (check_tn_node(c, tn)) { + dbg_readinode("new node bad CRC\n"); + jffs2_kill_tn(c, tn); + return 0; + } + /* ... and is good. Kill 'this'... */ + rb_replace_node(&this->rb, &tn->rb, &rii->tn_root); + tn->overlapped = this->overlapped; + jffs2_kill_tn(c, this); + /* ... and any subsequent nodes which are also overlapped */ + this = tn_next(tn); + while (this && this->fn->ofs + this->fn->size < fn_end) { + struct jffs2_tmp_dnode_info *next = tn_next(this); + if (this->version < tn->version) { + tn_erase(this, &rii->tn_root); + dbg_readinode("Kill overlapped ver %d, 0x%x-0x%x\n", + this->version, this->fn->ofs, + this->fn->ofs+this->fn->size); + jffs2_kill_tn(c, this); + } + this = next; + } + dbg_readinode("Done inserting new\n"); + return 0; + } + if (this->version > tn->version && + this->fn->ofs <= tn->fn->ofs && + this->fn->ofs+this->fn->size >= fn_end) { + /* New node entirely overlapped by 'this' */ + if (!check_tn_node(c, this)) { + dbg_readinode("Good CRC on old node. Kill new\n"); + jffs2_kill_tn(c, tn); + return 0; + } + /* ... but 'this' was bad. Replace it... */ + rb_replace_node(&this->rb, &tn->rb, &rii->tn_root); + dbg_readinode("Bad CRC on old overlapping node. Kill it\n"); + jffs2_kill_tn(c, this); + return 0; + } + /* We want to be inserted under the last node which is + either at a lower offset _or_ has a smaller range */ + if (this->fn->ofs < tn->fn->ofs || + (this->fn->ofs == tn->fn->ofs && + this->fn->size <= tn->fn->size)) + insert_point = this; + + this = tn_next(this); + } + dbg_readinode("insert_point %p, ver %d, 0x%x-0x%x, ov %d\n", + insert_point, insert_point->version, insert_point->fn->ofs, + insert_point->fn->ofs+insert_point->fn->size, + insert_point->overlapped); + /* We neither completely obsoleted nor were completely + obsoleted by an earlier node. Insert under insert_point */ + { + struct rb_node *parent = &insert_point->rb; + struct rb_node **link = &parent; + + while (*link) { + parent = *link; + insert_point = rb_entry(parent, struct jffs2_tmp_dnode_info, rb); + if (tn->fn->ofs > insert_point->fn->ofs) + link = &insert_point->rb.rb_right; + else if (tn->fn->ofs < insert_point->fn->ofs || + tn->fn->size < insert_point->fn->size) + link = &insert_point->rb.rb_left; + else + link = &insert_point->rb.rb_right; + } + rb_link_node(&tn->rb, &insert_point->rb, link); + rb_insert_color(&tn->rb, &rii->tn_root); + } + /* If there's anything behind that overlaps us, note it */ + this = tn_prev(tn); + if (this) { + while (1) { + if (this->fn->ofs + this->fn->size > tn->fn->ofs) { + dbg_readinode("Node is overlapped by %p (v %d, 0x%x-0x%x)\n", + this, this->version, this->fn->ofs, + this->fn->ofs+this->fn->size); + tn->overlapped = 1; + break; + } + if (!this->overlapped) + break; + this = tn_prev(this); + } + } + + /* If the new node overlaps anything ahead, note it */ + this = tn_next(tn); + while (this && this->fn->ofs < fn_end) { + this->overlapped = 1; + dbg_readinode("Node ver %d, 0x%x-0x%x is overlapped\n", + this->version, this->fn->ofs, + this->fn->ofs+this->fn->size); + this = tn_next(this); + } + return 0; +} + +/* Trivial function to remove the last node in the tree. Which by definition + has no right-hand -- so can be removed just by making its only child (if + any) take its place under its parent. */ +static void eat_last(struct rb_root *root, struct rb_node *node) +{ + struct rb_node *parent = rb_parent(node); + struct rb_node **link; + + /* LAST! */ + BUG_ON(node->rb_right); + + if (!parent) + link = &root->rb_node; + else if (node == parent->rb_left) + link = &parent->rb_left; + else + link = &parent->rb_right; + + *link = node->rb_left; + /* Colour doesn't matter now. Only the parent pointer. */ + if (node->rb_left) + node->rb_left->rb_parent_color = node->rb_parent_color; +} + +/* We put this in reverse order, so we can just use eat_last */ +static void ver_insert(struct rb_root *ver_root, struct jffs2_tmp_dnode_info *tn) +{ + struct rb_node **link = &ver_root->rb_node; + struct rb_node *parent = NULL; + struct jffs2_tmp_dnode_info *this_tn; + + while (*link) { + parent = *link; + this_tn = rb_entry(parent, struct jffs2_tmp_dnode_info, rb); + + if (tn->version > this_tn->version) + link = &parent->rb_left; + else + link = &parent->rb_right; + } + dbg_readinode("Link new node at %p (root is %p)\n", link, ver_root); + rb_link_node(&tn->rb, parent, link); + rb_insert_color(&tn->rb, ver_root); +} + +/* Build final, normal fragtree from tn tree. It doesn't matter which order + we add nodes to the real fragtree, as long as they don't overlap. And + having thrown away the majority of overlapped nodes as we went, there + really shouldn't be many sets of nodes which do overlap. If we start at + the end, we can use the overlap markers -- we can just eat nodes which + aren't overlapped, and when we encounter nodes which _do_ overlap we + sort them all into a temporary tree in version order before replaying them. */ +static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c, + struct jffs2_inode_info *f, + struct jffs2_readinode_info *rii) +{ + struct jffs2_tmp_dnode_info *pen, *last, *this; + struct rb_root ver_root = RB_ROOT; + uint32_t high_ver = 0; + + if (rii->mdata_tn) { + dbg_readinode("potential mdata is ver %d at %p\n", rii->mdata_tn->version, rii->mdata_tn); + high_ver = rii->mdata_tn->version; + rii->latest_ref = rii->mdata_tn->fn->raw; + } +#ifdef JFFS2_DBG_READINODE_MESSAGES + this = tn_last(&rii->tn_root); + while (this) { + dbg_readinode("tn %p ver %d range 0x%x-0x%x ov %d\n", this, this->version, this->fn->ofs, + this->fn->ofs+this->fn->size, this->overlapped); + this = tn_prev(this); + } +#endif + pen = tn_last(&rii->tn_root); + while ((last = pen)) { + pen = tn_prev(last); + + eat_last(&rii->tn_root, &last->rb); + ver_insert(&ver_root, last); + + if (unlikely(last->overlapped)) + continue; + + /* Now we have a bunch of nodes in reverse version + order, in the tree at ver_root. Most of the time, + there'll actually be only one node in the 'tree', + in fact. */ + this = tn_last(&ver_root); + + while (this) { + struct jffs2_tmp_dnode_info *vers_next; + int ret; + vers_next = tn_prev(this); + eat_last(&ver_root, &this->rb); + if (check_tn_node(c, this)) { + dbg_readinode("node ver %x, 0x%x-0x%x failed CRC\n", + this->version, this->fn->ofs, + this->fn->ofs+this->fn->size); + jffs2_kill_tn(c, this); + } else { + if (this->version > high_ver) { + /* Note that this is different from the other + highest_version, because this one is only + counting _valid_ nodes which could give the + latest inode metadata */ + high_ver = this->version; + rii->latest_ref = this->fn->raw; + } + dbg_readinode("Add %p (v %x, 0x%x-0x%x, ov %d) to fragtree\n", + this, this->version, this->fn->ofs, + this->fn->ofs+this->fn->size, this->overlapped); + + ret = jffs2_add_full_dnode_to_inode(c, f, this->fn); + if (ret) { + /* Free the nodes in vers_root; let the caller + deal with the rest */ + JFFS2_ERROR("Add node to tree failed %d\n", ret); + while (1) { + vers_next = tn_prev(this); + if (check_tn_node(c, this)) + jffs2_mark_node_obsolete(c, this->fn->raw); + jffs2_free_full_dnode(this->fn); + jffs2_free_tmp_dnode_info(this); + this = vers_next; + if (!this) + break; + eat_last(&ver_root, &vers_next->rb); + } + return ret; + } + jffs2_free_tmp_dnode_info(this); + } + this = vers_next; + } + } + return 0; } static void jffs2_free_tmp_dnode_info_list(struct rb_root *list) @@ -112,8 +590,8 @@ static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_r * negative error code on failure. */ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, - struct jffs2_raw_dirent *rd, size_t read, struct jffs2_full_dirent **fdp, - uint32_t *latest_mctime, uint32_t *mctime_ver) + struct jffs2_raw_dirent *rd, size_t read, + struct jffs2_readinode_info *rii) { struct jffs2_full_dirent *fd; uint32_t crc; @@ -125,7 +603,8 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r if (unlikely(crc != je32_to_cpu(rd->node_crc))) { JFFS2_NOTICE("header CRC failed on dirent node at %#08x: read %#08x, calculated %#08x\n", ref_offset(ref), je32_to_cpu(rd->node_crc), crc); - return 1; + jffs2_mark_node_obsolete(c, ref); + return 0; } /* If we've never checked the CRCs on this node, check them now */ @@ -137,7 +616,8 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) { JFFS2_ERROR("illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n", ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen)); - return 1; + jffs2_mark_node_obsolete(c, ref); + return 0; } jeb = &c->blocks[ref->flash_offset / c->sector_size]; @@ -161,10 +641,13 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r fd->ino = je32_to_cpu(rd->ino); fd->type = rd->type; + if (fd->version > rii->highest_version) + rii->highest_version = fd->version; + /* Pick out the mctime of the latest dirent */ - if(fd->version > *mctime_ver && je32_to_cpu(rd->mctime)) { - *mctime_ver = fd->version; - *latest_mctime = je32_to_cpu(rd->mctime); + if(fd->version > rii->mctime_ver && je32_to_cpu(rd->mctime)) { + rii->mctime_ver = fd->version; + rii->latest_mctime = je32_to_cpu(rd->mctime); } /* @@ -201,7 +684,7 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r * Wheee. We now have a complete jffs2_full_dirent structure, with * the name in it and everything. Link it into the list */ - jffs2_add_fd_to_list(c, fd, fdp); + jffs2_add_fd_to_list(c, fd, &rii->fds); return 0; } @@ -210,13 +693,13 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r * Helper function for jffs2_get_inode_nodes(). * It is called every time an inode node is found. * - * Returns: 0 on succes; + * Returns: 0 on success; * 1 if the node should be marked obsolete; * negative error code on failure. */ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, - struct jffs2_raw_inode *rd, struct rb_root *tnp, int rdlen, - uint32_t *latest_mctime, uint32_t *mctime_ver) + struct jffs2_raw_inode *rd, int rdlen, + struct jffs2_readinode_info *rii) { struct jffs2_tmp_dnode_info *tn; uint32_t len, csize; @@ -230,7 +713,8 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref if (unlikely(crc != je32_to_cpu(rd->node_crc))) { JFFS2_NOTICE("node CRC failed on dnode at %#08x: read %#08x, calculated %#08x\n", ref_offset(ref), je32_to_cpu(rd->node_crc), crc); - return 1; + jffs2_mark_node_obsolete(c, ref); + return 0; } tn = jffs2_alloc_tmp_dnode_info(); @@ -342,6 +826,10 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref tn->data_crc = je32_to_cpu(rd->data_crc); tn->csize = csize; tn->fn->raw = ref; + tn->overlapped = 0; + + if (tn->version > rii->highest_version) + rii->highest_version = tn->version; /* There was a bug where we wrote hole nodes out with csize/dsize swapped. Deal with it */ @@ -353,13 +841,25 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref dbg_readinode("dnode @%08x: ver %u, offset %#04x, dsize %#04x, csize %#04x\n", ref_offset(ref), je32_to_cpu(rd->version), je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize), csize); - jffs2_add_tn_to_tree(tn, tnp); + ret = jffs2_add_tn_to_tree(c, rii, tn); + if (ret) { + jffs2_free_full_dnode(tn->fn); + free_out: + jffs2_free_tmp_dnode_info(tn); + return ret; + } +#ifdef JFFS2_DBG_READINODE_MESSAGES + dbg_readinode("After adding ver %d:\n", tn->version); + tn = tn_first(&rii->tn_root); + while (tn) { + dbg_readinode("%p: v %d r 0x%x-0x%x ov %d\n", + tn, tn->version, tn->fn->ofs, + tn->fn->ofs+tn->fn->size, tn->overlapped); + tn = tn_next(tn); + } +#endif return 0; - -free_out: - jffs2_free_tmp_dnode_info(tn); - return ret; } /* @@ -379,7 +879,8 @@ static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_re JFFS2_ERROR("Node is {%04x,%04x,%08x,%08x}. Please report this error.\n", je16_to_cpu(un->magic), je16_to_cpu(un->nodetype), je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc)); - return 1; + jffs2_mark_node_obsolete(c, ref); + return 0; } un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype)); @@ -407,7 +908,8 @@ static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_re case JFFS2_FEATURE_RWCOMPAT_DELETE: JFFS2_NOTICE("unknown RWCOMPAT_DELETE nodetype %#04X at %#08x\n", je16_to_cpu(un->nodetype), ref_offset(ref)); - return 1; + jffs2_mark_node_obsolete(c, ref); + return 0; } return 0; @@ -421,92 +923,62 @@ static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_re * negative error code on failure. */ static int read_more(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, - int right_size, int *rdlen, unsigned char *buf, unsigned char *bufstart) + int needed_len, int *rdlen, unsigned char *buf) { - int right_len, err, len; + int err, to_read = needed_len - *rdlen; size_t retlen; uint32_t offs; if (jffs2_is_writebuffered(c)) { - right_len = c->wbuf_pagesize - (bufstart - buf); - if (right_size + (int)(bufstart - buf) > c->wbuf_pagesize) - right_len += c->wbuf_pagesize; - } else - right_len = right_size; + int rem = to_read % c->wbuf_pagesize; - if (*rdlen == right_len) - return 0; + if (rem) + to_read += c->wbuf_pagesize - rem; + } /* We need to read more data */ offs = ref_offset(ref) + *rdlen; - if (jffs2_is_writebuffered(c)) { - bufstart = buf + c->wbuf_pagesize; - len = c->wbuf_pagesize; - } else { - bufstart = buf + *rdlen; - len = right_size - *rdlen; - } - dbg_readinode("read more %d bytes\n", len); + dbg_readinode("read more %d bytes\n", to_read); - err = jffs2_flash_read(c, offs, len, &retlen, bufstart); + err = jffs2_flash_read(c, offs, to_read, &retlen, buf + *rdlen); if (err) { JFFS2_ERROR("can not read %d bytes from 0x%08x, " - "error code: %d.\n", len, offs, err); + "error code: %d.\n", to_read, offs, err); return err; } - if (retlen < len) { + if (retlen < to_read) { JFFS2_ERROR("short read at %#08x: %zu instead of %d.\n", - offs, retlen, len); + offs, retlen, to_read); return -EIO; } - *rdlen = right_len; - + *rdlen += to_read; return 0; } /* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated - with this ino, returning the former in order of version */ + with this ino. Perform a preliminary ordering on data nodes, throwing away + those which are completely obsoleted by newer ones. The naïve approach we + use to take of just returning them _all_ in version order will cause us to + run out of memory in certain degenerate cases. */ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, - struct rb_root *tnp, struct jffs2_full_dirent **fdp, - uint32_t *highest_version, uint32_t *latest_mctime, - uint32_t *mctime_ver) + struct jffs2_readinode_info *rii) { struct jffs2_raw_node_ref *ref, *valid_ref; - struct rb_root ret_tn = RB_ROOT; - struct jffs2_full_dirent *ret_fd = NULL; unsigned char *buf = NULL; union jffs2_node_union *node; size_t retlen; int len, err; - *mctime_ver = 0; + rii->mctime_ver = 0; dbg_readinode("ino #%u\n", f->inocache->ino); - if (jffs2_is_writebuffered(c)) { - /* - * If we have the write buffer, we assume the minimal I/O unit - * is c->wbuf_pagesize. We implement some optimizations which in - * this case and we need a temporary buffer of size = - * 2*c->wbuf_pagesize bytes (see comments in read_dnode()). - * Basically, we want to read not only the node header, but the - * whole wbuf (NAND page in case of NAND) or 2, if the node - * header overlaps the border between the 2 wbufs. - */ - len = 2*c->wbuf_pagesize; - } else { - /* - * When there is no write buffer, the size of the temporary - * buffer is the size of the larges node header. - */ - len = sizeof(union jffs2_node_union); - } - /* FIXME: in case of NOR and available ->point() this * needs to be fixed. */ + len = sizeof(union jffs2_node_union) + c->wbuf_pagesize; buf = kmalloc(len, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -516,8 +988,6 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf if (!valid_ref && f->inocache->ino != 1) JFFS2_WARNING("Eep. No valid nodes for ino #%u.\n", f->inocache->ino); while (valid_ref) { - unsigned char *bufstart; - /* We can hold a pointer to a non-obsolete node without the spinlock, but _obsolete_ nodes may disappear at any time, if the block they're in gets erased. So if we mark 'ref' obsolete while we're @@ -533,32 +1003,31 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf /* * At this point we don't know the type of the node we're going * to read, so we do not know the size of its header. In order - * to minimize the amount of flash IO we assume the node has - * size = JFFS2_MIN_NODE_HEADER. + * to minimize the amount of flash IO we assume the header is + * of size = JFFS2_MIN_NODE_HEADER. */ + len = JFFS2_MIN_NODE_HEADER; if (jffs2_is_writebuffered(c)) { + int end, rem; + /* - * We treat 'buf' as 2 adjacent wbufs. We want to - * adjust bufstart such as it points to the - * beginning of the node within this wbuf. + * We are about to read JFFS2_MIN_NODE_HEADER bytes, + * but this flash has some minimal I/O unit. It is + * possible that we'll need to read more soon, so read + * up to the next min. I/O unit, in order not to + * re-read the same min. I/O unit twice. */ - bufstart = buf + (ref_offset(ref) % c->wbuf_pagesize); - /* We will read either one wbuf or 2 wbufs. */ - len = c->wbuf_pagesize - (bufstart - buf); - if (JFFS2_MIN_NODE_HEADER + (int)(bufstart - buf) > c->wbuf_pagesize) { - /* The header spans the border of the first wbuf */ - len += c->wbuf_pagesize; - } - } else { - bufstart = buf; - len = JFFS2_MIN_NODE_HEADER; + end = ref_offset(ref) + len; + rem = end % c->wbuf_pagesize; + if (rem) + end += c->wbuf_pagesize - rem; + len = end - ref_offset(ref); } dbg_readinode("read %d bytes at %#08x(%d).\n", len, ref_offset(ref), ref_flags(ref)); /* FIXME: point() */ - err = jffs2_flash_read(c, ref_offset(ref), len, - &retlen, bufstart); + err = jffs2_flash_read(c, ref_offset(ref), len, &retlen, buf); if (err) { JFFS2_ERROR("can not read %d bytes from 0x%08x, " "error code: %d.\n", len, ref_offset(ref), err); goto free_out; @@ -570,7 +1039,7 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf goto free_out; } - node = (union jffs2_node_union *)bufstart; + node = (union jffs2_node_union *)buf; /* No need to mask in the valid bit; it shouldn't be invalid */ if (je32_to_cpu(node->u.hdr_crc) != crc32(0, node, sizeof(node->u)-4)) { @@ -583,10 +1052,10 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf jffs2_mark_node_obsolete(c, ref); goto cont; } - /* Due to poor choice of crc32 seed, an all-zero node will have a correct CRC */ - if (!je32_to_cpu(node->u.hdr_crc) && !je16_to_cpu(node->u.nodetype) && - !je16_to_cpu(node->u.magic) && !je32_to_cpu(node->u.totlen)) { - JFFS2_NOTICE("All zero node header at %#08x.\n", ref_offset(ref)); + if (je16_to_cpu(node->u.magic) != JFFS2_MAGIC_BITMASK) { + /* Not a JFFS2 node, whinge and move on */ + JFFS2_NOTICE("Wrong magic bitmask 0x%04x in node header at %#08x.\n", + je16_to_cpu(node->u.magic), ref_offset(ref)); jffs2_mark_node_obsolete(c, ref); goto cont; } @@ -596,46 +1065,34 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf case JFFS2_NODETYPE_DIRENT: if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_dirent)) { - err = read_more(c, ref, sizeof(struct jffs2_raw_dirent), &len, buf, bufstart); + err = read_more(c, ref, sizeof(struct jffs2_raw_dirent), &len, buf); if (unlikely(err)) goto free_out; } - err = read_direntry(c, ref, &node->d, retlen, &ret_fd, latest_mctime, mctime_ver); - if (err == 1) { - jffs2_mark_node_obsolete(c, ref); - break; - } else if (unlikely(err)) + err = read_direntry(c, ref, &node->d, retlen, rii); + if (unlikely(err)) goto free_out; - if (je32_to_cpu(node->d.version) > *highest_version) - *highest_version = je32_to_cpu(node->d.version); - break; case JFFS2_NODETYPE_INODE: if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_inode)) { - err = read_more(c, ref, sizeof(struct jffs2_raw_inode), &len, buf, bufstart); + err = read_more(c, ref, sizeof(struct jffs2_raw_inode), &len, buf); if (unlikely(err)) goto free_out; } - err = read_dnode(c, ref, &node->i, &ret_tn, len, latest_mctime, mctime_ver); - if (err == 1) { - jffs2_mark_node_obsolete(c, ref); - break; - } else if (unlikely(err)) + err = read_dnode(c, ref, &node->i, len, rii); + if (unlikely(err)) goto free_out; - if (je32_to_cpu(node->i.version) > *highest_version) - *highest_version = je32_to_cpu(node->i.version); - break; default: if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_unknown_node)) { - err = read_more(c, ref, sizeof(struct jffs2_unknown_node), &len, buf, bufstart); + err = read_more(c, ref, sizeof(struct jffs2_unknown_node), &len, buf); if (unlikely(err)) goto free_out; } @@ -653,17 +1110,19 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf } spin_unlock(&c->erase_completion_lock); - *tnp = ret_tn; - *fdp = ret_fd; kfree(buf); + f->highest_version = rii->highest_version; + dbg_readinode("nodes of inode #%u were read, the highest version is %u, latest_mctime %u, mctime_ver %u.\n", - f->inocache->ino, *highest_version, *latest_mctime, *mctime_ver); + f->inocache->ino, rii->highest_version, rii->latest_mctime, + rii->mctime_ver); return 0; free_out: - jffs2_free_tmp_dnode_info_list(&ret_tn); - jffs2_free_full_dirent_list(ret_fd); + jffs2_free_tmp_dnode_info_list(&rii->tn_root); + jffs2_free_full_dirent_list(rii->fds); + rii->fds = NULL; kfree(buf); return err; } @@ -672,20 +1131,17 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *latest_node) { - struct jffs2_tmp_dnode_info *tn; - struct rb_root tn_list; - struct rb_node *rb, *repl_rb; - struct jffs2_full_dirent *fd_list; - struct jffs2_full_dnode *fn, *first_fn = NULL; - uint32_t crc; - uint32_t latest_mctime, mctime_ver; + struct jffs2_readinode_info rii; + uint32_t crc, new_size; size_t retlen; int ret; dbg_readinode("ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink); + memset(&rii, 0, sizeof(rii)); + /* Grab all nodes relevant to this ino */ - ret = jffs2_get_inode_nodes(c, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver); + ret = jffs2_get_inode_nodes(c, f, &rii); if (ret) { JFFS2_ERROR("cannot read nodes for ino %u, returned error is %d\n", f->inocache->ino, ret); @@ -693,74 +1149,42 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); return ret; } - f->dents = fd_list; - - rb = rb_first(&tn_list); - while (rb) { - cond_resched(); - tn = rb_entry(rb, struct jffs2_tmp_dnode_info, rb); - fn = tn->fn; - ret = 1; - dbg_readinode("consider node ver %u, phys offset " - "%#08x(%d), range %u-%u.\n", tn->version, - ref_offset(fn->raw), ref_flags(fn->raw), - fn->ofs, fn->ofs + fn->size); - - if (fn->size) { - ret = jffs2_add_older_frag_to_fragtree(c, f, tn); - /* TODO: the error code isn't checked, check it */ - jffs2_dbg_fragtree_paranoia_check_nolock(f); - BUG_ON(ret < 0); - if (!first_fn && ret == 0) - first_fn = fn; - } else if (!first_fn) { - first_fn = fn; - f->metadata = fn; - ret = 0; /* Prevent freeing the metadata update node */ - } else - jffs2_mark_node_obsolete(c, fn->raw); - - BUG_ON(rb->rb_left); - if (rb_parent(rb) && rb_parent(rb)->rb_left == rb) { - /* We were then left-hand child of our parent. We need - * to move our own right-hand child into our place. */ - repl_rb = rb->rb_right; - if (repl_rb) - rb_set_parent(repl_rb, rb_parent(rb)); - } else - repl_rb = NULL; - - rb = rb_next(rb); - - /* Remove the spent tn from the tree; don't bother rebalancing - * but put our right-hand child in our own place. */ - if (rb_parent(&tn->rb)) { - if (rb_parent(&tn->rb)->rb_left == &tn->rb) - rb_parent(&tn->rb)->rb_left = repl_rb; - else if (rb_parent(&tn->rb)->rb_right == &tn->rb) - rb_parent(&tn->rb)->rb_right = repl_rb; - else BUG(); - } else if (tn->rb.rb_right) - rb_set_parent(tn->rb.rb_right, NULL); + ret = jffs2_build_inode_fragtree(c, f, &rii); + if (ret) { + JFFS2_ERROR("Failed to build final fragtree for inode #%u: error %d\n", + f->inocache->ino, ret); + if (f->inocache->state == INO_STATE_READING) + jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); + jffs2_free_tmp_dnode_info_list(&rii.tn_root); + /* FIXME: We could at least crc-check them all */ + if (rii.mdata_tn) { + jffs2_free_full_dnode(rii.mdata_tn->fn); + jffs2_free_tmp_dnode_info(rii.mdata_tn); + rii.mdata_tn = NULL; + } + return ret; + } - jffs2_free_tmp_dnode_info(tn); - if (ret) { - dbg_readinode("delete dnode %u-%u.\n", - fn->ofs, fn->ofs + fn->size); - jffs2_free_full_dnode(fn); + if (rii.mdata_tn) { + if (rii.mdata_tn->fn->raw == rii.latest_ref) { + f->metadata = rii.mdata_tn->fn; + jffs2_free_tmp_dnode_info(rii.mdata_tn); + } else { + jffs2_kill_tn(c, rii.mdata_tn); } + rii.mdata_tn = NULL; } - jffs2_dbg_fragtree_paranoia_check_nolock(f); - BUG_ON(first_fn && ref_obsolete(first_fn->raw)); + f->dents = rii.fds; - fn = first_fn; - if (unlikely(!first_fn)) { + jffs2_dbg_fragtree_paranoia_check_nolock(f); + + if (unlikely(!rii.latest_ref)) { /* No data nodes for this inode. */ if (f->inocache->ino != 1) { JFFS2_WARNING("no data nodes found for ino #%u\n", f->inocache->ino); - if (!fd_list) { + if (!rii.fds) { if (f->inocache->state == INO_STATE_READING) jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); return -EIO; @@ -778,7 +1202,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, return 0; } - ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(*latest_node), &retlen, (void *)latest_node); + ret = jffs2_flash_read(c, ref_offset(rii.latest_ref), sizeof(*latest_node), &retlen, (void *)latest_node); if (ret || retlen != sizeof(*latest_node)) { JFFS2_ERROR("failed to read from flash: error %d, %zd of %zd bytes read\n", ret, retlen, sizeof(*latest_node)); @@ -791,7 +1215,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, crc = crc32(0, latest_node, sizeof(*latest_node)-8); if (crc != je32_to_cpu(latest_node->node_crc)) { JFFS2_ERROR("CRC failed for read_inode of inode %u at physical location 0x%x\n", - f->inocache->ino, ref_offset(fn->raw)); + f->inocache->ino, ref_offset(rii.latest_ref)); up(&f->sem); jffs2_do_clear_inode(c, f); return -EIO; @@ -799,17 +1223,22 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, switch(jemode_to_cpu(latest_node->mode) & S_IFMT) { case S_IFDIR: - if (mctime_ver > je32_to_cpu(latest_node->version)) { + if (rii.mctime_ver > je32_to_cpu(latest_node->version)) { /* The times in the latest_node are actually older than mctime in the latest dirent. Cheat. */ - latest_node->ctime = latest_node->mtime = cpu_to_je32(latest_mctime); + latest_node->ctime = latest_node->mtime = cpu_to_je32(rii.latest_mctime); } break; case S_IFREG: /* If it was a regular file, truncate it to the latest node's isize */ - jffs2_truncate_fragtree(c, &f->fragtree, je32_to_cpu(latest_node->isize)); + new_size = jffs2_truncate_fragtree(c, &f->fragtree, je32_to_cpu(latest_node->isize)); + if (new_size != je32_to_cpu(latest_node->isize)) { + JFFS2_WARNING("Truncating ino #%u to %d bytes failed because it only had %d bytes to start with!\n", + f->inocache->ino, je32_to_cpu(latest_node->isize), new_size); + latest_node->isize = cpu_to_je32(new_size); + } break; case S_IFLNK: @@ -832,7 +1261,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, return -ENOMEM; } - ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node), + ret = jffs2_flash_read(c, ref_offset(rii.latest_ref) + sizeof(*latest_node), je32_to_cpu(latest_node->csize), &retlen, (char *)f->target); if (ret || retlen != je32_to_cpu(latest_node->csize)) { diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 7fb45bd4915c..2a1c976c7924 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -1,15 +1,14 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: scan.c,v 1.125 2005/09/30 13:59:13 dedekind Exp $ - * */ + #include <linux/kernel.h> #include <linux/sched.h> #include <linux/slab.h> @@ -636,16 +635,17 @@ scan_more: if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) { uint32_t inbuf_ofs; - uint32_t empty_start; + uint32_t empty_start, scan_end; empty_start = ofs; ofs += 4; + scan_end = min_t(uint32_t, EMPTY_SCAN_SIZE(c->sector_size)/8, buf_len); D1(printk(KERN_DEBUG "Found empty flash at 0x%08x\n", ofs)); more_empty: inbuf_ofs = ofs - buf_ofs; - while (inbuf_ofs < buf_len) { - if (*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff) { + while (inbuf_ofs < scan_end) { + if (unlikely(*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff)) { printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n", empty_start, ofs); if ((err = jffs2_scan_dirty_space(c, jeb, ofs-empty_start))) @@ -666,7 +666,11 @@ scan_more: D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size))); return BLK_STATE_CLEANMARKER; } - + if (!buf_size && (scan_end != buf_len)) {/* XIP/point case */ + scan_end = buf_len; + goto more_empty; + } + /* See how much more there is to read in this eraseblock... */ buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); if (!buf_len) { @@ -676,6 +680,8 @@ scan_more: empty_start)); break; } + /* point never reaches here */ + scan_end = buf_len; D1(printk(KERN_DEBUG "Reading another 0x%x at 0x%08x\n", buf_len, ofs)); err = jffs2_fill_scan_buf(c, buf, ofs, buf_len); if (err) @@ -734,18 +740,8 @@ scan_more: ofs += 4; continue; } - /* Due to poor choice of crc32 seed, an all-zero node will have a correct CRC */ - if (!je32_to_cpu(node->hdr_crc) && !je16_to_cpu(node->nodetype) && - !je16_to_cpu(node->magic) && !je32_to_cpu(node->totlen)) { - noisy_printk(&noise, "jffs2_scan_eraseblock(): All zero node header at 0x%08x.\n", ofs); - if ((err = jffs2_scan_dirty_space(c, jeb, 4))) - return err; - ofs += 4; - continue; - } - if (ofs + je32_to_cpu(node->totlen) > - jeb->offset + c->sector_size) { + if (ofs + je32_to_cpu(node->totlen) > jeb->offset + c->sector_size) { /* Eep. Node goes over the end of the erase block. */ printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n", ofs, je32_to_cpu(node->totlen)); @@ -952,8 +948,7 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s) { struct jffs2_inode_cache *ic; - uint32_t ino = je32_to_cpu(ri->ino); - int err; + uint32_t crc, ino = je32_to_cpu(ri->ino); D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", ofs)); @@ -966,21 +961,22 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc Which means that the _full_ amount of time to get to proper write mode with GC operational may actually be _longer_ than before. Sucks to be me. */ + /* Check the node CRC in any case. */ + crc = crc32(0, ri, sizeof(*ri)-8); + if (crc != je32_to_cpu(ri->node_crc)) { + printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on " + "node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ofs, je32_to_cpu(ri->node_crc), crc); + /* + * We believe totlen because the CRC on the node + * _header_ was OK, just the node itself failed. + */ + return jffs2_scan_dirty_space(c, jeb, + PAD(je32_to_cpu(ri->totlen))); + } + ic = jffs2_get_ino_cache(c, ino); if (!ic) { - /* Inocache get failed. Either we read a bogus ino# or it's just genuinely the - first node we found for this inode. Do a CRC check to protect against the former - case */ - uint32_t crc = crc32(0, ri, sizeof(*ri)-8); - - if (crc != je32_to_cpu(ri->node_crc)) { - printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", - ofs, je32_to_cpu(ri->node_crc), crc); - /* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */ - if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(ri->totlen))))) - return err; - return 0; - } ic = jffs2_scan_make_ino_cache(c, ino); if (!ic) return -ENOMEM; diff --git a/fs/jffs2/security.c b/fs/jffs2/security.c index 52a9894a6364..bc9f6ba10823 100644 --- a/fs/jffs2/security.c +++ b/fs/jffs2/security.c @@ -1,13 +1,14 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2006 NEC Corporation + * Copyright © 2006 NEC Corporation * * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> * * For licensing information, see the file 'LICENCE' in this directory. * */ + #include <linux/kernel.h> #include <linux/slab.h> #include <linux/fs.h> diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 30f888414ce7..d828b296392a 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -1,16 +1,14 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, - * 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> + * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, + * 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> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: summary.c,v 1.4 2005/09/26 11:37:21 havasi Exp $ - * */ #include <linux/kernel.h> diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h index 6bf1f6aa4552..0c6669e21390 100644 --- a/fs/jffs2/summary.h +++ b/fs/jffs2/summary.h @@ -1,15 +1,13 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, - * Zoltan Sogor <weth@inf.u-szeged.hu>, - * Patrik Kluba <pajko@halom.u-szeged.hu>, - * University of Szeged, Hungary + * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, + * Zoltan Sogor <weth@inf.u-szeged.hu>, + * Patrik Kluba <pajko@halom.u-szeged.hu>, + * University of Szeged, Hungary * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: summary.h,v 1.2 2005/09/26 11:37:21 havasi Exp $ - * */ #ifndef JFFS2_SUMMARY_H diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index cc7e8e71ad46..e51164a8a8d4 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -1,14 +1,12 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: super.c,v 1.110 2005/11/07 11:14:42 gleixner Exp $ - * */ #include <linux/kernel.h> @@ -347,7 +345,7 @@ static int __init init_jffs2_fs(void) #ifdef CONFIG_JFFS2_SUMMARY " (SUMMARY) " #endif - " (C) 2001-2006 Red Hat, Inc.\n"); + " © 2001-2006 Red Hat, Inc.\n"); jffs2_inode_cachep = kmem_cache_create("jffs2_i", sizeof(struct jffs2_inode_info), diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c index 7e4882c8a7ed..b7339c3b6ad9 100644 --- a/fs/jffs2/symlink.c +++ b/fs/jffs2/symlink.c @@ -1,17 +1,14 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001, 2002 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: symlink.c,v 1.19 2005/11/07 11:14:42 gleixner Exp $ - * */ - #include <linux/kernel.h> #include <linux/slab.h> #include <linux/fs.h> diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index ab86031b3c07..c556e85a565c 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -1,16 +1,14 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. - * Copyright (C) 2004 Thomas Gleixner <tglx@linutronix.de> + * Copyright © 2001-2007 Red Hat, Inc. + * Copyright © 2004 Thomas Gleixner <tglx@linutronix.de> * * Created by David Woodhouse <dwmw2@infradead.org> * Modified debugged and enhanced by Thomas Gleixner <tglx@linutronix.de> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: wbuf.c,v 1.100 2005/09/30 13:59:13 dedekind Exp $ - * */ #include <linux/kernel.h> @@ -345,6 +343,9 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) return; } + /* The summary is not recovered, so it must be disabled for this erase block */ + jffs2_sum_disable_collecting(c->summary); + ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, nr_refile); if (ret) { printk(KERN_WARNING "Failed to allocate node refs for wbuf recovery. Data loss ensues.\n"); @@ -967,9 +968,9 @@ exit: static const struct jffs2_unknown_node oob_cleanmarker = { - .magic = cpu_to_je16(JFFS2_MAGIC_BITMASK), - .nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER), - .totlen = cpu_to_je32(8) + .magic = constant_cpu_to_je16(JFFS2_MAGIC_BITMASK), + .nodetype = constant_cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER), + .totlen = constant_cpu_to_je32(8) }; /* diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index 67176792e138..c9fe0ab3a329 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c @@ -1,14 +1,12 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001-2003 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: write.c,v 1.97 2005/11/07 11:14:42 gleixner Exp $ - * */ #include <linux/kernel.h> @@ -507,8 +505,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t alloclen; int ret; - if (1 /* alternative branch needs testing */ || - !jffs2_can_mark_obsolete(c)) { + if (!jffs2_can_mark_obsolete(c)) { /* We can't mark stuff obsolete on the medium. We need to write a deletion dirent */ rd = jffs2_alloc_raw_dirent(); diff --git a/fs/jffs2/writev.c b/fs/jffs2/writev.c index c638ae1008de..b9276b11bac6 100644 --- a/fs/jffs2/writev.c +++ b/fs/jffs2/writev.c @@ -1,14 +1,12 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001, 2002 Red Hat, Inc. + * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: writev.c,v 1.8 2005/09/09 15:11:58 havasi Exp $ - * */ #include <linux/kernel.h> diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index 4bb3f1897330..78fc08893a6c 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c @@ -1,13 +1,14 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2006 NEC Corporation + * Copyright © 2006 NEC Corporation * * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> * * For licensing information, see the file 'LICENCE' in this directory. * */ + #include <linux/kernel.h> #include <linux/slab.h> #include <linux/fs.h> diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h index 06a5c69dcf8b..3b0ff2925937 100644 --- a/fs/jffs2/xattr.h +++ b/fs/jffs2/xattr.h @@ -1,13 +1,14 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2006 NEC Corporation + * Copyright © 2006 NEC Corporation * * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> * * For licensing information, see the file 'LICENCE' in this directory. * */ + #ifndef _JFFS2_FS_XATTR_H_ #define _JFFS2_FS_XATTR_H_ diff --git a/fs/jffs2/xattr_trusted.c b/fs/jffs2/xattr_trusted.c index ed046e19dbfa..8ec5765ef348 100644 --- a/fs/jffs2/xattr_trusted.c +++ b/fs/jffs2/xattr_trusted.c @@ -1,13 +1,14 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2006 NEC Corporation + * Copyright © 2006 NEC Corporation * * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> * * For licensing information, see the file 'LICENCE' in this directory. * */ + #include <linux/kernel.h> #include <linux/fs.h> #include <linux/jffs2.h> diff --git a/fs/jffs2/xattr_user.c b/fs/jffs2/xattr_user.c index 2f8e9aa01ea0..40942bc516bb 100644 --- a/fs/jffs2/xattr_user.c +++ b/fs/jffs2/xattr_user.c @@ -1,13 +1,14 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2006 NEC Corporation + * Copyright © 2006 NEC Corporation * * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> * * For licensing information, see the file 'LICENCE' in this directory. * */ + #include <linux/kernel.h> #include <linux/fs.h> #include <linux/jffs2.h> |