Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
authorDavid Woodhouse <dwmw2@infradead.org>
Thu, 26 Apr 2007 08:31:28 +0000 (09:31 +0100)
committerDavid Woodhouse <dwmw2@infradead.org>
Thu, 26 Apr 2007 08:31:28 +0000 (09:31 +0100)
72 files changed:
drivers/mtd/Kconfig
drivers/mtd/chips/Kconfig
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/chips/fwh_lock.h
drivers/mtd/devices/Kconfig
drivers/mtd/devices/Makefile
drivers/mtd/devices/at91_dataflash26.c [new file with mode: 0644]
drivers/mtd/devices/block2mtd.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/alchemy-flash.c
drivers/mtd/maps/plat-ram.c
drivers/mtd/maps/pmcmsp-flash.c [new file with mode: 0644]
drivers/mtd/maps/pmcmsp-ramroot.c [new file with mode: 0644]
drivers/mtd/mtd_blkdevs.c
drivers/mtd/mtdchar.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/cafe.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_ids.c
drivers/mtd/nand/nandsim.c
drivers/mtd/onenand/Kconfig
drivers/mtd/onenand/onenand_base.c
fs/jffs2/LICENCE
fs/jffs2/Makefile
fs/jffs2/README.Locking
fs/jffs2/TODO
fs/jffs2/acl.c
fs/jffs2/acl.h
fs/jffs2/background.c
fs/jffs2/build.c
fs/jffs2/compr.c
fs/jffs2/compr.h
fs/jffs2/compr_rtime.c
fs/jffs2/compr_rubin.c
fs/jffs2/compr_rubin.h [deleted file]
fs/jffs2/compr_zlib.c
fs/jffs2/comprtest.c [deleted file]
fs/jffs2/debug.c
fs/jffs2/debug.h
fs/jffs2/dir.c
fs/jffs2/erase.c
fs/jffs2/file.c
fs/jffs2/fs.c
fs/jffs2/gc.c
fs/jffs2/ioctl.c
fs/jffs2/jffs2_fs_i.h
fs/jffs2/jffs2_fs_sb.h
fs/jffs2/malloc.c
fs/jffs2/nodelist.c
fs/jffs2/nodelist.h
fs/jffs2/nodemgmt.c
fs/jffs2/os-linux.h
fs/jffs2/pushpull.h [deleted file]
fs/jffs2/read.c
fs/jffs2/readinode.c
fs/jffs2/scan.c
fs/jffs2/security.c
fs/jffs2/summary.c
fs/jffs2/summary.h
fs/jffs2/super.c
fs/jffs2/symlink.c
fs/jffs2/wbuf.c
fs/jffs2/write.c
fs/jffs2/writev.c
fs/jffs2/xattr.c
fs/jffs2/xattr.h
fs/jffs2/xattr_trusted.c
fs/jffs2/xattr_user.c
include/linux/mtd/iflash.h [deleted file]
include/linux/mtd/mtd.h
include/linux/mtd/nand.h

index 26f75c2..fedf9b7 100644 (file)
@@ -1,8 +1,6 @@
 # $Id: Kconfig,v 1.11 2005/11/07 11:14:19 gleixner Exp $
 
-menu "Memory Technology Devices (MTD)"
-
-config MTD
+menuconfig MTD
        tristate "Memory Technology Device (MTD) support"
        help
          Memory Technology Devices are flash, RAM and similar chips, often
@@ -13,9 +11,10 @@ config MTD
          them. It will also allow you to select individual drivers for
          particular hardware and users of MTD devices. If unsure, say N.
 
+if MTD
+
 config MTD_DEBUG
        bool "Debugging"
-       depends on MTD
        help
          This turns on low-level debugging for the entire MTD sub-system.
          Normally, you should say 'N'.
@@ -29,7 +28,6 @@ config MTD_DEBUG_VERBOSE
 
 config MTD_CONCAT
        tristate "MTD concatenating support"
-       depends on MTD
        help
          Support for concatenating several MTD devices into a single
          (virtual) one. This allows you to have -for example- a JFFS(2)
@@ -38,7 +36,6 @@ config MTD_CONCAT
 
 config MTD_PARTITIONS
        bool "MTD partitioning support"
-       depends on MTD
        help
          If you have a device which needs to divide its flash chip(s) up
          into multiple 'partitions', each of which appears to the user as
@@ -153,11 +150,9 @@ config MTD_AFS_PARTS
          'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example.
 
 comment "User Modules And Translation Layers"
-       depends on MTD
 
 config MTD_CHAR
        tristate "Direct char device access to MTD devices"
-       depends on MTD
        help
          This provides a character device for each MTD device present in
          the system, allowing the user to read and write directly to the
@@ -166,12 +161,12 @@ config MTD_CHAR
 
 config MTD_BLKDEVS
        tristate "Common interface to block layer for MTD 'translation layers'"
-       depends on MTD && BLOCK
+       depends on BLOCK
        default n
 
 config MTD_BLOCK
        tristate "Caching block device access to MTD devices"
-       depends on MTD && BLOCK
+       depends on BLOCK
        select MTD_BLKDEVS
        ---help---
          Although most flash chips have an erase size too large to be useful
@@ -194,7 +189,7 @@ config MTD_BLOCK
 
 config MTD_BLOCK_RO
        tristate "Readonly block device access to MTD devices"
-       depends on MTD_BLOCK!=y && MTD && BLOCK
+       depends on MTD_BLOCK!=y && BLOCK
        select MTD_BLKDEVS
        help
          This allows you to mount read-only file systems (such as cramfs)
@@ -206,7 +201,7 @@ config MTD_BLOCK_RO
 
 config FTL
        tristate "FTL (Flash Translation Layer) support"
-       depends on MTD && BLOCK
+       depends on BLOCK
        select MTD_BLKDEVS
        ---help---
          This provides support for the original Flash Translation Layer which
@@ -223,7 +218,7 @@ config FTL
 
 config NFTL
        tristate "NFTL (NAND Flash Translation Layer) support"
-       depends on MTD && BLOCK
+       depends on BLOCK
        select MTD_BLKDEVS
        ---help---
          This provides support for the NAND Flash Translation Layer which is
@@ -247,7 +242,7 @@ config NFTL_RW
 
 config INFTL
        tristate "INFTL (Inverse NAND Flash Translation Layer) support"
-       depends on MTD && BLOCK
+       depends on BLOCK
        select MTD_BLKDEVS
        ---help---
          This provides support for the Inverse NAND Flash Translation
@@ -265,7 +260,7 @@ config INFTL
 
 config RFD_FTL
         tristate "Resident Flash Disk (Flash Translation Layer) support"
-       depends on MTD && BLOCK
+       depends on BLOCK
        select MTD_BLKDEVS
        ---help---
          This provides support for the flash translation layer known
@@ -276,7 +271,7 @@ config RFD_FTL
 
 config SSFDC
        tristate "NAND SSFDC (SmartMedia) read only translation layer"
-       depends on MTD && BLOCK
+       depends on BLOCK
        select MTD_BLKDEVS
        help
          This enables read only access to SmartMedia formatted NAND
@@ -292,5 +287,4 @@ source "drivers/mtd/nand/Kconfig"
 
 source "drivers/mtd/onenand/Kconfig"
 
-endmenu
-
+endif # MTD
index 72e6d73..d28e0fc 100644 (file)
@@ -6,7 +6,6 @@ menu "RAM/ROM/Flash chip drivers"
 
 config MTD_CFI
        tristate "Detect flash chips by Common Flash Interface (CFI) probe"
-       depends on MTD
        select MTD_GEN_PROBE
        help
          The Common Flash Interface specification was developed by Intel,
@@ -18,7 +17,6 @@ config MTD_CFI
 
 config MTD_JEDECPROBE
        tristate "Detect non-CFI AMD/JEDEC-compatible flash chips"
-       depends on MTD
        select MTD_GEN_PROBE
        help
          This option enables JEDEC-style probing of flash chips which are not
@@ -213,21 +211,18 @@ config MTD_CFI_UTIL
 
 config MTD_RAM
        tristate "Support for RAM chips in bus mapping"
-       depends on MTD
        help
          This option enables basic support for RAM chips accessed through
          a bus mapping driver.
 
 config MTD_ROM
        tristate "Support for ROM chips in bus mapping"
-       depends on MTD
        help
          This option enables basic support for ROM chips accessed through
          a bus mapping driver.
 
 config MTD_ABSENT
        tristate "Support for absent chips in bus mapping"
-       depends on MTD
        help
          This option enables support for a dummy probing driver used to
          allocated placeholder MTD devices on systems that have socketed
@@ -237,7 +232,6 @@ config MTD_ABSENT
          with this driver will return -ENODEV upon access.
 
 config MTD_OBSOLETE_CHIPS
-       depends on MTD
        bool "Older (theoretically obsoleted now) drivers for non-CFI chips"
        help
          This option does not enable any code directly, but will allow you to
@@ -250,7 +244,7 @@ config MTD_OBSOLETE_CHIPS
 
 config MTD_AMDSTD
        tristate "AMD compatible flash chip support (non-CFI)"
-       depends on MTD && MTD_OBSOLETE_CHIPS && BROKEN
+       depends on MTD_OBSOLETE_CHIPS && BROKEN
        help
          This option enables support for flash chips using AMD-compatible
          commands, including some which are not CFI-compatible and hence
@@ -260,7 +254,7 @@ config MTD_AMDSTD
 
 config MTD_SHARP
        tristate "pre-CFI Sharp chip support"
-       depends on MTD && MTD_OBSOLETE_CHIPS
+       depends on MTD_OBSOLETE_CHIPS
        help
          This option enables support for flash chips using Sharp-compatible
          commands, including some which are not CFI-compatible and hence
@@ -268,7 +262,7 @@ config MTD_SHARP
 
 config MTD_JEDEC
        tristate "JEDEC device support"
-       depends on MTD && MTD_OBSOLETE_CHIPS && BROKEN
+       depends on MTD_OBSOLETE_CHIPS && BROKEN
        help
          Enable older JEDEC flash interface devices for self
          programming flash.  It is commonly used in older AMD chips.  It is
index f334959..2f19fa7 100644 (file)
@@ -15,6 +15,8 @@
  *     - optimized write buffer method
  * 02/05/2002  Christopher Hoover <ch@hpl.hp.com>/<ch@murgatroid.com>
  *     - reworked lock/unlock/erase support for var size flash
+ * 21/03/2007   Rodolfo Giometti <giometti@linux.it>
+ *     - auto unlock sectors on resume for auto locking flash on power up
  */
 
 #include <linux/module.h>
@@ -30,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/reboot.h>
+#include <linux/bitmap.h>
 #include <linux/mtd/xip.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/mtd.h>
@@ -220,6 +223,15 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
        }
 }
 
+/*
+ * Some chips power-up with all sectors locked by default.
+ */
+static void fixup_use_powerup_lock(struct mtd_info *mtd, void *param)
+{
+       printk(KERN_INFO "Using auto-unlock on power-up/resume\n" );
+       mtd->flags |= MTD_STUPID_LOCK;
+}
+
 static struct cfi_fixup cfi_fixup_table[] = {
 #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
        { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL },
@@ -232,6 +244,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
 #endif
        { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL },
        { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL },
+       { MANUFACTURER_INTEL, 0x891c,         fixup_use_powerup_lock, NULL, },
        { 0, 0, NULL, NULL }
 };
 
@@ -460,6 +473,7 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
                        mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
                        mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
                        mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
+                       mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].lockmap = kmalloc(ernum / 8 + 1, GFP_KERNEL);
                }
                offset += (ersize * ernum);
        }
@@ -1825,8 +1839,7 @@ static void cfi_intelext_sync (struct mtd_info *mtd)
        }
 }
 
-#ifdef DEBUG_LOCK_BITS
-static int __xipram do_printlockstatus_oneblock(struct map_info *map,
+static int __xipram do_getlockstatus_oneblock(struct map_info *map,
                                                struct flchip *chip,
                                                unsigned long adr,
                                                int len, void *thunk)
@@ -1840,8 +1853,17 @@ static int __xipram do_printlockstatus_oneblock(struct map_info *map,
        chip->state = FL_JEDEC_QUERY;
        status = cfi_read_query(map, adr+(2*ofs_factor));
        xip_enable(map, chip, 0);
+       return status;
+}
+
+#ifdef DEBUG_LOCK_BITS
+static int __xipram do_printlockstatus_oneblock(struct map_info *map,
+                                               struct flchip *chip,
+                                               unsigned long adr,
+                                               int len, void *thunk)
+{
        printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
-              adr, status);
+              adr, do_getlockstatus_oneblock(map, chip, adr, len, thunk));
        return 0;
 }
 #endif
@@ -2216,14 +2238,45 @@ static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd,
 
 #endif
 
+static void cfi_intelext_save_locks(struct mtd_info *mtd)
+{
+       struct mtd_erase_region_info *region;
+       int block, status, i;
+       unsigned long adr;
+       size_t len;
+
+       for (i = 0; i < mtd->numeraseregions; i++) {
+               region = &mtd->eraseregions[i];
+               if (!region->lockmap)
+                       continue;
+
+               for (block = 0; block < region->numblocks; block++){
+                       len = region->erasesize;
+                       adr = region->offset + block * len;
+
+                       status = cfi_varsize_frob(mtd,
+                                       do_getlockstatus_oneblock, adr, len, 0);
+                       if (status)
+                               set_bit(block, region->lockmap);
+                       else
+                               clear_bit(block, region->lockmap);
+               }
+       }
+}
+
 static int cfi_intelext_suspend(struct mtd_info *mtd)
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
+       struct cfi_pri_intelext *extp = cfi->cmdset_priv;
        int i;
        struct flchip *chip;
        int ret = 0;
 
+       if ((mtd->flags & MTD_STUPID_LOCK)
+           && extp && (extp->FeatureSupport & (1 << 5)))
+               cfi_intelext_save_locks(mtd);
+
        for (i=0; !ret && i<cfi->numchips; i++) {
                chip = &cfi->chips[i];
 
@@ -2285,10 +2338,33 @@ static int cfi_intelext_suspend(struct mtd_info *mtd)
        return ret;
 }
 
+static void cfi_intelext_restore_locks(struct mtd_info *mtd)
+{
+       struct mtd_erase_region_info *region;
+       int block, i;
+       unsigned long adr;
+       size_t len;
+
+       for (i = 0; i < mtd->numeraseregions; i++) {
+               region = &mtd->eraseregions[i];
+               if (!region->lockmap)
+                       continue;
+
+               for (block = 0; block < region->numblocks; block++) {
+                       len = region->erasesize;
+                       adr = region->offset + block * len;
+
+                       if (!test_bit(block, region->lockmap))
+                               cfi_intelext_unlock(mtd, adr, len);
+               }
+       }
+}
+
 static void cfi_intelext_resume(struct mtd_info *mtd)
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
+       struct cfi_pri_intelext *extp = cfi->cmdset_priv;
        int i;
        struct flchip *chip;
 
@@ -2307,6 +2383,10 @@ static void cfi_intelext_resume(struct mtd_info *mtd)
 
                spin_unlock(chip->mutex);
        }
+
+       if ((mtd->flags & MTD_STUPID_LOCK)
+           && extp && (extp->FeatureSupport & (1 << 5)))
+               cfi_intelext_restore_locks(mtd);
 }
 
 static int cfi_intelext_reset(struct mtd_info *mtd)
@@ -2347,12 +2427,19 @@ static void cfi_intelext_destroy(struct mtd_info *mtd)
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
+       struct mtd_erase_region_info *region;
+       int i;
        cfi_intelext_reset(mtd);
        unregister_reboot_notifier(&mtd->reboot_notifier);
        kfree(cfi->cmdset_priv);
        kfree(cfi->cfiq);
        kfree(cfi->chips[0].priv);
        kfree(cfi);
+       for (i = 0; i < mtd->numeraseregions; i++) {
+               region = &mtd->eraseregions[i];
+               if (region->lockmap)
+                       kfree(region->lockmap);
+       }
        kfree(mtd->eraseregions);
 }
 
index 77303ce..ab44f2b 100644 (file)
@@ -65,11 +65,12 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip,
                return ret;
        }
 
+       chip->oldstate = chip->state;
        chip->state = xxlt->state;
        map_write(map, CMD(xxlt->val), adr);
 
        /* Done and happy. */
-       chip->state = FL_READY;
+       chip->state = chip->oldstate;
        put_chip(map, chip, adr);
        spin_unlock(chip->mutex);
        return 0;
index 440f685..690c942 100644 (file)
@@ -6,7 +6,7 @@ menu "Self-contained MTD device drivers"
 
 config MTD_PMC551
        tristate "Ramix PMC551 PCI Mezzanine RAM card support"
-       depends on MTD && PCI
+       depends on PCI
        ---help---
          This provides a MTD device driver for the Ramix PMC551 RAM PCI card
          from Ramix Inc. <http://www.ramix.com/products/memory/pmc551.html>.
@@ -40,7 +40,7 @@ config MTD_PMC551_DEBUG
 
 config MTD_MS02NV
        tristate "DEC MS02-NV NVRAM module support"
-       depends on MTD && MACH_DECSTATION
+       depends on MACH_DECSTATION
        help
          This is an MTD driver for the DEC's MS02-NV (54-20948-01) battery
          backed-up NVRAM module.  The module was originally meant as an NFS
@@ -54,15 +54,23 @@ config MTD_MS02NV
 
 config MTD_DATAFLASH
        tristate "Support for AT45xxx DataFlash"
-       depends on MTD && SPI_MASTER && EXPERIMENTAL
+       depends on SPI_MASTER && EXPERIMENTAL
        help
          This enables access to AT45xxx DataFlash chips, using SPI.
          Sometimes DataFlash chips are packaged inside MMC-format
          cards; at this writing, the MMC stack won't handle those.
 
+config MTD_DATAFLASH26
+       tristate "AT91RM9200 DataFlash AT26xxx"
+       depends on MTD && ARCH_AT91RM9200 && AT91_SPI
+       help
+         This enables access to the DataFlash chip (AT26xxx) on an
+         AT91RM9200-based board.
+         If you have such a board and such a DataFlash, say 'Y'.
+
 config MTD_M25P80
        tristate "Support for M25 SPI Flash"
-       depends on MTD && SPI_MASTER && EXPERIMENTAL
+       depends on SPI_MASTER && EXPERIMENTAL
        help
          This enables access to ST M25P80 and similar SPI flash chips,
          used for program and data storage.  Set up your spi devices
@@ -70,7 +78,6 @@ config MTD_M25P80
 
 config MTD_SLRAM
        tristate "Uncached system RAM"
-       depends on MTD
        help
          If your CPU cannot cache all of the physical memory in your machine,
          you can still use it for storage or swap by using this driver to
@@ -78,7 +85,6 @@ config MTD_SLRAM
 
 config MTD_PHRAM
        tristate "Physical system RAM"
-       depends on MTD
        help
          This is a re-implementation of the slram driver above.
 
@@ -88,7 +94,7 @@ config MTD_PHRAM
 
 config MTD_LART
        tristate "28F160xx flash driver for LART"
-       depends on SA1100_LART && MTD
+       depends on SA1100_LART
        help
          This enables the flash driver for LART. Please note that you do
          not need any mapping/chip driver for LART. This one does it all
@@ -96,7 +102,6 @@ config MTD_LART
 
 config MTD_MTDRAM
        tristate "Test driver using RAM"
-       depends on MTD
        help
          This enables a test MTD device driver which uses vmalloc() to
          provide storage.  You probably want to say 'N' unless you're
@@ -136,7 +141,7 @@ config MTDRAM_ABS_POS
 
 config MTD_BLOCK2MTD
        tristate "MTD using block device"
-       depends on MTD && BLOCK
+       depends on BLOCK
        help
          This driver allows a block device to appear as an MTD. It would
          generally be used in the following cases:
@@ -150,7 +155,6 @@ comment "Disk-On-Chip Device Drivers"
 
 config MTD_DOC2000
        tristate "M-Systems Disk-On-Chip 2000 and Millennium (DEPRECATED)"
-       depends on MTD
        select MTD_DOCPROBE
        select MTD_NAND_IDS
        ---help---
@@ -173,7 +177,6 @@ config MTD_DOC2000
 
 config MTD_DOC2001
        tristate "M-Systems Disk-On-Chip Millennium-only alternative driver (DEPRECATED)"
-       depends on MTD
        select MTD_DOCPROBE
        select MTD_NAND_IDS
        ---help---
@@ -195,7 +198,6 @@ config MTD_DOC2001
 
 config MTD_DOC2001PLUS
        tristate "M-Systems Disk-On-Chip Millennium Plus"
-       depends on MTD
        select MTD_DOCPROBE
        select MTD_NAND_IDS
        ---help---
index 0f788d5..8ab568b 100644 (file)
@@ -16,4 +16,5 @@ obj-$(CONFIG_MTD_MTDRAM)      += mtdram.o
 obj-$(CONFIG_MTD_LART)         += lart.o
 obj-$(CONFIG_MTD_BLOCK2MTD)    += block2mtd.o
 obj-$(CONFIG_MTD_DATAFLASH)    += mtd_dataflash.o
+obj-$(CONFIG_MTD_DATAFLASH26)  += at91_dataflash26.o
 obj-$(CONFIG_MTD_M25P80)       += m25p80.o
diff --git a/drivers/mtd/devices/at91_dataflash26.c b/drivers/mtd/devices/at91_dataflash26.c
new file mode 100644 (file)
index 0000000..64ce37f
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+ * Atmel DataFlash driver for Atmel AT91RM9200 (Thunder)
+ * This is a largely modified version of at91_dataflash.c that
+ * supports AT26xxx dataflash chips. The original driver supports
+ * AT45xxx chips.
+ *
+ * Note: This driver was only tested with an AT26F004. It should be
+ * easy to make it work with other AT26xxx dataflash devices, though.
+ *
+ * Copyright (C) 2007 Hans J. Koch <hjk@linutronix.de>
+ * original Copyright (C) SAN People (Pty) Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+
+#include <asm/arch/at91_spi.h>
+
+#define DATAFLASH_MAX_DEVICES  4       /* max number of dataflash devices */
+
+#define MANUFACTURER_ID_ATMEL          0x1F
+
+/* command codes */
+
+#define AT26_OP_READ_STATUS            0x05
+#define AT26_OP_READ_DEV_ID            0x9F
+#define AT26_OP_ERASE_PAGE_4K          0x20
+#define AT26_OP_READ_ARRAY_FAST                0x0B
+#define AT26_OP_SEQUENTIAL_WRITE       0xAF
+#define AT26_OP_WRITE_ENABLE           0x06
+#define AT26_OP_WRITE_DISABLE          0x04
+#define AT26_OP_SECTOR_PROTECT         0x36
+#define AT26_OP_SECTOR_UNPROTECT       0x39
+
+/* status register bits */
+
+#define AT26_STATUS_BUSY               0x01
+#define AT26_STATUS_WRITE_ENABLE       0x02
+
+struct dataflash_local
+{
+       int spi;                        /* SPI chip-select number */
+       unsigned int page_size;         /* number of bytes per page */
+};
+
+
+/* Detected DataFlash devices */
+static struct mtd_info* mtd_devices[DATAFLASH_MAX_DEVICES];
+static int nr_devices = 0;
+
+/* Allocate a single SPI transfer descriptor.  We're assuming that if multiple
+   SPI transfers occur at the same time, spi_access_bus() will serialize them.
+   If this is not valid, then either (i) each dataflash 'priv' structure
+   needs it's own transfer descriptor, (ii) we lock this one, or (iii) use
+   another mechanism.   */
+static struct spi_transfer_list* spi_transfer_desc;
+
+/*
+ * Perform a SPI transfer to access the DataFlash device.
+ */
+static int do_spi_transfer(int nr, char* tx, int tx_len, char* rx, int rx_len,
+               char* txnext, int txnext_len, char* rxnext, int rxnext_len)
+{
+       struct spi_transfer_list* list = spi_transfer_desc;
+
+       list->tx[0] = tx;       list->txlen[0] = tx_len;
+       list->rx[0] = rx;       list->rxlen[0] = rx_len;
+
+       list->tx[1] = txnext;   list->txlen[1] = txnext_len;
+       list->rx[1] = rxnext;   list->rxlen[1] = rxnext_len;
+
+       list->nr_transfers = nr;
+       /* Note: spi_transfer() always returns 0, there are no error checks */
+       return spi_transfer(list);
+}
+
+/*
+ * Return the status of the DataFlash device.
+ */
+static unsigned char at91_dataflash26_status(void)
+{
+       unsigned char command[2];
+
+       command[0] = AT26_OP_READ_STATUS;
+       command[1] = 0;
+
+       do_spi_transfer(1, command, 2, command, 2, NULL, 0, NULL, 0);
+
+       return command[1];
+}
+
+/*
+ * Poll the DataFlash device until it is READY.
+ */
+static unsigned char at91_dataflash26_waitready(void)
+{
+       unsigned char status;
+
+       while (1) {
+               status = at91_dataflash26_status();
+               if (!(status & AT26_STATUS_BUSY))
+                       return status;
+       }
+}
+
+/*
+ * Enable/disable write access
+ */
+ static void at91_dataflash26_write_enable(int enable)
+{
+       unsigned char cmd[2];
+
+       DEBUG(MTD_DEBUG_LEVEL3, "write_enable: enable=%i\n", enable);
+
+       if (enable)
+               cmd[0] = AT26_OP_WRITE_ENABLE;
+       else
+               cmd[0] = AT26_OP_WRITE_DISABLE;
+       cmd[1] = 0;
+
+       do_spi_transfer(1, cmd, 2, cmd, 2, NULL, 0, NULL, 0);
+}
+
+/*
+ * Protect/unprotect sector
+ */
+ static void at91_dataflash26_sector_protect(loff_t addr, int protect)
+{
+       unsigned char cmd[4];
+
+       DEBUG(MTD_DEBUG_LEVEL3, "sector_protect: addr=0x%06x prot=%d\n",
+              addr, protect);
+
+       if (protect)
+               cmd[0] = AT26_OP_SECTOR_PROTECT;
+       else
+               cmd[0] = AT26_OP_SECTOR_UNPROTECT;
+       cmd[1] = (addr & 0x00FF0000) >> 16;
+       cmd[2] = (addr & 0x0000FF00) >> 8;
+       cmd[3] = (addr & 0x000000FF);
+
+       do_spi_transfer(1, cmd, 4, cmd, 4, NULL, 0, NULL, 0);
+}
+
+/*
+ * Erase blocks of flash.
+ */
+static int at91_dataflash26_erase(struct mtd_info *mtd,
+                                 struct erase_info *instr)
+{
+       struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
+       unsigned char cmd[4];
+
+       DEBUG(MTD_DEBUG_LEVEL1, "dataflash_erase: addr=0x%06x len=%i\n",
+              instr->addr, instr->len);
+
+       /* Sanity checks */
+       if (priv->page_size != 4096)
+               return -EINVAL; /* Can't handle other sizes at the moment */
+
+       if (   ((instr->len % mtd->erasesize) != 0)
+           || ((instr->len % priv->page_size) != 0)
+           || ((instr->addr % priv->page_size) != 0)
+           || ((instr->addr + instr->len) > mtd->size))
+               return -EINVAL;
+
+       spi_access_bus(priv->spi);
+
+       while (instr->len > 0) {
+               at91_dataflash26_write_enable(1);
+               at91_dataflash26_sector_protect(instr->addr, 0);
+               at91_dataflash26_write_enable(1);
+               cmd[0] = AT26_OP_ERASE_PAGE_4K;
+               cmd[1] = (instr->addr & 0x00FF0000) >> 16;
+               cmd[2] = (instr->addr & 0x0000FF00) >> 8;
+               cmd[3] = (instr->addr & 0x000000FF);
+
+               DEBUG(MTD_DEBUG_LEVEL3, "ERASE: (0x%02x) 0x%02x 0x%02x"
+                                       "0x%02x\n",
+                       cmd[0], cmd[1], cmd[2], cmd[3]);
+
+               do_spi_transfer(1, cmd, 4, cmd, 4, NULL, 0, NULL, 0);
+               at91_dataflash26_waitready();
+
+               instr->addr += priv->page_size;  /* next page */
+               instr->len -= priv->page_size;
+       }
+
+       at91_dataflash26_write_enable(0);
+       spi_release_bus(priv->spi);
+
+       /* Inform MTD subsystem that erase is complete */
+       instr->state = MTD_ERASE_DONE;
+       if (instr->callback)
+               instr->callback(instr);
+
+       return 0;
+}
+
+/*
+ * Read from the DataFlash device.
+ *   from   : Start offset in flash device
+ *   len    : Number of bytes to read
+ *   retlen : Number of bytes actually read
+ *   buf    : Buffer that will receive data
+ */
+static int at91_dataflash26_read(struct mtd_info *mtd, loff_t from, size_t len,
+                                size_t *retlen, u_char *buf)
+{
+       struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
+       unsigned char cmd[5];
+
+       DEBUG(MTD_DEBUG_LEVEL1, "dataflash_read: %lli .. %lli\n",
+             from, from+len);
+
+       *retlen = 0;
+
+       /* Sanity checks */
+       if (!len)
+               return 0;
+       if (from + len > mtd->size)
+               return -EINVAL;
+
+       cmd[0] = AT26_OP_READ_ARRAY_FAST;
+       cmd[1] = (from & 0x00FF0000) >> 16;
+       cmd[2] = (from & 0x0000FF00) >> 8;
+       cmd[3] = (from & 0x000000FF);
+       /* cmd[4] is a "Don't care" byte  */
+
+       DEBUG(MTD_DEBUG_LEVEL3, "READ: (0x%02x) 0x%02x 0x%02x 0x%02x\n",
+              cmd[0], cmd[1], cmd[2], cmd[3]);
+
+       spi_access_bus(priv->spi);
+       do_spi_transfer(2, cmd, 5, cmd, 5, buf, len, buf, len);
+       spi_release_bus(priv->spi);
+
+       *retlen = len;
+       return 0;
+}
+
+/*
+ * Write to the DataFlash device.
+ *   to     : Start offset in flash device
+ *   len    : Number of bytes to write
+ *   retlen : Number of bytes actually written
+ *   buf    : Buffer containing the data
+ */
+static int at91_dataflash26_write(struct mtd_info *mtd, loff_t to, size_t len,
+                                 size_t *retlen, const u_char *buf)
+{
+       struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
+       unsigned int addr, buf_index = 0;
+       int ret = -EIO, sector, last_sector;
+       unsigned char status, cmd[5];
+
+       DEBUG(MTD_DEBUG_LEVEL1, "dataflash_write: %lli .. %lli\n", to, to+len);
+
+       *retlen = 0;
+
+       /* Sanity checks */
+       if (!len)
+               return 0;
+       if (to + len > mtd->size)
+               return -EINVAL;
+
+       spi_access_bus(priv->spi);
+
+       addr = to;
+       last_sector = -1;
+
+       while (buf_index < len) {
+               sector = addr / priv->page_size;
+               /* Write first byte if a new sector begins */
+               if (sector != last_sector) {
+                       at91_dataflash26_write_enable(1);
+                       at91_dataflash26_sector_protect(addr, 0);
+                       at91_dataflash26_write_enable(1);
+
+                       /* Program first byte of a new sector */
+                       cmd[0] = AT26_OP_SEQUENTIAL_WRITE;
+                       cmd[1] = (addr & 0x00FF0000) >> 16;
+                       cmd[2] = (addr & 0x0000FF00) >> 8;
+                       cmd[3] = (addr & 0x000000FF);
+                       cmd[4] = buf[buf_index++];
+                       do_spi_transfer(1, cmd, 5, cmd, 5, NULL, 0, NULL, 0);
+                       status = at91_dataflash26_waitready();
+                       addr++;
+                       /* On write errors, the chip resets the write enable
+                          flag. This also happens after the last byte of a
+                          sector is successfully programmed. */
+                       if (   ( !(status & AT26_STATUS_WRITE_ENABLE))
+                           && ((addr % priv->page_size) != 0) ) {
+                               DEBUG(MTD_DEBUG_LEVEL1,
+                                       "write error1: addr=0x%06x, "
+                                       "status=0x%02x\n", addr, status);
+                               goto write_err;
+                       }
+                       (*retlen)++;
+                       last_sector = sector;
+               }
+
+               /* Write subsequent bytes in the same sector */
+               cmd[0] = AT26_OP_SEQUENTIAL_WRITE;
+               cmd[1] = buf[buf_index++];
+               do_spi_transfer(1, cmd, 2, cmd, 2, NULL, 0, NULL, 0);
+               status = at91_dataflash26_waitready();
+               addr++;
+
+               if (   ( !(status & AT26_STATUS_WRITE_ENABLE))
+                   && ((addr % priv->page_size) != 0) ) {
+                       DEBUG(MTD_DEBUG_LEVEL1, "write error2: addr=0x%06x, "
+                               "status=0x%02x\n", addr, status);
+                       goto write_err;
+               }
+
+               (*retlen)++;
+       }
+
+       ret = 0;
+       at91_dataflash26_write_enable(0);
+write_err:
+       spi_release_bus(priv->spi);
+       return ret;
+}
+
+/*
+ * Initialize and register DataFlash device with MTD subsystem.
+ */
+static int __init add_dataflash(int channel, char *name, int nr_pages,
+                               int pagesize)
+{
+       struct mtd_info *device;
+       struct dataflash_local *priv;
+
+       if (nr_devices >= DATAFLASH_MAX_DEVICES) {
+               printk(KERN_ERR "at91_dataflash26: Too many devices "
+                               "detected\n");
+               return 0;
+       }
+
+       device = kzalloc(sizeof(struct mtd_info) + strlen(name) + 8,
+                        GFP_KERNEL);
+       if (!device)
+               return -ENOMEM;
+
+       device->name = (char *)&device[1];
+       sprintf(device->name, "%s.spi%d", name, channel);
+       device->size = nr_pages * pagesize;
+       device->erasesize = pagesize;
+       device->owner = THIS_MODULE;
+       device->type = MTD_DATAFLASH;
+       device->flags = MTD_CAP_NORFLASH;
+       device->erase = at91_dataflash26_erase;
+       device->read = at91_dataflash26_read;
+       device->write = at91_dataflash26_write;
+
+       priv = (struct dataflash_local *)kzalloc(sizeof(struct dataflash_local),
+               GFP_KERNEL);
+       if (!priv) {
+               kfree(device);
+               return -ENOMEM;
+       }
+
+       priv->spi = channel;
+       priv->page_size = pagesize;
+       device->priv = priv;
+
+       mtd_devices[nr_devices] = device;
+       nr_devices++;
+       printk(KERN_INFO "at91_dataflash26: %s detected [spi%i] (%i bytes)\n",
+              name, channel, device->size);
+
+       return add_mtd_device(device);
+}
+
+/*
+ * Detect and initialize DataFlash device connected to specified SPI channel.
+ *
+ */
+
+struct dataflash26_types {
+       unsigned char id0;
+       unsigned char id1;
+       char *name;
+       int pagesize;
+       int nr_pages;
+};
+
+struct dataflash26_types df26_types[] = {
+       {
+               .id0 = 0x04,
+               .id1 = 0x00,
+               .name = "AT26F004",
+               .pagesize = 4096,
+               .nr_pages = 128,
+       },
+       {
+               .id0 = 0x45,
+               .id1 = 0x01,
+               .name = "AT26DF081A", /* Not tested ! */
+               .pagesize = 4096,
+               .nr_pages = 256,
+       },
+};
+
+static int __init at91_dataflash26_detect(int channel)
+{
+       unsigned char status, cmd[5];
+       int i;
+
+       spi_access_bus(channel);
+       status = at91_dataflash26_status();
+
+       if (status == 0 || status == 0xff) {
+               printk(KERN_ERR "at91_dataflash26_detect: status error %d\n",
+                       status);
+               spi_release_bus(channel);
+               return -ENODEV;
+       }
+
+       cmd[0] = AT26_OP_READ_DEV_ID;
+       do_spi_transfer(1, cmd, 5, cmd, 5, NULL, 0, NULL, 0);
+       spi_release_bus(channel);
+
+       if (cmd[1] != MANUFACTURER_ID_ATMEL)
+               return -ENODEV;
+
+       for (i = 0; i < ARRAY_SIZE(df26_types); i++) {
+               if (   cmd[2] == df26_types[i].id0
+                   && cmd[3] == df26_types[i].id1)
+                       return add_dataflash(channel,
+                                               df26_types[i].name,
+                                               df26_types[i].nr_pages,
+                                               df26_types[i].pagesize);
+       }
+
+       printk(KERN_ERR "at91_dataflash26_detect: Unsupported device "
+                       "(0x%02x/0x%02x)\n", cmd[2], cmd[3]);
+       return -ENODEV;
+}
+
+static int __init at91_dataflash26_init(void)
+{
+       spi_transfer_desc = kmalloc(sizeof(struct spi_transfer_list),
+                                   GFP_KERNEL);
+       if (!spi_transfer_desc)
+               return -ENOMEM;
+
+       /* DataFlash (SPI chip select 0) */
+       at91_dataflash26_detect(0);
+
+#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
+       /* DataFlash card (SPI chip select 3) */
+       at91_dataflash26_detect(3);
+#endif
+       return 0;
+}
+
+static void __exit at91_dataflash26_exit(void)
+{
+       int i;
+
+       for (i = 0; i < DATAFLASH_MAX_DEVICES; i++) {
+               if (mtd_devices[i]) {
+                       del_mtd_device(mtd_devices[i]);
+                       kfree(mtd_devices[i]->priv);
+                       kfree(mtd_devices[i]);
+               }
+       }
+       nr_devices = 0;
+       kfree(spi_transfer_desc);
+}
+
+module_init(at91_dataflash26_init);
+module_exit(at91_dataflash26_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Hans J. Koch");
+MODULE_DESCRIPTION("DataFlash AT26xxx driver for Atmel AT91RM9200");
index f9f2ce7..ce47544 100644 (file)
@@ -40,56 +40,9 @@ struct block2mtd_dev {
 static LIST_HEAD(blkmtd_device_list);
 
 
-#define PAGE_READAHEAD 64
-static void cache_readahead(struct address_space *mapping, int index)
+static struct page* page_read(struct address_space *mapping, int index)
 {
        filler_t *filler = (filler_t*)mapping->a_ops->readpage;
-       int i, pagei;
-       unsigned ret = 0;
-       unsigned long end_index;
-       struct page *page;
-       LIST_HEAD(page_pool);
-       struct inode *inode = mapping->host;
-       loff_t isize = i_size_read(inode);
-
-       if (!isize) {
-               INFO("iSize=0 in cache_readahead\n");
-               return;
-       }
-
-       end_index = ((isize - 1) >> PAGE_CACHE_SHIFT);
-
-       read_lock_irq(&mapping->tree_lock);
-       for (i = 0; i < PAGE_READAHEAD; i++) {
-               pagei = index + i;
-               if (pagei > end_index) {
-                       INFO("Overrun end of disk in cache readahead\n");
-                       break;
-               }
-               page = radix_tree_lookup(&mapping->page_tree, pagei);
-               if (page && (!i))
-                       break;
-               if (page)
-                       continue;
-               read_unlock_irq(&mapping->tree_lock);
-               page = page_cache_alloc_cold(mapping);
-               read_lock_irq(&mapping->tree_lock);
-               if (!page)
-                       break;
-               page->index = pagei;
-               list_add(&page->lru, &page_pool);
-               ret++;
-       }
-       read_unlock_irq(&mapping->tree_lock);
-       if (ret)
-               read_cache_pages(mapping, &page_pool, filler, NULL);
-}
-
-
-static struct page* page_readahead(struct address_space *mapping, int index)
-{
-       filler_t *filler = (filler_t*)mapping->a_ops->readpage;
-       cache_readahead(mapping, index);
        return read_cache_page(mapping, index, filler, NULL);
 }
 
@@ -105,14 +58,14 @@ static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len)
        u_long *max;
 
        while (pages) {
-               page = page_readahead(mapping, index);
+               page = page_read(mapping, index);
                if (!page)
                        return -ENOMEM;
                if (IS_ERR(page))
                        return PTR_ERR(page);
 
-               max = (u_long*)page_address(page) + PAGE_SIZE;
-               for (p=(u_long*)page_address(page); p<max; p++)
+               max = page_address(page) + PAGE_SIZE;
+               for (p=page_address(page); p<max; p++)
                        if (*p != -1UL) {
                                lock_page(page);
                                memset(page_address(page), 0xff, PAGE_SIZE);
@@ -174,8 +127,7 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
                        cpylen = len;   // this page
                len = len - cpylen;
 
-               //      Get page
-               page = page_readahead(dev->blkdev->bd_inode->i_mapping, index);
+               page = page_read(dev->blkdev->bd_inode->i_mapping, index);
                if (!page)
                        return -ENOMEM;
                if (IS_ERR(page))
@@ -213,8 +165,7 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf,
                        cpylen = len;                   // this page
                len = len - cpylen;
 
-               //      Get page
-               page = page_readahead(mapping, index);
+               page = page_read(mapping, index);
                if (!page)
                        return -ENOMEM;
                if (IS_ERR(page))
@@ -308,9 +259,9 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
                /* We might not have rootfs mounted at this point. Try
                   to resolve the device name by other means. */
 
-               dev_t dev = name_to_dev_t(devname);
-               if (dev != 0) {
-                       bdev = open_by_devnum(dev, FMODE_WRITE | FMODE_READ);
+               dev_t devt = name_to_dev_t(devname);
+               if (devt) {
+                       bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ);
                }
        }
 #endif
index bbf0553..d990d81 100644 (file)
@@ -6,7 +6,6 @@ menu "Mapping drivers for chip access"
 
 config MTD_COMPLEX_MAPPINGS
        bool "Support non-linear mappings of flash chips"
-       depends on MTD
        help
          This causes the chip drivers to allow for complicated
          paged mappings of flash chips.
@@ -69,6 +68,39 @@ config MTD_PHYSMAP_OF
          physically into the CPU's memory. The mapping description here is
          taken from OF device tree.
 
+config MTD_PMC_MSP_EVM
+       tristate "CFI Flash device mapped on PMC-Sierra MSP"
+       depends on PMC_MSP && MTD_CFI
+       select MTD_PARTITIONS
+       help
+         This provides a 'mapping' driver which support the way
+          in which user-programmable flash chips are connected on the
+          PMC-Sierra MSP eval/demo boards
+
+choice
+       prompt "Maximum mappable memory avialable for flash IO"
+       depends on MTD_PMC_MSP_EVM
+       default MSP_FLASH_MAP_LIMIT_32M
+
+config MSP_FLASH_MAP_LIMIT_32M
+       bool "32M"
+
+endchoice
+
+config MSP_FLASH_MAP_LIMIT
+       hex
+       default "0x02000000"
+       depends on MSP_FLASH_MAP_LIMIT_32M
+
+config MTD_PMC_MSP_RAMROOT
+       tristate "Embedded RAM block device for root on PMC-Sierra MSP"
+       depends on PMC_MSP_EMBEDDED_ROOTFS && \
+                       (MTD_BLOCK || MTD_BLOCK_RO) && \
+                       MTD_RAM
+       help
+         This provides support for the embedded root file system
+          on PMC MSP devices.  This memory is mapped as a MTD block device.
+
 config MTD_SUN_UFLASH
        tristate "Sun Microsystems userflash support"
        depends on SPARC && MTD_CFI
@@ -240,13 +272,13 @@ config MTD_NETtel
 
 config MTD_ALCHEMY
        tristate "AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support"
-       depends on SOC_AU1X00
+       depends on SOC_AU1X00 && MTD_PARTITIONS && MTD_CFI
        help
          Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards
 
 config MTD_MTX1
        tristate "4G Systems MTX-1 Flash device"
-       depends on MIPS && MIPS_MTX1
+       depends on MIPS_MTX1 && MTD_CFI
        help
          Flash memory access on 4G Systems MTX-1 Board. If you have one of
          these boards and would like to use the flash chips on it, say 'Y'.
@@ -384,7 +416,7 @@ config MTD_TQM834x
 
 config MTD_OCELOT
        tristate "Momenco Ocelot boot flash device"
-       depends on MIPS && MOMENCO_OCELOT
+       depends on MOMENCO_OCELOT
        help
          This enables access routines for the boot flash device and for the
          NVRAM on the Momenco Ocelot board. If you have one of these boards
@@ -517,7 +549,7 @@ config MTD_OMAP_NOR
 # This needs CFI or JEDEC, depending on the cards found.
 config MTD_PCI
        tristate "PCI MTD driver"
-       depends on MTD && PCI && MTD_COMPLEX_MAPPINGS
+       depends on PCI && MTD_COMPLEX_MAPPINGS
        help
          Mapping for accessing flash devices on add-in cards like the Intel XScale
          IQ80310 card, and the Intel EBSA285 card in blank ROM programming mode
@@ -527,7 +559,7 @@ config MTD_PCI
 
 config MTD_PCMCIA
        tristate "PCMCIA MTD driver"
-       depends on MTD && PCMCIA && MTD_COMPLEX_MAPPINGS && BROKEN
+       depends on PCMCIA && MTD_COMPLEX_MAPPINGS && BROKEN
        help
          Map driver for accessing PCMCIA linear flash memory cards. These
          cards are usually around 4-16MiB in size. This does not include
@@ -591,13 +623,12 @@ config MTD_BAST_MAXSIZE
 
 config MTD_SHARP_SL
        bool "ROM mapped on Sharp SL Series"
-       depends on MTD && ARCH_PXA
+       depends on ARCH_PXA
        help
          This enables access to the flash chip on the Sharp SL Series of PDAs.
 
 config MTD_PLATRAM
        tristate "Map driver for platform device RAM (mtd-ram)"
-       depends on MTD
        select MTD_RAM
        help
          Map driver for RAM areas described via the platform device
index 071d0bf..de036c5 100644 (file)
@@ -27,6 +27,8 @@ obj-$(CONFIG_MTD_CEIVA)               += ceiva.o
 obj-$(CONFIG_MTD_OCTAGON)      += octagon-5066.o
 obj-$(CONFIG_MTD_PHYSMAP)      += physmap.o
 obj-$(CONFIG_MTD_PHYSMAP_OF)   += physmap_of.o
+obj-$(CONFIG_MTD_PMC_MSP_EVM)   += pmcmsp-flash.o
+obj-$(CONFIG_MTD_PMC_MSP_RAMROOT)+= pmcmsp-ramroot.o
 obj-$(CONFIG_MTD_PNC2000)      += pnc2000.o
 obj-$(CONFIG_MTD_PCMCIA)       += pcmciamtd.o
 obj-$(CONFIG_MTD_RPXLITE)      += rpxlite.o
index 7fc8097..84fbe0e 100644 (file)
@@ -1,10 +1,7 @@
 /*
  * Flash memory access on AMD Alchemy evaluation boards
  *
- * $Id: alchemy-flash.c,v 1.2 2005/11/07 11:14:26 gleixner Exp $
- *
  * (C) 2003, 2004 Pete Popov <ppopov@embeddedalley.com>
- *
  */
 
 #include <linux/init.h>
 
 #include <asm/io.h>
 
-#ifdef         DEBUG_RW
-#define        DBG(x...)       printk(x)
-#else
-#define        DBG(x...)
-#endif
-
 #ifdef CONFIG_MIPS_PB1000
 #define BOARD_MAP_NAME "Pb1000 Flash"
 #define BOARD_FLASH_SIZE 0x00800000 /* 8MB */
index 2b6504e..894c0b2 100644 (file)
@@ -169,7 +169,8 @@ static int platram_probe(struct platform_device *pdev)
                goto exit_free;
        }
 
-       dev_dbg(&pdev->dev, "got platform resource %p (0x%lx)\n", res, res->start);
+       dev_dbg(&pdev->dev, "got platform resource %p (0x%llx)\n", res,
+               (unsigned long long)res->start);
 
        /* setup map parameters */
 
diff --git a/drivers/mtd/maps/pmcmsp-flash.c b/drivers/mtd/maps/pmcmsp-flash.c
new file mode 100644 (file)
index 0000000..7e0377e
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions.
+ * Config with both CFI and JEDEC device support.
+ *
+ * Basically physmap.c with the addition of partitions and
+ * an array of mapping info to accomodate more than one flash type per board.
+ *
+ * Copyright 2005-2007 PMC-Sierra, Inc.
+ *
+ *  This program 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 Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+
+#include <msp_prom.h>
+#include <msp_regs.h>
+
+
+static struct mtd_info **msp_flash;
+static struct mtd_partition **msp_parts;
+static struct map_info *msp_maps;
+static int fcnt;
+
+#define DEBUG_MARKER printk(KERN_NOTICE "%s[%d]\n",__FUNCTION__,__LINE__)
+
+int __init init_msp_flash(void)
+{
+       int i, j;
+       int offset, coff;
+       char *env;
+       int pcnt;
+       char flash_name[] = "flash0";
+       char part_name[] = "flash0_0";
+       unsigned addr, size;
+
+       /* If ELB is disabled by "ful-mux" mode, we can't get at flash */
+       if ((*DEV_ID_REG & DEV_ID_SINGLE_PC) &&
+           (*ELB_1PC_EN_REG & SINGLE_PCCARD)) {
+               printk(KERN_NOTICE "Single PC Card mode: no flash access\n");
+               return -ENXIO;
+       }
+
+       /* examine the prom environment for flash devices */
+       for (fcnt = 0; (env = prom_getenv(flash_name)); fcnt++)
+               flash_name[5] = '0' + fcnt + 1;
+
+       if (fcnt < 1)
+               return -ENXIO;
+
+       printk(KERN_NOTICE "Found %d PMC flash devices\n", fcnt);
+       msp_flash = (struct mtd_info **)kmalloc(
+                       fcnt * sizeof(struct map_info *), GFP_KERNEL);
+       msp_parts = (struct mtd_partition **)kmalloc(
+                       fcnt * sizeof(struct mtd_partition *), GFP_KERNEL);
+       msp_maps = (struct map_info *)kmalloc(
+                       fcnt * sizeof(struct mtd_info), GFP_KERNEL);
+       memset(msp_maps, 0, fcnt * sizeof(struct mtd_info));
+
+       /* loop over the flash devices, initializing each */
+       for (i = 0; i < fcnt; i++) {
+               /* examine the prom environment for flash partititions */
+               part_name[5] = '0' + i;
+               part_name[7] = '0';
+               for (pcnt = 0; (env = prom_getenv(part_name)); pcnt++)
+                       part_name[7] = '0' + pcnt + 1;
+
+               if (pcnt == 0) {
+                       printk(KERN_NOTICE "Skipping flash device %d "
+                               "(no partitions defined)\n", i);
+                       continue;
+               }
+
+               msp_parts[i] = (struct mtd_partition *)kmalloc(
+                       pcnt * sizeof(struct mtd_partition), GFP_KERNEL);
+               memset(msp_parts[i], 0, pcnt * sizeof(struct mtd_partition));
+
+               /* now initialize the devices proper */
+               flash_name[5] = '0' + i;
+               env = prom_getenv(flash_name);
+
+               if (sscanf(env, "%x:%x", &addr, &size) < 2)
+                       return -ENXIO;
+               addr = CPHYSADDR(addr);
+
+               printk(KERN_NOTICE
+                       "MSP flash device \"%s\": 0x%08x at 0x%08x\n",
+                       flash_name, size, addr);
+               /* This must matchs the actual size of the flash chip */
+               msp_maps[i].size = size;
+               msp_maps[i].phys = addr;
+
+               /*
+                * Platforms have a specific limit of the size of memory
+                * which may be mapped for flash:
+                */
+               if (size > CONFIG_MSP_FLASH_MAP_LIMIT)
+                       size = CONFIG_MSP_FLASH_MAP_LIMIT;
+               msp_maps[i].virt = ioremap(addr, size);
+               msp_maps[i].bankwidth = 1;
+               msp_maps[i].name = strncpy(kmalloc(7, GFP_KERNEL),
+                                       flash_name, 7);
+
+               if (msp_maps[i].virt == NULL)
+                       return -ENXIO;
+
+               for (j = 0; j < pcnt; j++) {
+                       part_name[5] = '0' + i;
+                       part_name[7] = '0' + j;
+
+                       env = prom_getenv(part_name);
+
+                       if (sscanf(env, "%x:%x:%n", &offset, &size, &coff) < 2)
+                               return -ENXIO;
+
+                       msp_parts[i][j].size = size;
+                       msp_parts[i][j].offset = offset;
+                       msp_parts[i][j].name = env + coff;
+               }
+
+               /* now probe and add the device */
+               simple_map_init(&msp_maps[i]);
+               msp_flash[i] = do_map_probe("cfi_probe", &msp_maps[i]);
+               if (msp_flash[i]) {
+                       msp_flash[i]->owner = THIS_MODULE;
+                       add_mtd_partitions(msp_flash[i], msp_parts[i], pcnt);
+               } else {
+                       printk(KERN_ERR "map probe failed for flash\n");
+                       return -ENXIO;
+               }
+       }
+
+       return 0;
+}
+
+static void __exit cleanup_msp_flash(void)
+{
+       int i;
+
+       for (i = 0; i < sizeof(msp_flash) / sizeof(struct mtd_info **); i++) {
+               del_mtd_partitions(msp_flash[i]);
+               map_destroy(msp_flash[i]);
+               iounmap((void *)msp_maps[i].virt);
+
+               /* free the memory */
+               kfree(msp_maps[i].name);
+               kfree(msp_parts[i]);
+       }
+
+       kfree(msp_flash);
+       kfree(msp_parts);
+       kfree(msp_maps);
+}
+
+MODULE_AUTHOR("PMC-Sierra, Inc");
+MODULE_DESCRIPTION("MTD map driver for PMC-Sierra MSP boards");
+MODULE_LICENSE("GPL");
+
+module_init(init_msp_flash);
+module_exit(cleanup_msp_flash);
diff --git a/drivers/mtd/maps/pmcmsp-ramroot.c b/drivers/mtd/maps/pmcmsp-ramroot.c
new file mode 100644 (file)
index 0000000..18049bc
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Mapping of the rootfs in a physical region of memory
+ *
+ * Copyright (C) 2005-2007 PMC-Sierra Inc.
+ * Author: Andrew Hughes, Andrew_Hughes@pmc-sierra.com
+ *
+ *  This program 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 Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/root_dev.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+
+#include <asm/io.h>
+
+#include <msp_prom.h>
+
+static struct mtd_info *rr_mtd;
+
+struct map_info rr_map = {
+       .name = "ramroot",
+       .bankwidth = 4,
+};
+
+static int __init init_rrmap(void)
+{
+       void *ramroot_start;
+       unsigned long ramroot_size;
+
+       /* Check for supported rootfs types */
+       if (get_ramroot(&ramroot_start, &ramroot_size)) {
+               rr_map.phys = CPHYSADDR(ramroot_start);
+               rr_map.size = ramroot_size;
+
+               printk(KERN_NOTICE
+                       "PMC embedded root device: 0x%08lx @ 0x%08lx\n",
+                       rr_map.size, (unsigned long)rr_map.phys);
+       } else {
+               printk(KERN_ERR
+                       "init_rrmap: no supported embedded rootfs detected!\n");
+               return -ENXIO;
+       }
+
+       /* Map rootfs to I/O space for block device driver */
+       rr_map.virt = ioremap(rr_map.phys, rr_map.size);
+       if (!rr_map.virt) {
+               printk(KERN_ERR "Failed to ioremap\n");
+               return -EIO;
+       }
+
+       simple_map_init(&rr_map);
+
+       rr_mtd = do_map_probe("map_ram", &rr_map);
+       if (rr_mtd) {
+               rr_mtd->owner = THIS_MODULE;
+
+               add_mtd_device(rr_mtd);
+               ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, rr_mtd->index);
+
+               return 0;
+       }
+
+       iounmap(rr_map.virt);
+       return -ENXIO;
+}
+
+static void __exit cleanup_rrmap(void)
+{
+       del_mtd_device(rr_mtd);
+       map_destroy(rr_mtd);
+
+       iounmap(rr_map.virt);
+       rr_map.virt = NULL;
+}
+
+MODULE_AUTHOR("PMC-Sierra, Inc");
+MODULE_DESCRIPTION("MTD map driver for embedded PMC-Sierra MSP filesystem");
+MODULE_LICENSE("GPL");
+
+module_init(init_rrmap);
+module_exit(cleanup_rrmap);
index b879a66..524b83b 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/hdreg.h>
 #include <linux/init.h>
 #include <linux/mutex.h>
+#include <linux/kthread.h>
 #include <asm/uaccess.h>
 
 static LIST_HEAD(blktrans_majors);
@@ -28,9 +29,7 @@ extern struct mutex mtd_table_mutex;
 extern struct mtd_info *mtd_table[];
 
 struct mtd_blkcore_priv {
-       struct completion thread_dead;
-       int exiting;
-       wait_queue_head_t thread_wq;
+       struct task_struct *thread;
        struct request_queue *rq;
        spinlock_t queue_lock;
 };
@@ -83,38 +82,19 @@ static int mtd_blktrans_thread(void *arg)
        /* we might get involved when memory gets low, so use PF_MEMALLOC */
        current->flags |= PF_MEMALLOC | PF_NOFREEZE;
 
-       daemonize("%sd", tr->name);
-
-       /* daemonize() doesn't do this for us since some kernel threads
-          actually want to deal with signals. We can't just call
-          exit_sighand() since that'll cause an oops when we finally
-          do exit. */
-       spin_lock_irq(&current->sighand->siglock);
-       sigfillset(&current->blocked);
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
        spin_lock_irq(rq->queue_lock);
-
-       while (!tr->blkcore_priv->exiting) {
+       while (!kthread_should_stop()) {
                struct request *req;
                struct mtd_blktrans_dev *dev;
                int res = 0;
-               DECLARE_WAITQUEUE(wait, current);
 
                req = elv_next_request(rq);
 
                if (!req) {
-                       add_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
                        set_current_state(TASK_INTERRUPTIBLE);
-
                        spin_unlock_irq(rq->queue_lock);
-
                        schedule();
-                       remove_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
-
                        spin_lock_irq(rq->queue_lock);
-
                        continue;
                }
 
@@ -133,13 +113,13 @@ static int mtd_blktrans_thread(void *arg)
        }
        spin_unlock_irq(rq->queue_lock);
 
-       complete_and_exit(&tr->blkcore_priv->thread_dead, 0);
+       return 0;
 }
 
 static void mtd_blktrans_request(struct request_queue *rq)
 {
        struct mtd_blktrans_ops *tr = rq->queuedata;
-       wake_up(&tr->blkcore_priv->thread_wq);
+       wake_up_process(tr->blkcore_priv->thread);
 }
 
 
@@ -388,8 +368,6 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
                return ret;
        }
        spin_lock_init(&tr->blkcore_priv->queue_lock);
-       init_completion(&tr->blkcore_priv->thread_dead);
-       init_waitqueue_head(&tr->blkcore_priv->thread_wq);
 
        tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock);
        if (!tr->blkcore_priv->rq) {
@@ -403,13 +381,14 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
        blk_queue_hardsect_size(tr->blkcore_priv->rq, tr->blksize);
        tr->blkshift = ffs(tr->blksize) - 1;
 
-       ret = kernel_thread(mtd_blktrans_thread, tr, CLONE_KERNEL);
-       if (ret < 0) {
+       tr->blkcore_priv->thread = kthread_run(mtd_blktrans_thread, tr,
+                       "%sd", tr->name);
+       if (IS_ERR(tr->blkcore_priv->thread)) {
                blk_cleanup_queue(tr->blkcore_priv->rq);
                unregister_blkdev(tr->major, tr->name);
                kfree(tr->blkcore_priv);
                mutex_unlock(&mtd_table_mutex);
-               return ret;
+               return PTR_ERR(tr->blkcore_priv->thread);
        }
 
        INIT_LIST_HEAD(&tr->devs);
@@ -432,9 +411,7 @@ int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr)
        mutex_lock(&mtd_table_mutex);
 
        /* Clean up the kernel thread */
-       tr->blkcore_priv->exiting = 1;
-       wake_up(&tr->blkcore_priv->thread_wq);
-       wait_for_completion(&tr->blkcore_priv->thread_dead);
+       kthread_stop(tr->blkcore_priv->thread);
 
        /* Remove it from the list of active majors */
        list_del(&tr->list);
index 1592eac..8c86b80 100644 (file)
@@ -553,7 +553,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                ops.datbuf = NULL;
                ops.mode = MTD_OOB_PLACE;
 
-               if (ops.ooboffs && ops.len > (mtd->oobsize - ops.ooboffs))
+               if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))
                        return -EINVAL;
 
                ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);
index 2d12dcd..4e62afe 100644 (file)
@@ -1,10 +1,7 @@
 # drivers/mtd/nand/Kconfig
 # $Id: Kconfig,v 1.35 2005/11/07 11:14:30 gleixner Exp $
 
-menu "NAND Flash Device Drivers"
-       depends on MTD!=n
-
-config MTD_NAND
+menuconfig MTD_NAND
        tristate "NAND Device Support"
        depends on MTD
        select MTD_NAND_IDS
@@ -13,9 +10,10 @@ config MTD_NAND
          devices. For further information see
          <http://www.linux-mtd.infradead.org/doc/nand.html>.
 
+if MTD_NAND
+
 config MTD_NAND_VERIFY_WRITE
        bool "Verify NAND page writes"
-       depends on MTD_NAND
        help
          This adds an extra check when data is written to the flash. The
          NAND flash device internally checks only bits transitioning
@@ -25,53 +23,61 @@ config MTD_NAND_VERIFY_WRITE
 
 config MTD_NAND_ECC_SMC
        bool "NAND ECC Smart Media byte order"
-       depends on MTD_NAND
        default n
        help
          Software ECC according to the Smart Media Specification.
          The original Linux implementation had byte 0 and 1 swapped.
 
+config MTD_NAND_MUSEUM_IDS
+       bool "Enable chip ids for obsolete ancient NAND devices"
+       depends on MTD_NAND
+       default n
+       help
+         Enable this option only when your board has first generation
+         NAND chips (page size 256 byte, erase size 4-8KiB). The IDs
+         of these chips were reused by later, larger chips.
+
 config MTD_NAND_AUTCPU12
        tristate "SmartMediaCard on autronix autcpu12 board"
-       depends on MTD_NAND && ARCH_AUTCPU12
+       depends on ARCH_AUTCPU12
        help
          This enables the driver for the autronix autcpu12 board to
          access the SmartMediaCard.
 
 config MTD_NAND_EDB7312
        tristate "Support for Cirrus Logic EBD7312 evaluation board"
-       depends on MTD_NAND && ARCH_EDB7312
+       depends on ARCH_EDB7312
        help
          This enables the driver for the Cirrus Logic EBD7312 evaluation
          board to access the onboard NAND Flash.
 
 config MTD_NAND_H1900
        tristate "iPAQ H1900 flash"
-       depends on MTD_NAND && ARCH_PXA && MTD_PARTITIONS
+       depends on ARCH_PXA && MTD_PARTITIONS
        help
          This enables the driver for the iPAQ h1900 flash.
 
 config MTD_NAND_SPIA
        tristate "NAND Flash device on SPIA board"
-       depends on ARCH_P720T && MTD_NAND
+       depends on ARCH_P720T
        help
          If you had to ask, you don't have one. Say 'N'.
 
 config MTD_NAND_AMS_DELTA
        tristate "NAND Flash device on Amstrad E3"
-       depends on MACH_AMS_DELTA && MTD_NAND
+       depends on MACH_AMS_DELTA
        help
          Support for NAND flash on Amstrad E3 (Delta).
 
 config MTD_NAND_TOTO
        tristate "NAND Flash device on TOTO board"
-       depends on ARCH_OMAP && MTD_NAND && BROKEN
+       depends on ARCH_OMAP && BROKEN
        help
          Support for NAND flash on Texas Instruments Toto platform.
 
 config MTD_NAND_TS7250
        tristate "NAND Flash device on TS-7250 board"
-       depends on MACH_TS72XX && MTD_NAND
+       depends on MACH_TS72XX
        help
          Support for NAND flash on Technologic Systems TS-7250 platform.
 
@@ -80,14 +86,14 @@ config MTD_NAND_IDS
 
 config MTD_NAND_AU1550
        tristate "Au1550/1200 NAND support"
-       depends on (SOC_AU1200 || SOC_AU1550) && MTD_NAND
+       depends on SOC_AU1200 || SOC_AU1550
        help
          This enables the driver for the NAND flash controller on the
          AMD/Alchemy 1550 SOC.
 
 config MTD_NAND_RTC_FROM4
        tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)"
-       depends on MTD_NAND && SH_SOLUTION_ENGINE
+       depends on SH_SOLUTION_ENGINE
        select REED_SOLOMON
        select REED_SOLOMON_DEC8
        select BITREVERSE
@@ -97,13 +103,13 @@ config MTD_NAND_RTC_FROM4
 
 config MTD_NAND_PPCHAMELEONEVB
        tristate "NAND Flash device on PPChameleonEVB board"
-       depends on PPCHAMELEONEVB && MTD_NAND && BROKEN
+       depends on PPCHAMELEONEVB && BROKEN
        help
          This enables the NAND flash driver on the PPChameleon EVB Board.
 
 config MTD_NAND_S3C2410
        tristate "NAND Flash support for S3C2410/S3C2440 SoC"
-       depends on ARCH_S3C2410 && MTD_NAND
+       depends on ARCH_S3C2410
        help
          This enables the NAND flash controller on the S3C2410 and S3C2440
          SoCs
@@ -128,7 +134,7 @@ config MTD_NAND_S3C2410_HWECC
 
 config MTD_NAND_NDFC
        tristate "NDFC NanD Flash Controller"
-       depends on MTD_NAND && 44x
+       depends on 44x
        select MTD_NAND_ECC_SMC
        help
         NDFC Nand Flash Controllers are integrated in EP44x SoCs
@@ -145,7 +151,7 @@ config MTD_NAND_S3C2410_CLKSTOP
 
 config MTD_NAND_DISKONCHIP
        tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)"
-       depends on MTD_NAND && EXPERIMENTAL
+       depends on EXPERIMENTAL
        select REED_SOLOMON
        select REED_SOLOMON_DEC16
        help
@@ -215,11 +221,11 @@ config MTD_NAND_DISKONCHIP_BBTWRITE
 
 config MTD_NAND_SHARPSL
        tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
-       depends on MTD_NAND && ARCH_PXA
+       depends on ARCH_PXA
 
 config MTD_NAND_BASLER_EXCITE
        tristate  "Support for NAND Flash on Basler eXcite"
-       depends on MTD_NAND && BASLER_EXCITE
+       depends on BASLER_EXCITE
        help
           This enables the driver for the NAND flash device found on the
           Basler eXcite Smart Camera. If built as a module, the driver
@@ -227,14 +233,14 @@ config MTD_NAND_BASLER_EXCITE
 
 config MTD_NAND_CAFE
        tristate "NAND support for OLPC CAFÉ chip"
-       depends on MTD_NAND && PCI
+       depends on PCI
        help
         Use NAND flash attached to the CAFÉ chip designed for the $100
         laptop.
 
 config MTD_NAND_CS553X
        tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
-       depends on MTD_NAND && X86_32 && (X86_PC || X86_GENERICARCH)
+       depends on X86_32 && (X86_PC || X86_GENERICARCH)
        help
          The CS553x companion chips for the AMD Geode processor
          include NAND flash controllers with built-in hardware ECC
@@ -247,16 +253,16 @@ config MTD_NAND_CS553X
 
 config MTD_NAND_AT91
        bool "Support for NAND Flash / SmartMedia on AT91"
-       depends on MTD_NAND && ARCH_AT91
+       depends on ARCH_AT91
        help
          Enables support for NAND Flash / Smart Media Card interface
          on Atmel AT91 processors.
 
 config MTD_NAND_NANDSIM
        tristate "Support for NAND Flash Simulator"
-       depends on MTD_NAND && MTD_PARTITIONS
+       depends on MTD_PARTITIONS
        help
          The simulator may simulate various NAND flash chips for the
          MTD nand layer.
 
-endmenu
+endif # MTD_NAND
index fd6bb3e..c328a75 100644 (file)
@@ -530,7 +530,6 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
 {
        struct mtd_info *mtd;
        struct cafe_priv *cafe;
-       uint32_t timing1, timing2, timing3;
        uint32_t ctrl;
        int err = 0;
 
@@ -587,21 +586,19 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
        }
 
        if (numtimings == 3) {
-               timing1 = timing[0];
-               timing2 = timing[1];
-               timing3 = timing[2];
                cafe_dev_dbg(&cafe->pdev->dev, "Using provided timings (%08x %08x %08x)\n",
-                            timing1, timing2, timing3);
+                            timing[0], timing[1], timing[2]);
        } else {
-               timing1 = cafe_readl(cafe, NAND_TIMING1);
-               timing2 = cafe_readl(cafe, NAND_TIMING2);
-               timing3 = cafe_readl(cafe, NAND_TIMING3);
+               timing[0] = cafe_readl(cafe, NAND_TIMING1);
+               timing[1] = cafe_readl(cafe, NAND_TIMING2);
+               timing[2] = cafe_readl(cafe, NAND_TIMING3);
 
-               if (timing1 | timing2 | timing3) {
-                       cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n", timing1, timing2, timing3);
+               if (timing[0] | timing[1] | timing[2]) {
+                       cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n",
+                                    timing[0], timing[1], timing[2]);
                } else {
                        dev_warn(&cafe->pdev->dev, "Timing registers unset; using most conservative defaults\n");
-                       timing1 = timing2 = timing3 = 0xffffffff;
+                       timing[0] = timing[1] = timing[2] = 0xffffffff;
                }
        }
 
@@ -609,9 +606,9 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
        cafe_writel(cafe, 1, NAND_RESET);
        cafe_writel(cafe, 0, NAND_RESET);
 
-       cafe_writel(cafe, timing1, NAND_TIMING1);
-       cafe_writel(cafe, timing2, NAND_TIMING2);
-       cafe_writel(cafe, timing3, NAND_TIMING3);
+       cafe_writel(cafe, timing[0], NAND_TIMING1);
+       cafe_writel(cafe, timing[1], NAND_TIMING2);
+       cafe_writel(cafe, timing[2], NAND_TIMING3);
 
        cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
        err = request_irq(pdev->irq, &cafe_nand_interrupt, IRQF_SHARED,
index 6af37b8..ab3b2d1 100644 (file)
@@ -350,7 +350,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
        int block, ret;
 
        /* Get block number */
-       block = ((int)ofs) >> chip->bbt_erase_shift;
+       block = (int)(ofs >> chip->bbt_erase_shift);
        if (chip->bbt)
                chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
 
@@ -771,7 +771,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
        uint8_t *ecc_code = chip->buffers->ecccode;
        int *eccpos = chip->ecc.layout->eccpos;
 
-       nand_read_page_raw(mtd, chip, buf);
+       chip->ecc.read_page_raw(mtd, chip, buf);
 
        for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
                chip->ecc.calculate(mtd, p, &ecc_calc[i]);
@@ -1426,7 +1426,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
        for (i = 0; i < chip->ecc.total; i++)
                chip->oob_poi[eccpos[i]] = ecc_calc[i];
 
-       nand_write_page_raw(mtd, chip, buf);
+       chip->ecc.write_page_raw(mtd, chip, buf);
 }
 
 /**
index 2e2cdf2..2fc674a 100644 (file)
@@ -24,6 +24,8 @@
 *      512     512 Byte page size
 */
 struct nand_flash_dev nand_flash_ids[] = {
+
+#ifdef CONFIG_MTD_NAND_MUSEUM_IDS
        {"NAND 1MiB 5V 8-bit",          0x6e, 256, 1, 0x1000, 0},
        {"NAND 2MiB 5V 8-bit",          0x64, 256, 2, 0x1000, 0},
        {"NAND 4MiB 5V 8-bit",          0x6b, 512, 4, 0x2000, 0},
@@ -39,6 +41,7 @@ struct nand_flash_dev nand_flash_ids[] = {
        {"NAND 8MiB 3,3V 8-bit",        0xe6, 512, 8, 0x2000, 0},
        {"NAND 8MiB 1,8V 16-bit",       0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
        {"NAND 8MiB 3,3V 16-bit",       0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
+#endif
 
        {"NAND 16MiB 1,8V 8-bit",       0x33, 512, 16, 0x4000, 0},
        {"NAND 16MiB 3,3V 8-bit",       0x73, 512, 16, 0x4000, 0},
@@ -137,6 +140,7 @@ struct nand_manufacturers nand_manuf_ids[] = {
        {NAND_MFR_RENESAS, "Renesas"},
        {NAND_MFR_STMICRO, "ST Micro"},
        {NAND_MFR_HYNIX, "Hynix"},
+       {NAND_MFR_MICRON, "Micron"},
        {0x0, "Unknown"}
 };
 
index c3bca95..205df0f 100644 (file)
@@ -37,6 +37,8 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/random.h>
 
 /* Default simulator parameters values */
 #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE)  || \
@@ -90,6 +92,15 @@ static uint bus_width      = CONFIG_NANDSIM_BUS_WIDTH;
 static uint do_delays      = CONFIG_NANDSIM_DO_DELAYS;
 static uint log            = CONFIG_NANDSIM_LOG;
 static uint dbg            = CONFIG_NANDSIM_DBG;
+static unsigned long parts[MAX_MTD_DEVICES];
+static unsigned int parts_num;
+static char *badblocks = NULL;
+static char *weakblocks = NULL;
+static char *weakpages = NULL;
+static unsigned int bitflips = 0;
+static char *gravepages = NULL;
+static unsigned int rptwear = 0;
+static unsigned int overridesize = 0;
 
 module_param(first_id_byte,  uint, 0400);
 module_param(second_id_byte, uint, 0400);
@@ -104,8 +115,16 @@ module_param(bus_width,      uint, 0400);
 module_param(do_delays,      uint, 0400);
 module_param(log,            uint, 0400);
 module_param(dbg,            uint, 0400);
-
-MODULE_PARM_DESC(first_id_byte,  "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)");
+module_param_array(parts, ulong, &parts_num, 0400);
+module_param(badblocks,      charp, 0400);
+module_param(weakblocks,     charp, 0400);
+module_param(weakpages,      charp, 0400);
+module_param(bitflips,       uint, 0400);
+module_param(gravepages,     charp, 0400);
+module_param(rptwear,        uint, 0400);
+module_param(overridesize,   uint, 0400);
+
+MODULE_PARM_DESC(first_id_byte,  "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)");
 MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)");
 MODULE_PARM_DESC(third_id_byte,  "The third byte returned by NAND Flash 'read ID' command");
 MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command");
@@ -118,6 +137,23 @@ MODULE_PARM_DESC(bus_width,      "Chip's bus width (8- or 16-bit)");
 MODULE_PARM_DESC(do_delays,      "Simulate NAND delays using busy-waits if not zero");
 MODULE_PARM_DESC(log,            "Perform logging if not zero");
 MODULE_PARM_DESC(dbg,            "Output debug information if not zero");
+MODULE_PARM_DESC(parts,          "Partition sizes (in erase blocks) separated by commas");
+/* Page and erase block positions for the following parameters are independent of any partitions */
+MODULE_PARM_DESC(badblocks,      "Erase blocks that are initially marked bad, separated by commas");
+MODULE_PARM_DESC(weakblocks,     "Weak erase blocks [: remaining erase cycles (defaults to 3)]"
+                                " separated by commas e.g. 113:2 means eb 113"
+                                " can be erased only twice before failing");
+MODULE_PARM_DESC(weakpages,      "Weak pages [: maximum writes (defaults to 3)]"
+                                " separated by commas e.g. 1401:2 means page 1401"
+                                " can be written only twice before failing");
+MODULE_PARM_DESC(bitflips,       "Maximum number of random bit flips per page (zero by default)");
+MODULE_PARM_DESC(gravepages,     "Pages that lose data [: maximum reads (defaults to 3)]"
+                                " separated by commas e.g. 1401:2 means page 1401"
+                                " can be read only twice before failing");
+MODULE_PARM_DESC(rptwear,        "Number of erases inbetween reporting wear, if not zero");
+MODULE_PARM_DESC(overridesize,   "Specifies the NAND Flash size overriding the ID bytes. "
+                                "The size is specified in erase blocks and as the exponent of a power of two"
+                                " e.g. 5 means a size of 32 erase blocks");
 
 /* The largest possible page size */
 #define NS_LARGEST_PAGE_SIZE   2048
@@ -131,9 +167,11 @@ MODULE_PARM_DESC(dbg,            "Output debug information if not zero");
 #define NS_DBG(args...) \
        do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0)
 #define NS_WARN(args...) \
-       do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warnig: " args); } while(0)
+       do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warning: " args); } while(0)
 #define NS_ERR(args...) \
-       do { printk(KERN_ERR NS_OUTPUT_PREFIX " errorr: " args); } while(0)
+       do { printk(KERN_ERR NS_OUTPUT_PREFIX " error: " args); } while(0)
+#define NS_INFO(args...) \
+       do { printk(KERN_INFO NS_OUTPUT_PREFIX " " args); } while(0)
 
 /* Busy-wait delay macros (microseconds, milliseconds) */
 #define NS_UDELAY(us) \
@@ -238,7 +276,8 @@ union ns_mem {
  * The structure which describes all the internal simulator data.
  */
 struct nandsim {
-       struct mtd_partition part;
+       struct mtd_partition partitions[MAX_MTD_DEVICES];
+       unsigned int nbparts;
 
        uint busw;              /* flash chip bus width (8 or 16) */
        u_char ids[4];          /* chip's ID bytes */
@@ -338,6 +377,38 @@ static struct nandsim_operations {
                               STATE_DATAOUT, STATE_READY}}
 };
 
+struct weak_block {
+       struct list_head list;
+       unsigned int erase_block_no;
+       unsigned int max_erases;
+       unsigned int erases_done;
+};
+
+static LIST_HEAD(weak_blocks);
+
+struct weak_page {
+       struct list_head list;
+       unsigned int page_no;
+       unsigned int max_writes;
+       unsigned int writes_done;
+};
+
+static LIST_HEAD(weak_pages);
+
+struct grave_page {
+       struct list_head list;
+       unsigned int page_no;
+       unsigned int max_reads;
+       unsigned int reads_done;
+};
+
+static LIST_HEAD(grave_pages);
+
+static unsigned long *erase_block_wear = NULL;
+static unsigned int wear_eb_count = 0;
+static unsigned long total_wear = 0;
+static unsigned int rptwear_cnt = 0;
+
 /* MTD structure for NAND controller */
 static struct mtd_info *nsmtd;
 
@@ -381,6 +452,13 @@ static void free_device(struct nandsim *ns)
        }
 }
 
+static char *get_partition_name(int i)
+{
+       char buf[64];
+       sprintf(buf, "NAND simulator partition %d", i);
+       return kstrdup(buf, GFP_KERNEL);
+}
+
 /*
  * Initialize the nandsim structure.
  *
@@ -390,7 +468,9 @@ static int init_nandsim(struct mtd_info *mtd)
 {
        struct nand_chip *chip = (struct nand_chip *)mtd->priv;
        struct nandsim   *ns   = (struct nandsim *)(chip->priv);
-       int i;
+       int i, ret = 0;
+       u_int32_t remains;
+       u_int32_t next_offset;
 
        if (NS_IS_INITIALIZED(ns)) {
                NS_ERR("init_nandsim: nandsim is already initialized\n");
@@ -448,6 +528,40 @@ static int init_nandsim(struct mtd_info *mtd)
                }
        }
 
+       /* Fill the partition_info structure */
+       if (parts_num > ARRAY_SIZE(ns->partitions)) {
+               NS_ERR("too many partitions.\n");
+               ret = -EINVAL;
+               goto error;
+       }
+       remains = ns->geom.totsz;
+       next_offset = 0;
+       for (i = 0; i < parts_num; ++i) {
+               unsigned long part = parts[i];
+               if (!part || part > remains / ns->geom.secsz) {
+                       NS_ERR("bad partition size.\n");
+                       ret = -EINVAL;
+                       goto error;
+               }
+               ns->partitions[i].name   = get_partition_name(i);
+               ns->partitions[i].offset = next_offset;
+               ns->partitions[i].size   = part * ns->geom.secsz;
+               next_offset += ns->partitions[i].size;
+               remains -= ns->partitions[i].size;
+       }
+       ns->nbparts = parts_num;
+       if (remains) {
+               if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) {
+                       NS_ERR("too many partitions.\n");
+                       ret = -EINVAL;
+                       goto error;
+               }
+               ns->partitions[i].name   = get_partition_name(i);
+               ns->partitions[i].offset = next_offset;
+               ns->partitions[i].size   = remains;
+               ns->nbparts += 1;
+       }
+
        /* Detect how many ID bytes the NAND chip outputs */
         for (i = 0; nand_flash_ids[i].name != NULL; i++) {
                 if (second_id_byte != nand_flash_ids[i].id)
@@ -474,7 +588,7 @@ static int init_nandsim(struct mtd_info *mtd)
        printk("sector address bytes: %u\n",    ns->geom.secaddrbytes);
        printk("options: %#x\n",                ns->options);
 
-       if (alloc_device(ns) != 0)
+       if ((ret = alloc_device(ns)) != 0)
                goto error;
 
        /* Allocate / initialize the internal buffer */
@@ -482,21 +596,17 @@ static int init_nandsim(struct mtd_info *mtd)
        if (!ns->buf.byte) {
                NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n",
                        ns->geom.pgszoob);
+               ret = -ENOMEM;
                goto error;
        }
        memset(ns->buf.byte, 0xFF, ns->geom.pgszoob);
 
-       /* Fill the partition_info structure */
-       ns->part.name   = "NAND simulator partition";
-       ns->part.offset = 0;
-       ns->part.size   = ns->geom.totsz;
-
        return 0;
 
 error:
        free_device(ns);
 
-       return -ENOMEM;
+       return ret;
 }
 
 /*
@@ -510,6 +620,287 @@ static void free_nandsim(struct nandsim *ns)
        return;
 }
 
+static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd)
+{
+       char *w;
+       int zero_ok;
+       unsigned int erase_block_no;
+       loff_t offset;
+
+       if (!badblocks)
+               return 0;
+       w = badblocks;
+       do {
+               zero_ok = (*w == '0' ? 1 : 0);
+               erase_block_no = simple_strtoul(w, &w, 0);
+               if (!zero_ok && !erase_block_no) {
+                       NS_ERR("invalid badblocks.\n");
+                       return -EINVAL;
+               }
+               offset = erase_block_no * ns->geom.secsz;
+               if (mtd->block_markbad(mtd, offset)) {
+                       NS_ERR("invalid badblocks.\n");
+                       return -EINVAL;
+               }
+               if (*w == ',')
+                       w += 1;
+       } while (*w);
+       return 0;
+}
+
+static int parse_weakblocks(void)
+{
+       char *w;
+       int zero_ok;
+       unsigned int erase_block_no;
+       unsigned int max_erases;
+       struct weak_block *wb;
+
+       if (!weakblocks)
+               return 0;
+       w = weakblocks;
+       do {
+               zero_ok = (*w == '0' ? 1 : 0);
+               erase_block_no = simple_strtoul(w, &w, 0);
+               if (!zero_ok && !erase_block_no) {
+                       NS_ERR("invalid weakblocks.\n");
+                       return -EINVAL;
+               }
+               max_erases = 3;
+               if (*w == ':') {
+                       w += 1;
+                       max_erases = simple_strtoul(w, &w, 0);
+               }
+               if (*w == ',')
+                       w += 1;
+               wb = kzalloc(sizeof(*wb), GFP_KERNEL);
+               if (!wb) {
+                       NS_ERR("unable to allocate memory.\n");
+                       return -ENOMEM;
+               }
+               wb->erase_block_no = erase_block_no;
+               wb->max_erases = max_erases;
+               list_add(&wb->list, &weak_blocks);
+       } while (*w);
+       return 0;
+}
+
+static int erase_error(unsigned int erase_block_no)
+{
+       struct weak_block *wb;
+
+       list_for_each_entry(wb, &weak_blocks, list)
+               if (wb->erase_block_no == erase_block_no) {
+                       if (wb->erases_done >= wb->max_erases)
+                               return 1;
+                       wb->erases_done += 1;
+                       return 0;
+               }
+       return 0;
+}
+
+static int parse_weakpages(void)
+{
+       char *w;
+       int zero_ok;
+       unsigned int page_no;
+       unsigned int max_writes;
+       struct weak_page *wp;
+
+       if (!weakpages)
+               return 0;
+       w = weakpages;
+       do {
+               zero_ok = (*w == '0' ? 1 : 0);
+               page_no = simple_strtoul(w, &w, 0);
+               if (!zero_ok && !page_no) {
+                       NS_ERR("invalid weakpagess.\n");
+                       return -EINVAL;
+               }
+               max_writes = 3;
+               if (*w == ':') {
+                       w += 1;
+                       max_writes = simple_strtoul(w, &w, 0);
+               }
+               if (*w == ',')
+                       w += 1;
+               wp = kzalloc(sizeof(*wp), GFP_KERNEL);
+               if (!wp) {
+                       NS_ERR("unable to allocate memory.\n");
+                       return -ENOMEM;
+               }
+               wp->page_no = page_no;
+               wp->max_writes = max_writes;
+               list_add(&wp->list, &weak_pages);
+       } while (*w);
+       return 0;
+}
+
+static int write_error(unsigned int page_no)
+{
+       struct weak_page *wp;
+
+       list_for_each_entry(wp, &weak_pages, list)
+               if (wp->page_no == page_no) {
+                       if (wp->writes_done >= wp->max_writes)
+                               return 1;
+                       wp->writes_done += 1;
+                       return 0;
+               }
+       return 0;
+}
+
+static int parse_gravepages(void)
+{
+       char *g;
+       int zero_ok;
+       unsigned int page_no;
+       unsigned int max_reads;
+       struct grave_page *gp;
+
+       if (!gravepages)
+               return 0;
+       g = gravepages;
+       do {
+               zero_ok = (*g == '0' ? 1 : 0);
+               page_no = simple_strtoul(g, &g, 0);
+               if (!zero_ok && !page_no) {
+                       NS_ERR("invalid gravepagess.\n");
+                       return -EINVAL;
+               }
+               max_reads = 3;
+               if (*g == ':') {
+                       g += 1;
+                       max_reads = simple_strtoul(g, &g, 0);
+               }
+               if (*g == ',')
+                       g += 1;
+               gp = kzalloc(sizeof(*gp), GFP_KERNEL);
+               if (!gp) {
+                       NS_ERR("unable to allocate memory.\n");
+                       return -ENOMEM;
+               }
+               gp->page_no = page_no;
+               gp->max_reads = max_reads;
+               list_add(&gp->list, &grave_pages);
+       } while (*g);
+       return 0;
+}
+
+static int read_error(unsigned int page_no)
+{
+       struct grave_page *gp;
+
+       list_for_each_entry(gp, &grave_pages, list)
+               if (gp->page_no == page_no) {
+                       if (gp->reads_done >= gp->max_reads)
+                               return 1;
+                       gp->reads_done += 1;
+                       return 0;
+               }
+       return 0;
+}
+
+static void free_lists(void)
+{
+       struct list_head *pos, *n;
+       list_for_each_safe(pos, n, &weak_blocks) {
+               list_del(pos);
+               kfree(list_entry(pos, struct weak_block, list));
+       }
+       list_for_each_safe(pos, n, &weak_pages) {
+               list_del(pos);
+               kfree(list_entry(pos, struct weak_page, list));
+       }
+       list_for_each_safe(pos, n, &grave_pages) {
+               list_del(pos);
+               kfree(list_entry(pos, struct grave_page, list));
+       }
+       kfree(erase_block_wear);
+}
+
+static int setup_wear_reporting(struct mtd_info *mtd)
+{
+       size_t mem;
+
+       if (!rptwear)
+               return 0;
+       wear_eb_count = mtd->size / mtd->erasesize;
+       mem = wear_eb_count * sizeof(unsigned long);
+       if (mem / sizeof(unsigned long) != wear_eb_count) {
+               NS_ERR("Too many erase blocks for wear reporting\n");
+               return -ENOMEM;
+       }
+       erase_block_wear = kzalloc(mem, GFP_KERNEL);
+       if (!erase_block_wear) {
+               NS_ERR("Too many erase blocks for wear reporting\n");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static void update_wear(unsigned int erase_block_no)
+{
+       unsigned long wmin = -1, wmax = 0, avg;
+       unsigned long deciles[10], decile_max[10], tot = 0;
+       unsigned int i;
+
+       if (!erase_block_wear)
+               return;
+       total_wear += 1;
+       if (total_wear == 0)
+               NS_ERR("Erase counter total overflow\n");
+       erase_block_wear[erase_block_no] += 1;
+       if (erase_block_wear[erase_block_no] == 0)
+               NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no);
+       rptwear_cnt += 1;
+       if (rptwear_cnt < rptwear)
+               return;
+       rptwear_cnt = 0;
+       /* Calc wear stats */
+       for (i = 0; i < wear_eb_count; ++i) {
+               unsigned long wear = erase_block_wear[i];
+               if (wear < wmin)
+                       wmin = wear;
+               if (wear > wmax)
+                       wmax = wear;
+               tot += wear;
+       }
+       for (i = 0; i < 9; ++i) {
+               deciles[i] = 0;
+               decile_max[i] = (wmax * (i + 1) + 5) / 10;
+       }
+       deciles[9] = 0;
+       decile_max[9] = wmax;
+       for (i = 0; i < wear_eb_count; ++i) {
+               int d;
+               unsigned long wear = erase_block_wear[i];
+               for (d = 0; d < 10; ++d)
+                       if (wear <= decile_max[d]) {
+                               deciles[d] += 1;
+                               break;
+                       }
+       }
+       avg = tot / wear_eb_count;
+       /* Output wear report */
+       NS_INFO("*** Wear Report ***\n");
+       NS_INFO("Total numbers of erases:  %lu\n", tot);
+       NS_INFO("Number of erase blocks:   %u\n", wear_eb_count);
+       NS_INFO("Average number of erases: %lu\n", avg);
+       NS_INFO("Maximum number of erases: %lu\n", wmax);
+       NS_INFO("Minimum number of erases: %lu\n", wmin);
+       for (i = 0; i < 10; ++i) {
+               unsigned long from = (i ? decile_max[i - 1] + 1 : 0);
+               if (from > decile_max[i])
+                       continue;
+               NS_INFO("Number of ebs with erase counts from %lu to %lu : %lu\n",
+                       from,
+                       decile_max[i],
+                       deciles[i]);
+       }
+       NS_INFO("*** End of Wear Report ***\n");
+}
+
 /*
  * Returns the string representation of 'state' state.
  */
@@ -822,9 +1213,31 @@ static void read_page(struct nandsim *ns, int num)
                NS_DBG("read_page: page %d not allocated\n", ns->regs.row);
                memset(ns->buf.byte, 0xFF, num);
        } else {
+               unsigned int page_no = ns->regs.row;
                NS_DBG("read_page: page %d allocated, reading from %d\n",
                        ns->regs.row, ns->regs.column + ns->regs.off);
+               if (read_error(page_no)) {
+                       int i;
+                       memset(ns->buf.byte, 0xFF, num);
+                       for (i = 0; i < num; ++i)
+                               ns->buf.byte[i] = random32();
+                       NS_WARN("simulating read error in page %u\n", page_no);
+                       return;
+               }
                memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num);
+               if (bitflips && random32() < (1 << 22)) {
+                       int flips = 1;
+                       if (bitflips > 1)
+                               flips = (random32() % (int) bitflips) + 1;
+                       while (flips--) {
+                               int pos = random32() % (num * 8);
+                               ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
+                               NS_WARN("read_page: flipping bit %d in page %d "
+                                       "reading from %d ecc: corrected=%u failed=%u\n",
+                                       pos, ns->regs.row, ns->regs.column + ns->regs.off,
+                                       nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed);
+                       }
+               }
        }
 }
 
@@ -883,6 +1296,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
 {
        int num;
        int busdiv = ns->busw == 8 ? 1 : 2;
+       unsigned int erase_block_no, page_no;
 
        action &= ACTION_MASK;
 
@@ -942,14 +1356,24 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
                                8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column;
                ns->regs.column = 0;
 
+               erase_block_no = ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift);
+
                NS_DBG("do_state_action: erase sector at address %#x, off = %d\n",
                                ns->regs.row, NS_RAW_OFFSET(ns));
-               NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift));
+               NS_LOG("erase sector %u\n", erase_block_no);
 
                erase_sector(ns);
 
                NS_MDELAY(erase_delay);
 
+               if (erase_block_wear)
+                       update_wear(erase_block_no);
+
+               if (erase_error(erase_block_no)) {
+                       NS_WARN("simulating erase failure in erase block %u\n", erase_block_no);
+                       return -1;
+               }
+
                break;
 
        case ACTION_PRGPAGE:
@@ -972,6 +1396,8 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
                if (prog_page(ns, num) == -1)
                        return -1;
 
+               page_no = ns->regs.row;
+
                NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
                        num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off);
                NS_LOG("programm page %d\n", ns->regs.row);
@@ -979,6 +1405,11 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
                NS_UDELAY(programm_delay);
                NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv);
 
+               if (write_error(page_no)) {
+                       NS_WARN("simulating write failure in page %u\n", page_no);
+                       return -1;
+               }
+
                break;
 
        case ACTION_ZEROOFF:
@@ -1503,7 +1934,7 @@ static int __init ns_init_module(void)
 {
        struct nand_chip *chip;
        struct nandsim *nand;
-       int retval = -ENOMEM;
+       int retval = -ENOMEM, i;
 
        if (bus_width != 8 && bus_width != 16) {
                NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width);
@@ -1533,6 +1964,8 @@ static int __init ns_init_module(void)
        chip->verify_buf = ns_nand_verify_buf;
        chip->read_word  = ns_nand_read_word;
        chip->ecc.mode   = NAND_ECC_SOFT;
+       /* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
+       /* and 'badblocks' parameters to work */
        chip->options   |= NAND_SKIP_BBTSCAN;
 
        /*
@@ -1557,6 +1990,15 @@ static int __init ns_init_module(void)
 
        nsmtd->owner = THIS_MODULE;
 
+       if ((retval = parse_weakblocks()) != 0)
+               goto error;
+
+       if ((retval = parse_weakpages()) != 0)
+               goto error;
+
+       if ((retval = parse_gravepages()) != 0)
+               goto error;
+
        if ((retval = nand_scan(nsmtd, 1)) != 0) {
                NS_ERR("can't register NAND Simulator\n");
                if (retval > 0)
@@ -1564,23 +2006,44 @@ static int __init ns_init_module(void)
                goto error;
        }
 
-       if ((retval = init_nandsim(nsmtd)) != 0) {
-               NS_ERR("scan_bbt: can't initialize the nandsim structure\n");
-               goto error;
+       if (overridesize) {
+               u_int32_t new_size = nsmtd->erasesize << overridesize;
+               if (new_size >> overridesize != nsmtd->erasesize) {
+                       NS_ERR("overridesize is too big\n");
+                       goto err_exit;
+               }
+               /* N.B. This relies on nand_scan not doing anything with the size before we change it */
+               nsmtd->size = new_size;
+               chip->chipsize = new_size;
+               chip->chip_shift = ffs(new_size) - 1;
        }
 
-       if ((retval = nand_default_bbt(nsmtd)) != 0) {
-               free_nandsim(nand);
-               goto error;
-       }
+       if ((retval = setup_wear_reporting(nsmtd)) != 0)
+               goto err_exit;
+
+       if ((retval = init_nandsim(nsmtd)) != 0)
+               goto err_exit;
 
-       /* Register NAND as one big partition */
-       add_mtd_partitions(nsmtd, &nand->part, 1);
+       if ((retval = parse_badblocks(nand, nsmtd)) != 0)
+               goto err_exit;
+
+       if ((retval = nand_default_bbt(nsmtd)) != 0)
+               goto err_exit;
+
+       /* Register NAND partitions */
+       if ((retval = add_mtd_partitions(nsmtd, &nand->partitions[0], nand->nbparts)) != 0)
+               goto err_exit;
 
         return 0;
 
+err_exit:
+       free_nandsim(nand);
+       nand_release(nsmtd);
+       for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i)
+               kfree(nand->partitions[i].name);
 error:
        kfree(nsmtd);
+       free_lists();
 
        return retval;
 }
@@ -1593,10 +2056,14 @@ module_init(ns_init_module);
 static void __exit ns_cleanup_module(void)
 {
        struct nandsim *ns = (struct nandsim *)(((struct nand_chip *)nsmtd->priv)->priv);
+       int i;
 
        free_nandsim(ns);    /* Free nandsim private resources */
-       nand_release(nsmtd); /* Unregisterd drived */
+       nand_release(nsmtd); /* Unregister driver */
+       for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
+               kfree(ns->partitions[i].name);
        kfree(nsmtd);        /* Free other structures */
+       free_lists();
 }
 
 module_exit(ns_cleanup_module);
@@ -1604,4 +2071,3 @@ module_exit(ns_cleanup_module);
 MODULE_LICENSE ("GPL");
 MODULE_AUTHOR ("Artem B. Bityuckiy");
 MODULE_DESCRIPTION ("The NAND flash simulator");
-
index 373bddc..c257d39 100644 (file)
@@ -2,20 +2,18 @@
 # linux/drivers/mtd/onenand/Kconfig
 #
 
-menu "OneNAND Flash Device Drivers"
-       depends on MTD != n
-
-config MTD_ONENAND
+menuconfig MTD_ONENAND
        tristate "OneNAND Device Support"
        depends on MTD
        help
          This enables support for accessing all type of OneNAND flash
          devices. For further information see
-         <http://www.samsung.com/Products/Semiconductor/Flash/OneNAND_TM/index.htm>.
+         <http://www.samsung.com/Products/Semiconductor/OneNAND/index.htm>
+
+if MTD_ONENAND
 
 config MTD_ONENAND_VERIFY_WRITE
        bool "Verify OneNAND page writes"
-       depends on MTD_ONENAND
        help
          This adds an extra check when data is written to the flash. The
          OneNAND flash device internally checks only bits transitioning
@@ -25,13 +23,12 @@ config MTD_ONENAND_VERIFY_WRITE
 
 config MTD_ONENAND_GENERIC
        tristate "OneNAND Flash device via platform device driver"
-       depends on MTD_ONENAND && ARM
+       depends on ARM
        help
          Support for OneNAND flash via platform device driver.
 
 config MTD_ONENAND_OTP
        bool "OneNAND OTP Support"
-       depends on MTD_ONENAND
        help
          One Block of the NAND Flash Array memory is reserved as
          a One-Time Programmable Block memory area.
@@ -43,4 +40,4 @@ config MTD_ONENAND_OTP
 
          OTP block is fully-guaranteed to be a valid block.
 
-endmenu
+endif # MTD_ONENAND
index 9e14a26..000794c 100644 (file)
@@ -836,9 +836,11 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col
        int readcol = column;
        int readend = column + thislen;
        int lastgap = 0;
+       unsigned int i;
        uint8_t *oob_buf = this->oob_buf;
 
-       for (free = this->ecclayout->oobfree; free->length; ++free) {
+       free = this->ecclayout->oobfree;
+       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
                if (readcol >= lastgap)
                        readcol += free->offset - lastgap;
                if (readend >= lastgap)
@@ -846,7 +848,8 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col
                lastgap = free->offset + free->length;
        }
        this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
-       for (free = this->ecclayout->oobfree; free->length; ++free) {
+       free = this->ecclayout->oobfree;
+       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
                int free_end = free->offset + free->length;
                if (free->offset < readend && free_end > readcol) {
                        int st = max_t(int,free->offset,readcol);
@@ -854,7 +857,7 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col
                        int n = ed - st;
                        memcpy(buf, oob_buf + st, n);
                        buf += n;
-               } else
+               } else if (column == 0)
                        break;
        }
        return 0;
@@ -1280,15 +1283,18 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
        int writecol = column;
        int writeend = column + thislen;
        int lastgap = 0;
+       unsigned int i;
 
-       for (free = this->ecclayout->oobfree; free->length; ++free) {
+       free = this->ecclayout->oobfree;
+       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
                if (writecol >= lastgap)
                        writecol += free->offset - lastgap;
                if (writeend >= lastgap)
                        writeend += free->offset - lastgap;
                lastgap = free->offset + free->length;
        }
-       for (free = this->ecclayout->oobfree; free->length; ++free) {
+       free = this->ecclayout->oobfree;
+       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
                int free_end = free->offset + free->length;
                if (free->offset < writeend && free_end > writecol) {
                        int st = max_t(int,free->offset,writecol);
@@ -1296,7 +1302,7 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
                        int n = ed - st;
                        memcpy(oob_buf + st, buf, n);
                        buf += n;
-               } else
+               } else if (column == 0)
                        break;
        }
        return 0;
@@ -2386,7 +2392,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
         * the out of band area
         */
        this->ecclayout->oobavail = 0;
-       for (i = 0; this->ecclayout->oobfree[i].length; i++)
+       for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES &&
+           this->ecclayout->oobfree[i].length; i++)
                this->ecclayout->oobavail +=
                        this->ecclayout->oobfree[i].length;
        mtd->oobavail = this->ecclayout->oobavail;
index cd81d83..5628859 100644 (file)
@@ -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 $
index 7f28ee0..c32b241 100644 (file)
@@ -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
index c8f0bd6..d14d5a4 100644 (file)
@@ -1,4 +1,3 @@
-       $Id: README.Locking,v 1.12 2005/04/13 13:22:35 dwmw2 Exp $
 
        JFFS2 LOCKING DOCUMENTATION
        ---------------------------
index d0e23b2..5d3ea40 100644 (file)
@@ -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:
index 73f0d60..a46101e 100644 (file)
@@ -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>
index fa327db..c84378c 100644 (file)
@@ -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;
index 888f236..0c82dfc 100644 (file)
@@ -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>
index 07119c4..0ca2fff 100644 (file)
@@ -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>
index 7001ba2..485d065 100644 (file)
@@ -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)
index 509b8b1..68cc701 100644 (file)
@@ -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 */
 
index 2eb1b74..0d0bfd2 100644 (file)
@@ -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.
index e792e67..ea0431e 100644 (file)
@@ -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 (file)
index bf1a934..0000000
+++ /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];
-};
index 0c1fc6e..2b87fcc 100644 (file)
@@ -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 (file)
index f0fb8be..0000000
+++ /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;
-}
index 4189e4a..3a32c64 100644 (file)
@@ -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>
index f89c85d..2a49f2c 100644 (file)
@@ -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_
 
index 9fa2e27..c1dfca3 100644 (file)
@@ -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>
index ad01210..66e7c2f 100644 (file)
@@ -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;
index e82eeaf..9987127 100644 (file)
@@ -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>
index abb90c0..23029f4 100644 (file)
@@ -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>
index 3a3cf22..2d99e06 100644 (file)
@@ -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);
index 6909983..f4d525b 100644 (file)
@@ -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>
index 3a56607..0b78fdc 100644 (file)
@@ -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
index ea88f69..b13298a 100644 (file)
@@ -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
index 83f9881..35c1a5e 100644 (file)
@@ -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>
index 5a6b4d6..4bf8608 100644 (file)
@@ -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);
index 4178b4b..25126a0 100644 (file)
@@ -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,
index d883769..dbc908a 100644 (file)
@@ -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;
index e07a0ed..2379c7e 100644 (file)
@@ -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 (file)
index c0c2a91..0000000
+++ /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__ */
index f3b86da..cfe05c1 100644 (file)
@@ -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>
index 717a48c..6aff389 100644 (file)
@@ -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>
 #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)) {
index 7fb45bd..2a1c976 100644 (file)
@@ -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;
index 52a9894..bc9f6ba 100644 (file)
@@ -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>
index 30f8884..d828b29 100644 (file)
@@ -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>
index 6bf1f6a..0c6669e 100644 (file)
@@ -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
index cc7e8e7..e51164a 100644 (file)
@@ -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),
index 7e4882c..b7339c3 100644 (file)
@@ -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>
index 4fac6dd..dafcd41 100644 (file)
@@ -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)
 };
 
 /*
index 6717679..c9fe0ab 100644 (file)
@@ -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();
index c638ae1..b9276b1 100644 (file)
@@ -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>
index 4bb3f18..78fc088 100644 (file)
@@ -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>
index 06a5c69..3b0ff29 100644 (file)
@@ -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_
 
index ed046e1..8ec5765 100644 (file)
@@ -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>
index 2f8e9aa..40942bc 100644 (file)
@@ -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/include/linux/mtd/iflash.h b/include/linux/mtd/iflash.h
deleted file mode 100644 (file)
index 9aa5b4f..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/* $Id: iflash.h,v 1.2 2000/11/13 18:01:54 dwmw2 Exp $ */
-
-#ifndef __MTD_IFLASH_H__
-#define __MTD_IFLASH_H__
-
-/* Extended CIS registers for Series 2 and 2+ cards */
-/* The registers are all offsets from 0x4000 */
-#define CISREG_CSR             0x0100
-#define CISREG_WP              0x0104
-#define CISREG_RDYBSY          0x0140
-
-/* Extended CIS registers for Series 2 cards */
-#define CISREG_SLEEP           0x0118
-#define CISREG_RDY_MASK                0x0120
-#define CISREG_RDY_STATUS      0x0130
-
-/* Extended CIS registers for Series 2+ cards */
-#define CISREG_VCR             0x010c
-
-/* Card Status Register */
-#define CSR_SRESET             0x20    /* Soft reset */
-#define CSR_CMWP               0x10    /* Common memory write protect */
-#define CSR_PWRDOWN            0x08    /* Power down status */
-#define CSR_CISWP              0x04    /* Common memory CIS WP */
-#define CSR_WP                 0x02    /* Mechanical write protect */
-#define CSR_READY              0x01    /* Ready/busy status */
-
-/* Write Protection Register */
-#define WP_BLKEN               0x04    /* Enable block locking */
-#define WP_CMWP                        0x02    /* Common memory write protect */
-#define WP_CISWP               0x01    /* Common memory CIS WP */
-
-/* Voltage Control Register */
-#define VCR_VCC_LEVEL          0x80    /* 0 = 5V, 1 = 3.3V */
-#define VCR_VPP_VALID          0x02    /* Vpp Valid */
-#define VCR_VPP_GEN            0x01    /* Integrated Vpp generator */
-
-/* Ready/Busy Mode Register */
-#define RDYBSY_RACK            0x02    /* Ready acknowledge */
-#define RDYBSY_MODE            0x01    /* 1 = high performance */
-
-#define LOW(x) ((x) & 0xff)
-
-/* 28F008SA-Compatible Command Set */
-#define IF_READ_ARRAY          0xffff
-#define IF_INTEL_ID            0x9090
-#define IF_READ_CSR            0x7070
-#define IF_CLEAR_CSR           0x5050
-#define IF_WRITE               0x4040
-#define IF_BLOCK_ERASE         0x2020
-#define IF_ERASE_SUSPEND       0xb0b0
-#define IF_CONFIRM             0xd0d0
-
-/* 28F016SA Performance Enhancement Commands */
-#define IF_READ_PAGE           0x7575
-#define IF_PAGE_SWAP           0x7272
-#define IF_SINGLE_LOAD         0x7474
-#define IF_SEQ_LOAD            0xe0e0
-#define IF_PAGE_WRITE          0x0c0c
-#define IF_RDY_MODE            0x9696
-#define IF_RDY_LEVEL           0x0101
-#define IF_RDY_PULSE_WRITE     0x0202
-#define IF_RDY_PULSE_ERASE     0x0303
-#define IF_RDY_DISABLE         0x0404
-#define IF_LOCK_BLOCK          0x7777
-#define IF_UPLOAD_STATUS       0x9797
-#define IF_READ_ESR            0x7171
-#define IF_ERASE_UNLOCKED      0xa7a7
-#define IF_SLEEP               0xf0f0
-#define IF_ABORT               0x8080
-#define IF_UPLOAD_DEVINFO      0x9999
-
-/* Definitions for Compatible Status Register */
-#define CSR_WR_READY           0x80