packages/linux/linux-magicbox-2.6.18.6: Add kernel 2.6.18.6 for the Magicbox board
authorStelios Koroneos <skoroneos@digital-opsis.com>
Sat, 28 Apr 2007 21:25:16 +0000 (21:25 +0000)
committerStelios Koroneos <skoroneos@digital-opsis.com>
Sat, 28 Apr 2007 21:25:16 +0000 (21:25 +0000)
packages/linux/linux-magicbox-2.6.18.6/.mtn2git_empty [new file with mode: 0644]
packages/linux/linux-magicbox-2.6.18.6/000-fix-makefile.patch [new file with mode: 0644]
packages/linux/linux-magicbox-2.6.18.6/001-magicbox-board-2.6.18.patch [new file with mode: 0644]
packages/linux/linux-magicbox-2.6.18.6/002-magicbox-mtd-map-2.6.18.patch [new file with mode: 0644]
packages/linux/linux-magicbox-2.6.18.6/010-load-ramdisk-even-if-rootdev-equals-ramdisk.patch [new file with mode: 0644]
packages/linux/linux-magicbox-2.6.18.6/config-2.6.18-magicbox2 [new file with mode: 0644]
packages/linux/linux-magicbox-2.6.18.6/kernel-2.6.18-layer7-2.6.patch [new file with mode: 0644]
packages/linux/linux-magicbox-2.6.18.6/magicbox2-ide-cf_2.6.18.patch [new file with mode: 0644]
packages/linux/linux-magicbox-2.6.18.6/squashfs3.1-patch [new file with mode: 0644]
packages/linux/linux-magicbox_2.6.18.6.bb [new file with mode: 0644]

diff --git a/packages/linux/linux-magicbox-2.6.18.6/.mtn2git_empty b/packages/linux/linux-magicbox-2.6.18.6/.mtn2git_empty
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/packages/linux/linux-magicbox-2.6.18.6/000-fix-makefile.patch b/packages/linux/linux-magicbox-2.6.18.6/000-fix-makefile.patch
new file mode 100644 (file)
index 0000000..ce52a02
--- /dev/null
@@ -0,0 +1,12 @@
+diff -ru linux-2.6.18/Makefile linux-2.6.18-magicbox/Makefile
+--- linux-2.6.18/Makefile      2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-magicbox/Makefile     2006-09-22 20:16:55.000000000 +0200
+@@ -1,7 +1,7 @@
+ VERSION = 2
+ PATCHLEVEL = 6
+ SUBLEVEL = 18
+-EXTRAVERSION = .6
++EXTRAVERSION = -magicbox2
+ NAME=Avast! A bilge rat!
+ # *DOCUMENTATION*
diff --git a/packages/linux/linux-magicbox-2.6.18.6/001-magicbox-board-2.6.18.patch b/packages/linux/linux-magicbox-2.6.18.6/001-magicbox-board-2.6.18.patch
new file mode 100644 (file)
index 0000000..bd3214d
--- /dev/null
@@ -0,0 +1,381 @@
+diff -Nru linux-2.6.18/arch/ppc/platforms/4xx/Kconfig linux-2.6.18-magicbox/arch/ppc/platforms/4xx/Kconfig
+--- linux-2.6.18/arch/ppc/platforms/4xx/Kconfig        2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-magicbox/arch/ppc/platforms/4xx/Kconfig       2006-09-22 03:38:30.000000000 +0200
+@@ -14,7 +14,7 @@
+ choice
+       prompt "Machine Type"
+       depends on 40x
+-      default WALNUT
++      default MAGICBOX
+ config BUBINGA
+       bool "Bubinga"
+@@ -52,6 +52,12 @@
+       help
+         This option enables support for the IBM PPC405GP evaluation board.
++config MAGICBOX
++      bool "MagicBox"
++      select WANT_EARLY_SERIAL
++      help
++        This option enables support for the IBM PPC405EP evaluation board.
++
+ config XILINX_ML300
+       bool "Xilinx-ML300"
+       help
+@@ -173,7 +179,7 @@
+ config IBM_OCP
+       bool
+-      depends on ASH || BAMBOO || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || YUCCA || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT
++      depends on ASH || BAMBOO || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || YUCCA || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT || MAGICBOX
+       default y
+ config IBM_EMAC4
+@@ -183,7 +189,7 @@
+ config BIOS_FIXUP
+       bool
+-      depends on BUBINGA || EP405 || SYCAMORE || WALNUT || CPCI405
++      depends on BUBINGA || EP405 || SYCAMORE || WALNUT || CPCI405 || MAGICBOX
+       default y
+ # OAK doesn't exist but wanted to keep this around for any future 403GCX boards
+@@ -194,7 +200,7 @@
+ config 405EP
+       bool
+-      depends on BUBINGA
++      depends on BUBINGA || MAGICBOX
+       default y
+ config 405GP
+diff -Nru linux-2.6.18/arch/ppc/platforms/4xx/Makefile linux-2.6.18-magicbox/arch/ppc/platforms/4xx/Makefile
+--- linux-2.6.18/arch/ppc/platforms/4xx/Makefile       2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-magicbox/arch/ppc/platforms/4xx/Makefile      2006-09-22 03:37:18.000000000 +0200
+@@ -13,6 +13,7 @@
+ obj-$(CONFIG_REDWOOD_6)               += redwood6.o
+ obj-$(CONFIG_SYCAMORE)                += sycamore.o
+ obj-$(CONFIG_WALNUT)          += walnut.o
++obj-$(CONFIG_MAGICBOX)                += magicbox.o
+ obj-$(CONFIG_XILINX_ML300)    += xilinx_ml300.o
+ obj-$(CONFIG_XILINX_ML403)    += xilinx_ml403.o
+diff -Nru linux-2.6.18/arch/ppc/platforms/4xx/magicbox.c linux-2.6.18-magicbox/arch/ppc/platforms/4xx/magicbox.c
+--- linux-2.6.18/arch/ppc/platforms/4xx/magicbox.c     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-magicbox/arch/ppc/platforms/4xx/magicbox.c    2006-09-22 03:37:18.000000000 +0200
+@@ -0,0 +1,249 @@
++/*
++ * Support for IBM PPC 405EP-based MagicBox board 
++ * Copyright (C) 2006  Karol Lewandowski
++ *
++ * Heavily based on bubinga.c
++ *
++ * Author: SAW (IBM), derived from walnut.c.
++ *         Maintained by MontaVista Software <source@mvista.com>
++ *
++ * 2003 (c) MontaVista Softare Inc.  This file is licensed under the
++ * terms of the GNU General Public License version 2. This program is
++ * licensed "as is" without any warranty of any kind, whether express
++ * or implied.
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/smp.h>
++#include <linux/threads.h>
++#include <linux/param.h>
++#include <linux/string.h>
++#include <linux/blkdev.h>
++#include <linux/pci.h>
++#include <linux/tty.h>
++#include <linux/serial.h>
++#include <linux/serial_core.h>
++
++#include <asm/system.h>
++#include <asm/pci-bridge.h>
++#include <asm/processor.h>
++#include <asm/machdep.h>
++#include <asm/page.h>
++#include <asm/time.h>
++#include <asm/io.h>
++#include <asm/kgdb.h>
++#include <asm/ocp.h>
++#include <asm/ibm_ocp_pci.h>
++
++#include <platforms/4xx/ibm405ep.h>
++
++#undef DEBUG
++
++#ifdef DEBUG
++#define DBG(x...) printk(x)
++#else
++#define DBG(x...)
++#endif
++
++extern bd_t __res;
++
++/* Some IRQs unique to board
++ * Used by the generic 405 PCI setup functions in ppc4xx_pci.c
++ */
++int __init
++ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
++{
++      static char pci_irq_table[][4] =
++          /*
++           *      PCI IDSEL/INTPIN->INTLINE
++           *      A       B       C       D
++           */
++      {
++              {28, 28, 28, 28},       /* IDSEL 1 - PCI slot 1 */
++              {29, 29, 29, 29},       /* IDSEL 2 - PCI slot 2 */
++              {30, 30, 30, 30},       /* IDSEL 3 - PCI slot 3 */
++              {31, 31, 31, 31},       /* IDSEL 4 - PCI slot 4 */
++      };
++
++      const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
++      return PCI_IRQ_TABLE_LOOKUP;
++};
++
++
++/* The serial clock for the chip is an internal clock determined by
++ * different clock speeds/dividers.
++ * Calculate the proper input baud rate and setup the serial driver.
++ */
++static void __init
++magicbox_early_serial_map(void)
++{
++      u32 uart_div;
++      int uart_clock;
++      struct uart_port port;
++
++         /* Calculate the serial clock input frequency
++          *
++          * The base baud is the PLL OUTA (provided in the board info
++          * structure) divided by the external UART Divisor, divided
++          * by 16.
++          */
++      uart_div = (mfdcr(DCRN_CPC0_UCR_BASE) & DCRN_CPC0_UCR_U0DIV);
++      uart_clock = __res.bi_procfreq / uart_div;
++
++      /* Setup serial port access */
++      memset(&port, 0, sizeof(port));
++      port.membase = (void*)ACTING_UART0_IO_BASE;
++      port.irq = ACTING_UART0_INT;
++      port.uartclk = uart_clock;
++      port.regshift = 0;
++      port.iotype = UPIO_MEM;
++      port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
++      port.line = 0;
++
++      if (early_serial_setup(&port) != 0) {
++              printk("Early serial init of port 0 failed\n");
++      }
++
++      port.membase = (void*)ACTING_UART1_IO_BASE;
++      port.irq = ACTING_UART1_INT;
++      port.line = 1;
++
++      if (early_serial_setup(&port) != 0) {
++              printk("Early serial init of port 1 failed\n");
++      }
++}
++
++void __init
++bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip)
++{
++      unsigned int bar_response, bar;
++      /*
++       * Expected PCI mapping:
++       *
++       *  PLB addr             PCI memory addr
++       *  ---------------------       ---------------------
++       *  0000'0000 - 7fff'ffff <---  0000'0000 - 7fff'ffff
++       *  8000'0000 - Bfff'ffff --->  8000'0000 - Bfff'ffff
++       *
++       *  PLB addr             PCI io addr
++       *  ---------------------       ---------------------
++       *  e800'0000 - e800'ffff --->  0000'0000 - 0001'0000
++       *
++       * The following code is simplified by assuming that the bootrom
++       * has been well behaved in following this mapping.
++       */
++
++#ifdef DEBUG
++      int i;
++
++      printk("ioremap PCLIO_BASE = 0x%x\n", pcip);
++      printk("PCI bridge regs before fixup \n");
++      for (i = 0; i <= 3; i++) {
++              printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
++              printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
++              printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
++              printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
++      }
++      printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
++      printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
++      printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
++      printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
++
++#endif
++
++      /* added for IBM boot rom version 1.15 bios bar changes  -AK */
++
++      /* Disable region first */
++      out_le32((void *) &(pcip->pmm[0].ma), 0x00000000);
++      /* PLB starting addr, PCI: 0x80000000 */
++      out_le32((void *) &(pcip->pmm[0].la), 0x80000000);
++      /* PCI start addr, 0x80000000 */
++      out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE);
++      /* 512MB range of PLB to PCI */
++      out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000);
++      /* Enable no pre-fetch, enable region */
++      out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff -
++                                              (PPC405_PCI_UPPER_MEM -
++                                               PPC405_PCI_MEM_BASE)) | 0x01));
++
++      /* Disable region one */
++      out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
++      out_le32((void *) &(pcip->pmm[1].la), 0x00000000);
++      out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000);
++      out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000);
++      out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
++      out_le32((void *) &(pcip->ptm1ms), 0x00000001);
++
++      /* Disable region two */
++      out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
++      out_le32((void *) &(pcip->pmm[2].la), 0x00000000);
++      out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000);
++      out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000);
++      out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
++      out_le32((void *) &(pcip->ptm2ms), 0x00000000);
++      out_le32((void *) &(pcip->ptm2la), 0x00000000);
++
++      /* Zero config bars */
++      for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
++              early_write_config_dword(hose, hose->first_busno,
++                                       PCI_FUNC(hose->first_busno), bar,
++                                       0x00000000);
++              early_read_config_dword(hose, hose->first_busno,
++                                      PCI_FUNC(hose->first_busno), bar,
++                                      &bar_response);
++              DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n",
++                  hose->first_busno, PCI_SLOT(hose->first_busno),
++                  PCI_FUNC(hose->first_busno), bar, bar_response);
++      }
++      /* end work arround */
++
++#ifdef DEBUG
++      printk("PCI bridge regs after fixup \n");
++      for (i = 0; i <= 3; i++) {
++              printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
++              printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
++              printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
++              printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
++      }
++      printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
++      printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
++      printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
++      printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
++
++#endif /* DEBUG */
++}
++
++void __init
++magicbox_setup_arch(void)
++{
++      ppc4xx_setup_arch();
++
++      ibm_ocp_set_emac(0, 1);
++
++      magicbox_early_serial_map();
++
++      /* Identify the system */
++      printk("MagicBox port (C) 2005 Karol Lewandowski <kl@jasmine.eu.org>\n");
++}
++
++void __init
++magicbox_map_io(void)
++{
++      ppc4xx_map_io();
++}
++
++void __init
++platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
++            unsigned long r6, unsigned long r7)
++{
++      ppc4xx_init(r3, r4, r5, r6, r7);
++
++      ppc_md.setup_arch = magicbox_setup_arch;
++      ppc_md.setup_io_mappings = magicbox_map_io;
++
++#ifdef CONFIG_KGDB
++      ppc_md.early_serial_map = magicbox_early_serial_map;
++#endif
++
++}
+diff -Nru linux-2.6.18/arch/ppc/platforms/4xx/magicbox.h linux-2.6.18-magicbox/arch/ppc/platforms/4xx/magicbox.h
+--- linux-2.6.18/arch/ppc/platforms/4xx/magicbox.h     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-magicbox/arch/ppc/platforms/4xx/magicbox.h    2006-09-22 03:37:18.000000000 +0200
+@@ -0,0 +1,47 @@
++/*
++ * Support for IBM PPC 405EP-based MagicBox board
++ *
++ * Heavily based on bubinga.h
++ *
++ *
++ * Author: SAW (IBM), derived from walnut.h.
++ *         Maintained by MontaVista Software <source@mvista.com>
++ *
++ * 2003 (c) MontaVista Softare Inc.  This file is licensed under the
++ * terms of the GNU General Public License version 2. This program is
++ * licensed "as is" without any warranty of any kind, whether express
++ * or implied.
++ */
++
++#ifdef __KERNEL__
++#ifndef __MAGICBOX_H__
++#define __MAGICBOX_H__
++
++#include <linux/config.h>
++#include <platforms/4xx/ibm405ep.h>
++#include <asm/ppcboot.h>
++
++/* Memory map for the "MagicBox" 405EP evaluation board -- generic 4xx. */
++
++/* The UART clock is based off an internal clock -
++ * define BASE_BAUD based on the internal clock and divider(s).
++ * Since BASE_BAUD must be a constant, we will initialize it
++ * using clock/divider values which OpenBIOS initializes
++ * for typical configurations at various CPU speeds.
++ * The base baud is calculated as (FWDA / EXT UART DIV / 16)
++ */
++#define BASE_BAUD       0
++
++/* Flash */
++#define PPC40x_FPGA_BASE      0xF0300000
++#define PPC40x_FPGA_REG_OFFS  1       /* offset to flash map reg */
++#define PPC40x_FLASH_ONBD_N(x)        (x & 0x02)
++#define PPC40x_FLASH_SRAM_SEL(x) (x & 0x01)
++#define PPC40x_FLASH_LOW      0xFFF00000
++#define PPC40x_FLASH_HIGH     0xFFF80000
++#define PPC40x_FLASH_SIZE     0x80000
++
++#define PPC4xx_MACHINE_NAME   "MagicBox"
++
++#endif /* __MAGICBOX_H__ */
++#endif /* __KERNEL__ */
+diff -Nru linux-2.6.18/include/asm-ppc/ibm4xx.h linux-2.6.18-magicbox/include/asm-ppc/ibm4xx.h
+--- linux-2.6.18/include/asm-ppc/ibm4xx.h      2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-magicbox/include/asm-ppc/ibm4xx.h     2006-09-22 03:37:18.000000000 +0200
+@@ -18,6 +18,10 @@
+ #ifdef CONFIG_40x
++#if defined(CONFIG_MAGICBOX)
++#include <platforms/4xx/magicbox.h>
++#endif
++
+ #if defined(CONFIG_BUBINGA)
+ #include <platforms/4xx/bubinga.h>
+ #endif
diff --git a/packages/linux/linux-magicbox-2.6.18.6/002-magicbox-mtd-map-2.6.18.patch b/packages/linux/linux-magicbox-2.6.18.6/002-magicbox-mtd-map-2.6.18.patch
new file mode 100644 (file)
index 0000000..f549f34
--- /dev/null
@@ -0,0 +1,136 @@
+diff -Nru linux-2.6.18/drivers/mtd/maps/Kconfig linux-2.6.18-magicmap/drivers/mtd/maps/Kconfig
+--- linux-2.6.18/drivers/mtd/maps/Kconfig      2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-magicmap/drivers/mtd/maps/Kconfig     2006-09-22 03:36:25.000000000 +0200
+@@ -323,6 +323,15 @@
+         Walnut board. If you have one of these boards and would like to
+         use the flash chips on it, say 'Y'.
++config MTD_MAGICMAP
++      tristate "Flash device mapped on IBM 405EP MagicBox"
++      depends on MTD_CFI && MTD_PARTITIONS && 40x && MAGICBOX
++      help
++        This enables access routines for the flash chips on the IBM 405EP
++        MagicBox board. If you have one of these boards and would like to
++        use the flash chips on it, say 'Y'.
++
++
+ config MTD_EBONY
+       tristate "Flash devices mapped on IBM 440GP Ebony"
+       depends on MTD_JEDECPROBE && EBONY
+diff -Nru linux-2.6.18/drivers/mtd/maps/Makefile linux-2.6.18-magicmap/drivers/mtd/maps/Makefile
+--- linux-2.6.18/drivers/mtd/maps/Makefile     2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-magicmap/drivers/mtd/maps/Makefile    2006-09-22 03:36:25.000000000 +0200
+@@ -58,6 +58,7 @@
+ obj-$(CONFIG_MTD_BEECH)               += beech-mtd.o
+ obj-$(CONFIG_MTD_ARCTIC)      += arctic-mtd.o
+ obj-$(CONFIG_MTD_WALNUT)        += walnut.o
++obj-$(CONFIG_MTD_MAGICMAP)      += magicmap.o
+ obj-$(CONFIG_MTD_H720X)               += h720x-flash.o
+ obj-$(CONFIG_MTD_SBC8240)     += sbc8240.o
+ obj-$(CONFIG_MTD_NOR_TOTO)    += omap-toto-flash.o
+diff -Nru linux-2.6.18/drivers/mtd/maps/magicmap.c linux-2.6.18-magicmap/drivers/mtd/maps/magicmap.c
+--- linux-2.6.18/drivers/mtd/maps/magicmap.c   1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-magicmap/drivers/mtd/maps/magicmap.c  2006-09-22 03:36:25.000000000 +0200
+@@ -0,0 +1,102 @@
++/*
++ * magicmap.c: Copyleft 2005  Karol Lewandowski
++ *
++ * Mapping for MagicBox flash.
++ * Based on walnut.c.
++ *
++ * Heikki Lindholm <holindho@infradead.org>
++ *
++ *
++ * 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.
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++#include <linux/config.h>
++#include <asm/io.h>
++
++static struct mtd_info *flash;
++
++static struct map_info magic_map = {
++      .name =         "Magically mapped flash",
++      .phys =         0xffc00000,
++      .size =         0x400000,
++      .bankwidth =    2,
++};
++
++static struct mtd_partition magic_partitions[] = {
++      {
++              .name =   "kernel",
++              .offset = 0x0,
++              .size =   0x0e0000,
++      },
++      {
++              .name =   "ramdisk",
++              .offset = 0x0e0000,
++              .size =   0x2c0000,
++      },
++      {
++              .name =   "persistent",
++              .offset = 0x3a0000,
++              .size =   0x020000,
++      },
++      {
++              .name =   "bootloader",
++              .offset = 0x3c0000,
++              .size =   0x040000,
++              .mask_flags = MTD_WRITEABLE,
++      },
++};
++
++int __init init_magic(void)
++{
++      magic_map.virt =
++              (void __iomem *)ioremap(magic_map.phys, magic_map.size);
++
++      if (!magic_map.virt) {
++              printk("Failed to ioremap flash.\n");
++              return -EIO;
++      }
++
++      simple_map_init(&magic_map);
++
++      flash = do_map_probe("cfi_probe", &magic_map);
++      if (flash) {
++              flash->owner = THIS_MODULE;
++              add_mtd_partitions(flash, magic_partitions,
++                                      ARRAY_SIZE(magic_partitions));
++      } else {
++              printk("map probe failed for flash\n");
++              return -ENXIO;
++      }
++
++      return 0;
++}
++
++static void __exit cleanup_magic(void)
++{
++      if (flash) {
++              del_mtd_partitions(flash);
++              map_destroy(flash);
++      }
++
++      if (magic_map.virt) {
++              iounmap((void *)magic_map.virt);
++              magic_map.virt = NULL;
++      }
++}
++
++module_init(init_magic);
++module_exit(cleanup_magic);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Karol Lewandowski");
++MODULE_DESCRIPTION("MTD map and partitions for IBM 405EP MagicBox boards");
diff --git a/packages/linux/linux-magicbox-2.6.18.6/010-load-ramdisk-even-if-rootdev-equals-ramdisk.patch b/packages/linux/linux-magicbox-2.6.18.6/010-load-ramdisk-even-if-rootdev-equals-ramdisk.patch
new file mode 100644 (file)
index 0000000..d980be9
--- /dev/null
@@ -0,0 +1,16 @@
+--- linux-2.6.15-magicbox3/init/do_mounts_initrd.c~    2005-08-31 00:26:43.000000000 +0200
++++ linux-2.6.15-magicbox3/init/do_mounts_initrd.c     2006-05-14 14:00:35.000000000 +0200
+@@ -112,8 +112,12 @@
+                * unless /dev/ram0 is supposed to be our actual root device,
+                * in that case the ram disk is just set up here, and gets
+                * mounted in the normal path.
++               *
++               * Not true for magicbox: someone put root=/dev/ram into
++               * bootloader defaults and prepared hundreds of boards...
++               * Fix issue there.
+                */
+-              if (rd_load_image("/initrd.image") && ROOT_DEV != Root_RAM0) {
++              if (rd_load_image("/initrd.image")) {
+                       sys_unlink("/initrd.image");
+                       handle_initrd();
+                       return 1;
diff --git a/packages/linux/linux-magicbox-2.6.18.6/config-2.6.18-magicbox2 b/packages/linux/linux-magicbox-2.6.18.6/config-2.6.18-magicbox2
new file mode 100644 (file)
index 0000000..c181d18
--- /dev/null
@@ -0,0 +1,1204 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.18-magicbox2
+# Thu Dec 28 19:45:11 2006
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+CONFIG_40x=y
+# CONFIG_44x is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+# CONFIG_E500 is not set
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_KEXEC is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_4xx=y
+CONFIG_WANT_EARLY_SERIAL=y
+
+#
+# IBM 4xx options
+#
+# CONFIG_BUBINGA is not set
+# CONFIG_CPCI405 is not set
+# CONFIG_EP405 is not set
+# CONFIG_REDWOOD_5 is not set
+# CONFIG_REDWOOD_6 is not set
+# CONFIG_SYCAMORE is not set
+# CONFIG_WALNUT is not set
+CONFIG_MAGICBOX=y
+# CONFIG_XILINX_ML300 is not set
+# CONFIG_XILINX_ML403 is not set
+CONFIG_IBM_OCP=y
+CONFIG_BIOS_FIXUP=y
+CONFIG_405EP=y
+CONFIG_PPC4xx_DMA=y
+CONFIG_PPC4xx_EDMA=y
+CONFIG_PPC_GEN550=y
+CONFIG_UART0_TTYS0=y
+# CONFIG_UART0_TTYS1 is not set
+CONFIG_NOT_COHERENT_CACHE=y
+
+#
+# Platform options
+#
+# CONFIG_PC_KEYBOARD is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SECCOMP is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+# CONFIG_PPC_I8259 is not set
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_START=0xff100000
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_BOOT_LOAD=0x00400000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+CONFIG_NET_IPGRE=y
+CONFIG_NET_IPGRE_BROADCAST=y
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+CONFIG_NETFILTER_XT_MATCH_ESP=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_REALM=y
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_NETBIOS_NS is not set
+CONFIG_IP_NF_TFTP=m
+# CONFIG_IP_NF_AMANDA is not set
+CONFIG_IP_NF_PPTP=m
+# CONFIG_IP_NF_H323 is not set
+# CONFIG_IP_NF_SIP is not set
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_IPRANGE=y
+CONFIG_IP_NF_MATCH_LAYER7=m
+# CONFIG_IP_NF_MATCH_LAYER7_DEBUG is not set
+CONFIG_IP_NF_MATCH_TOS=y
+# CONFIG_IP_NF_MATCH_RECENT is not set
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_DSCP=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_TTL=y
+# CONFIG_IP_NF_MATCH_OWNER is not set
+CONFIG_IP_NF_MATCH_ADDRTYPE=y
+CONFIG_IP_NF_MATCH_HASHLIMIT=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=y
+CONFIG_IP_NF_TARGET_ULOG=y
+CONFIG_IP_NF_TARGET_TCPMSS=y
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_TOS=y
+CONFIG_IP_NF_TARGET_ECN=y
+# CONFIG_IP_NF_TARGET_DSCP is not set
+CONFIG_IP_NF_TARGET_TTL=y
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+
+#
+# Bridge: Netfilter Configuration
+#
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_BRIDGE_EBT_T_FILTER=y
+CONFIG_BRIDGE_EBT_T_NAT=y
+CONFIG_BRIDGE_EBT_802_3=y
+CONFIG_BRIDGE_EBT_AMONG=y
+CONFIG_BRIDGE_EBT_ARP=y
+CONFIG_BRIDGE_EBT_IP=y
+CONFIG_BRIDGE_EBT_LIMIT=y
+CONFIG_BRIDGE_EBT_MARK=y
+CONFIG_BRIDGE_EBT_PKTTYPE=y
+CONFIG_BRIDGE_EBT_STP=y
+CONFIG_BRIDGE_EBT_VLAN=y
+CONFIG_BRIDGE_EBT_ARPREPLY=y
+CONFIG_BRIDGE_EBT_DNAT=y
+CONFIG_BRIDGE_EBT_MARK_T=y
+CONFIG_BRIDGE_EBT_REDIRECT=y
+CONFIG_BRIDGE_EBT_SNAT=y
+CONFIG_BRIDGE_EBT_LOG=y
+CONFIG_BRIDGE_EBT_ULOG=y
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CLK_JIFFIES=y
+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
+# CONFIG_NET_SCH_CLK_CPU is not set
+
+#
+# Queueing/Scheduling
+#
+# CONFIG_NET_SCH_CBQ is not set
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=y
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=y
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+# CONFIG_NET_SCH_NETEM is not set
+CONFIG_NET_SCH_INGRESS=y
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=y
+CONFIG_NET_CLS_TCINDEX=y
+CONFIG_NET_CLS_ROUTE4=y
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+# CONFIG_CLS_U32_PERF is not set
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+# CONFIG_NET_CLS_POLICE is not set
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+CONFIG_IEEE80211_CRYPT_TKIP=m
+# CONFIG_IEEE80211_SOFTMAC is not set
+CONFIG_WIRELESS_EXT=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+# CONFIG_MTD_BLOCK is not set
+# CONFIG_MTD_BLOCK_RO is not set
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_MAGICMAP=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=4
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_IDEPCI is not set
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_MAGICBOX_IDE=y
+CONFIG_BLK_DEV_MAGICBOX_PROTOTYPE=y
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+CONFIG_IBM_EMAC=y
+CONFIG_IBM_EMAC_RXB=64
+CONFIG_IBM_EMAC_TXB=8
+CONFIG_IBM_EMAC_POLL_WEIGHT=32
+CONFIG_IBM_EMAC_RX_COPY_THRESHOLD=256
+CONFIG_IBM_EMAC_RX_SKB_HEADROOM=0
+# CONFIG_IBM_EMAC_PHY_RX_CLK_FIX is not set
+# CONFIG_IBM_EMAC_DEBUG is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_NET_WIRELESS_RTNETLINK is not set
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_AIRO is not set
+CONFIG_HERMES=m
+# CONFIG_PLX_HERMES is not set
+# CONFIG_TMD_HERMES is not set
+# CONFIG_NORTEL_HERMES is not set
+CONFIG_PCI_HERMES=m
+# CONFIG_ATMEL is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+# CONFIG_PRISM54 is not set
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+# CONFIG_HOSTAP_FIRMWARE_NVRAM is not set
+# CONFIG_HOSTAP_PLX is not set
+CONFIG_HOSTAP_PCI=m
+CONFIG_NET_WIRELESS=y
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+CONFIG_SOFT_WATCHDOG=y
+# CONFIG_BOOKE_WDT is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_IBM_IIC=y
+# CONFIG_I2C_MPC is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+CONFIG_SENSORS_LM75=y
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=y
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_SQUASHFS_VMALLOC is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# IBM 40x options
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=y
+CONFIG_TEXTSEARCH_BM=y
+CONFIG_TEXTSEARCH_FSM=y
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_FS is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+CONFIG_PPC_OCP=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_ARC4=y
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+CONFIG_CRYPTO_MICHAEL_MIC=y
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/packages/linux/linux-magicbox-2.6.18.6/kernel-2.6.18-layer7-2.6.patch b/packages/linux/linux-magicbox-2.6.18.6/kernel-2.6.18-layer7-2.6.patch
new file mode 100644 (file)
index 0000000..63e36d7
--- /dev/null
@@ -0,0 +1,2051 @@
+--- linux-2.6.18/include/linux/netfilter_ipv4/ip_conntrack.h   2006-09-19 22:42:06.000000000 -0500
++++ linux-2.6.18-layer7/include/linux/netfilter_ipv4/ip_conntrack.h    2006-09-24 10:17:45.000000000 -0500
+@@ -127,6 +127,15 @@ struct ip_conntrack
+       /* Traversed often, so hopefully in different cacheline to top */
+       /* These are my tuples; original and reply */
+       struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
++
++#if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE)
++        struct {
++                char * app_proto; /* e.g. "http". NULL before decision. "unknown" after decision if no match */
++                char * app_data;  /* application layer data so far.  NULL after match decision */
++                unsigned int app_data_len;
++        } layer7;
++#endif
++
+ };
+ struct ip_conntrack_expect
+--- linux-2.6.18/include/linux/netfilter_ipv4/ipt_layer7.h     1969-12-31 18:00:00.000000000 -0600
++++ linux-2.6.18-layer7/include/linux/netfilter_ipv4/ipt_layer7.h      2006-09-24 10:17:45.000000000 -0500
+@@ -0,0 +1,26 @@
++/*
++  By Matthew Strait <quadong@users.sf.net>, Dec 2003.
++  http://l7-filter.sf.net
++
++  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.
++  http://www.gnu.org/licenses/gpl.txt
++*/
++
++#ifndef _IPT_LAYER7_H
++#define _IPT_LAYER7_H
++
++#define MAX_PATTERN_LEN 8192
++#define MAX_PROTOCOL_LEN 256
++
++typedef char *(*proc_ipt_search) (char *, char, char *);
++
++struct ipt_layer7_info {
++    char protocol[MAX_PROTOCOL_LEN];
++    char invert:1;
++    char pattern[MAX_PATTERN_LEN];
++};
++
++#endif /* _IPT_LAYER7_H */
+--- linux-2.6.18/net/ipv4/netfilter/Kconfig    2006-09-19 22:42:06.000000000 -0500
++++ linux-2.6.18-layer7/net/ipv4/netfilter/Kconfig     2006-09-24 10:17:45.000000000 -0500
+@@ -248,6 +248,24 @@ config IP_NF_MATCH_IPRANGE
+         To compile it as a module, choose M here.  If unsure, say N.
++config IP_NF_MATCH_LAYER7
++      tristate "Layer 7 match support (EXPERIMENTAL)"
++      depends on IP_NF_IPTABLES && IP_NF_CT_ACCT && IP_NF_CONNTRACK && EXPERIMENTAL
++      help
++        Say Y if you want to be able to classify connections (and their
++        packets) based on regular expression matching of their application
++        layer data.   This is one way to classify applications such as
++        peer-to-peer filesharing systems that do not always use the same
++        port.
++
++        To compile it as a module, choose M here.  If unsure, say N.
++
++config IP_NF_MATCH_LAYER7_DEBUG
++      bool "Layer 7 debugging output"
++      depends on IP_NF_MATCH_LAYER7
++      help
++        Say Y to get lots of debugging output.
++
+ config IP_NF_MATCH_TOS
+       tristate "TOS match support"
+       depends on IP_NF_IPTABLES
+--- linux-2.6.18/net/ipv4/netfilter/Makefile   2006-09-19 22:42:06.000000000 -0500
++++ linux-2.6.18-layer7/net/ipv4/netfilter/Makefile    2006-09-24 10:17:45.000000000 -0500
+@@ -64,6 +64,8 @@ obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o
+ obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
+ obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
++obj-$(CONFIG_IP_NF_MATCH_LAYER7) += ipt_layer7.o
++
+ # targets
+ obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
+ obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o
+--- linux-2.6.18/net/ipv4/netfilter/ip_conntrack_core.c        2006-09-19 22:42:06.000000000 -0500
++++ linux-2.6.18-layer7/net/ipv4/netfilter/ip_conntrack_core.c 2006-09-24 10:17:45.000000000 -0500
+@@ -338,6 +338,13 @@ destroy_conntrack(struct nf_conntrack *n
+        * too. */
+       ip_ct_remove_expectations(ct);
++      #if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE)
++      if(ct->layer7.app_proto)
++              kfree(ct->layer7.app_proto);
++      if(ct->layer7.app_data)
++              kfree(ct->layer7.app_data);
++      #endif
++
+       /* We overload first tuple to link into unconfirmed list. */
+       if (!is_confirmed(ct)) {
+               BUG_ON(list_empty(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list));
+--- linux-2.6.18/net/ipv4/netfilter/ip_conntrack_standalone.c  2006-09-19 22:42:06.000000000 -0500
++++ linux-2.6.18-layer7/net/ipv4/netfilter/ip_conntrack_standalone.c   2006-09-24 10:17:45.000000000 -0500
+@@ -193,6 +193,12 @@ static int ct_seq_show(struct seq_file *
+               return -ENOSPC;
+ #endif
++#if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE)
++      if(conntrack->layer7.app_proto)
++              if (seq_printf(s, "l7proto=%s ",conntrack->layer7.app_proto))
++                      return 1;
++#endif
++
+       if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use)))
+               return -ENOSPC;
+--- linux-2.6.18/net/ipv4/netfilter/ipt_layer7.c       1969-12-31 18:00:00.000000000 -0600
++++ linux-2.6.18-layer7/net/ipv4/netfilter/ipt_layer7.c        2006-09-24 10:59:55.000000000 -0500
+@@ -0,0 +1,582 @@
++/*
++  Kernel module to match application layer (OSI layer 7)
++  data in connections.
++
++  http://l7-filter.sf.net
++
++  By Matthew Strait and Ethan Sommer, 2003-2005.
++
++  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.
++  http://www.gnu.org/licenses/gpl.txt
++
++  Based on ipt_string.c (C) 2000 Emmanuel Roger <winfield@freegates.be>
++  and cls_layer7.c (C) 2003 Matthew Strait, Ethan Sommer, Justin Levandoski
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++#include <linux/proc_fs.h>
++#include <linux/ctype.h>
++#include <net/ip.h>
++#include <net/tcp.h>
++#include <linux/spinlock.h>
++
++#include "regexp/regexp.c"
++
++#include <linux/netfilter_ipv4/ipt_layer7.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++MODULE_AUTHOR("Matthew Strait <quadong@users.sf.net>, Ethan Sommer <sommere@users.sf.net>");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("iptables application layer match module");
++MODULE_VERSION("2.0");
++
++static int maxdatalen = 2048; // this is the default
++module_param(maxdatalen, int, 0444);
++MODULE_PARM_DESC(maxdatalen, "maximum bytes of data looked at by l7-filter");
++
++#ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG
++      #define DPRINTK(format,args...) printk(format,##args)
++#else
++      #define DPRINTK(format,args...)
++#endif
++
++#define TOTAL_PACKETS master_conntrack->counters[IP_CT_DIR_ORIGINAL].packets + \
++                    master_conntrack->counters[IP_CT_DIR_REPLY].packets
++
++/* Number of packets whose data we look at.
++This can be modified through /proc/net/layer7_numpackets */
++static int num_packets = 10;
++
++static struct pattern_cache {
++      char * regex_string;
++      regexp * pattern;
++      struct pattern_cache * next;
++} * first_pattern_cache = NULL;
++
++/* I'm new to locking.  Here are my assumptions:
++
++- No one will write to /proc/net/layer7_numpackets over and over very fast;
++  if they did, nothing awful would happen.
++
++- This code will never be processing the same packet twice at the same time,
++  because iptables rules are traversed in order.
++
++- It doesn't matter if two packets from different connections are in here at
++  the same time, because they don't share any data.
++
++- It _does_ matter if two packets from the same connection (or one from a
++  master and one from its child) are here at the same time.  In this case,
++  we have to protect the conntracks and the list of compiled patterns.
++*/
++DEFINE_RWLOCK(ct_lock);
++DEFINE_SPINLOCK(list_lock);
++
++#ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG
++/* Converts an unfriendly string into a friendly one by
++replacing unprintables with periods and all whitespace with " ". */
++static char * friendly_print(unsigned char * s)
++{
++      char * f = kmalloc(strlen(s) + 1, GFP_ATOMIC);
++      int i;
++
++      if(!f) {
++              if (net_ratelimit())
++                      printk(KERN_ERR "layer7: out of memory in friendly_print, bailing.\n");
++              return NULL;
++      }
++
++      for(i = 0; i < strlen(s); i++){
++              if(isprint(s[i]) && s[i] < 128) f[i] = s[i];
++              else if(isspace(s[i]))          f[i] = ' ';
++              else                            f[i] = '.';
++      }
++      f[i] = '\0';
++      return f;
++}
++
++static char dec2hex(int i)
++{
++      switch (i) {
++              case 0 ... 9:
++                      return (char)(i + '0');
++                      break;
++              case 10 ... 15:
++                      return (char)(i - 10 + 'a');
++                      break;
++              default:
++                      if (net_ratelimit())
++                              printk("Problem in dec2hex\n");
++                      return '\0';
++      }
++}
++
++static char * hex_print(unsigned char * s)
++{
++      char * g = kmalloc(strlen(s)*3 + 1, GFP_ATOMIC);
++      int i;
++
++      if(!g) {
++             if (net_ratelimit())
++                      printk(KERN_ERR "layer7: out of memory in hex_print, bailing.\n");
++             return NULL;
++      }
++
++      for(i = 0; i < strlen(s); i++) {
++              g[i*3    ] = dec2hex(s[i]/16);
++              g[i*3 + 1] = dec2hex(s[i]%16);
++              g[i*3 + 2] = ' ';
++      }
++      g[i*3] = '\0';
++
++      return g;
++}
++#endif // DEBUG
++
++/* Use instead of regcomp.  As we expect to be seeing the same regexps over and
++over again, it make sense to cache the results. */
++static regexp * compile_and_cache(char * regex_string, char * protocol)
++{
++      struct pattern_cache * node               = first_pattern_cache;
++      struct pattern_cache * last_pattern_cache = first_pattern_cache;
++      struct pattern_cache * tmp;
++      unsigned int len;
++
++      while (node != NULL) {
++              if (!strcmp(node->regex_string, regex_string))
++              return node->pattern;
++
++              last_pattern_cache = node;/* points at the last non-NULL node */
++              node = node->next;
++      }
++
++      /* If we reach the end of the list, then we have not yet cached
++         the pattern for this regex. Let's do that now.
++         Be paranoid about running out of memory to avoid list corruption. */
++      tmp = kmalloc(sizeof(struct pattern_cache), GFP_ATOMIC);
++
++      if(!tmp) {
++              if (net_ratelimit())
++                      printk(KERN_ERR "layer7: out of memory in compile_and_cache, bailing.\n");
++              return NULL;
++      }
++
++      tmp->regex_string  = kmalloc(strlen(regex_string) + 1, GFP_ATOMIC);
++      tmp->pattern       = kmalloc(sizeof(struct regexp),    GFP_ATOMIC);
++      tmp->next = NULL;
++
++      if(!tmp->regex_string || !tmp->pattern) {
++              if (net_ratelimit())
++                      printk(KERN_ERR "layer7: out of memory in compile_and_cache, bailing.\n");
++              kfree(tmp->regex_string);
++              kfree(tmp->pattern);
++              kfree(tmp);
++              return NULL;
++      }
++
++      /* Ok.  The new node is all ready now. */
++      node = tmp;
++
++      if(first_pattern_cache == NULL) /* list is empty */
++              first_pattern_cache = node; /* make node the beginning */
++      else
++              last_pattern_cache->next = node; /* attach node to the end */
++
++      /* copy the string and compile the regex */
++      len = strlen(regex_string);
++      DPRINTK("About to compile this: \"%s\"\n", regex_string);
++      node->pattern = regcomp(regex_string, &len);
++      if ( !node->pattern ) {
++              if (net_ratelimit())
++                      printk(KERN_ERR "layer7: Error compiling regexp \"%s\" (%s)\n", regex_string, protocol);
++              /* pattern is now cached as NULL, so we won't try again. */
++      }
++
++      strcpy(node->regex_string, regex_string);
++      return node->pattern;
++}
++
++static int can_handle(const struct sk_buff *skb)
++{
++      if(!skb->nh.iph) /* not IP */
++              return 0;
++      if(skb->nh.iph->protocol != IPPROTO_TCP &&
++         skb->nh.iph->protocol != IPPROTO_UDP &&
++         skb->nh.iph->protocol != IPPROTO_ICMP)
++              return 0;
++      return 1;
++}
++
++/* Returns offset the into the skb->data that the application data starts */
++static int app_data_offset(const struct sk_buff *skb)
++{
++      /* In case we are ported somewhere (ebtables?) where skb->nh.iph
++      isn't set, this can be gotten from 4*(skb->data[0] & 0x0f) as well. */
++      int ip_hl = 4*skb->nh.iph->ihl;
++
++      if( skb->nh.iph->protocol == IPPROTO_TCP ) {
++              /* 12 == offset into TCP header for the header length field.
++              Can't get this with skb->h.th->doff because the tcphdr
++              struct doesn't get set when routing (this is confirmed to be
++              true in Netfilter as well as QoS.) */
++              int tcp_hl = 4*(skb->data[ip_hl + 12] >> 4);
++
++              return ip_hl + tcp_hl;
++      } else if( skb->nh.iph->protocol == IPPROTO_UDP  ) {
++              return ip_hl + 8; /* UDP header is always 8 bytes */
++      } else if( skb->nh.iph->protocol == IPPROTO_ICMP ) {
++              return ip_hl + 8; /* ICMP header is 8 bytes */
++      } else {
++              if (net_ratelimit())
++                      printk(KERN_ERR "layer7: tried to handle unknown protocol!\n");
++              return ip_hl + 8; /* something reasonable */
++      }
++}
++
++/* handles whether there's a match when we aren't appending data anymore */
++static int match_no_append(struct ip_conntrack * conntrack, struct ip_conntrack * master_conntrack,
++                      enum ip_conntrack_info ctinfo, enum ip_conntrack_info master_ctinfo,
++                      struct ipt_layer7_info * info)
++{
++      /* If we're in here, throw the app data away */
++      write_lock(&ct_lock);
++      if(master_conntrack->layer7.app_data != NULL) {
++
++      #ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG
++              if(!master_conntrack->layer7.app_proto) {
++                      char * f = friendly_print(master_conntrack->layer7.app_data);
++                      char * g = hex_print(master_conntrack->layer7.app_data);
++                      DPRINTK("\nl7-filter gave up after %d bytes (%d packets):\n%s\n",
++                              strlen(f), TOTAL_PACKETS, f);
++                      kfree(f);
++                      DPRINTK("In hex: %s\n", g);
++                      kfree(g);
++              }
++      #endif
++
++              kfree(master_conntrack->layer7.app_data);
++              master_conntrack->layer7.app_data = NULL; /* don't free again */
++      }
++      write_unlock(&ct_lock);
++
++      if(master_conntrack->layer7.app_proto){
++              /* Here child connections set their .app_proto (for /proc/net/ip_conntrack) */
++              write_lock(&ct_lock);
++              if(!conntrack->layer7.app_proto) {
++                      conntrack->layer7.app_proto = kmalloc(strlen(master_conntrack->layer7.app_proto)+1, GFP_ATOMIC);
++                      if(!conntrack->layer7.app_proto){
++                              if (net_ratelimit())
++                                      printk(KERN_ERR "layer7: out of memory in match_no_append, bailing.\n");
++                              write_unlock(&ct_lock);
++                              return 1;
++                      }
++                      strcpy(conntrack->layer7.app_proto, master_conntrack->layer7.app_proto);
++              }
++              write_unlock(&ct_lock);
++
++              return (!strcmp(master_conntrack->layer7.app_proto, info->protocol));
++      }
++      else {
++              /* If not classified, set to "unknown" to distinguish from
++              connections that are still being tested. */
++              write_lock(&ct_lock);
++              master_conntrack->layer7.app_proto = kmalloc(strlen("unknown")+1, GFP_ATOMIC);
++              if(!master_conntrack->layer7.app_proto){
++                      if (net_ratelimit())
++                              printk(KERN_ERR "layer7: out of memory in match_no_append, bailing.\n");
++                      write_unlock(&ct_lock);
++                      return 1;
++              }
++              strcpy(master_conntrack->layer7.app_proto, "unknown");
++              write_unlock(&ct_lock);
++              return 0;
++      }
++}
++
++/* add the new app data to the conntrack.  Return number of bytes added. */
++static int add_data(struct ip_conntrack * master_conntrack,
++                      char * app_data, int appdatalen)
++{
++      int length = 0, i;
++      int oldlength = master_conntrack->layer7.app_data_len;
++
++      // This is a fix for a race condition by Deti Fliegl. However, I'm not 
++      // clear on whether the race condition exists or whether this really 
++      // fixes it.  I might just be being dense... Anyway, if it's not really 
++      // a fix, all it does is waste a very small amount of time.
++      if(!master_conntrack->layer7.app_data) return 0;
++
++      /* Strip nulls. Make everything lower case (our regex lib doesn't
++      do case insensitivity).  Add it to the end of the current data. */
++      for(i = 0; i < maxdatalen-oldlength-1 &&
++                 i < appdatalen; i++) {
++              if(app_data[i] != '\0') {
++                      master_conntrack->layer7.app_data[length+oldlength] =
++                              /* the kernel version of tolower mungs 'upper ascii' */
++                              isascii(app_data[i])? tolower(app_data[i]) : app_data[i];
++                      length++;
++              }
++      }
++
++      master_conntrack->layer7.app_data[length+oldlength] = '\0';
++      master_conntrack->layer7.app_data_len = length + oldlength;
++
++      return length;
++}
++
++/* Returns true on match and false otherwise.  */
++static int match(/* const */ struct sk_buff *skb,
++      const struct net_device *in, const struct net_device *out,
++      const struct xt_match *match, const void *matchinfo,
++      int offset, unsigned int protoff, int *hotdrop)
++{
++      struct ipt_layer7_info * info = (struct ipt_layer7_info *)matchinfo;
++      enum ip_conntrack_info master_ctinfo, ctinfo;
++      struct ip_conntrack *master_conntrack, *conntrack;
++      unsigned char * app_data;
++      unsigned int pattern_result, appdatalen;
++      regexp * comppattern;
++
++      if(!can_handle(skb)){
++              DPRINTK("layer7: This is some protocol I can't handle.\n");
++              return info->invert;
++      }
++
++      /* Treat parent & all its children together as one connection, except
++      for the purpose of setting conntrack->layer7.app_proto in the actual
++      connection. This makes /proc/net/ip_conntrack more satisfying. */
++      if(!(conntrack = ip_conntrack_get((struct sk_buff *)skb, &ctinfo)) ||
++         !(master_conntrack = ip_conntrack_get((struct sk_buff *)skb, &master_ctinfo))) {
++              //DPRINTK("layer7: packet is not from a known connection, giving up.\n");
++              return info->invert;
++      }
++
++      /* Try to get a master conntrack (and its master etc) for FTP, etc. */
++      while (master_ct(master_conntrack) != NULL)
++              master_conntrack = master_ct(master_conntrack);
++
++      /* if we've classified it or seen too many packets */
++      if(TOTAL_PACKETS > num_packets ||
++         master_conntrack->layer7.app_proto) {
++
++              pattern_result = match_no_append(conntrack, master_conntrack, ctinfo, master_ctinfo, info);
++
++              /* skb->cb[0] == seen. Avoid doing things twice if there are two l7
++              rules. I'm not sure that using cb for this purpose is correct, although
++              it says "put your private variables there". But it doesn't look like it
++              is being used for anything else in the skbs that make it here. How can
++              I write to cb without making the compiler angry? */
++              skb->cb[0] = 1; /* marking it seen here is probably irrelevant, but consistant */
++
++              return (pattern_result ^ info->invert);
++      }
++
++      if(skb_is_nonlinear(skb)){
++              if(skb_linearize(skb) != 0){
++                      if (net_ratelimit())
++                              printk(KERN_ERR "layer7: failed to linearize packet, bailing.\n");
++                      return info->invert;
++              }
++      }
++
++      /* now that the skb is linearized, it's safe to set these. */
++      app_data = skb->data + app_data_offset(skb);
++      appdatalen = skb->tail - app_data;
++
++      spin_lock_bh(&list_lock);
++      /* the return value gets checked later, when we're ready to use it */
++      comppattern = compile_and_cache(info->pattern, info->protocol);
++      spin_unlock_bh(&list_lock);
++
++      /* On the first packet of a connection, allocate space for app data */
++      write_lock(&ct_lock);
++      if(TOTAL_PACKETS == 1 && !skb->cb[0] && !master_conntrack->layer7.app_data) {
++              master_conntrack->layer7.app_data = kmalloc(maxdatalen, GFP_ATOMIC);
++              if(!master_conntrack->layer7.app_data){
++                      if (net_ratelimit())
++                              printk(KERN_ERR "layer7: out of memory in match, bailing.\n");
++                      write_unlock(&ct_lock);
++                      return info->invert;
++              }
++
++              master_conntrack->layer7.app_data[0] = '\0';
++      }
++      write_unlock(&ct_lock);
++
++      /* Can be here, but unallocated, if numpackets is increased near
++      the beginning of a connection */
++      if(master_conntrack->layer7.app_data == NULL)
++              return (info->invert); /* unmatched */
++
++      if(!skb->cb[0]){
++              int newbytes;
++              write_lock(&ct_lock);
++              newbytes = add_data(master_conntrack, app_data, appdatalen);
++              write_unlock(&ct_lock);
++
++              if(newbytes == 0) { /* didn't add any data */
++                      skb->cb[0] = 1;
++                      /* Didn't match before, not going to match now */
++                      return info->invert;
++              }
++      }
++
++      /* If looking for "unknown", then never match.  "Unknown" means that
++      we've given up; we're still trying with these packets. */
++      read_lock(&ct_lock);
++      if(!strcmp(info->protocol, "unknown")) {
++              pattern_result = 0;
++      /* If the regexp failed to compile, don't bother running it */
++      } else if(comppattern && regexec(comppattern, master_conntrack->layer7.app_data)) {
++              DPRINTK("layer7: matched %s\n", info->protocol);
++              pattern_result = 1;
++      } else pattern_result = 0;
++      read_unlock(&ct_lock);
++
++      if(pattern_result) {
++              write_lock(&ct_lock);
++              master_conntrack->layer7.app_proto = kmalloc(strlen(info->protocol)+1, GFP_ATOMIC);
++              if(!master_conntrack->layer7.app_proto){
++                      if (net_ratelimit())
++                              printk(KERN_ERR "layer7: out of memory in match, bailing.\n");
++                      write_unlock(&ct_lock);
++                      return (pattern_result ^ info->invert);
++              }
++              strcpy(master_conntrack->layer7.app_proto, info->protocol);
++              write_unlock(&ct_lock);
++      }
++
++      /* mark the packet seen */
++      skb->cb[0] = 1;
++
++      return (pattern_result ^ info->invert);
++}
++
++static int checkentry(const char *tablename, const void *ip,
++      const struct xt_match *match, void *matchinfo, unsigned int matchsize,
++      unsigned int hook_mask)
++{
++//        struct ipt_layer7_info * info = (struct ipt_layer7_info *)matchinfo;
++
++      if (matchsize != IPT_ALIGN(sizeof(struct ipt_layer7_info)))
++              return 0;
++
++      return 1;
++}
++
++static struct ipt_match layer7_match = {
++      .name = "layer7",
++      .match = &match,
++      .checkentry = &checkentry,
++      .matchsize  = sizeof(struct ipt_layer7_info),
++      .me = THIS_MODULE
++};
++
++/* taken from drivers/video/modedb.c */
++static int my_atoi(const char *s)
++{
++      int val = 0;
++
++      for (;; s++) {
++              switch (*s) {
++                      case '0'...'9':
++                      val = 10*val+(*s-'0');
++                      break;
++              default:
++                      return val;
++              }
++      }
++}
++
++/* write out num_packets to userland. */
++static int layer7_read_proc(char* page, char ** start, off_t off, int count,
++                   int* eof, void * data)
++{
++      if(num_packets > 99 && net_ratelimit())
++              printk(KERN_ERR "layer7: NOT REACHED. num_packets too big\n");
++
++      page[0] = num_packets/10 + '0';
++      page[1] = num_packets%10 + '0';
++      page[2] = '\n';
++      page[3] = '\0';
++
++      *eof=1;
++
++      return 3;
++}
++
++/* Read in num_packets from userland */
++static int layer7_write_proc(struct file* file, const char* buffer,
++                    unsigned long count, void *data)
++{
++      char * foo = kmalloc(count, GFP_ATOMIC);
++
++      if(!foo){
++              if (net_ratelimit())
++                      printk(KERN_ERR "layer7: out of memory, bailing. num_packets unchanged.\n");
++              return count;
++      }
++
++      if(copy_from_user(foo, buffer, count)) {
++              return -EFAULT;
++      }
++
++
++      num_packets = my_atoi(foo);
++      kfree (foo);
++
++      /* This has an arbitrary limit to make the math easier. I'm lazy.
++      But anyway, 99 is a LOT! If you want more, you're doing it wrong! */
++      if(num_packets > 99) {
++              printk(KERN_WARNING "layer7: num_packets can't be > 99.\n");
++              num_packets = 99;
++      } else if(num_packets < 1) {
++              printk(KERN_WARNING "layer7: num_packets can't be < 1.\n");
++              num_packets = 1;
++      }
++
++      return count;
++}
++
++/* register the proc file */
++static void layer7_init_proc(void)
++{
++      struct proc_dir_entry* entry;
++      entry = create_proc_entry("layer7_numpackets", 0644, proc_net);
++      entry->read_proc = layer7_read_proc;
++      entry->write_proc = layer7_write_proc;
++}
++
++static void layer7_cleanup_proc(void)
++{
++      remove_proc_entry("layer7_numpackets", proc_net);
++}
++
++static int __init ipt_layer7_init(void)
++{
++      layer7_init_proc();
++      if(maxdatalen < 1) {
++              printk(KERN_WARNING "layer7: maxdatalen can't be < 1, using 1\n");
++              maxdatalen = 1;
++      }
++      /* This is not a hard limit.  It's just here to prevent people from
++      bringing their slow machines to a grinding halt. */
++      else if(maxdatalen > 65536) {
++              printk(KERN_WARNING "layer7: maxdatalen can't be > 65536, using 65536\n");
++              maxdatalen = 65536;
++      }
++      return ipt_register_match(&layer7_match);
++}
++
++static void __exit ipt_layer7_fini(void)
++{
++      layer7_cleanup_proc();
++      ipt_unregister_match(&layer7_match);
++}
++
++module_init(ipt_layer7_init);
++module_exit(ipt_layer7_fini);
+--- linux-2.6.18/net/ipv4/netfilter/regexp/regexp.c    1969-12-31 18:00:00.000000000 -0600
++++ linux-2.6.18-layer7/net/ipv4/netfilter/regexp/regexp.c     2006-09-24 10:17:45.000000000 -0500
+@@ -0,0 +1,1197 @@
++/*
++ * regcomp and regexec -- regsub and regerror are elsewhere
++ * @(#)regexp.c       1.3 of 18 April 87
++ *
++ *    Copyright (c) 1986 by University of Toronto.
++ *    Written by Henry Spencer.  Not derived from licensed software.
++ *
++ *    Permission is granted to anyone to use this software for any
++ *    purpose on any computer system, and to redistribute it freely,
++ *    subject to the following restrictions:
++ *
++ *    1. The author is not responsible for the consequences of use of
++ *            this software, no matter how awful, even if they arise
++ *            from defects in it.
++ *
++ *    2. The origin of this software must not be misrepresented, either
++ *            by explicit claim or by omission.
++ *
++ *    3. Altered versions must be plainly marked as such, and must not
++ *            be misrepresented as being the original software.
++ *
++ * Beware that some of this code is subtly aware of the way operator
++ * precedence is structured in regular expressions.  Serious changes in
++ * regular-expression syntax might require a total rethink.
++ *
++ * This code was modified by Ethan Sommer to work within the kernel
++ * (it now uses kmalloc etc..)
++ *
++ * Modified slightly by Matthew Strait to use more modern C.
++ */
++
++#include "regexp.h"
++#include "regmagic.h"
++
++/* added by ethan and matt.  Lets it work in both kernel and user space.
++(So iptables can use it, for instance.)  Yea, it goes both ways... */
++#if __KERNEL__
++  #define malloc(foo) kmalloc(foo,GFP_ATOMIC)
++#else
++  #define printk(format,args...) printf(format,##args)
++#endif
++
++void regerror(char * s)
++{
++        printk("<3>Regexp: %s\n", s);
++        /* NOTREACHED */
++}
++
++/*
++ * The "internal use only" fields in regexp.h are present to pass info from
++ * compile to execute that permits the execute phase to run lots faster on
++ * simple cases.  They are:
++ *
++ * regstart   char that must begin a match; '\0' if none obvious
++ * reganch    is the match anchored (at beginning-of-line only)?
++ * regmust    string (pointer into program) that match must include, or NULL
++ * regmlen    length of regmust string
++ *
++ * Regstart and reganch permit very fast decisions on suitable starting points
++ * for a match, cutting down the work a lot.  Regmust permits fast rejection
++ * of lines that cannot possibly match.  The regmust tests are costly enough
++ * that regcomp() supplies a regmust only if the r.e. contains something
++ * potentially expensive (at present, the only such thing detected is * or +
++ * at the start of the r.e., which can involve a lot of backup).  Regmlen is
++ * supplied because the test in regexec() needs it and regcomp() is computing
++ * it anyway.
++ */
++
++/*
++ * Structure for regexp "program".  This is essentially a linear encoding
++ * of a nondeterministic finite-state machine (aka syntax charts or
++ * "railroad normal form" in parsing technology).  Each node is an opcode
++ * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
++ * all nodes except BRANCH implement concatenation; a "next" pointer with
++ * a BRANCH on both ends of it is connecting two alternatives.  (Here we
++ * have one of the subtle syntax dependencies:  an individual BRANCH (as
++ * opposed to a collection of them) is never concatenated with anything
++ * because of operator precedence.)  The operand of some types of node is
++ * a literal string; for others, it is a node leading into a sub-FSM.  In
++ * particular, the operand of a BRANCH node is the first node of the branch.
++ * (NB this is *not* a tree structure:  the tail of the branch connects
++ * to the thing following the set of BRANCHes.)  The opcodes are:
++ */
++
++/* definition number  opnd?   meaning */
++#define       END     0       /* no   End of program. */
++#define       BOL     1       /* no   Match "" at beginning of line. */
++#define       EOL     2       /* no   Match "" at end of line. */
++#define       ANY     3       /* no   Match any one character. */
++#define       ANYOF   4       /* str  Match any character in this string. */
++#define       ANYBUT  5       /* str  Match any character not in this string. */
++#define       BRANCH  6       /* node Match this alternative, or the next... */
++#define       BACK    7       /* no   Match "", "next" ptr points backward. */
++#define       EXACTLY 8       /* str  Match this string. */
++#define       NOTHING 9       /* no   Match empty string. */
++#define       STAR    10      /* node Match this (simple) thing 0 or more times. */
++#define       PLUS    11      /* node Match this (simple) thing 1 or more times. */
++#define       OPEN    20      /* no   Mark this point in input as start of #n. */
++                      /*      OPEN+1 is number 1, etc. */
++#define       CLOSE   30      /* no   Analogous to OPEN. */
++
++/*
++ * Opcode notes:
++ *
++ * BRANCH     The set of branches constituting a single choice are hooked
++ *            together with their "next" pointers, since precedence prevents
++ *            anything being concatenated to any individual branch.  The
++ *            "next" pointer of the last BRANCH in a choice points to the
++ *            thing following the whole choice.  This is also where the
++ *            final "next" pointer of each individual branch points; each
++ *            branch starts with the operand node of a BRANCH node.
++ *
++ * BACK               Normal "next" pointers all implicitly point forward; BACK
++ *            exists to make loop structures possible.
++ *
++ * STAR,PLUS  '?', and complex '*' and '+', are implemented as circular
++ *            BRANCH structures using BACK.  Simple cases (one character
++ *            per match) are implemented with STAR and PLUS for speed
++ *            and to minimize recursive plunges.
++ *
++ * OPEN,CLOSE ...are numbered at compile time.
++ */
++
++/*
++ * A node is one char of opcode followed by two chars of "next" pointer.
++ * "Next" pointers are stored as two 8-bit pieces, high order first.  The
++ * value is a positive offset from the opcode of the node containing it.
++ * An operand, if any, simply follows the node.  (Note that much of the
++ * code generation knows about this implicit relationship.)
++ *
++ * Using two bytes for the "next" pointer is vast overkill for most things,
++ * but allows patterns to get big without disasters.
++ */
++#define       OP(p)   (*(p))
++#define       NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
++#define       OPERAND(p)      ((p) + 3)
++
++/*
++ * See regmagic.h for one further detail of program structure.
++ */
++
++
++/*
++ * Utility definitions.
++ */
++#ifndef CHARBITS
++#define       UCHARAT(p)      ((int)*(unsigned char *)(p))
++#else
++#define       UCHARAT(p)      ((int)*(p)&CHARBITS)
++#endif
++
++#define       FAIL(m) { regerror(m); return(NULL); }
++#define       ISMULT(c)       ((c) == '*' || (c) == '+' || (c) == '?')
++#define       META    "^$.[()|?+*\\"
++
++/*
++ * Flags to be passed up and down.
++ */
++#define       HASWIDTH        01      /* Known never to match null string. */
++#define       SIMPLE          02      /* Simple enough to be STAR/PLUS operand. */
++#define       SPSTART         04      /* Starts with * or +. */
++#define       WORST           0       /* Worst case. */
++
++/*
++ * Global work variables for regcomp().
++ */
++struct match_globals {
++char *reginput;               /* String-input pointer. */
++char *regbol;         /* Beginning of input, for ^ check. */
++char **regstartp;     /* Pointer to startp array. */
++char **regendp;               /* Ditto for endp. */
++char *regparse;               /* Input-scan pointer. */
++int regnpar;          /* () count. */
++char regdummy;
++char *regcode;                /* Code-emit pointer; &regdummy = don't. */
++long regsize;         /* Code size. */
++};
++
++/*
++ * Forward declarations for regcomp()'s friends.
++ */
++#ifndef STATIC
++#define       STATIC  static
++#endif
++STATIC char *reg(struct match_globals *g, int paren,int *flagp);
++STATIC char *regbranch(struct match_globals *g, int *flagp);
++STATIC char *regpiece(struct match_globals *g, int *flagp);
++STATIC char *regatom(struct match_globals *g, int *flagp);
++STATIC char *regnode(struct match_globals *g, char op);
++STATIC char *regnext(struct match_globals *g, char *p);
++STATIC void regc(struct match_globals *g, char b);
++STATIC void reginsert(struct match_globals *g, char op, char *opnd);
++STATIC void regtail(struct match_globals *g, char *p, char *val);
++STATIC void regoptail(struct match_globals *g, char *p, char *val);
++
++
++__kernel_size_t my_strcspn(const char *s1,const char *s2)
++{
++        char *scan1;
++        char *scan2;
++        int count;
++
++        count = 0;
++        for (scan1 = (char *)s1; *scan1 != '\0'; scan1++) {
++                for (scan2 = (char *)s2; *scan2 != '\0';)       /* ++ moved down. */
++                        if (*scan1 == *scan2++)
++                                return(count);
++                count++;
++        }
++        return(count);
++}
++
++/*
++ - regcomp - compile a regular expression into internal code
++ *
++ * We can't allocate space until we know how big the compiled form will be,
++ * but we can't compile it (and thus know how big it is) until we've got a
++ * place to put the code.  So we cheat:  we compile it twice, once with code
++ * generation turned off and size counting turned on, and once "for real".
++ * This also means that we don't allocate space until we are sure that the
++ * thing really will compile successfully, and we never have to move the
++ * code and thus invalidate pointers into it.  (Note that it has to be in
++ * one piece because free() must be able to free it all.)
++ *
++ * Beware that the optimization-preparation code in here knows about some
++ * of the structure of the compiled regexp.
++ */
++regexp *
++regcomp(char *exp,int *patternsize)
++{
++      register regexp *r;
++      register char *scan;
++      register char *longest;
++      register int len;
++      int flags;
++      struct match_globals g;
++      
++      /* commented out by ethan
++         extern char *malloc();
++      */
++
++      if (exp == NULL)
++              FAIL("NULL argument");
++
++      /* First pass: determine size, legality. */
++      g.regparse = exp;
++      g.regnpar = 1;
++      g.regsize = 0L;
++      g.regcode = &g.regdummy;
++      regc(&g, MAGIC);
++      if (reg(&g, 0, &flags) == NULL)
++              return(NULL);
++
++      /* Small enough for pointer-storage convention? */
++      if (g.regsize >= 32767L)                /* Probably could be 65535L. */
++              FAIL("regexp too big");
++
++      /* Allocate space. */
++      *patternsize=sizeof(regexp) + (unsigned)g.regsize;
++      r = (regexp *)malloc(sizeof(regexp) + (unsigned)g.regsize);
++      if (r == NULL)
++              FAIL("out of space");
++
++      /* Second pass: emit code. */
++      g.regparse = exp;
++      g.regnpar = 1;
++      g.regcode = r->program;
++      regc(&g, MAGIC);
++      if (reg(&g, 0, &flags) == NULL)
++              return(NULL);
++
++      /* Dig out information for optimizations. */
++      r->regstart = '\0';     /* Worst-case defaults. */
++      r->reganch = 0;
++      r->regmust = NULL;
++      r->regmlen = 0;
++      scan = r->program+1;                    /* First BRANCH. */
++      if (OP(regnext(&g, scan)) == END) {             /* Only one top-level choice. */
++              scan = OPERAND(scan);
++
++              /* Starting-point info. */
++              if (OP(scan) == EXACTLY)
++                      r->regstart = *OPERAND(scan);
++              else if (OP(scan) == BOL)
++                      r->reganch++;
++
++              /*
++               * If there's something expensive in the r.e., find the
++               * longest literal string that must appear and make it the
++               * regmust.  Resolve ties in favor of later strings, since
++               * the regstart check works with the beginning of the r.e.
++               * and avoiding duplication strengthens checking.  Not a
++               * strong reason, but sufficient in the absence of others.
++               */
++              if (flags&SPSTART) {
++                      longest = NULL;
++                      len = 0;
++                      for (; scan != NULL; scan = regnext(&g, scan))
++                              if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
++                                      longest = OPERAND(scan);
++                                      len = strlen(OPERAND(scan));
++                              }
++                      r->regmust = longest;
++                      r->regmlen = len;
++              }
++      }
++
++      return(r);
++}
++
++/*
++ - reg - regular expression, i.e. main body or parenthesized thing
++ *
++ * Caller must absorb opening parenthesis.
++ *
++ * Combining parenthesis handling with the base level of regular expression
++ * is a trifle forced, but the need to tie the tails of the branches to what
++ * follows makes it hard to avoid.
++ */
++static char *
++reg(struct match_globals *g, int paren, int *flagp /* Parenthesized? */ )
++{
++      register char *ret;
++      register char *br;
++      register char *ender;
++      register int parno = 0; /* 0 makes gcc happy */
++      int flags;
++
++      *flagp = HASWIDTH;      /* Tentatively. */
++
++      /* Make an OPEN node, if parenthesized. */
++      if (paren) {
++              if (g->regnpar >= NSUBEXP)
++                      FAIL("too many ()");
++              parno = g->regnpar;
++              g->regnpar++;
++              ret = regnode(g, OPEN+parno);
++      } else
++              ret = NULL;
++
++      /* Pick up the branches, linking them together. */
++      br = regbranch(g, &flags);
++      if (br == NULL)
++              return(NULL);
++      if (ret != NULL)
++              regtail(g, ret, br);    /* OPEN -> first. */
++      else
++              ret = br;
++      if (!(flags&HASWIDTH))
++              *flagp &= ~HASWIDTH;
++      *flagp |= flags&SPSTART;
++      while (*g->regparse == '|') {
++              g->regparse++;
++              br = regbranch(g, &flags);
++              if (br == NULL)
++                      return(NULL);
++              regtail(g, ret, br);    /* BRANCH -> BRANCH. */
++              if (!(flags&HASWIDTH))
++                      *flagp &= ~HASWIDTH;
++              *flagp |= flags&SPSTART;
++      }
++
++      /* Make a closing node, and hook it on the end. */
++      ender = regnode(g, (paren) ? CLOSE+parno : END);        
++      regtail(g, ret, ender);
++
++      /* Hook the tails of the branches to the closing node. */
++      for (br = ret; br != NULL; br = regnext(g, br))
++              regoptail(g, br, ender);
++
++      /* Check for proper termination. */
++      if (paren && *g->regparse++ != ')') {
++              FAIL("unmatched ()");
++      } else if (!paren && *g->regparse != '\0') {
++              if (*g->regparse == ')') {
++                      FAIL("unmatched ()");
++              } else
++                      FAIL("junk on end");    /* "Can't happen". */
++              /* NOTREACHED */
++      }
++
++      return(ret);
++}
++
++/*
++ - regbranch - one alternative of an | operator
++ *
++ * Implements the concatenation operator.
++ */
++static char *
++regbranch(struct match_globals *g, int *flagp)
++{
++      register char *ret;
++      register char *chain;
++      register char *latest;
++      int flags;
++
++      *flagp = WORST;         /* Tentatively. */
++
++      ret = regnode(g, BRANCH);
++      chain = NULL;
++      while (*g->regparse != '\0' && *g->regparse != '|' && *g->regparse != ')') {
++              latest = regpiece(g, &flags);
++              if (latest == NULL)
++                      return(NULL);
++              *flagp |= flags&HASWIDTH;
++              if (chain == NULL)      /* First piece. */
++                      *flagp |= flags&SPSTART;
++              else
++                      regtail(g, chain, latest);
++              chain = latest;
++      }
++      if (chain == NULL)      /* Loop ran zero times. */
++              (void) regnode(g, NOTHING);
++
++      return(ret);
++}
++
++/*
++ - regpiece - something followed by possible [*+?]
++ *
++ * Note that the branching code sequences used for ? and the general cases
++ * of * and + are somewhat optimized:  they use the same NOTHING node as
++ * both the endmarker for their branch list and the body of the last branch.
++ * It might seem that this node could be dispensed with entirely, but the
++ * endmarker role is not redundant.
++ */
++static char *
++regpiece(struct match_globals *g, int *flagp)
++{
++      register char *ret;
++      register char op;
++      register char *next;
++      int flags;
++
++      ret = regatom(g, &flags);
++      if (ret == NULL)
++              return(NULL);
++
++      op = *g->regparse;
++      if (!ISMULT(op)) {
++              *flagp = flags;
++              return(ret);
++      }
++
++      if (!(flags&HASWIDTH) && op != '?')
++              FAIL("*+ operand could be empty");
++      *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
++
++      if (op == '*' && (flags&SIMPLE))
++              reginsert(g, STAR, ret);
++      else if (op == '*') {
++              /* Emit x* as (x&|), where & means "self". */
++              reginsert(g, BRANCH, ret);                      /* Either x */
++              regoptail(g, ret, regnode(g, BACK));            /* and loop */
++              regoptail(g, ret, ret);                 /* back */
++              regtail(g, ret, regnode(g, BRANCH));            /* or */
++              regtail(g, ret, regnode(g, NOTHING));           /* null. */
++      } else if (op == '+' && (flags&SIMPLE))
++              reginsert(g, PLUS, ret);
++      else if (op == '+') {
++              /* Emit x+ as x(&|), where & means "self". */
++              next = regnode(g, BRANCH);                      /* Either */
++              regtail(g, ret, next);
++              regtail(g, regnode(g, BACK), ret);              /* loop back */
++              regtail(g, next, regnode(g, BRANCH));           /* or */
++              regtail(g, ret, regnode(g, NOTHING));           /* null. */
++      } else if (op == '?') {
++              /* Emit x? as (x|) */
++              reginsert(g, BRANCH, ret);                      /* Either x */
++              regtail(g, ret, regnode(g, BRANCH));            /* or */
++              next = regnode(g, NOTHING);             /* null. */
++              regtail(g, ret, next);
++              regoptail(g, ret, next);
++      }
++      g->regparse++;
++      if (ISMULT(*g->regparse))
++              FAIL("nested *?+");
++
++      return(ret);
++}
++
++/*
++ - regatom - the lowest level
++ *
++ * Optimization:  gobbles an entire sequence of ordinary characters so that
++ * it can turn them into a single node, which is smaller to store and
++ * faster to run.  Backslashed characters are exceptions, each becoming a
++ * separate node; the code is simpler that way and it's not worth fixing.
++ */
++static char *
++regatom(struct match_globals *g, int *flagp)
++{
++      register char *ret;
++      int flags;
++
++      *flagp = WORST;         /* Tentatively. */
++
++      switch (*g->regparse++) {
++      case '^':
++              ret = regnode(g, BOL);
++              break;
++      case '$':
++              ret = regnode(g, EOL);
++              break;
++      case '.':
++              ret = regnode(g, ANY);
++              *flagp |= HASWIDTH|SIMPLE;
++              break;
++      case '[': {
++                      register int class;
++                      register int classend;
++
++                      if (*g->regparse == '^') {      /* Complement of range. */
++                              ret = regnode(g, ANYBUT);
++                              g->regparse++;
++                      } else
++                              ret = regnode(g, ANYOF);
++                      if (*g->regparse == ']' || *g->regparse == '-')
++                              regc(g, *g->regparse++);
++                      while (*g->regparse != '\0' && *g->regparse != ']') {
++                              if (*g->regparse == '-') {
++                                      g->regparse++;
++                                      if (*g->regparse == ']' || *g->regparse == '\0')
++                                              regc(g, '-');
++                                      else {
++                                              class = UCHARAT(g->regparse-2)+1;
++                                              classend = UCHARAT(g->regparse);
++                                              if (class > classend+1)
++                                                      FAIL("invalid [] range");
++                                              for (; class <= classend; class++)
++                                                      regc(g, class);
++                                              g->regparse++;
++                                      }
++                              } else
++                                      regc(g, *g->regparse++);
++                      }
++                      regc(g, '\0');
++                      if (*g->regparse != ']')
++                              FAIL("unmatched []");
++                      g->regparse++;
++                      *flagp |= HASWIDTH|SIMPLE;
++              }
++              break;
++      case '(':
++              ret = reg(g, 1, &flags);
++              if (ret == NULL)
++                      return(NULL);
++              *flagp |= flags&(HASWIDTH|SPSTART);
++              break;
++      case '\0':
++      case '|':
++      case ')':
++              FAIL("internal urp");   /* Supposed to be caught earlier. */
++              break;
++      case '?':
++      case '+':
++      case '*':
++              FAIL("?+* follows nothing");
++              break;
++      case '\\':
++              if (*g->regparse == '\0')
++                      FAIL("trailing \\");
++              ret = regnode(g, EXACTLY);
++              regc(g, *g->regparse++);
++              regc(g, '\0');
++              *flagp |= HASWIDTH|SIMPLE;
++              break;
++      default: {
++                      register int len;
++                      register char ender;
++
++                      g->regparse--;
++                      len = my_strcspn((const char *)g->regparse, (const char *)META);
++                      if (len <= 0)
++                              FAIL("internal disaster");
++                      ender = *(g->regparse+len);
++                      if (len > 1 && ISMULT(ender))
++                              len--;          /* Back off clear of ?+* operand. */
++                      *flagp |= HASWIDTH;
++                      if (len == 1)
++                              *flagp |= SIMPLE;
++                      ret = regnode(g, EXACTLY);
++                      while (len > 0) {
++                              regc(g, *g->regparse++);
++                              len--;
++                      }
++                      regc(g, '\0');
++              }
++              break;
++      }
++
++      return(ret);
++}
++
++/*
++ - regnode - emit a node
++ */
++static char *                 /* Location. */
++regnode(struct match_globals *g, char op)
++{
++      register char *ret;
++      register char *ptr;
++
++      ret = g->regcode;
++      if (ret == &g->regdummy) {
++              g->regsize += 3;
++              return(ret);
++      }
++
++      ptr = ret;
++      *ptr++ = op;
++      *ptr++ = '\0';          /* Null "next" pointer. */
++      *ptr++ = '\0';
++      g->regcode = ptr;
++
++      return(ret);
++}
++
++/*
++ - regc - emit (if appropriate) a byte of code
++ */
++static void
++regc(struct match_globals *g, char b)
++{
++      if (g->regcode != &g->regdummy)
++              *g->regcode++ = b;
++      else
++              g->regsize++;
++}
++
++/*
++ - reginsert - insert an operator in front of already-emitted operand
++ *
++ * Means relocating the operand.
++ */
++static void
++reginsert(struct match_globals *g, char op, char* opnd)
++{
++      register char *src;
++      register char *dst;
++      register char *place;
++
++      if (g->regcode == &g->regdummy) {
++              g->regsize += 3;
++              return;
++      }
++
++      src = g->regcode;
++      g->regcode += 3;
++      dst = g->regcode;
++      while (src > opnd)
++              *--dst = *--src;
++
++      place = opnd;           /* Op node, where operand used to be. */
++      *place++ = op;
++      *place++ = '\0';
++      *place++ = '\0';
++}
++
++/*
++ - regtail - set the next-pointer at the end of a node chain
++ */
++static void
++regtail(struct match_globals *g, char *p, char *val)
++{
++      register char *scan;
++      register char *temp;
++      register int offset;
++
++      if (p == &g->regdummy)
++              return;
++
++      /* Find last node. */
++      scan = p;
++      for (;;) {
++              temp = regnext(g, scan);
++              if (temp == NULL)
++                      break;
++              scan = temp;
++      }
++
++      if (OP(scan) == BACK)
++              offset = scan - val;
++      else
++              offset = val - scan;
++      *(scan+1) = (offset>>8)&0377;
++      *(scan+2) = offset&0377;
++}
++
++/*
++ - regoptail - regtail on operand of first argument; nop if operandless
++ */
++static void
++regoptail(struct match_globals *g, char *p, char *val)
++{
++      /* "Operandless" and "op != BRANCH" are synonymous in practice. */
++      if (p == NULL || p == &g->regdummy || OP(p) != BRANCH)
++              return;
++      regtail(g, OPERAND(p), val);
++}
++
++/*
++ * regexec and friends
++ */
++
++
++/*
++ * Forwards.
++ */
++STATIC int regtry(struct match_globals *g, regexp *prog, char *string);
++STATIC int regmatch(struct match_globals *g, char *prog);
++STATIC int regrepeat(struct match_globals *g, char *p);
++
++#ifdef DEBUG
++int regnarrate = 0;
++void regdump();
++STATIC char *regprop(char *op);
++#endif
++
++/*
++ - regexec - match a regexp against a string
++ */
++int
++regexec(regexp *prog, char *string)
++{
++      register char *s;
++      struct match_globals g;
++
++      /* Be paranoid... */
++      if (prog == NULL || string == NULL) {
++              printk("<3>Regexp: NULL parameter\n");
++              return(0);
++      }
++
++      /* Check validity of program. */
++      if (UCHARAT(prog->program) != MAGIC) {
++              printk("<3>Regexp: corrupted program\n");
++              return(0);
++      }
++
++      /* If there is a "must appear" string, look for it. */
++      if (prog->regmust != NULL) {
++              s = string;
++              while ((s = strchr(s, prog->regmust[0])) != NULL) {
++                      if (strncmp(s, prog->regmust, prog->regmlen) == 0)
++                              break;  /* Found it. */
++                      s++;
++              }
++              if (s == NULL)  /* Not present. */
++                      return(0);
++      }
++
++      /* Mark beginning of line for ^ . */
++      g.regbol = string;
++
++      /* Simplest case:  anchored match need be tried only once. */
++      if (prog->reganch)
++              return(regtry(&g, prog, string));
++
++      /* Messy cases:  unanchored match. */
++      s = string;
++      if (prog->regstart != '\0')
++              /* We know what char it must start with. */
++              while ((s = strchr(s, prog->regstart)) != NULL) {
++                      if (regtry(&g, prog, s))
++                              return(1);
++                      s++;
++              }
++      else
++              /* We don't -- general case. */
++              do {
++                      if (regtry(&g, prog, s))
++                              return(1);
++              } while (*s++ != '\0');
++
++      /* Failure. */
++      return(0);
++}
++
++/*
++ - regtry - try match at specific point
++ */
++static int                    /* 0 failure, 1 success */
++regtry(struct match_globals *g, regexp *prog, char *string)
++{
++      register int i;
++      register char **sp;
++      register char **ep;
++
++      g->reginput = string;
++      g->regstartp = prog->startp;
++      g->regendp = prog->endp;
++
++      sp = prog->startp;
++      ep = prog->endp;
++      for (i = NSUBEXP; i > 0; i--) {
++              *sp++ = NULL;
++              *ep++ = NULL;
++      }
++      if (regmatch(g, prog->program + 1)) {
++              prog->startp[0] = string;
++              prog->endp[0] = g->reginput;
++              return(1);
++      } else
++              return(0);
++}
++
++/*
++ - regmatch - main matching routine
++ *
++ * Conceptually the strategy is simple:  check to see whether the current
++ * node matches, call self recursively to see whether the rest matches,
++ * and then act accordingly.  In practice we make some effort to avoid
++ * recursion, in particular by going through "ordinary" nodes (that don't
++ * need to know whether the rest of the match failed) by a loop instead of
++ * by recursion.
++ */
++static int                    /* 0 failure, 1 success */
++regmatch(struct match_globals *g, char *prog)
++{
++      register char *scan = prog; /* Current node. */
++      char *next;                 /* Next node. */
++
++#ifdef DEBUG
++      if (scan != NULL && regnarrate)
++              fprintf(stderr, "%s(\n", regprop(scan));
++#endif
++      while (scan != NULL) {
++#ifdef DEBUG
++              if (regnarrate)
++                      fprintf(stderr, "%s...\n", regprop(scan));
++#endif
++              next = regnext(g, scan);
++
++              switch (OP(scan)) {
++              case BOL:
++                      if (g->reginput != g->regbol)
++                              return(0);
++                      break;
++              case EOL:
++                      if (*g->reginput != '\0')
++                              return(0);
++                      break;
++              case ANY:
++                      if (*g->reginput == '\0')
++                              return(0);
++                      g->reginput++;
++                      break;
++              case EXACTLY: {
++                              register int len;
++                              register char *opnd;
++
++                              opnd = OPERAND(scan);
++                              /* Inline the first character, for speed. */
++                              if (*opnd != *g->reginput)
++                                      return(0);
++                              len = strlen(opnd);
++                              if (len > 1 && strncmp(opnd, g->reginput, len) != 0)
++                                      return(0);
++                              g->reginput += len;
++                      }
++                      break;
++              case ANYOF:
++                      if (*g->reginput == '\0' || strchr(OPERAND(scan), *g->reginput) == NULL)
++                              return(0);
++                      g->reginput++;
++                      break;
++              case ANYBUT:
++                      if (*g->reginput == '\0' || strchr(OPERAND(scan), *g->reginput) != NULL)
++                              return(0);
++                      g->reginput++;
++                      break;
++              case NOTHING:
++              case BACK:
++                      break;
++              case OPEN+1:
++              case OPEN+2:
++              case OPEN+3:
++              case OPEN+4:
++              case OPEN+5:
++              case OPEN+6:
++              case OPEN+7:
++              case OPEN+8:
++              case OPEN+9: {
++                              register int no;
++                              register char *save;
++
++                              no = OP(scan) - OPEN;
++                              save = g->reginput;
++
++                              if (regmatch(g, next)) {
++                                      /*
++                                       * Don't set startp if some later
++                                       * invocation of the same parentheses
++                                       * already has.
++                                       */
++                                      if (g->regstartp[no] == NULL)
++                                              g->regstartp[no] = save;
++                                      return(1);
++                              } else
++                                      return(0);
++                      }
++                      break;
++              case CLOSE+1:
++              case CLOSE+2:
++              case CLOSE+3:
++              case CLOSE+4:
++              case CLOSE+5:
++              case CLOSE+6:
++              case CLOSE+7:
++              case CLOSE+8:
++              case CLOSE+9:
++                      {
++                              register int no;
++                              register char *save;
++
++                              no = OP(scan) - CLOSE;
++                              save = g->reginput;
++
++                              if (regmatch(g, next)) {
++                                      /*
++                                       * Don't set endp if some later
++                                       * invocation of the same parentheses
++                                       * already has.
++                                       */
++                                      if (g->regendp[no] == NULL)
++                                              g->regendp[no] = save;
++                                      return(1);
++                              } else
++                                      return(0);
++                      }
++                      break;
++              case BRANCH: {
++                              register char *save;
++
++                              if (OP(next) != BRANCH)         /* No choice. */
++                                      next = OPERAND(scan);   /* Avoid recursion. */
++                              else {
++                                      do {
++                                              save = g->reginput;
++                                              if (regmatch(g, OPERAND(scan)))
++                                                      return(1);
++                                              g->reginput = save;
++                                              scan = regnext(g, scan);
++                                      } while (scan != NULL && OP(scan) == BRANCH);
++                                      return(0);
++                                      /* NOTREACHED */
++                              }
++                      }
++                      break;
++              case STAR:
++              case PLUS: {
++                              register char nextch;
++                              register int no;
++                              register char *save;
++                              register int min;
++
++                              /*
++                               * Lookahead to avoid useless match attempts
++                               * when we know what character comes next.
++                               */
++                              nextch = '\0';
++                              if (OP(next) == EXACTLY)
++                                      nextch = *OPERAND(next);
++                              min = (OP(scan) == STAR) ? 0 : 1;
++                              save = g->reginput;
++                              no = regrepeat(g, OPERAND(scan));
++                              while (no >= min) {
++                                      /* If it could work, try it. */
++                                      if (nextch == '\0' || *g->reginput == nextch)
++                                              if (regmatch(g, next))
++                                                      return(1);
++                                      /* Couldn't or didn't -- back up. */
++                                      no--;
++                                      g->reginput = save + no;
++                              }
++                              return(0);
++                      }
++                      break;
++              case END:
++                      return(1);      /* Success! */
++                      break;
++              default:
++                      printk("<3>Regexp: memory corruption\n");
++                      return(0);
++                      break;
++              }
++
++              scan = next;
++      }
++
++      /*
++       * We get here only if there's trouble -- normally "case END" is
++       * the terminating point.
++       */
++      printk("<3>Regexp: corrupted pointers\n");
++      return(0);
++}
++
++/*
++ - regrepeat - repeatedly match something simple, report how many
++ */
++static int
++regrepeat(struct match_globals *g, char *p)
++{
++      register int count = 0;
++      register char *scan;
++      register char *opnd;
++
++      scan = g->reginput;
++      opnd = OPERAND(p);
++      switch (OP(p)) {
++      case ANY:
++              count = strlen(scan);
++              scan += count;
++              break;
++      case EXACTLY:
++              while (*opnd == *scan) {
++                      count++;
++                      scan++;
++              }
++              break;
++      case ANYOF:
++              while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
++                      count++;
++                      scan++;
++              }
++              break;
++      case ANYBUT:
++              while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
++                      count++;
++                      scan++;
++              }
++              break;
++      default:                /* Oh dear.  Called inappropriately. */
++              printk("<3>Regexp: internal foulup\n");
++              count = 0;      /* Best compromise. */
++              break;
++      }
++      g->reginput = scan;
++
++      return(count);
++}
++
++/*
++ - regnext - dig the "next" pointer out of a node
++ */
++static char*
++regnext(struct match_globals *g, char *p)
++{
++      register int offset;
++
++      if (p == &g->regdummy)
++              return(NULL);
++
++      offset = NEXT(p);
++      if (offset == 0)
++              return(NULL);
++
++      if (OP(p) == BACK)
++              return(p-offset);
++      else
++              return(p+offset);
++}
++
++#ifdef DEBUG
++
++STATIC char *regprop();
++
++/*
++ - regdump - dump a regexp onto stdout in vaguely comprehensible form
++ */
++void
++regdump(regexp *r)
++{
++      register char *s;
++      register char op = EXACTLY;     /* Arbitrary non-END op. */
++      register char *next;
++      /* extern char *strchr(); */
++
++
++      s = r->program + 1;
++      while (op != END) {     /* While that wasn't END last time... */
++              op = OP(s);
++              printf("%2d%s", s-r->program, regprop(s));      /* Where, what. */
++              next = regnext(s);
++              if (next == NULL)               /* Next ptr. */
++                      printf("(0)");
++              else
++                      printf("(%d)", (s-r->program)+(next-s));
++              s += 3;
++              if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
++                      /* Literal string, where present. */
++                      while (*s != '\0') {
++                              putchar(*s);
++                              s++;
++                      }
++                      s++;
++              }
++              putchar('\n');
++      }
++
++      /* Header fields of interest. */
++      if (r->regstart != '\0')
++              printf("start `%c' ", r->regstart);
++      if (r->reganch)
++              printf("anchored ");
++      if (r->regmust != NULL)
++              printf("must have \"%s\"", r->regmust);
++      printf("\n");
++}
++
++/*
++ - regprop - printable representation of opcode
++ */
++static char *
++regprop(char *op)
++{
++#define BUFLEN 50
++      register char *p;
++      static char buf[BUFLEN];
++
++      strcpy(buf, ":");
++
++      switch (OP(op)) {
++      case BOL:
++              p = "BOL";
++              break;
++      case EOL:
++              p = "EOL";
++              break;
++      case ANY:
++              p = "ANY";
++              break;
++      case ANYOF:
++              p = "ANYOF";
++              break;
++      case ANYBUT:
++              p = "ANYBUT";
++              break;
++      case BRANCH:
++              p = "BRANCH";
++              break;
++      case EXACTLY:
++              p = "EXACTLY";
++              break;
++      case NOTHING:
++              p = "NOTHING";
++              break;
++      case BACK:
++              p = "BACK";
++              break;
++      case END:
++              p = "END";
++              break;
++      case OPEN+1:
++      case OPEN+2:
++      case OPEN+3:
++      case OPEN+4:
++      case OPEN+5:
++      case OPEN+6:
++      case OPEN+7:
++      case OPEN+8:
++      case OPEN+9:
++              snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "OPEN%d", OP(op)-OPEN);
++              p = NULL;
++              break;
++      case CLOSE+1:
++      case CLOSE+2:
++      case CLOSE+3:
++      case CLOSE+4:
++      case CLOSE+5:
++      case CLOSE+6:
++      case CLOSE+7:
++      case CLOSE+8:
++      case CLOSE+9:
++              snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "CLOSE%d", OP(op)-CLOSE);
++              p = NULL;
++              break;
++      case STAR:
++              p = "STAR";
++              break;
++      case PLUS:
++              p = "PLUS";
++              break;
++      default:
++              printk("<3>Regexp: corrupted opcode\n");
++              break;
++      }
++      if (p != NULL)
++              strncat(buf, p, BUFLEN-strlen(buf));
++      return(buf);
++}
++#endif
++
++
+--- linux-2.6.18/net/ipv4/netfilter/regexp/regexp.h    1969-12-31 18:00:00.000000000 -0600
++++ linux-2.6.18-layer7/net/ipv4/netfilter/regexp/regexp.h     2006-09-24 10:17:45.000000000 -0500
+@@ -0,0 +1,41 @@
++/*
++ * Definitions etc. for regexp(3) routines.
++ *
++ * Caveat:  this is V8 regexp(3) [actually, a reimplementation thereof],
++ * not the System V one.
++ */
++
++#ifndef REGEXP_H
++#define REGEXP_H
++
++
++/*
++http://www.opensource.apple.com/darwinsource/10.3/expect-1/expect/expect.h ,
++which contains a version of this library, says:
++
++ *
++ * NSUBEXP must be at least 10, and no greater than 117 or the parser
++ * will not work properly.
++ *
++
++However, it looks rather like this library is limited to 10.  If you think
++otherwise, let us know.
++*/
++
++#define NSUBEXP  10
++typedef struct regexp {
++      char *startp[NSUBEXP];
++      char *endp[NSUBEXP];
++      char regstart;          /* Internal use only. */
++      char reganch;           /* Internal use only. */
++      char *regmust;          /* Internal use only. */
++      int regmlen;            /* Internal use only. */
++      char program[1];        /* Unwarranted chumminess with compiler. */
++} regexp;
++
++regexp * regcomp(char *exp, int *patternsize);
++int regexec(regexp *prog, char *string);
++void regsub(regexp *prog, char *source, char *dest);
++void regerror(char *s);
++
++#endif
+--- linux-2.6.18/net/ipv4/netfilter/regexp/regmagic.h  1969-12-31 18:00:00.000000000 -0600
++++ linux-2.6.18-layer7/net/ipv4/netfilter/regexp/regmagic.h   2006-09-24 10:17:45.000000000 -0500
+@@ -0,0 +1,5 @@
++/*
++ * The first byte of the regexp internal "program" is actually this magic
++ * number; the start node begins in the second byte.
++ */
++#define       MAGIC   0234
+--- linux-2.6.18/net/ipv4/netfilter/regexp/regsub.c    1969-12-31 18:00:00.000000000 -0600
++++ linux-2.6.18-layer7/net/ipv4/netfilter/regexp/regsub.c     2006-09-24 10:17:45.000000000 -0500
+@@ -0,0 +1,95 @@
++/*
++ * regsub
++ * @(#)regsub.c       1.3 of 2 April 86
++ *
++ *    Copyright (c) 1986 by University of Toronto.
++ *    Written by Henry Spencer.  Not derived from licensed software.
++ *
++ *    Permission is granted to anyone to use this software for any
++ *    purpose on any computer system, and to redistribute it freely,
++ *    subject to the following restrictions:
++ *
++ *    1. The author is not responsible for the consequences of use of
++ *            this software, no matter how awful, even if they arise
++ *            from defects in it.
++ *
++ *    2. The origin of this software must not be misrepresented, either
++ *            by explicit claim or by omission.
++ *
++ *    3. Altered versions must be plainly marked as such, and must not
++ *            be misrepresented as being the original software.
++ *
++ *
++ * This code was modified by Ethan Sommer to work within the kernel
++ * (it now uses kmalloc etc..)
++ *
++ */
++#include "regexp.h"
++#include "regmagic.h"
++#include <linux/string.h>
++
++
++#ifndef CHARBITS
++#define       UCHARAT(p)      ((int)*(unsigned char *)(p))
++#else
++#define       UCHARAT(p)      ((int)*(p)&CHARBITS)
++#endif
++
++#if 0
++//void regerror(char * s)
++//{
++//        printk("regexp(3): %s", s);
++//        /* NOTREACHED */
++//}
++#endif
++
++/*
++ - regsub - perform substitutions after a regexp match
++ */
++void
++regsub(regexp * prog, char * source, char * dest)
++{
++      register char *src;
++      register char *dst;
++      register char c;
++      register int no;
++      register int len;
++      
++      /* Not necessary and gcc doesn't like it -MLS */
++      /*extern char *strncpy();*/
++
++      if (prog == NULL || source == NULL || dest == NULL) {
++              regerror("NULL parm to regsub");
++              return;
++      }
++      if (UCHARAT(prog->program) != MAGIC) {
++              regerror("damaged regexp fed to regsub");
++              return;
++      }
++
++      src = source;
++      dst = dest;
++      while ((c = *src++) != '\0') {
++              if (c == '&')
++                      no = 0;
++              else if (c == '\\' && '0' <= *src && *src <= '9')
++                      no = *src++ - '0';
++              else
++                      no = -1;
++
++              if (no < 0) {   /* Ordinary character. */
++                      if (c == '\\' && (*src == '\\' || *src == '&'))
++                              c = *src++;
++                      *dst++ = c;
++              } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) {
++                      len = prog->endp[no] - prog->startp[no];
++                      (void) strncpy(dst, prog->startp[no], len);
++                      dst += len;
++                      if (len != 0 && *(dst-1) == '\0') {     /* strncpy hit NUL. */
++                              regerror("damaged match string");
++                              return;
++                      }
++              }
++      }
++      *dst++ = '\0';
++}
diff --git a/packages/linux/linux-magicbox-2.6.18.6/magicbox2-ide-cf_2.6.18.patch b/packages/linux/linux-magicbox-2.6.18.6/magicbox2-ide-cf_2.6.18.patch
new file mode 100644 (file)
index 0000000..113d5c4
--- /dev/null
@@ -0,0 +1,221 @@
+diff -Nru linux-2.6.18/drivers/ide/Kconfig linux-2.6.18-magicbox2-cf-ide/drivers/ide/Kconfig
+--- linux-2.6.18/drivers/ide/Kconfig   2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-magicbox2-cf-ide/drivers/ide/Kconfig  2006-12-28 19:33:33.000000000 +0100
+@@ -926,6 +926,24 @@
+         If unsure, say N.
++config BLK_DEV_MAGICBOX_IDE
++      bool "MagicBox 2.0 CF IDE support"
++      depends on 4xx && IDE=y && BLK_DEV_IDE=y
++      help
++        This option provides support for IDE on MagicBox 2.0 boards.
++
++        If unsure, say N.
++
++config BLK_DEV_MAGICBOX_PROTOTYPE
++      bool "Compile driver for prototype boards"
++      depends on BLK_DEV_MAGICBOX_IDE
++      help
++        Compile driver for first revision of MagicBox 2.0 boards
++        (wiring changes).
++
++        If unsure, say N.
++
++
+ choice
+       prompt "Type of MPC8xx IDE interface"
+       depends on BLK_DEV_MPC8xx_IDE
+diff -Nru linux-2.6.18/drivers/ide/Makefile linux-2.6.18-magicbox2-cf-ide/drivers/ide/Makefile
+--- linux-2.6.18/drivers/ide/Makefile  2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-magicbox2-cf-ide/drivers/ide/Makefile 2006-12-28 19:27:00.000000000 +0100
+@@ -36,6 +36,7 @@
+ # built-in only drivers from ppc/
+ ide-core-$(CONFIG_BLK_DEV_MPC8xx_IDE) += ppc/mpc8xx.o
+ ide-core-$(CONFIG_BLK_DEV_IDE_PMAC)   += ppc/pmac.o
++ide-core-$(CONFIG_BLK_DEV_MAGICBOX_IDE)       += ppc/magicbox_ide.o
+ # built-in only drivers from h8300/
+ ide-core-$(CONFIG_H8300)              += h8300/ide-h8300.o
+diff -Nru linux-2.6.18/drivers/ide/ide.c linux-2.6.18-magicbox2-cf-ide/drivers/ide/ide.c
+--- linux-2.6.18/drivers/ide/ide.c     2006-09-20 05:42:06.000000000 +0200
++++ linux-2.6.18-magicbox2-cf-ide/drivers/ide/ide.c    2006-12-28 19:27:00.000000000 +0100
+@@ -1836,6 +1836,13 @@
+ #ifdef CONFIG_H8300
+       h8300_ide_init();
+ #endif
++#ifdef CONFIG_BLK_DEV_MAGICBOX_IDE
++      {
++              extern void ide_magicbox_init();
++              ide_magicbox_init();
++      }
++#endif
++
+ }
+ void ide_register_subdriver(ide_drive_t *drive, ide_driver_t *driver)
+diff -Nru linux-2.6.18/drivers/ide/ppc/magicbox_ide.c linux-2.6.18-magicbox2-cf-ide/drivers/ide/ppc/magicbox_ide.c
+--- linux-2.6.18/drivers/ide/ppc/magicbox_ide.c        1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-magicbox2-cf-ide/drivers/ide/ppc/magicbox_ide.c       2006-12-30 21:00:18.000000000 +0100
+@@ -0,0 +1,161 @@
++/* Driver for MagicBox 2.0 onboard CompactFlash adapter.
++ * Written by Wojtek Kaniewski <wojtekka@toxygen.net>
++ *
++ * GNU General Public License.
++ */
++
++#include <linux/types.h>
++#include <linux/mm.h>
++#include <linux/interrupt.h>
++#include <linux/blkdev.h>
++#include <linux/hdreg.h>
++#include <linux/ide.h>
++#include <linux/delay.h>
++
++
++#define UIC0_PR 0xc4
++#define UIC0_TR 0xc5
++#define IRQ 25
++
++static int ide_offsets[IDE_NR_PORTS] = {0, 2, 4, 6, 8, 10, 12, 14, -1, -1};
++
++static u8 magicbox_ide_inb (unsigned long port)
++{
++      return (u8) (readw((void __iomem *) port) >> 8) & 255;
++}
++
++static u16 magicbox_ide_inw (unsigned long port)
++{
++      return (u16) readw((void __iomem *) port);
++}
++
++static void magicbox_ide_insw (unsigned long port, void *addr, u32 count)
++{
++      u16 *ptr;
++
++      for (ptr = addr; count--; ptr++)
++              *ptr = readw((void __iomem *) port);
++}
++
++static u32 magicbox_ide_inl (unsigned long port)
++{
++      return (u32) readl((void __iomem *) port);
++}
++
++static void magicbox_ide_insl (unsigned long port, void *addr, u32 count)
++{
++      u32 *ptr;
++
++      for (ptr = addr; count--; ptr++)
++              *ptr = readl((void __iomem *) port);
++}
++
++static void magicbox_ide_outb (u8 value, unsigned long port)
++{
++      writew(value << 8, (void __iomem *) port);
++}
++
++static void magicbox_ide_outbsync (ide_drive_t *drive, u8 value, unsigned long port)
++{
++      writew(value << 8, (void __iomem *) port);
++}
++
++static void magicbox_ide_outw (u16 value, unsigned long port)
++{
++      writew(value, (void __iomem *) port);
++}
++
++static void magicbox_ide_outsw (unsigned long port, void *addr, u32 count)
++{
++      u16 *ptr;
++
++      for (ptr = addr; count--; ptr++)
++              writew(*ptr, (void __iomem *) port);
++}
++
++static void magicbox_ide_outl (u32 value, unsigned long port)
++{
++      writel(value, (void __iomem *) port);
++}
++
++static void magicbox_ide_outsl (unsigned long port, void *addr, u32 count)
++{
++      u32 *ptr;
++
++      for (ptr = addr; count--; ptr++)
++              writel(*ptr, (void __iomem *) port);
++}
++
++
++static void __init ide_magicbox_register(unsigned long addr,
++                                       unsigned long caddr, int irq)
++{
++      hw_regs_t hw;
++      ide_hwif_t *hwif;
++
++      memset(&hw, 0, sizeof(hw));
++      ide_setup_ports(&hw, addr, ide_offsets, caddr + 12, 0, NULL,irq);
++
++      if (ide_register_hw(&hw, &hwif) != -1)
++      {
++              printk(KERN_NOTICE "magicbox-ide: Registered IDE-CF driver\n");
++              hwif->mmio = 2;
++              hwif->drives[0].unmask = 1;
++              hwif->OUTB = magicbox_ide_outb;
++              hwif->OUTBSYNC = magicbox_ide_outbsync;
++              hwif->OUTW = magicbox_ide_outw;
++              hwif->OUTL = magicbox_ide_outl;
++              hwif->OUTSW = magicbox_ide_outsw;
++              hwif->OUTSL = magicbox_ide_outsl;
++              hwif->INB = magicbox_ide_inb;
++              hwif->INW = magicbox_ide_inw;
++              hwif->INL = magicbox_ide_inl;
++              hwif->INSW = magicbox_ide_insw;
++              hwif->INSL = magicbox_ide_insl;
++      }
++}
++
++void __init ide_magicbox_init(void)
++{
++      volatile u16 *addr;
++      volatile u16 *caddr;
++
++      /* Turn on PerWE instead of PCIsomething */
++      mtdcr(DCRN_CPC0_PCI_BASE, mfdcr(DCRN_CPC0_PCI_BASE) | (0x80000000L >> 27));
++
++#ifdef CONFIG_BLK_DEV_MAGICBOX_PROTOTYPE
++      /* PerCS2 (CF's CS0): base 0xff100000, 16-bit, rw */
++      mtdcr(DCRN_EBC_BASE, 2);
++      mtdcr(DCRN_EBC_BASE + 1, 0xff11a000);
++      mtdcr(DCRN_EBC_BASE, 0x12);
++      mtdcr(DCRN_EBC_BASE + 1, 0x080bd800);
++
++      /* PerCS1 (CF's CS1): base 0xff200000, 16-bit, rw */
++      mtdcr(DCRN_EBC_BASE, 1);
++      mtdcr(DCRN_EBC_BASE + 1, 0xff21a000);
++      mtdcr(DCRN_EBC_BASE, 0x11);
++      mtdcr(DCRN_EBC_BASE + 1, 0x080bd800);
++#else
++      /* PerCS1 (CF's CS0): base 0xff100000, 16-bit, rw */
++      mtdcr(DCRN_EBC_BASE, 1);
++      mtdcr(DCRN_EBC_BASE + 1, 0xff11a000);
++      mtdcr(DCRN_EBC_BASE, 0x11);
++      mtdcr(DCRN_EBC_BASE + 1, 0x080bd800);
++
++      /* PerCS2 (CF's CS1): base 0xff200000, 16-bit, rw */
++      mtdcr(DCRN_EBC_BASE, 2);
++      mtdcr(DCRN_EBC_BASE + 1, 0xff21a000);
++      mtdcr(DCRN_EBC_BASE, 0x12);
++      mtdcr(DCRN_EBC_BASE + 1, 0x080bd800);
++#endif
++
++      /* Remap physical address space */
++      addr = ioremap_nocache(0xff100000, 4096);
++      caddr = ioremap_nocache(0xff200000, 4096);
++
++      /* Set interrupt to low-to-high-edge-triggered */
++      mtdcr(UIC0_TR, mfdcr(UIC0_TR) & ~(0x80000000L >> IRQ));
++      mtdcr(UIC0_PR, mfdcr(UIC0_PR) | (0x80000000L >> IRQ));
++
++      ide_magicbox_register((unsigned long)addr, (unsigned long)caddr, IRQ);
++}
diff --git a/packages/linux/linux-magicbox-2.6.18.6/squashfs3.1-patch b/packages/linux/linux-magicbox-2.6.18.6/squashfs3.1-patch
new file mode 100644 (file)
index 0000000..9f24221
--- /dev/null
@@ -0,0 +1,4227 @@
+diff --new-file -urp linux-2.6.18/fs/Kconfig linux-2.6.18-squashfs3.1/fs/Kconfig
+--- linux-2.6.18/fs/Kconfig    2006-08-11 00:03:11.000000000 +0100
++++ linux-2.6.18-squashfs3.1/fs/Kconfig        2006-08-21 00:13:12.000000000 +0100
+@@ -1249,6 +1249,71 @@ config CRAMFS
+         If unsure, say N.
++config SQUASHFS
++      tristate "SquashFS 3.1 - Squashed file system support"
++      select ZLIB_INFLATE
++      help
++        Saying Y here includes support for SquashFS 3.1 (a Compressed Read-Only File
++        System).  Squashfs is a highly compressed read-only filesystem for Linux.
++        It uses zlib compression to compress both files, inodes and directories.
++        Inodes in the system are very small and all blocks are packed to minimise
++        data overhead. Block sizes greater than 4K are supported up to a maximum of 64K.
++        SquashFS 3.1 supports 64 bit filesystems and files (larger than 4GB), full
++        uid/gid information, hard links and timestamps.
++
++        Squashfs is intended for general read-only filesystem use, for archival
++        use (i.e. in cases where a .tar.gz file may be used), and in embedded
++        systems where low overhead is needed.  Further information and filesystem tools
++        are available from http://squashfs.sourceforge.net.
++
++        If you want to compile this as a module ( = code which can be
++        inserted in and removed from the running kernel whenever you want),
++        say M here and read <file:Documentation/modules.txt>.  The module
++        will be called squashfs.  Note that the root file system (the one
++        containing the directory /) cannot be compiled as a module.
++
++        If unsure, say N.
++
++config SQUASHFS_EMBEDDED
++
++      bool "Additional options for memory-constrained systems" 
++      depends on SQUASHFS
++      default n
++      help
++        Saying Y here allows you to specify cache sizes and how Squashfs
++        allocates memory.  This is only intended for memory constrained
++        systems.
++
++        If unsure, say N.
++
++config SQUASHFS_FRAGMENT_CACHE_SIZE
++      int "Number of fragments cached" if SQUASHFS_EMBEDDED
++      depends on SQUASHFS
++      default "3"
++      help
++        By default SquashFS caches the last 3 fragments read from
++        the filesystem.  Increasing this amount may mean SquashFS
++        has to re-read fragments less often from disk, at the expense
++        of extra system memory.  Decreasing this amount will mean
++        SquashFS uses less memory at the expense of extra reads from disk.
++
++        Note there must be at least one cached fragment.  Anything
++        much more than three will probably not make much difference.
++
++config SQUASHFS_VMALLOC
++      bool "Use Vmalloc rather than Kmalloc" if SQUASHFS_EMBEDDED
++      depends on SQUASHFS
++      default n
++      help
++        By default SquashFS uses kmalloc to obtain fragment cache memory.
++        Kmalloc memory is the standard kernel allocator, but it can fail
++        on memory constrained systems.  Because of the way Vmalloc works,
++        Vmalloc can succeed when kmalloc fails.  Specifying this option
++        will make SquashFS always use Vmalloc to allocate the
++        fragment cache memory.
++
++        If unsure, say N.
++
+ config VXFS_FS
+       tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)"
+       help
+diff --new-file -urp linux-2.6.18/fs/Makefile linux-2.6.18-squashfs3.1/fs/Makefile
+--- linux-2.6.18/fs/Makefile   2006-08-11 00:03:12.000000000 +0100
++++ linux-2.6.18-squashfs3.1/fs/Makefile       2006-08-21 00:13:12.000000000 +0100
+@@ -57,6 +57,7 @@ obj-$(CONFIG_EXT3_FS)                += ext3/ # Before
+ obj-$(CONFIG_JBD)             += jbd/
+ obj-$(CONFIG_EXT2_FS)         += ext2/
+ obj-$(CONFIG_CRAMFS)          += cramfs/
++obj-$(CONFIG_SQUASHFS)                += squashfs/
+ obj-$(CONFIG_RAMFS)           += ramfs/
+ obj-$(CONFIG_HUGETLBFS)               += hugetlbfs/
+ obj-$(CONFIG_CODA_FS)         += coda/
+diff --new-file -urp linux-2.6.18/fs/squashfs/inode.c linux-2.6.18-squashfs3.1/fs/squashfs/inode.c
+--- linux-2.6.18/fs/squashfs/inode.c   1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-squashfs3.1/fs/squashfs/inode.c       2006-08-21 00:15:29.000000000 +0100
+@@ -0,0 +1,2156 @@
++/*
++ * Squashfs - a compressed read only filesystem for Linux
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006
++ * Phillip Lougher <phillip@lougher.org.uk>
++ *
++ * 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,
++ * or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * inode.c
++ */
++
++#include <linux/types.h>
++#include <linux/squashfs_fs.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/zlib.h>
++#include <linux/fs.h>
++#include <linux/smp_lock.h>
++#include <linux/slab.h>
++#include <linux/squashfs_fs_sb.h>
++#include <linux/squashfs_fs_i.h>
++#include <linux/buffer_head.h>
++#include <linux/vfs.h>
++#include <linux/init.h>
++#include <linux/dcache.h>
++#include <linux/wait.h>
++#include <linux/blkdev.h>
++#include <linux/vmalloc.h>
++#include <asm/uaccess.h>
++#include <asm/semaphore.h>
++
++#include "squashfs.h"
++
++static void squashfs_put_super(struct super_block *);
++static int squashfs_statfs(struct dentry *, struct kstatfs *);
++static int squashfs_symlink_readpage(struct file *file, struct page *page);
++static int squashfs_readpage(struct file *file, struct page *page);
++static int squashfs_readpage4K(struct file *file, struct page *page);
++static int squashfs_readdir(struct file *, void *, filldir_t);
++static struct inode *squashfs_alloc_inode(struct super_block *sb);
++static void squashfs_destroy_inode(struct inode *inode);
++static int init_inodecache(void);
++static void destroy_inodecache(void);
++static struct dentry *squashfs_lookup(struct inode *, struct dentry *,
++                              struct nameidata *);
++static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode);
++static long long read_blocklist(struct inode *inode, int index,
++                              int readahead_blks, char *block_list,
++                              unsigned short **block_p, unsigned int *bsize);
++static int squashfs_get_sb(struct file_system_type *, int, const char *, void *,
++                              struct vfsmount *);
++
++static struct file_system_type squashfs_fs_type = {
++      .owner = THIS_MODULE,
++      .name = "squashfs",
++      .get_sb = squashfs_get_sb,
++      .kill_sb = kill_block_super,
++      .fs_flags = FS_REQUIRES_DEV
++};
++
++static unsigned char squashfs_filetype_table[] = {
++      DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
++};
++
++static struct super_operations squashfs_ops = {
++      .alloc_inode = squashfs_alloc_inode,
++      .destroy_inode = squashfs_destroy_inode,
++      .statfs = squashfs_statfs,
++      .put_super = squashfs_put_super,
++};
++
++SQSH_EXTERN struct address_space_operations squashfs_symlink_aops = {
++      .readpage = squashfs_symlink_readpage
++};
++
++SQSH_EXTERN struct address_space_operations squashfs_aops = {
++      .readpage = squashfs_readpage
++};
++
++SQSH_EXTERN struct address_space_operations squashfs_aops_4K = {
++      .readpage = squashfs_readpage4K
++};
++
++static struct file_operations squashfs_dir_ops = {
++      .read = generic_read_dir,
++      .readdir = squashfs_readdir
++};
++
++SQSH_EXTERN struct inode_operations squashfs_dir_inode_ops = {
++      .lookup = squashfs_lookup
++};
++
++
++static struct buffer_head *get_block_length(struct super_block *s,
++                              int *cur_index, int *offset, int *c_byte)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      unsigned short temp;
++      struct buffer_head *bh;
++
++      if (!(bh = sb_bread(s, *cur_index)))
++              goto out;
++
++      if (msblk->devblksize - *offset == 1) {
++              if (msblk->swap)
++                      ((unsigned char *) &temp)[1] = *((unsigned char *)
++                              (bh->b_data + *offset));
++              else
++                      ((unsigned char *) &temp)[0] = *((unsigned char *)
++                              (bh->b_data + *offset));
++              brelse(bh);
++              if (!(bh = sb_bread(s, ++(*cur_index))))
++                      goto out;
++              if (msblk->swap)
++                      ((unsigned char *) &temp)[0] = *((unsigned char *)
++                              bh->b_data); 
++              else
++                      ((unsigned char *) &temp)[1] = *((unsigned char *)
++                              bh->b_data); 
++              *c_byte = temp;
++              *offset = 1;
++      } else {
++              if (msblk->swap) {
++                      ((unsigned char *) &temp)[1] = *((unsigned char *)
++                              (bh->b_data + *offset));
++                      ((unsigned char *) &temp)[0] = *((unsigned char *)
++                              (bh->b_data + *offset + 1)); 
++              } else {
++                      ((unsigned char *) &temp)[0] = *((unsigned char *)
++                              (bh->b_data + *offset));
++                      ((unsigned char *) &temp)[1] = *((unsigned char *)
++                              (bh->b_data + *offset + 1)); 
++              }
++              *c_byte = temp;
++              *offset += 2;
++      }
++
++      if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) {
++              if (*offset == msblk->devblksize) {
++                      brelse(bh);
++                      if (!(bh = sb_bread(s, ++(*cur_index))))
++                              goto out;
++                      *offset = 0;
++              }
++              if (*((unsigned char *) (bh->b_data + *offset)) !=
++                                              SQUASHFS_MARKER_BYTE) {
++                      ERROR("Metadata block marker corrupt @ %x\n",
++                                              *cur_index);
++                      brelse(bh);
++                      goto out;
++              }
++              (*offset)++;
++      }
++      return bh;
++
++out:
++      return NULL;
++}
++
++
++SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer,
++                      long long index, unsigned int length,
++                      long long *next_index)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >>
++                      msblk->devblksize_log2) + 2];
++      unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1);
++      unsigned int cur_index = index >> msblk->devblksize_log2;
++      int bytes, avail_bytes, b = 0, k;
++      char *c_buffer;
++      unsigned int compressed;
++      unsigned int c_byte = length;
++
++      if (c_byte) {
++              bytes = msblk->devblksize - offset;
++              compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);
++              c_buffer = compressed ? msblk->read_data : buffer;
++              c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
++
++              TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
++                                      ? "" : "un", (unsigned int) c_byte);
++
++              if (!(bh[0] = sb_getblk(s, cur_index)))
++                      goto block_release;
++
++              for (b = 1; bytes < c_byte; b++) {
++                      if (!(bh[b] = sb_getblk(s, ++cur_index)))
++                              goto block_release;
++                      bytes += msblk->devblksize;
++              }
++              ll_rw_block(READ, b, bh);
++      } else {
++              if (!(bh[0] = get_block_length(s, &cur_index, &offset,
++                                                              &c_byte)))
++                      goto read_failure;
++
++              bytes = msblk->devblksize - offset;
++              compressed = SQUASHFS_COMPRESSED(c_byte);
++              c_buffer = compressed ? msblk->read_data : buffer;
++              c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
++
++              TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
++                                      ? "" : "un", (unsigned int) c_byte);
++
++              for (b = 1; bytes < c_byte; b++) {
++                      if (!(bh[b] = sb_getblk(s, ++cur_index)))
++                              goto block_release;
++                      bytes += msblk->devblksize;
++              }
++              ll_rw_block(READ, b - 1, bh + 1);
++      }
++
++      if (compressed)
++              down(&msblk->read_data_mutex);
++
++      for (bytes = 0, k = 0; k < b; k++) {
++              avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ?
++                                      msblk->devblksize - offset :
++                                      c_byte - bytes;
++              wait_on_buffer(bh[k]);
++              if (!buffer_uptodate(bh[k]))
++                      goto block_release;
++              memcpy(c_buffer + bytes, bh[k]->b_data + offset, avail_bytes);
++              bytes += avail_bytes;
++              offset = 0;
++              brelse(bh[k]);
++      }
++
++      /*
++       * uncompress block
++       */
++      if (compressed) {
++              int zlib_err;
++
++              msblk->stream.next_in = c_buffer;
++              msblk->stream.avail_in = c_byte;
++              msblk->stream.next_out = buffer;
++              msblk->stream.avail_out = msblk->read_size;
++
++              if (((zlib_err = zlib_inflateInit(&msblk->stream)) != Z_OK) ||
++                              ((zlib_err = zlib_inflate(&msblk->stream, Z_FINISH))
++                               != Z_STREAM_END) || ((zlib_err =
++                              zlib_inflateEnd(&msblk->stream)) != Z_OK)) {
++                      ERROR("zlib_fs returned unexpected result 0x%x\n",
++                              zlib_err);
++                      bytes = 0;
++              } else
++                      bytes = msblk->stream.total_out;
++              
++              up(&msblk->read_data_mutex);
++      }
++
++      if (next_index)
++              *next_index = index + c_byte + (length ? 0 :
++                              (SQUASHFS_CHECK_DATA(msblk->sblk.flags)
++                               ? 3 : 2));
++      return bytes;
++
++block_release:
++      while (--b >= 0)
++              brelse(bh[b]);
++
++read_failure:
++      ERROR("sb_bread failed reading block 0x%x\n", cur_index);
++      return 0;
++}
++
++
++SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer,
++                              long long block, unsigned int offset,
++                              int length, long long *next_block,
++                              unsigned int *next_offset)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      int n, i, bytes, return_length = length;
++      long long next_index;
++
++      TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset);
++
++      while ( 1 ) {
++              for (i = 0; i < SQUASHFS_CACHED_BLKS; i++) 
++                      if (msblk->block_cache[i].block == block)
++                              break; 
++              
++              down(&msblk->block_cache_mutex);
++
++              if (i == SQUASHFS_CACHED_BLKS) {
++                      /* read inode header block */
++                      for (i = msblk->next_cache, n = SQUASHFS_CACHED_BLKS;
++                                      n ; n --, i = (i + 1) %
++                                      SQUASHFS_CACHED_BLKS)
++                              if (msblk->block_cache[i].block !=
++                                                      SQUASHFS_USED_BLK)
++                                      break;
++
++                      if (n == 0) {
++                              wait_queue_t wait;
++
++                              init_waitqueue_entry(&wait, current);
++                              add_wait_queue(&msblk->waitq, &wait);
++                              set_current_state(TASK_UNINTERRUPTIBLE);
++                              up(&msblk->block_cache_mutex);
++                              schedule();
++                              set_current_state(TASK_RUNNING);
++                              remove_wait_queue(&msblk->waitq, &wait);
++                              continue;
++                      }
++                      msblk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS;
++
++                      if (msblk->block_cache[i].block ==
++                                                      SQUASHFS_INVALID_BLK) {
++                              if (!(msblk->block_cache[i].data =
++                                              kmalloc(SQUASHFS_METADATA_SIZE,
++                                              GFP_KERNEL))) {
++                                      ERROR("Failed to allocate cache"
++                                                      "block\n");
++                                      up(&msblk->block_cache_mutex);
++                                      goto out;
++                              }
++                      }
++      
++                      msblk->block_cache[i].block = SQUASHFS_USED_BLK;
++                      up(&msblk->block_cache_mutex);
++
++                      if (!(msblk->block_cache[i].length =
++                                              squashfs_read_data(s,
++                                              msblk->block_cache[i].data,
++                                              block, 0, &next_index))) {
++                              ERROR("Unable to read cache block [%llx:%x]\n",
++                                              block, offset);
++                              goto out;
++                      }
++
++                      down(&msblk->block_cache_mutex);
++                      wake_up(&msblk->waitq);
++                      msblk->block_cache[i].block = block;
++                      msblk->block_cache[i].next_index = next_index;
++                      TRACE("Read cache block [%llx:%x]\n", block, offset);
++              }
++
++              if (msblk->block_cache[i].block != block) {
++                      up(&msblk->block_cache_mutex);
++                      continue;
++              }
++
++              if ((bytes = msblk->block_cache[i].length - offset) >= length) {
++                      if (buffer)
++                              memcpy(buffer, msblk->block_cache[i].data +
++                                              offset, length);
++                      if (msblk->block_cache[i].length - offset == length) {
++                              *next_block = msblk->block_cache[i].next_index;
++                              *next_offset = 0;
++                      } else {
++                              *next_block = block;
++                              *next_offset = offset + length;
++                      }
++                      up(&msblk->block_cache_mutex);
++                      goto finish;
++              } else {
++                      if (buffer) {
++                              memcpy(buffer, msblk->block_cache[i].data +
++                                              offset, bytes);
++                              buffer += bytes;
++                      }
++                      block = msblk->block_cache[i].next_index;
++                      up(&msblk->block_cache_mutex);
++                      length -= bytes;
++                      offset = 0;
++              }
++      }
++
++finish:
++      return return_length;
++out:
++      return 0;
++}
++
++
++static int get_fragment_location(struct super_block *s, unsigned int fragment,
++                              long long *fragment_start_block,
++                              unsigned int *fragment_size)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      long long start_block =
++              msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)];
++      int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
++      struct squashfs_fragment_entry fragment_entry;
++
++      if (msblk->swap) {
++              struct squashfs_fragment_entry sfragment_entry;
++
++              if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
++                                      start_block, offset,
++                                      sizeof(sfragment_entry), &start_block,
++                                      &offset))
++                      goto out;
++              SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry);
++      } else
++              if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
++                                      start_block, offset,
++                                      sizeof(fragment_entry), &start_block,
++                                      &offset))
++                      goto out;
++
++      *fragment_start_block = fragment_entry.start_block;
++      *fragment_size = fragment_entry.size;
++
++      return 1;
++
++out:
++      return 0;
++}
++
++
++SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, struct
++                                      squashfs_fragment_cache *fragment)
++{
++      down(&msblk->fragment_mutex);
++      fragment->locked --;
++      wake_up(&msblk->fragment_wait_queue);
++      up(&msblk->fragment_mutex);
++}
++
++
++SQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_block
++                                      *s, long long start_block,
++                                      int length)
++{
++      int i, n;
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++
++      while ( 1 ) {
++              down(&msblk->fragment_mutex);
++
++              for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS &&
++                              msblk->fragment[i].block != start_block; i++);
++
++              if (i == SQUASHFS_CACHED_FRAGMENTS) {
++                      for (i = msblk->next_fragment, n =
++                              SQUASHFS_CACHED_FRAGMENTS; n &&
++                              msblk->fragment[i].locked; n--, i = (i + 1) %
++                              SQUASHFS_CACHED_FRAGMENTS);
++
++                      if (n == 0) {
++                              wait_queue_t wait;
++
++                              init_waitqueue_entry(&wait, current);
++                              add_wait_queue(&msblk->fragment_wait_queue,
++                                                                      &wait);
++                              set_current_state(TASK_UNINTERRUPTIBLE);
++                              up(&msblk->fragment_mutex);
++                              schedule();
++                              set_current_state(TASK_RUNNING);
++                              remove_wait_queue(&msblk->fragment_wait_queue,
++                                                                      &wait);
++                              continue;
++                      }
++                      msblk->next_fragment = (msblk->next_fragment + 1) %
++                              SQUASHFS_CACHED_FRAGMENTS;
++                      
++                      if (msblk->fragment[i].data == NULL)
++                              if (!(msblk->fragment[i].data = SQUASHFS_ALLOC
++                                              (SQUASHFS_FILE_MAX_SIZE))) {
++                                      ERROR("Failed to allocate fragment "
++                                                      "cache block\n");
++                                      up(&msblk->fragment_mutex);
++                                      goto out;
++                              }
++
++                      msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
++                      msblk->fragment[i].locked = 1;
++                      up(&msblk->fragment_mutex);
++
++                      if (!(msblk->fragment[i].length = squashfs_read_data(s,
++                                              msblk->fragment[i].data,
++                                              start_block, length, NULL))) {
++                              ERROR("Unable to read fragment cache block "
++                                                      "[%llx]\n", start_block);
++                              msblk->fragment[i].locked = 0;
++                              goto out;
++                      }
++
++                      msblk->fragment[i].block = start_block;
++                      TRACE("New fragment %d, start block %lld, locked %d\n",
++                                              i, msblk->fragment[i].block,
++                                              msblk->fragment[i].locked);
++                      break;
++              }
++
++              msblk->fragment[i].locked++;
++              up(&msblk->fragment_mutex);
++              TRACE("Got fragment %d, start block %lld, locked %d\n", i,
++                                              msblk->fragment[i].block,
++                                              msblk->fragment[i].locked);
++              break;
++      }
++
++      return &msblk->fragment[i];
++
++out:
++      return NULL;
++}
++
++
++static struct inode *squashfs_new_inode(struct super_block *s,
++              struct squashfs_base_inode_header *inodeb)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct inode *i = new_inode(s);
++
++      if (i) {
++              i->i_ino = inodeb->inode_number;
++              i->i_mtime.tv_sec = inodeb->mtime;
++              i->i_atime.tv_sec = inodeb->mtime;
++              i->i_ctime.tv_sec = inodeb->mtime;
++              i->i_uid = msblk->uid[inodeb->uid];
++              i->i_mode = inodeb->mode;
++              i->i_size = 0;
++              if (inodeb->guid == SQUASHFS_GUIDS)
++                      i->i_gid = i->i_uid;
++              else
++                      i->i_gid = msblk->guid[inodeb->guid];
++      }
++
++      return i;
++}
++
++
++static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode)
++{
++      struct inode *i;
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      long long block = SQUASHFS_INODE_BLK(inode) +
++              sblk->inode_table_start;
++      unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
++      long long next_block;
++      unsigned int next_offset;
++      union squashfs_inode_header id, sid;
++      struct squashfs_base_inode_header *inodeb = &id.base,
++                                        *sinodeb = &sid.base;
++
++      TRACE("Entered squashfs_iget\n");
++
++      if (msblk->swap) {
++              if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
++                                      offset, sizeof(*sinodeb), &next_block,
++                                      &next_offset))
++                      goto failed_read;
++              SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb,
++                                      sizeof(*sinodeb));
++      } else
++              if (!squashfs_get_cached_block(s, (char *) inodeb, block,
++                                      offset, sizeof(*inodeb), &next_block,
++                                      &next_offset))
++                      goto failed_read;
++
++      switch(inodeb->inode_type) {
++              case SQUASHFS_FILE_TYPE: {
++                      unsigned int frag_size;
++                      long long frag_blk;
++                      struct squashfs_reg_inode_header *inodep = &id.reg;
++                      struct squashfs_reg_inode_header *sinodep = &sid.reg;
++                              
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep);
++                      } else
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      frag_blk = SQUASHFS_INVALID_BLK;
++                      if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
++                                      !get_fragment_location(s,
++                                      inodep->fragment, &frag_blk, &frag_size))
++                              goto failed_read;
++                              
++                      if((i = squashfs_new_inode(s, inodeb)) == NULL)
++                              goto failed_read1;
++
++                      i->i_nlink = 1;
++                      i->i_size = inodep->file_size;
++                      i->i_fop = &generic_ro_fops;
++                      i->i_mode |= S_IFREG;
++                      i->i_blocks = ((i->i_size - 1) >> 9) + 1;
++                      i->i_blksize = PAGE_CACHE_SIZE;
++                      SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
++                      SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
++                      SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
++                      SQUASHFS_I(i)->start_block = inodep->start_block;
++                      SQUASHFS_I(i)->u.s1.block_list_start = next_block;
++                      SQUASHFS_I(i)->offset = next_offset;
++                      if (sblk->block_size > 4096)
++                              i->i_data.a_ops = &squashfs_aops;
++                      else
++                              i->i_data.a_ops = &squashfs_aops_4K;
++
++                      TRACE("File inode %x:%x, start_block %llx, "
++                                      "block_list_start %llx, offset %x\n",
++                                      SQUASHFS_INODE_BLK(inode), offset,
++                                      inodep->start_block, next_block,
++                                      next_offset);
++                      break;
++              }
++              case SQUASHFS_LREG_TYPE: {
++                      unsigned int frag_size;
++                      long long frag_blk;
++                      struct squashfs_lreg_inode_header *inodep = &id.lreg;
++                      struct squashfs_lreg_inode_header *sinodep = &sid.lreg;
++                              
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep);
++                      } else
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      frag_blk = SQUASHFS_INVALID_BLK;
++                      if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
++                                      !get_fragment_location(s,
++                                      inodep->fragment, &frag_blk, &frag_size))
++                              goto failed_read;
++                              
++                      if((i = squashfs_new_inode(s, inodeb)) == NULL)
++                              goto failed_read1;
++
++                      i->i_nlink = inodep->nlink;
++                      i->i_size = inodep->file_size;
++                      i->i_fop = &generic_ro_fops;
++                      i->i_mode |= S_IFREG;
++                      i->i_blocks = ((i->i_size - 1) >> 9) + 1;
++                      i->i_blksize = PAGE_CACHE_SIZE;
++                      SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
++                      SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
++                      SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
++                      SQUASHFS_I(i)->start_block = inodep->start_block;
++                      SQUASHFS_I(i)->u.s1.block_list_start = next_block;
++                      SQUASHFS_I(i)->offset = next_offset;
++                      if (sblk->block_size > 4096)
++                              i->i_data.a_ops = &squashfs_aops;
++                      else
++                              i->i_data.a_ops = &squashfs_aops_4K;
++
++                      TRACE("File inode %x:%x, start_block %llx, "
++                                      "block_list_start %llx, offset %x\n",
++                                      SQUASHFS_INODE_BLK(inode), offset,
++                                      inodep->start_block, next_block,
++                                      next_offset);
++                      break;
++              }
++              case SQUASHFS_DIR_TYPE: {
++                      struct squashfs_dir_inode_header *inodep = &id.dir;
++                      struct squashfs_dir_inode_header *sinodep = &sid.dir;
++
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep);
++                      } else
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      if((i = squashfs_new_inode(s, inodeb)) == NULL)
++                              goto failed_read1;
++
++                      i->i_nlink = inodep->nlink;
++                      i->i_size = inodep->file_size;
++                      i->i_op = &squashfs_dir_inode_ops;
++                      i->i_fop = &squashfs_dir_ops;
++                      i->i_mode |= S_IFDIR;
++                      SQUASHFS_I(i)->start_block = inodep->start_block;
++                      SQUASHFS_I(i)->offset = inodep->offset;
++                      SQUASHFS_I(i)->u.s2.directory_index_count = 0;
++                      SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
++
++                      TRACE("Directory inode %x:%x, start_block %x, offset "
++                                      "%x\n", SQUASHFS_INODE_BLK(inode),
++                                      offset, inodep->start_block,
++                                      inodep->offset);
++                      break;
++              }
++              case SQUASHFS_LDIR_TYPE: {
++                      struct squashfs_ldir_inode_header *inodep = &id.ldir;
++                      struct squashfs_ldir_inode_header *sinodep = &sid.ldir;
++
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep,
++                                              sinodep);
++                      } else
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      if((i = squashfs_new_inode(s, inodeb)) == NULL)
++                              goto failed_read1;
++
++                      i->i_nlink = inodep->nlink;
++                      i->i_size = inodep->file_size;
++                      i->i_op = &squashfs_dir_inode_ops;
++                      i->i_fop = &squashfs_dir_ops;
++                      i->i_mode |= S_IFDIR;
++                      SQUASHFS_I(i)->start_block = inodep->start_block;
++                      SQUASHFS_I(i)->offset = inodep->offset;
++                      SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
++                      SQUASHFS_I(i)->u.s2.directory_index_offset =
++                                                              next_offset;
++                      SQUASHFS_I(i)->u.s2.directory_index_count =
++                                                              inodep->i_count;
++                      SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
++
++                      TRACE("Long directory inode %x:%x, start_block %x, "
++                                      "offset %x\n",
++                                      SQUASHFS_INODE_BLK(inode), offset,
++                                      inodep->start_block, inodep->offset);
++                      break;
++              }
++              case SQUASHFS_SYMLINK_TYPE: {
++                      struct squashfs_symlink_inode_header *inodep =
++                                                              &id.symlink;
++                      struct squashfs_symlink_inode_header *sinodep =
++                                                              &sid.symlink;
++      
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep,
++                                                              sinodep);
++                      } else
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      if((i = squashfs_new_inode(s, inodeb)) == NULL)
++                              goto failed_read1;
++
++                      i->i_nlink = inodep->nlink;
++                      i->i_size = inodep->symlink_size;
++                      i->i_op = &page_symlink_inode_operations;
++                      i->i_data.a_ops = &squashfs_symlink_aops;
++                      i->i_mode |= S_IFLNK;
++                      SQUASHFS_I(i)->start_block = next_block;
++                      SQUASHFS_I(i)->offset = next_offset;
++
++                      TRACE("Symbolic link inode %x:%x, start_block %llx, "
++                                      "offset %x\n",
++                                      SQUASHFS_INODE_BLK(inode), offset,
++                                      next_block, next_offset);
++                      break;
++               }
++               case SQUASHFS_BLKDEV_TYPE:
++               case SQUASHFS_CHRDEV_TYPE: {
++                      struct squashfs_dev_inode_header *inodep = &id.dev;
++                      struct squashfs_dev_inode_header *sinodep = &sid.dev;
++
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep);
++                      } else  
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      if ((i = squashfs_new_inode(s, inodeb)) == NULL)
++                              goto failed_read1;
++
++                      i->i_nlink = inodep->nlink;
++                      i->i_mode |= (inodeb->inode_type ==
++                                      SQUASHFS_CHRDEV_TYPE) ?  S_IFCHR :
++                                      S_IFBLK;
++                      init_special_inode(i, i->i_mode,
++                                      old_decode_dev(inodep->rdev));
++
++                      TRACE("Device inode %x:%x, rdev %x\n",
++                                      SQUASHFS_INODE_BLK(inode), offset,
++                                      inodep->rdev);
++                      break;
++               }
++               case SQUASHFS_FIFO_TYPE:
++               case SQUASHFS_SOCKET_TYPE: {
++                      struct squashfs_ipc_inode_header *inodep = &id.ipc;
++                      struct squashfs_ipc_inode_header *sinodep = &sid.ipc;
++
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep);
++                      } else  
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      if ((i = squashfs_new_inode(s, inodeb)) == NULL)
++                              goto failed_read1;
++
++                      i->i_nlink = inodep->nlink;
++                      i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
++                                                      ? S_IFIFO : S_IFSOCK;
++                      init_special_inode(i, i->i_mode, 0);
++                      break;
++               }
++               default:
++                      ERROR("Unknown inode type %d in squashfs_iget!\n",
++                                      inodeb->inode_type);
++                      goto failed_read1;
++      }
++      
++      insert_inode_hash(i);
++      return i;
++
++failed_read:
++      ERROR("Unable to read inode [%llx:%x]\n", block, offset);
++
++failed_read1:
++      return NULL;
++}
++
++
++static int read_fragment_index_table(struct super_block *s)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++
++      /* Allocate fragment index table */
++      if (!(msblk->fragment_index = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES
++                                      (sblk->fragments), GFP_KERNEL))) {
++              ERROR("Failed to allocate uid/gid table\n");
++              return 0;
++      }
++   
++      if (SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments) &&
++                                      !squashfs_read_data(s, (char *)
++                                      msblk->fragment_index,
++                                      sblk->fragment_table_start,
++                                      SQUASHFS_FRAGMENT_INDEX_BYTES
++                                      (sblk->fragments) |
++                                      SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
++              ERROR("unable to read fragment index table\n");
++              return 0;
++      }
++
++      if (msblk->swap) {
++              int i;
++              long long fragment;
++
++              for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments);
++                                                                      i++) {
++                      SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment),
++                                              &msblk->fragment_index[i], 1);
++                      msblk->fragment_index[i] = fragment;
++              }
++      }
++
++      return 1;
++}
++
++
++static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent)
++{
++      struct squashfs_super_block *sblk = &msblk->sblk;
++
++      msblk->iget = squashfs_iget;
++      msblk->read_blocklist = read_blocklist;
++      msblk->read_fragment_index_table = read_fragment_index_table;
++
++      if (sblk->s_major == 1) {
++              if (!squashfs_1_0_supported(msblk)) {
++                      SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems "
++                              "are unsupported\n");
++                      SERROR("Please recompile with "
++                              "Squashfs 1.0 support enabled\n");
++                      return 0;
++              }
++      } else if (sblk->s_major == 2) {
++              if (!squashfs_2_0_supported(msblk)) {
++                      SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems "
++                              "are unsupported\n");
++                      SERROR("Please recompile with "
++                              "Squashfs 2.0 support enabled\n");
++                      return 0;
++              }
++      } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor >
++                      SQUASHFS_MINOR) {
++              SERROR("Major/Minor mismatch, trying to mount newer %d.%d "
++                              "filesystem\n", sblk->s_major, sblk->s_minor);
++              SERROR("Please update your kernel\n");
++              return 0;
++      }
++
++      return 1;
++}
++
++
++static int squashfs_fill_super(struct super_block *s, void *data, int silent)
++{
++      struct squashfs_sb_info *msblk;
++      struct squashfs_super_block *sblk;
++      int i;
++      char b[BDEVNAME_SIZE];
++      struct inode *root;
++
++      TRACE("Entered squashfs_read_superblock\n");
++
++      if (!(s->s_fs_info = kmalloc(sizeof(struct squashfs_sb_info),
++                                              GFP_KERNEL))) {
++              ERROR("Failed to allocate superblock\n");
++              goto failure;
++      }
++      memset(s->s_fs_info, 0, sizeof(struct squashfs_sb_info));
++      msblk = s->s_fs_info;
++      if (!(msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize()))) {
++              ERROR("Failed to allocate zlib workspace\n");
++              goto failure;
++      }
++      sblk = &msblk->sblk;
++      
++      msblk->devblksize = sb_min_blocksize(s, BLOCK_SIZE);
++      msblk->devblksize_log2 = ffz(~msblk->devblksize);
++
++      init_MUTEX(&msblk->read_data_mutex);
++      init_MUTEX(&msblk->read_page_mutex);
++      init_MUTEX(&msblk->block_cache_mutex);
++      init_MUTEX(&msblk->fragment_mutex);
++      init_MUTEX(&msblk->meta_index_mutex);
++      
++      init_waitqueue_head(&msblk->waitq);
++      init_waitqueue_head(&msblk->fragment_wait_queue);
++
++      if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START,
++                                      sizeof(struct squashfs_super_block) |
++                                      SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
++              SERROR("unable to read superblock\n");
++              goto failed_mount;
++      }
++
++      /* Check it is a SQUASHFS superblock */
++      msblk->swap = 0;
++      if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) {
++              if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) {
++                      struct squashfs_super_block ssblk;
++
++                      WARNING("Mounting a different endian SQUASHFS "
++                              "filesystem on %s\n", bdevname(s->s_bdev, b));
++
++                      SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk);
++                      memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block));
++                      msblk->swap = 1;
++              } else  {
++                      SERROR("Can't find a SQUASHFS superblock on %s\n",
++                                                      bdevname(s->s_bdev, b));
++                      goto failed_mount;
++              }
++      }
++
++      /* Check the MAJOR & MINOR versions */
++      if(!supported_squashfs_filesystem(msblk, silent))
++              goto failed_mount;
++
++      TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b));
++      TRACE("Inodes are %scompressed\n",
++                                      SQUASHFS_UNCOMPRESSED_INODES
++                                      (sblk->flags) ? "un" : "");
++      TRACE("Data is %scompressed\n",
++                                      SQUASHFS_UNCOMPRESSED_DATA(sblk->flags)
++                                      ? "un" : "");
++      TRACE("Check data is %s present in the filesystem\n",
++                                      SQUASHFS_CHECK_DATA(sblk->flags) ?
++                                      "" : "not");
++      TRACE("Filesystem size %lld bytes\n", sblk->bytes_used);
++      TRACE("Block size %d\n", sblk->block_size);
++      TRACE("Number of inodes %d\n", sblk->inodes);
++      if (sblk->s_major > 1)
++              TRACE("Number of fragments %d\n", sblk->fragments);
++      TRACE("Number of uids %d\n", sblk->no_uids);
++      TRACE("Number of gids %d\n", sblk->no_guids);
++      TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start);
++      TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start);
++      if (sblk->s_major > 1)
++              TRACE("sblk->fragment_table_start %llx\n",
++                                      sblk->fragment_table_start);
++      TRACE("sblk->uid_start %llx\n", sblk->uid_start);
++
++      s->s_flags |= MS_RDONLY;
++      s->s_op = &squashfs_ops;
++
++      /* Init inode_table block pointer array */
++      if (!(msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) *
++                                      SQUASHFS_CACHED_BLKS, GFP_KERNEL))) {
++              ERROR("Failed to allocate block cache\n");
++              goto failed_mount;
++      }
++
++      for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
++              msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
++
++      msblk->next_cache = 0;
++
++      /* Allocate read_data block */
++      msblk->read_size = (sblk->block_size < SQUASHFS_METADATA_SIZE) ?
++                                      SQUASHFS_METADATA_SIZE :
++                                      sblk->block_size;
++
++      if (!(msblk->read_data = kmalloc(msblk->read_size, GFP_KERNEL))) {
++              ERROR("Failed to allocate read_data block\n");
++              goto failed_mount;
++      }
++
++      /* Allocate read_page block */
++      if (!(msblk->read_page = kmalloc(sblk->block_size, GFP_KERNEL))) {
++              ERROR("Failed to allocate read_page block\n");
++              goto failed_mount;
++      }
++
++      /* Allocate uid and gid tables */
++      if (!(msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) *
++                                      sizeof(unsigned int), GFP_KERNEL))) {
++              ERROR("Failed to allocate uid/gid table\n");
++              goto failed_mount;
++      }
++      msblk->guid = msblk->uid + sblk->no_uids;
++   
++      if (msblk->swap) {
++              unsigned int suid[sblk->no_uids + sblk->no_guids];
++
++              if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start,
++                                      ((sblk->no_uids + sblk->no_guids) *
++                                       sizeof(unsigned int)) |
++                                      SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
++                      ERROR("unable to read uid/gid table\n");
++                      goto failed_mount;
++              }
++
++              SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids +
++                      sblk->no_guids), (sizeof(unsigned int) * 8));
++      } else
++              if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start,
++                                      ((sblk->no_uids + sblk->no_guids) *
++                                       sizeof(unsigned int)) |
++                                      SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
++                      ERROR("unable to read uid/gid table\n");
++                      goto failed_mount;
++              }
++
++
++      if (sblk->s_major == 1 && squashfs_1_0_supported(msblk))
++              goto allocate_root;
++
++      if (!(msblk->fragment = kmalloc(sizeof(struct squashfs_fragment_cache) *
++                              SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) {
++              ERROR("Failed to allocate fragment block cache\n");
++              goto failed_mount;
++      }
++
++      for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) {
++              msblk->fragment[i].locked = 0;
++              msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
++              msblk->fragment[i].data = NULL;
++      }
++
++      msblk->next_fragment = 0;
++
++      /* Allocate fragment index table */
++      if (msblk->read_fragment_index_table(s) == 0)
++              goto failed_mount;
++
++allocate_root:
++      if ((root = (msblk->iget)(s, sblk->root_inode)) == NULL)
++              goto failed_mount;
++
++      if ((s->s_root = d_alloc_root(root)) == NULL) {
++              ERROR("Root inode create failed\n");
++              iput(root);
++              goto failed_mount;
++      }
++
++      TRACE("Leaving squashfs_read_super\n");
++      return 0;
++
++failed_mount:
++      kfree(msblk->fragment_index);
++      kfree(msblk->fragment);
++      kfree(msblk->uid);
++      kfree(msblk->read_page);
++      kfree(msblk->read_data);
++      kfree(msblk->block_cache);
++      kfree(msblk->fragment_index_2);
++      vfree(msblk->stream.workspace);
++      kfree(s->s_fs_info);
++      s->s_fs_info = NULL;
++      return -EINVAL;
++
++failure:
++      return -ENOMEM;
++}
++
++
++static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)
++{
++      struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++
++      TRACE("Entered squashfs_statfs\n");
++
++      buf->f_type = SQUASHFS_MAGIC;
++      buf->f_bsize = sblk->block_size;
++      buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1;
++      buf->f_bfree = buf->f_bavail = 0;
++      buf->f_files = sblk->inodes;
++      buf->f_ffree = 0;
++      buf->f_namelen = SQUASHFS_NAME_LEN;
++
++      return 0;
++}
++
++
++static int squashfs_symlink_readpage(struct file *file, struct page *page)
++{
++      struct inode *inode = page->mapping->host;
++      int index = page->index << PAGE_CACHE_SHIFT, length, bytes;
++      long long block = SQUASHFS_I(inode)->start_block;
++      int offset = SQUASHFS_I(inode)->offset;
++      void *pageaddr = kmap(page);
++
++      TRACE("Entered squashfs_symlink_readpage, page index %ld, start block "
++                              "%llx, offset %x\n", page->index,
++                              SQUASHFS_I(inode)->start_block,
++                              SQUASHFS_I(inode)->offset);
++
++      for (length = 0; length < index; length += bytes) {
++              if (!(bytes = squashfs_get_cached_block(inode->i_sb, NULL,
++                              block, offset, PAGE_CACHE_SIZE, &block,
++                              &offset))) {
++                      ERROR("Unable to read symbolic link [%llx:%x]\n", block,
++                                      offset);
++                      goto skip_read;
++              }
++      }
++
++      if (length != index) {
++              ERROR("(squashfs_symlink_readpage) length != index\n");
++              bytes = 0;
++              goto skip_read;
++      }
++
++      bytes = (i_size_read(inode) - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE :
++                                      i_size_read(inode) - length;
++
++      if (!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block,
++                                      offset, bytes, &block, &offset)))
++              ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
++
++skip_read:
++      memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
++      kunmap(page);
++      SetPageUptodate(page);
++      unlock_page(page);
++
++      return 0;
++}
++
++
++struct meta_index *locate_meta_index(struct inode *inode, int index, int offset)
++{
++      struct meta_index *meta = NULL;
++      struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
++      int i;
++
++      down(&msblk->meta_index_mutex);
++
++      TRACE("locate_meta_index: index %d, offset %d\n", index, offset);
++
++      if(msblk->meta_index == NULL)
++              goto not_allocated;
++
++      for (i = 0; i < SQUASHFS_META_NUMBER; i ++)
++              if (msblk->meta_index[i].inode_number == inode->i_ino &&
++                              msblk->meta_index[i].offset >= offset &&
++                              msblk->meta_index[i].offset <= index &&
++                              msblk->meta_index[i].locked == 0) {
++                      TRACE("locate_meta_index: entry %d, offset %d\n", i,
++                                      msblk->meta_index[i].offset);
++                      meta = &msblk->meta_index[i];
++                      offset = meta->offset;
++              }
++
++      if (meta)
++              meta->locked = 1;
++
++not_allocated:
++      up(&msblk->meta_index_mutex);
++
++      return meta;
++}
++
++
++struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip)
++{
++      struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
++      struct meta_index *meta = NULL;
++      int i;
++
++      down(&msblk->meta_index_mutex);
++
++      TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip);
++
++      if(msblk->meta_index == NULL) {
++              if (!(msblk->meta_index = kmalloc(sizeof(struct meta_index) *
++                                      SQUASHFS_META_NUMBER, GFP_KERNEL))) {
++                      ERROR("Failed to allocate meta_index\n");
++                      goto failed;
++              }
++              for(i = 0; i < SQUASHFS_META_NUMBER; i++) {
++                      msblk->meta_index[i].inode_number = 0;
++                      msblk->meta_index[i].locked = 0;
++              }
++              msblk->next_meta_index = 0;
++      }
++
++      for(i = SQUASHFS_META_NUMBER; i &&
++                      msblk->meta_index[msblk->next_meta_index].locked; i --)
++              msblk->next_meta_index = (msblk->next_meta_index + 1) %
++                      SQUASHFS_META_NUMBER;
++
++      if(i == 0) {
++              TRACE("empty_meta_index: failed!\n");
++              goto failed;
++      }
++
++      TRACE("empty_meta_index: returned meta entry %d, %p\n",
++                      msblk->next_meta_index,
++                      &msblk->meta_index[msblk->next_meta_index]);
++
++      meta = &msblk->meta_index[msblk->next_meta_index];
++      msblk->next_meta_index = (msblk->next_meta_index + 1) %
++                      SQUASHFS_META_NUMBER;
++
++      meta->inode_number = inode->i_ino;
++      meta->offset = offset;
++      meta->skip = skip;
++      meta->entries = 0;
++      meta->locked = 1;
++
++failed:
++      up(&msblk->meta_index_mutex);
++      return meta;
++}
++
++
++void release_meta_index(struct inode *inode, struct meta_index *meta)
++{
++      meta->locked = 0;
++}
++
++
++static int read_block_index(struct super_block *s, int blocks, char *block_list,
++              long long *start_block, int *offset)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      unsigned int *block_listp;
++      int block = 0;
++      
++      if (msblk->swap) {
++              char sblock_list[blocks << 2];
++
++              if (!squashfs_get_cached_block(s, sblock_list, *start_block,
++                              *offset, blocks << 2, start_block, offset)) {
++                      ERROR("Unable to read block list [%llx:%x]\n",
++                              *start_block, *offset);
++                      goto failure;
++              }
++              SQUASHFS_SWAP_INTS(((unsigned int *)block_list),
++                              ((unsigned int *)sblock_list), blocks);
++      } else
++              if (!squashfs_get_cached_block(s, block_list, *start_block,
++                              *offset, blocks << 2, start_block, offset)) {
++                      ERROR("Unable to read block list [%llx:%x]\n",
++                              *start_block, *offset);
++                      goto failure;
++              }
++
++      for (block_listp = (unsigned int *) block_list; blocks;
++                              block_listp++, blocks --)
++              block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp);
++
++      return block;
++
++failure:
++      return -1;
++}
++
++
++#define SIZE 256
++
++static inline int calculate_skip(int blocks) {
++      int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES);
++      return skip >= 7 ? 7 : skip + 1;
++}
++
++
++static int get_meta_index(struct inode *inode, int index,
++              long long *index_block, int *index_offset,
++              long long *data_block, char *block_list)
++{
++      struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      int skip = calculate_skip(i_size_read(inode) >> sblk->block_log);
++      int offset = 0;
++      struct meta_index *meta;
++      struct meta_entry *meta_entry;
++      long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start;
++      int cur_offset = SQUASHFS_I(inode)->offset;
++      long long cur_data_block = SQUASHFS_I(inode)->start_block;
++      int i;
++ 
++      index /= SQUASHFS_META_INDEXES * skip;
++
++      while ( offset < index ) {
++              meta = locate_meta_index(inode, index, offset + 1);
++
++              if (meta == NULL) {
++                      if ((meta = empty_meta_index(inode, offset + 1,
++                                                      skip)) == NULL)
++                              goto all_done;
++              } else {
++                      offset = index < meta->offset + meta->entries ? index :
++                              meta->offset + meta->entries - 1;
++                      meta_entry = &meta->meta_entry[offset - meta->offset];
++                      cur_index_block = meta_entry->index_block + sblk->inode_table_start;
++                      cur_offset = meta_entry->offset;
++                      cur_data_block = meta_entry->data_block;
++                      TRACE("get_meta_index: offset %d, meta->offset %d, "
++                              "meta->entries %d\n", offset, meta->offset,
++                              meta->entries);
++                      TRACE("get_meta_index: index_block 0x%llx, offset 0x%x"
++                              " data_block 0x%llx\n", cur_index_block,
++                              cur_offset, cur_data_block);
++              }
++
++              for (i = meta->offset + meta->entries; i <= index &&
++                              i < meta->offset + SQUASHFS_META_ENTRIES; i++) {
++                      int blocks = skip * SQUASHFS_META_INDEXES;
++
++                      while (blocks) {
++                              int block = blocks > (SIZE >> 2) ? (SIZE >> 2) :
++                                      blocks;
++                              int res = read_block_index(inode->i_sb, block,
++                                      block_list, &cur_index_block,
++                                      &cur_offset);
++
++                              if (res == -1)
++                                      goto failed;
++
++                              cur_data_block += res;
++                              blocks -= block;
++                      }
++
++                      meta_entry = &meta->meta_entry[i - meta->offset];
++                      meta_entry->index_block = cur_index_block - sblk->inode_table_start;
++                      meta_entry->offset = cur_offset;
++                      meta_entry->data_block = cur_data_block;
++                      meta->entries ++;
++                      offset ++;
++              }
++
++              TRACE("get_meta_index: meta->offset %d, meta->entries %d\n",
++                              meta->offset, meta->entries);
++
++              release_meta_index(inode, meta);
++      }
++
++all_done:
++      *index_block = cur_index_block;
++      *index_offset = cur_offset;
++      *data_block = cur_data_block;
++
++      return offset * SQUASHFS_META_INDEXES * skip;
++
++failed:
++      release_meta_index(inode, meta);
++      return -1;
++}
++
++
++static long long read_blocklist(struct inode *inode, int index,
++                              int readahead_blks, char *block_list,
++                              unsigned short **block_p, unsigned int *bsize)
++{
++      long long block_ptr;
++      int offset;
++      long long block;
++      int res = get_meta_index(inode, index, &block_ptr, &offset, &block,
++              block_list);
++
++      TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset"
++                     " 0x%x, block 0x%llx\n", res, index, block_ptr, offset,
++                     block);
++
++      if(res == -1)
++              goto failure;
++
++      index -= res;
++
++      while ( index ) {
++              int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index;
++              int res = read_block_index(inode->i_sb, blocks, block_list,
++                      &block_ptr, &offset);
++              if (res == -1)
++                      goto failure;
++              block += res;
++              index -= blocks;
++      }
++
++      if (read_block_index(inode->i_sb, 1, block_list,
++                      &block_ptr, &offset) == -1)
++              goto failure;
++      *bsize = *((unsigned int *) block_list);
++
++      return block;
++
++failure:
++      return 0;
++}
++
++
++static int squashfs_readpage(struct file *file, struct page *page)
++{
++      struct inode *inode = page->mapping->host;
++      struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      unsigned char *block_list;
++      long long block;
++      unsigned int bsize, i = 0, bytes = 0, byte_offset = 0;
++      int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT);
++      void *pageaddr;
++      struct squashfs_fragment_cache *fragment = NULL;
++      char *data_ptr = msblk->read_page;
++      
++      int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1;
++      int start_index = page->index & ~mask;
++      int end_index = start_index | mask;
++
++      TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
++                                      page->index,
++                                      SQUASHFS_I(inode)->start_block);
++
++      if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) {
++              ERROR("Failed to allocate block_list\n");
++              goto skip_read;
++      }
++
++      if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
++                                      PAGE_CACHE_SHIFT))
++              goto skip_read;
++
++      if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
++                                      || index < (i_size_read(inode) >>
++                                      sblk->block_log)) {
++              if ((block = (msblk->read_blocklist)(inode, index, 1,
++                                      block_list, NULL, &bsize)) == 0)
++                      goto skip_read;
++
++              down(&msblk->read_page_mutex);
++              
++              if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page,
++                                      block, bsize, NULL))) {
++                      ERROR("Unable to read page, block %llx, size %x\n", block,
++                                      bsize);
++                      up(&msblk->read_page_mutex);
++                      goto skip_read;
++              }
++      } else {
++              if ((fragment = get_cached_fragment(inode->i_sb,
++                                      SQUASHFS_I(inode)->
++                                      u.s1.fragment_start_block,
++                                      SQUASHFS_I(inode)->u.s1.fragment_size))
++                                      == NULL) {
++                      ERROR("Unable to read page, block %llx, size %x\n",
++                                      SQUASHFS_I(inode)->
++                                      u.s1.fragment_start_block,
++                                      (int) SQUASHFS_I(inode)->
++                                      u.s1.fragment_size);
++                      goto skip_read;
++              }
++              bytes = SQUASHFS_I(inode)->u.s1.fragment_offset +
++                                      (i_size_read(inode) & (sblk->block_size
++                                      - 1));
++              byte_offset = SQUASHFS_I(inode)->u.s1.fragment_offset;
++              data_ptr = fragment->data;
++      }
++
++      for (i = start_index; i <= end_index && byte_offset < bytes;
++                                      i++, byte_offset += PAGE_CACHE_SIZE) {
++              struct page *push_page;
++              int available_bytes = (bytes - byte_offset) > PAGE_CACHE_SIZE ?
++                                      PAGE_CACHE_SIZE : bytes - byte_offset;
++
++              TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n",
++                                      bytes, i, byte_offset, available_bytes);
++
++              if (i == page->index)  {
++                      pageaddr = kmap_atomic(page, KM_USER0);
++                      memcpy(pageaddr, data_ptr + byte_offset,
++                                      available_bytes);
++                      memset(pageaddr + available_bytes, 0,
++                                      PAGE_CACHE_SIZE - available_bytes);
++                      kunmap_atomic(pageaddr, KM_USER0);
++                      flush_dcache_page(page);
++                      SetPageUptodate(page);
++                      unlock_page(page);
++              } else if ((push_page =
++                              grab_cache_page_nowait(page->mapping, i))) {
++                      pageaddr = kmap_atomic(push_page, KM_USER0);
++
++                      memcpy(pageaddr, data_ptr + byte_offset,
++                                      available_bytes);
++                      memset(pageaddr + available_bytes, 0,
++                                      PAGE_CACHE_SIZE - available_bytes);
++                      kunmap_atomic(pageaddr, KM_USER0);
++                      flush_dcache_page(push_page);
++                      SetPageUptodate(push_page);
++                      unlock_page(push_page);
++                      page_cache_release(push_page);
++              }
++      }
++
++      if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
++                                      || index < (i_size_read(inode) >>
++                                      sblk->block_log))
++              up(&msblk->read_page_mutex);
++      else
++              release_cached_fragment(msblk, fragment);
++
++      kfree(block_list);
++      return 0;
++
++skip_read:
++      pageaddr = kmap_atomic(page, KM_USER0);
++      memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
++      kunmap_atomic(pageaddr, KM_USER0);
++      flush_dcache_page(page);
++      SetPageUptodate(page);
++      unlock_page(page);
++
++      kfree(block_list);
++      return 0;
++}
++
++
++static int squashfs_readpage4K(struct file *file, struct page *page)
++{
++      struct inode *inode = page->mapping->host;
++      struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      unsigned char *block_list;
++      long long block;
++      unsigned int bsize, bytes = 0;
++      void *pageaddr;
++      
++      TRACE("Entered squashfs_readpage4K, page index %lx, start block %llx\n",
++                                      page->index,
++                                      SQUASHFS_I(inode)->start_block);
++
++      if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
++                                      PAGE_CACHE_SHIFT)) {
++              pageaddr = kmap_atomic(page, KM_USER0);
++              block_list = NULL;
++              goto skip_read;
++      }
++
++      if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) {
++              ERROR("Failed to allocate block_list\n");
++              pageaddr = kmap_atomic(page, KM_USER0);
++              block_list = NULL;
++              goto skip_read;
++      }
++
++      if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
++                                      || page->index < (i_size_read(inode) >>
++                                      sblk->block_log)) {
++              block = (msblk->read_blocklist)(inode, page->index, 1,
++                                      block_list, NULL, &bsize);
++
++              down(&msblk->read_page_mutex);
++              bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block,
++                                      bsize, NULL);
++              pageaddr = kmap_atomic(page, KM_USER0);
++              if (bytes)
++                      memcpy(pageaddr, msblk->read_page, bytes);
++              else
++                      ERROR("Unable to read page, block %llx, size %x\n",
++                                      block, bsize);
++              up(&msblk->read_page_mutex);
++      } else {
++              struct squashfs_fragment_cache *fragment =
++                      get_cached_fragment(inode->i_sb,
++                                      SQUASHFS_I(inode)->
++                                      u.s1.fragment_start_block,
++                                      SQUASHFS_I(inode)-> u.s1.fragment_size);
++              pageaddr = kmap_atomic(page, KM_USER0);
++              if (fragment) {
++                      bytes = i_size_read(inode) & (sblk->block_size - 1);
++                      memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)->
++                                      u.s1.fragment_offset, bytes);
++                      release_cached_fragment(msblk, fragment);
++              } else
++                      ERROR("Unable to read page, block %llx, size %x\n",
++                                      SQUASHFS_I(inode)->
++                                      u.s1.fragment_start_block, (int)
++                                      SQUASHFS_I(inode)-> u.s1.fragment_size);
++      }
++
++skip_read:
++      memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
++      kunmap_atomic(pageaddr, KM_USER0);
++      flush_dcache_page(page);
++      SetPageUptodate(page);
++      unlock_page(page);
++
++      kfree(block_list);
++      return 0;
++}
++
++
++static int get_dir_index_using_offset(struct super_block *s, long long 
++                              *next_block, unsigned int *next_offset,
++                              long long index_start,
++                              unsigned int index_offset, int i_count,
++                              long long f_pos)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      int i, length = 0;
++      struct squashfs_dir_index index;
++
++      TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
++                                      i_count, (unsigned int) f_pos);
++
++      f_pos =- 3;
++      if (f_pos == 0)
++              goto finish;
++
++      for (i = 0; i < i_count; i++) {
++              if (msblk->swap) {
++                      struct squashfs_dir_index sindex;
++                      squashfs_get_cached_block(s, (char *) &sindex,
++                                      index_start, index_offset,
++                                      sizeof(sindex), &index_start,
++                                      &index_offset);
++                      SQUASHFS_SWAP_DIR_INDEX(&index, &sindex);
++              } else
++                      squashfs_get_cached_block(s, (char *) &index,
++                                      index_start, index_offset,
++                                      sizeof(index), &index_start,
++                                      &index_offset);
++
++              if (index.index > f_pos)
++                      break;
++
++              squashfs_get_cached_block(s, NULL, index_start, index_offset,
++                                      index.size + 1, &index_start,
++                                      &index_offset);
++
++              length = index.index;
++              *next_block = index.start_block + sblk->directory_table_start;
++      }
++
++      *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
++
++finish:
++      return length + 3;
++}
++
++
++static int get_dir_index_using_name(struct super_block *s, long long
++                              *next_block, unsigned int *next_offset,
++                              long long index_start,
++                              unsigned int index_offset, int i_count,
++                              const char *name, int size)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      int i, length = 0;
++      struct squashfs_dir_index *index;
++      char *str;
++
++      TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
++
++      if (!(str = kmalloc(sizeof(struct squashfs_dir_index) +
++              (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) {
++              ERROR("Failed to allocate squashfs_dir_index\n");
++              goto failure;
++      }
++
++      index = (struct squashfs_dir_index *) (str + SQUASHFS_NAME_LEN + 1);
++      strncpy(str, name, size);
++      str[size] = '\0';
++
++      for (i = 0; i < i_count; i++) {
++              if (msblk->swap) {
++                      struct squashfs_dir_index sindex;
++                      squashfs_get_cached_block(s, (char *) &sindex,
++                                      index_start, index_offset,
++                                      sizeof(sindex), &index_start,
++                                      &index_offset);
++                      SQUASHFS_SWAP_DIR_INDEX(index, &sindex);
++              } else
++                      squashfs_get_cached_block(s, (char *) index,
++                                      index_start, index_offset,
++                                      sizeof(struct squashfs_dir_index),
++                                      &index_start, &index_offset);
++
++              squashfs_get_cached_block(s, index->name, index_start,
++                                      index_offset, index->size + 1,
++                                      &index_start, &index_offset);
++
++              index->name[index->size + 1] = '\0';
++
++              if (strcmp(index->name, str) > 0)
++                      break;
++
++              length = index->index;
++              *next_block = index->start_block + sblk->directory_table_start;
++      }
++
++      *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
++      kfree(str);
++failure:
++      return length + 3;
++}
++
++              
++static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
++{
++      struct inode *i = file->f_dentry->d_inode;
++      struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      long long next_block = SQUASHFS_I(i)->start_block +
++              sblk->directory_table_start;
++      int next_offset = SQUASHFS_I(i)->offset, length = 0,
++              dir_count;
++      struct squashfs_dir_header dirh;
++      struct squashfs_dir_entry *dire;
++
++      TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset);
++
++      if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
++              SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
++              ERROR("Failed to allocate squashfs_dir_entry\n");
++              goto finish;
++      }
++
++      while(file->f_pos < 3) {
++              char *name;
++              int size, i_ino;
++
++              if(file->f_pos == 0) {
++                      name = ".";
++                      size = 1;
++                      i_ino = i->i_ino;
++              } else {
++                      name = "..";
++                      size = 2;
++                      i_ino = SQUASHFS_I(i)->u.s2.parent_inode;
++              }
++              TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n",
++                              (unsigned int) dirent, name, size, (int)
++                              file->f_pos, i_ino,
++                              squashfs_filetype_table[1]);
++
++              if (filldir(dirent, name, size,
++                              file->f_pos, i_ino,
++                              squashfs_filetype_table[1]) < 0) {
++                              TRACE("Filldir returned less than 0\n");
++                              goto finish;
++              }
++              file->f_pos += size;
++      }
++
++      length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
++                              SQUASHFS_I(i)->u.s2.directory_index_start,
++                              SQUASHFS_I(i)->u.s2.directory_index_offset,
++                              SQUASHFS_I(i)->u.s2.directory_index_count,
++                              file->f_pos);
++
++      while (length < i_size_read(i)) {
++              /* read directory header */
++              if (msblk->swap) {
++                      struct squashfs_dir_header sdirh;
++                      
++                      if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
++                                      next_block, next_offset, sizeof(sdirh),
++                                      &next_block, &next_offset))
++                              goto failed_read;
++
++                      length += sizeof(sdirh);
++                      SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
++              } else {
++                      if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
++                                      next_block, next_offset, sizeof(dirh),
++                                      &next_block, &next_offset))
++                              goto failed_read;
++
++                      length += sizeof(dirh);
++              }
++
++              dir_count = dirh.count + 1;
++              while (dir_count--) {
++                      if (msblk->swap) {
++                              struct squashfs_dir_entry sdire;
++                              if (!squashfs_get_cached_block(i->i_sb, (char *)
++                                              &sdire, next_block, next_offset,
++                                              sizeof(sdire), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              
++                              length += sizeof(sdire);
++                              SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
++                      } else {
++                              if (!squashfs_get_cached_block(i->i_sb, (char *)
++                                              dire, next_block, next_offset,
++                                              sizeof(*dire), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                              length += sizeof(*dire);
++                      }
++
++                      if (!squashfs_get_cached_block(i->i_sb, dire->name,
++                                              next_block, next_offset,
++                                              dire->size + 1, &next_block,
++                                              &next_offset))
++                              goto failed_read;
++
++                      length += dire->size + 1;
++
++                      if (file->f_pos >= length)
++                              continue;
++
++                      dire->name[dire->size + 1] = '\0';
++
++                      TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n",
++                                      (unsigned int) dirent, dire->name,
++                                      dire->size + 1, (int) file->f_pos,
++                                      dirh.start_block, dire->offset,
++                                      dirh.inode_number + dire->inode_number,
++                                      squashfs_filetype_table[dire->type]);
++
++                      if (filldir(dirent, dire->name, dire->size + 1,
++                                      file->f_pos,
++                                      dirh.inode_number + dire->inode_number,
++                                      squashfs_filetype_table[dire->type])
++                                      < 0) {
++                              TRACE("Filldir returned less than 0\n");
++                              goto finish;
++                      }
++                      file->f_pos = length;
++              }
++      }
++
++finish:
++      kfree(dire);
++      return 0;
++
++failed_read:
++      ERROR("Unable to read directory block [%llx:%x]\n", next_block,
++              next_offset);
++      return 0;
++}
++
++
++static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry,
++                              struct nameidata *nd)
++{
++      const unsigned char *name = dentry->d_name.name;
++      int len = dentry->d_name.len;
++      struct inode *inode = NULL;
++      struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      long long next_block = SQUASHFS_I(i)->start_block +
++                              sblk->directory_table_start;
++      int next_offset = SQUASHFS_I(i)->offset, length = 0,
++                              dir_count;
++      struct squashfs_dir_header dirh;
++      struct squashfs_dir_entry *dire;
++
++      TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
++
++      if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
++              SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
++              ERROR("Failed to allocate squashfs_dir_entry\n");
++              goto exit_loop;
++      }
++
++      if (len > SQUASHFS_NAME_LEN)
++              goto exit_loop;
++
++      length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
++                              SQUASHFS_I(i)->u.s2.directory_index_start,
++                              SQUASHFS_I(i)->u.s2.directory_index_offset,
++                              SQUASHFS_I(i)->u.s2.directory_index_count, name,
++                              len);
++
++      while (length < i_size_read(i)) {
++              /* read directory header */
++              if (msblk->swap) {
++                      struct squashfs_dir_header sdirh;
++                      if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
++                                      next_block, next_offset, sizeof(sdirh),
++                                      &next_block, &next_offset))
++                              goto failed_read;
++
++                      length += sizeof(sdirh);
++                      SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
++              } else {
++                      if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
++                                      next_block, next_offset, sizeof(dirh),
++                                      &next_block, &next_offset))
++                              goto failed_read;
++
++                      length += sizeof(dirh);
++              }
++
++              dir_count = dirh.count + 1;
++              while (dir_count--) {
++                      if (msblk->swap) {
++                              struct squashfs_dir_entry sdire;
++                              if (!squashfs_get_cached_block(i->i_sb, (char *)
++                                              &sdire, next_block,next_offset,
++                                              sizeof(sdire), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              
++                              length += sizeof(sdire);
++                              SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
++                      } else {
++                              if (!squashfs_get_cached_block(i->i_sb, (char *)
++                                              dire, next_block,next_offset,
++                                              sizeof(*dire), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                              length += sizeof(*dire);
++                      }
++
++                      if (!squashfs_get_cached_block(i->i_sb, dire->name,
++                                      next_block, next_offset, dire->size + 1,
++                                      &next_block, &next_offset))
++                              goto failed_read;
++
++                      length += dire->size + 1;
++
++                      if (name[0] < dire->name[0])
++                              goto exit_loop;
++
++                      if ((len == dire->size + 1) && !strncmp(name,
++                                              dire->name, len)) {
++                              squashfs_inode_t ino =
++                                      SQUASHFS_MKINODE(dirh.start_block,
++                                      dire->offset);
++
++                              TRACE("calling squashfs_iget for directory "
++                                      "entry %s, inode %x:%x, %d\n", name,
++                                      dirh.start_block, dire->offset,
++                                      dirh.inode_number + dire->inode_number);
++
++                              inode = (msblk->iget)(i->i_sb, ino);
++
++                              goto exit_loop;
++                      }
++              }
++      }
++
++exit_loop:
++      kfree(dire);
++      d_add(dentry, inode);
++      return ERR_PTR(0);
++
++failed_read:
++      ERROR("Unable to read directory block [%llx:%x]\n", next_block,
++              next_offset);
++      goto exit_loop;
++}
++
++
++static void squashfs_put_super(struct super_block *s)
++{
++      int i;
++
++      if (s->s_fs_info) {
++              struct squashfs_sb_info *sbi = s->s_fs_info;
++              if (sbi->block_cache)
++                      for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
++                              if (sbi->block_cache[i].block !=
++                                                      SQUASHFS_INVALID_BLK)
++                                      kfree(sbi->block_cache[i].data);
++              if (sbi->fragment)
++                      for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) 
++                              SQUASHFS_FREE(sbi->fragment[i].data);
++              kfree(sbi->fragment);
++              kfree(sbi->block_cache);
++              kfree(sbi->read_data);
++              kfree(sbi->read_page);
++              kfree(sbi->uid);
++              kfree(sbi->fragment_index);
++              kfree(sbi->fragment_index_2);
++              kfree(sbi->meta_index);
++              vfree(sbi->stream.workspace);
++              kfree(s->s_fs_info);
++              s->s_fs_info = NULL;
++      }
++}
++
++
++static int squashfs_get_sb(struct file_system_type *fs_type, int flags,
++                              const char *dev_name, void *data,
++                              struct vfsmount *mnt)
++{
++      return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super,
++                              mnt);
++}
++
++
++static int __init init_squashfs_fs(void)
++{
++      int err = init_inodecache();
++      if (err)
++              goto out;
++
++      printk(KERN_INFO "squashfs: version 3.1 (2006/08/19) "
++              "Phillip Lougher\n");
++
++      if ((err = register_filesystem(&squashfs_fs_type)))
++              destroy_inodecache();
++
++out:
++      return err;
++}
++
++
++static void __exit exit_squashfs_fs(void)
++{
++      unregister_filesystem(&squashfs_fs_type);
++      destroy_inodecache();
++}
++
++
++static kmem_cache_t * squashfs_inode_cachep;
++
++
++static struct inode *squashfs_alloc_inode(struct super_block *sb)
++{
++      struct squashfs_inode_info *ei;
++      ei = kmem_cache_alloc(squashfs_inode_cachep, SLAB_KERNEL);
++      if (!ei)
++              return NULL;
++      return &ei->vfs_inode;
++}
++
++
++static void squashfs_destroy_inode(struct inode *inode)
++{
++      kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode));
++}
++
++
++static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
++{
++      struct squashfs_inode_info *ei = foo;
++
++      if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
++                                                      SLAB_CTOR_CONSTRUCTOR)
++              inode_init_once(&ei->vfs_inode);
++}
++ 
++
++static int __init init_inodecache(void)
++{
++      squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache",
++           sizeof(struct squashfs_inode_info),
++           0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
++           init_once, NULL);
++      if (squashfs_inode_cachep == NULL)
++              return -ENOMEM;
++      return 0;
++}
++
++
++static void destroy_inodecache(void)
++{
++      if (kmem_cache_destroy(squashfs_inode_cachep))
++              printk(KERN_INFO "squashfs_inode_cache: not all structures "
++                      "were freed\n");
++}
++
++
++module_init(init_squashfs_fs);
++module_exit(exit_squashfs_fs);
++MODULE_DESCRIPTION("squashfs 3.1, a compressed read-only filesystem");
++MODULE_AUTHOR("Phillip Lougher <phillip@lougher.org.uk>");
++MODULE_LICENSE("GPL");
+diff --new-file -urp linux-2.6.18/fs/squashfs/Makefile linux-2.6.18-squashfs3.1/fs/squashfs/Makefile
+--- linux-2.6.18/fs/squashfs/Makefile  1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-squashfs3.1/fs/squashfs/Makefile      2006-08-21 00:13:12.000000000 +0100
+@@ -0,0 +1,7 @@
++#
++# Makefile for the linux squashfs routines.
++#
++
++obj-$(CONFIG_SQUASHFS) += squashfs.o
++squashfs-y += inode.o
++squashfs-y += squashfs2_0.o
+diff --new-file -urp linux-2.6.18/fs/squashfs/squashfs2_0.c linux-2.6.18-squashfs3.1/fs/squashfs/squashfs2_0.c
+--- linux-2.6.18/fs/squashfs/squashfs2_0.c     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-squashfs3.1/fs/squashfs/squashfs2_0.c 2006-08-21 00:14:55.000000000 +0100
+@@ -0,0 +1,779 @@
++/*
++ * Squashfs - a compressed read only filesystem for Linux
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006
++ * Phillip Lougher <phillip@lougher.org.uk>
++ *
++ * 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,
++ * or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * squashfs2_0.c
++ */
++
++#include <linux/types.h>
++#include <linux/squashfs_fs.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/zlib.h>
++#include <linux/fs.h>
++#include <linux/smp_lock.h>
++#include <linux/slab.h>
++#include <linux/squashfs_fs_sb.h>
++#include <linux/squashfs_fs_i.h>
++#include <linux/buffer_head.h>
++#include <linux/vfs.h>
++#include <linux/init.h>
++#include <linux/dcache.h>
++#include <linux/wait.h>
++#include <linux/zlib.h>
++#include <linux/blkdev.h>
++#include <linux/vmalloc.h>
++#include <asm/uaccess.h>
++#include <asm/semaphore.h>
++
++#include "squashfs.h"
++static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir);
++static struct dentry *squashfs_lookup_2(struct inode *, struct dentry *,
++                              struct nameidata *);
++
++static struct file_operations squashfs_dir_ops_2 = {
++      .read = generic_read_dir,
++      .readdir = squashfs_readdir_2
++};
++
++static struct inode_operations squashfs_dir_inode_ops_2 = {
++      .lookup = squashfs_lookup_2
++};
++
++static unsigned char squashfs_filetype_table[] = {
++      DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
++};
++
++static int read_fragment_index_table_2(struct super_block *s)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++
++      if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2
++                                      (sblk->fragments), GFP_KERNEL))) {
++              ERROR("Failed to allocate uid/gid table\n");
++              return 0;
++      }
++   
++      if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) &&
++                                      !squashfs_read_data(s, (char *)
++                                      msblk->fragment_index_2,
++                                      sblk->fragment_table_start,
++                                      SQUASHFS_FRAGMENT_INDEX_BYTES_2
++                                      (sblk->fragments) |
++                                      SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
++              ERROR("unable to read fragment index table\n");
++              return 0;
++      }
++
++      if (msblk->swap) {
++              int i;
++              unsigned int fragment;
++
++              for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments);
++                                                                      i++) {
++                      SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment),
++                                              &msblk->fragment_index_2[i], 1);
++                      msblk->fragment_index_2[i] = fragment;
++              }
++      }
++
++      return 1;
++}
++
++
++static int get_fragment_location_2(struct super_block *s, unsigned int fragment,
++                              long long *fragment_start_block,
++                              unsigned int *fragment_size)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      long long start_block =
++              msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)];
++      int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment);
++      struct squashfs_fragment_entry_2 fragment_entry;
++
++      if (msblk->swap) {
++              struct squashfs_fragment_entry_2 sfragment_entry;
++
++              if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
++                                      start_block, offset,
++                                      sizeof(sfragment_entry), &start_block,
++                                      &offset))
++                      goto out;
++              SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry);
++      } else
++              if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
++                                      start_block, offset,
++                                      sizeof(fragment_entry), &start_block,
++                                      &offset))
++                      goto out;
++
++      *fragment_start_block = fragment_entry.start_block;
++      *fragment_size = fragment_entry.size;
++
++      return 1;
++
++out:
++      return 0;
++}
++
++
++static struct inode *squashfs_new_inode(struct super_block *s,
++              struct squashfs_base_inode_header_2 *inodeb, unsigned int ino)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      struct inode *i = new_inode(s);
++
++      if (i) {
++              i->i_ino = ino;
++              i->i_mtime.tv_sec = sblk->mkfs_time;
++              i->i_atime.tv_sec = sblk->mkfs_time;
++              i->i_ctime.tv_sec = sblk->mkfs_time;
++              i->i_uid = msblk->uid[inodeb->uid];
++              i->i_mode = inodeb->mode;
++              i->i_nlink = 1;
++              i->i_size = 0;
++              if (inodeb->guid == SQUASHFS_GUIDS)
++                      i->i_gid = i->i_uid;
++              else
++                      i->i_gid = msblk->guid[inodeb->guid];
++      }
++
++      return i;
++}
++
++
++static struct inode *squashfs_iget_2(struct super_block *s, squashfs_inode_t inode)
++{
++      struct inode *i;
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      unsigned int block = SQUASHFS_INODE_BLK(inode) +
++              sblk->inode_table_start;
++      unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
++      unsigned int ino = SQUASHFS_MK_VFS_INODE(block
++              - sblk->inode_table_start, offset);
++      long long next_block;
++      unsigned int next_offset;
++      union squashfs_inode_header_2 id, sid;
++      struct squashfs_base_inode_header_2 *inodeb = &id.base,
++                                        *sinodeb = &sid.base;
++
++      TRACE("Entered squashfs_iget\n");
++
++      if (msblk->swap) {
++              if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
++                                      offset, sizeof(*sinodeb), &next_block,
++                                      &next_offset))
++                      goto failed_read;
++              SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb,
++                                      sizeof(*sinodeb));
++      } else
++              if (!squashfs_get_cached_block(s, (char *) inodeb, block,
++                                      offset, sizeof(*inodeb), &next_block,
++                                      &next_offset))
++                      goto failed_read;
++
++      switch(inodeb->inode_type) {
++              case SQUASHFS_FILE_TYPE: {
++                      struct squashfs_reg_inode_header_2 *inodep = &id.reg;
++                      struct squashfs_reg_inode_header_2 *sinodep = &sid.reg;
++                      long long frag_blk;
++                      unsigned int frag_size;
++                              
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep);
++                      } else
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      frag_blk = SQUASHFS_INVALID_BLK;
++                      if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
++                                      !get_fragment_location_2(s,
++                                      inodep->fragment, &frag_blk, &frag_size))
++                              goto failed_read;
++                              
++                      if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
++                              goto failed_read1;
++
++                      i->i_size = inodep->file_size;
++                      i->i_fop = &generic_ro_fops;
++                      i->i_mode |= S_IFREG;
++                      i->i_mtime.tv_sec = inodep->mtime;
++                      i->i_atime.tv_sec = inodep->mtime;
++                      i->i_ctime.tv_sec = inodep->mtime;
++                      i->i_blocks = ((i->i_size - 1) >> 9) + 1;
++                      i->i_blksize = PAGE_CACHE_SIZE;
++                      SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
++                      SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
++                      SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
++                      SQUASHFS_I(i)->start_block = inodep->start_block;
++                      SQUASHFS_I(i)->u.s1.block_list_start = next_block;
++                      SQUASHFS_I(i)->offset = next_offset;
++                      if (sblk->block_size > 4096)
++                              i->i_data.a_ops = &squashfs_aops;
++                      else
++                              i->i_data.a_ops = &squashfs_aops_4K;
++
++                      TRACE("File inode %x:%x, start_block %x, "
++                                      "block_list_start %llx, offset %x\n",
++                                      SQUASHFS_INODE_BLK(inode), offset,
++                                      inodep->start_block, next_block,
++                                      next_offset);
++                      break;
++              }
++              case SQUASHFS_DIR_TYPE: {
++                      struct squashfs_dir_inode_header_2 *inodep = &id.dir;
++                      struct squashfs_dir_inode_header_2 *sinodep = &sid.dir;
++
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep);
++                      } else
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
++                              goto failed_read1;
++
++                      i->i_size = inodep->file_size;
++                      i->i_op = &squashfs_dir_inode_ops_2;
++                      i->i_fop = &squashfs_dir_ops_2;
++                      i->i_mode |= S_IFDIR;
++                      i->i_mtime.tv_sec = inodep->mtime;
++                      i->i_atime.tv_sec = inodep->mtime;
++                      i->i_ctime.tv_sec = inodep->mtime;
++                      SQUASHFS_I(i)->start_block = inodep->start_block;
++                      SQUASHFS_I(i)->offset = inodep->offset;
++                      SQUASHFS_I(i)->u.s2.directory_index_count = 0;
++                      SQUASHFS_I(i)->u.s2.parent_inode = 0;
++
++                      TRACE("Directory inode %x:%x, start_block %x, offset "
++                                      "%x\n", SQUASHFS_INODE_BLK(inode),
++                                      offset, inodep->start_block,
++                                      inodep->offset);
++                      break;
++              }
++              case SQUASHFS_LDIR_TYPE: {
++                      struct squashfs_ldir_inode_header_2 *inodep = &id.ldir;
++                      struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir;
++
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep,
++                                              sinodep);
++                      } else
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
++                              goto failed_read1;
++
++                      i->i_size = inodep->file_size;
++                      i->i_op = &squashfs_dir_inode_ops_2;
++                      i->i_fop = &squashfs_dir_ops_2;
++                      i->i_mode |= S_IFDIR;
++                      i->i_mtime.tv_sec = inodep->mtime;
++                      i->i_atime.tv_sec = inodep->mtime;
++                      i->i_ctime.tv_sec = inodep->mtime;
++                      SQUASHFS_I(i)->start_block = inodep->start_block;
++                      SQUASHFS_I(i)->offset = inodep->offset;
++                      SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
++                      SQUASHFS_I(i)->u.s2.directory_index_offset =
++                                                              next_offset;
++                      SQUASHFS_I(i)->u.s2.directory_index_count =
++                                                              inodep->i_count;
++                      SQUASHFS_I(i)->u.s2.parent_inode = 0;
++
++                      TRACE("Long directory inode %x:%x, start_block %x, "
++                                      "offset %x\n",
++                                      SQUASHFS_INODE_BLK(inode), offset,
++                                      inodep->start_block, inodep->offset);
++                      break;
++              }
++              case SQUASHFS_SYMLINK_TYPE: {
++                      struct squashfs_symlink_inode_header_2 *inodep =
++                                                              &id.symlink;
++                      struct squashfs_symlink_inode_header_2 *sinodep =
++                                                              &sid.symlink;
++      
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep,
++                                                              sinodep);
++                      } else
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
++                              goto failed_read1;
++
++                      i->i_size = inodep->symlink_size;
++                      i->i_op = &page_symlink_inode_operations;
++                      i->i_data.a_ops = &squashfs_symlink_aops;
++                      i->i_mode |= S_IFLNK;
++                      SQUASHFS_I(i)->start_block = next_block;
++                      SQUASHFS_I(i)->offset = next_offset;
++
++                      TRACE("Symbolic link inode %x:%x, start_block %llx, "
++                                      "offset %x\n",
++                                      SQUASHFS_INODE_BLK(inode), offset,
++                                      next_block, next_offset);
++                      break;
++               }
++               case SQUASHFS_BLKDEV_TYPE:
++               case SQUASHFS_CHRDEV_TYPE: {
++                      struct squashfs_dev_inode_header_2 *inodep = &id.dev;
++                      struct squashfs_dev_inode_header_2 *sinodep = &sid.dev;
++
++                      if (msblk->swap) {
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              sinodep, block, offset,
++                                              sizeof(*sinodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep);
++                      } else  
++                              if (!squashfs_get_cached_block(s, (char *)
++                                              inodep, block, offset,
++                                              sizeof(*inodep), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                      if ((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
++                              goto failed_read1;
++
++                      i->i_mode |= (inodeb->inode_type ==
++                                      SQUASHFS_CHRDEV_TYPE) ?  S_IFCHR :
++                                      S_IFBLK;
++                      init_special_inode(i, i->i_mode,
++                                      old_decode_dev(inodep->rdev));
++
++                      TRACE("Device inode %x:%x, rdev %x\n",
++                                      SQUASHFS_INODE_BLK(inode), offset,
++                                      inodep->rdev);
++                      break;
++               }
++               case SQUASHFS_FIFO_TYPE:
++               case SQUASHFS_SOCKET_TYPE: {
++                      if ((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
++                              goto failed_read1;
++
++                      i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
++                                                      ? S_IFIFO : S_IFSOCK;
++                      init_special_inode(i, i->i_mode, 0);
++                      break;
++               }
++               default:
++                      ERROR("Unknown inode type %d in squashfs_iget!\n",
++                                      inodeb->inode_type);
++                      goto failed_read1;
++      }
++      
++      insert_inode_hash(i);
++      return i;
++
++failed_read:
++      ERROR("Unable to read inode [%x:%x]\n", block, offset);
++
++failed_read1:
++      return NULL;
++}
++
++
++static int get_dir_index_using_offset(struct super_block *s, long long 
++                              *next_block, unsigned int *next_offset,
++                              long long index_start,
++                              unsigned int index_offset, int i_count,
++                              long long f_pos)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      int i, length = 0;
++      struct squashfs_dir_index_2 index;
++
++      TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
++                                      i_count, (unsigned int) f_pos);
++
++      if (f_pos == 0)
++              goto finish;
++
++      for (i = 0; i < i_count; i++) {
++              if (msblk->swap) {
++                      struct squashfs_dir_index_2 sindex;
++                      squashfs_get_cached_block(s, (char *) &sindex,
++                                      index_start, index_offset,
++                                      sizeof(sindex), &index_start,
++                                      &index_offset);
++                      SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex);
++              } else
++                      squashfs_get_cached_block(s, (char *) &index,
++                                      index_start, index_offset,
++                                      sizeof(index), &index_start,
++                                      &index_offset);
++
++              if (index.index > f_pos)
++                      break;
++
++              squashfs_get_cached_block(s, NULL, index_start, index_offset,
++                                      index.size + 1, &index_start,
++                                      &index_offset);
++
++              length = index.index;
++              *next_block = index.start_block + sblk->directory_table_start;
++      }
++
++      *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
++
++finish:
++      return length;
++}
++
++
++static int get_dir_index_using_name(struct super_block *s, long long
++                              *next_block, unsigned int *next_offset,
++                              long long index_start,
++                              unsigned int index_offset, int i_count,
++                              const char *name, int size)
++{
++      struct squashfs_sb_info *msblk = s->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      int i, length = 0;
++      struct squashfs_dir_index_2 *index;
++      char *str;
++
++      TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
++
++      if (!(str = kmalloc(sizeof(struct squashfs_dir_index) +
++              (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) {
++              ERROR("Failed to allocate squashfs_dir_index\n");
++              goto failure;
++      }
++
++      index = (struct squashfs_dir_index_2 *) (str + SQUASHFS_NAME_LEN + 1);
++      strncpy(str, name, size);
++      str[size] = '\0';
++
++      for (i = 0; i < i_count; i++) {
++              if (msblk->swap) {
++                      struct squashfs_dir_index_2 sindex;
++                      squashfs_get_cached_block(s, (char *) &sindex,
++                                      index_start, index_offset,
++                                      sizeof(sindex), &index_start,
++                                      &index_offset);
++                      SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex);
++              } else
++                      squashfs_get_cached_block(s, (char *) index,
++                                      index_start, index_offset,
++                                      sizeof(struct squashfs_dir_index_2),
++                                      &index_start, &index_offset);
++
++              squashfs_get_cached_block(s, index->name, index_start,
++                                      index_offset, index->size + 1,
++                                      &index_start, &index_offset);
++
++              index->name[index->size + 1] = '\0';
++
++              if (strcmp(index->name, str) > 0)
++                      break;
++
++              length = index->index;
++              *next_block = index->start_block + sblk->directory_table_start;
++      }
++
++      *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
++      kfree(str);
++failure:
++      return length;
++}
++
++              
++static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir)
++{
++      struct inode *i = file->f_dentry->d_inode;
++      struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      long long next_block = SQUASHFS_I(i)->start_block +
++              sblk->directory_table_start;
++      int next_offset = SQUASHFS_I(i)->offset, length = 0,
++              dir_count;
++      struct squashfs_dir_header_2 dirh;
++      struct squashfs_dir_entry_2 *dire;
++
++      TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset);
++
++      if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
++              SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
++              ERROR("Failed to allocate squashfs_dir_entry\n");
++              goto finish;
++      }
++
++      length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
++                              SQUASHFS_I(i)->u.s2.directory_index_start,
++                              SQUASHFS_I(i)->u.s2.directory_index_offset,
++                              SQUASHFS_I(i)->u.s2.directory_index_count,
++                              file->f_pos);
++
++      while (length < i_size_read(i)) {
++              /* read directory header */
++              if (msblk->swap) {
++                      struct squashfs_dir_header_2 sdirh;
++                      
++                      if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
++                                      next_block, next_offset, sizeof(sdirh),
++                                      &next_block, &next_offset))
++                              goto failed_read;
++
++                      length += sizeof(sdirh);
++                      SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
++              } else {
++                      if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
++                                      next_block, next_offset, sizeof(dirh),
++                                      &next_block, &next_offset))
++                              goto failed_read;
++
++                      length += sizeof(dirh);
++              }
++
++              dir_count = dirh.count + 1;
++              while (dir_count--) {
++                      if (msblk->swap) {
++                              struct squashfs_dir_entry_2 sdire;
++                              if (!squashfs_get_cached_block(i->i_sb, (char *)
++                                              &sdire, next_block, next_offset,
++                                              sizeof(sdire), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              
++                              length += sizeof(sdire);
++                              SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
++                      } else {
++                              if (!squashfs_get_cached_block(i->i_sb, (char *)
++                                              dire, next_block, next_offset,
++                                              sizeof(*dire), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                              length += sizeof(*dire);
++                      }
++
++                      if (!squashfs_get_cached_block(i->i_sb, dire->name,
++                                              next_block, next_offset,
++                                              dire->size + 1, &next_block,
++                                              &next_offset))
++                              goto failed_read;
++
++                      length += dire->size + 1;
++
++                      if (file->f_pos >= length)
++                              continue;
++
++                      dire->name[dire->size + 1] = '\0';
++
++                      TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n",
++                                      (unsigned int) dirent, dire->name,
++                                      dire->size + 1, (int) file->f_pos,
++                                      dirh.start_block, dire->offset,
++                                      squashfs_filetype_table[dire->type]);
++
++                      if (filldir(dirent, dire->name, dire->size + 1,
++                                      file->f_pos, SQUASHFS_MK_VFS_INODE(
++                                      dirh.start_block, dire->offset),
++                                      squashfs_filetype_table[dire->type])
++                                      < 0) {
++                              TRACE("Filldir returned less than 0\n");
++                              goto finish;
++                      }
++                      file->f_pos = length;
++              }
++      }
++
++finish:
++      kfree(dire);
++      return 0;
++
++failed_read:
++      ERROR("Unable to read directory block [%llx:%x]\n", next_block,
++              next_offset);
++      kfree(dire);
++      return 0;
++}
++
++
++static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry,
++                              struct nameidata *nd)
++{
++      const unsigned char *name = dentry->d_name.name;
++      int len = dentry->d_name.len;
++      struct inode *inode = NULL;
++      struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
++      struct squashfs_super_block *sblk = &msblk->sblk;
++      long long next_block = SQUASHFS_I(i)->start_block +
++                              sblk->directory_table_start;
++      int next_offset = SQUASHFS_I(i)->offset, length = 0,
++                              dir_count;
++      struct squashfs_dir_header_2 dirh;
++      struct squashfs_dir_entry_2 *dire;
++      int sorted = sblk->s_major == 2 && sblk->s_minor >= 1;
++
++      TRACE("Entered squashfs_lookup_2 [%llx:%x]\n", next_block, next_offset);
++
++      if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
++              SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
++              ERROR("Failed to allocate squashfs_dir_entry\n");
++              goto exit_loop;
++      }
++
++      if (len > SQUASHFS_NAME_LEN)
++              goto exit_loop;
++
++      length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
++                              SQUASHFS_I(i)->u.s2.directory_index_start,
++                              SQUASHFS_I(i)->u.s2.directory_index_offset,
++                              SQUASHFS_I(i)->u.s2.directory_index_count, name,
++                              len);
++
++      while (length < i_size_read(i)) {
++              /* read directory header */
++              if (msblk->swap) {
++                      struct squashfs_dir_header_2 sdirh;
++                      if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
++                                      next_block, next_offset, sizeof(sdirh),
++                                      &next_block, &next_offset))
++                              goto failed_read;
++
++                      length += sizeof(sdirh);
++                      SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
++              } else {
++                      if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
++                                      next_block, next_offset, sizeof(dirh),
++                                      &next_block, &next_offset))
++                              goto failed_read;
++
++                      length += sizeof(dirh);
++              }
++
++              dir_count = dirh.count + 1;
++              while (dir_count--) {
++                      if (msblk->swap) {
++                              struct squashfs_dir_entry_2 sdire;
++                              if (!squashfs_get_cached_block(i->i_sb, (char *)
++                                              &sdire, next_block,next_offset,
++                                              sizeof(sdire), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++                              
++                              length += sizeof(sdire);
++                              SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
++                      } else {
++                              if (!squashfs_get_cached_block(i->i_sb, (char *)
++                                              dire, next_block,next_offset,
++                                              sizeof(*dire), &next_block,
++                                              &next_offset))
++                                      goto failed_read;
++
++                              length += sizeof(*dire);
++                      }
++
++                      if (!squashfs_get_cached_block(i->i_sb, dire->name,
++                                      next_block, next_offset, dire->size + 1,
++                                      &next_block, &next_offset))
++                              goto failed_read;
++
++                      length += dire->size + 1;
++
++                      if (sorted && name[0] < dire->name[0])
++                              goto exit_loop;
++
++                      if ((len == dire->size + 1) && !strncmp(name,
++                                              dire->name, len)) {
++                              squashfs_inode_t ino =
++                                      SQUASHFS_MKINODE(dirh.start_block,
++                                      dire->offset);
++
++                              TRACE("calling squashfs_iget for directory "
++                                      "entry %s, inode %x:%x, %lld\n", name,
++                                      dirh.start_block, dire->offset, ino);
++
++                              inode = (msblk->iget)(i->i_sb, ino);
++
++                              goto exit_loop;
++                      }
++              }
++      }
++
++exit_loop:
++      kfree(dire);
++      d_add(dentry, inode);
++      return ERR_PTR(0);
++
++failed_read:
++      ERROR("Unable to read directory block [%llx:%x]\n", next_block,
++              next_offset);
++      goto exit_loop;
++}
++
++
++int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
++{
++      struct squashfs_super_block *sblk = &msblk->sblk;
++
++      msblk->iget = squashfs_iget_2;
++      msblk->read_fragment_index_table = read_fragment_index_table_2;
++
++      sblk->bytes_used = sblk->bytes_used_2;
++      sblk->uid_start = sblk->uid_start_2;
++      sblk->guid_start = sblk->guid_start_2;
++      sblk->inode_table_start = sblk->inode_table_start_2;
++      sblk->directory_table_start = sblk->directory_table_start_2;
++      sblk->fragment_table_start = sblk->fragment_table_start_2;
++
++      return 1;
++}
+diff --new-file -urp linux-2.6.18/fs/squashfs/squashfs.h linux-2.6.18-squashfs3.1/fs/squashfs/squashfs.h
+--- linux-2.6.18/fs/squashfs/squashfs.h        1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-squashfs3.1/fs/squashfs/squashfs.h    2006-08-21 00:13:12.000000000 +0100
+@@ -0,0 +1,86 @@
++/*
++ * Squashfs - a compressed read only filesystem for Linux
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006
++ * Phillip Lougher <phillip@lougher.org.uk>
++ *
++ * 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,
++ * or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * squashfs.h
++ */
++
++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
++#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY
++#endif
++
++#ifdef SQUASHFS_TRACE
++#define TRACE(s, args...)     printk(KERN_NOTICE "SQUASHFS: "s, ## args)
++#else
++#define TRACE(s, args...)     {}
++#endif
++
++#define ERROR(s, args...)     printk(KERN_ERR "SQUASHFS error: "s, ## args)
++
++#define SERROR(s, args...)    do { \
++                              if (!silent) \
++                              printk(KERN_ERR "SQUASHFS error: "s, ## args);\
++                              } while(0)
++
++#define WARNING(s, args...)   printk(KERN_WARNING "SQUASHFS: "s, ## args)
++
++static inline struct squashfs_inode_info *SQUASHFS_I(struct inode *inode)
++{
++      return list_entry(inode, struct squashfs_inode_info, vfs_inode);
++}
++
++#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY)
++#define SQSH_EXTERN
++extern unsigned int squashfs_read_data(struct super_block *s, char *buffer,
++                              long long index, unsigned int length,
++                              long long *next_index);
++extern int squashfs_get_cached_block(struct super_block *s, char *buffer,
++                              long long block, unsigned int offset,
++                              int length, long long *next_block,
++                              unsigned int *next_offset);
++extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct
++                                      squashfs_fragment_cache *fragment);
++extern struct squashfs_fragment_cache *get_cached_fragment(struct super_block
++                                      *s, long long start_block,
++                                      int length);
++extern struct address_space_operations squashfs_symlink_aops;
++extern struct address_space_operations squashfs_aops;
++extern struct address_space_operations squashfs_aops_4K;
++extern struct inode_operations squashfs_dir_inode_ops;
++#else
++#define SQSH_EXTERN static
++#endif
++
++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
++extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk);
++#else
++static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk)
++{
++      return 0;
++}
++#endif
++
++#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
++extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk);
++#else
++static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
++{
++      return 0;
++}
++#endif
+diff --new-file -urp linux-2.6.18/include/linux/squashfs_fs.h linux-2.6.18-squashfs3.1/include/linux/squashfs_fs.h
+--- linux-2.6.18/include/linux/squashfs_fs.h   1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-squashfs3.1/include/linux/squashfs_fs.h       2006-08-21 00:13:19.000000000 +0100
+@@ -0,0 +1,911 @@
++#ifndef SQUASHFS_FS
++#define SQUASHFS_FS
++
++/*
++ * Squashfs
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006
++ * Phillip Lougher <phillip@lougher.org.uk>
++ *
++ * 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,
++ * or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * squashfs_fs.h
++ */
++
++#ifndef CONFIG_SQUASHFS_2_0_COMPATIBILITY
++#define CONFIG_SQUASHFS_2_0_COMPATIBILITY
++#endif
++
++#ifdef        CONFIG_SQUASHFS_VMALLOC
++#define SQUASHFS_ALLOC(a)             vmalloc(a)
++#define SQUASHFS_FREE(a)              vfree(a)
++#else
++#define SQUASHFS_ALLOC(a)             kmalloc(a, GFP_KERNEL)
++#define SQUASHFS_FREE(a)              kfree(a)
++#endif
++#define SQUASHFS_CACHED_FRAGMENTS     CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE     
++#define SQUASHFS_MAJOR                        3
++#define SQUASHFS_MINOR                        0
++#define SQUASHFS_MAGIC                        0x73717368
++#define SQUASHFS_MAGIC_SWAP           0x68737173
++#define SQUASHFS_START                        0
++
++/* size of metadata (inode and directory) blocks */
++#define SQUASHFS_METADATA_SIZE                8192
++#define SQUASHFS_METADATA_LOG         13
++
++/* default size of data blocks */
++#define SQUASHFS_FILE_SIZE            65536
++#define SQUASHFS_FILE_LOG             16
++
++#define SQUASHFS_FILE_MAX_SIZE                65536
++
++/* Max number of uids and gids */
++#define SQUASHFS_UIDS                 256
++#define SQUASHFS_GUIDS                        255
++
++/* Max length of filename (not 255) */
++#define SQUASHFS_NAME_LEN             256
++
++#define SQUASHFS_INVALID              ((long long) 0xffffffffffff)
++#define SQUASHFS_INVALID_FRAG         ((unsigned int) 0xffffffff)
++#define SQUASHFS_INVALID_BLK          ((long long) -1)
++#define SQUASHFS_USED_BLK             ((long long) -2)
++
++/* Filesystem flags */
++#define SQUASHFS_NOI                  0
++#define SQUASHFS_NOD                  1
++#define SQUASHFS_CHECK                        2
++#define SQUASHFS_NOF                  3
++#define SQUASHFS_NO_FRAG              4
++#define SQUASHFS_ALWAYS_FRAG          5
++#define SQUASHFS_DUPLICATE            6
++
++#define SQUASHFS_BIT(flag, bit)               ((flag >> bit) & 1)
++
++#define SQUASHFS_UNCOMPRESSED_INODES(flags)   SQUASHFS_BIT(flags, \
++                                              SQUASHFS_NOI)
++
++#define SQUASHFS_UNCOMPRESSED_DATA(flags)     SQUASHFS_BIT(flags, \
++                                              SQUASHFS_NOD)
++
++#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags)        SQUASHFS_BIT(flags, \
++                                              SQUASHFS_NOF)
++
++#define SQUASHFS_NO_FRAGMENTS(flags)          SQUASHFS_BIT(flags, \
++                                              SQUASHFS_NO_FRAG)
++
++#define SQUASHFS_ALWAYS_FRAGMENTS(flags)      SQUASHFS_BIT(flags, \
++                                              SQUASHFS_ALWAYS_FRAG)
++
++#define SQUASHFS_DUPLICATES(flags)            SQUASHFS_BIT(flags, \
++                                              SQUASHFS_DUPLICATE)
++
++#define SQUASHFS_CHECK_DATA(flags)            SQUASHFS_BIT(flags, \
++                                              SQUASHFS_CHECK)
++
++#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \
++              duplicate_checking)     (noi | (nod << 1) | (check_data << 2) \
++              | (nof << 3) | (no_frag << 4) | (always_frag << 5) | \
++              (duplicate_checking << 6))
++
++/* Max number of types and file types */
++#define SQUASHFS_DIR_TYPE             1
++#define SQUASHFS_FILE_TYPE            2
++#define SQUASHFS_SYMLINK_TYPE         3
++#define SQUASHFS_BLKDEV_TYPE          4
++#define SQUASHFS_CHRDEV_TYPE          5
++#define SQUASHFS_FIFO_TYPE            6
++#define SQUASHFS_SOCKET_TYPE          7
++#define SQUASHFS_LDIR_TYPE            8
++#define SQUASHFS_LREG_TYPE            9
++
++/* 1.0 filesystem type definitions */
++#define SQUASHFS_TYPES                        5
++#define SQUASHFS_IPC_TYPE             0
++
++/* Flag whether block is compressed or uncompressed, bit is set if block is
++ * uncompressed */
++#define SQUASHFS_COMPRESSED_BIT               (1 << 15)
++
++#define SQUASHFS_COMPRESSED_SIZE(B)   (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
++              (B) & ~SQUASHFS_COMPRESSED_BIT :  SQUASHFS_COMPRESSED_BIT)
++
++#define SQUASHFS_COMPRESSED(B)                (!((B) & SQUASHFS_COMPRESSED_BIT))
++
++#define SQUASHFS_COMPRESSED_BIT_BLOCK         (1 << 24)
++
++#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B)     (((B) & \
++      ~SQUASHFS_COMPRESSED_BIT_BLOCK) ? (B) & \
++      ~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK)
++
++#define SQUASHFS_COMPRESSED_BLOCK(B)  (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
++
++/*
++ * Inode number ops.  Inodes consist of a compressed block number, and an
++ * uncompressed  offset within that block
++ */
++#define SQUASHFS_INODE_BLK(a)         ((unsigned int) ((a) >> 16))
++
++#define SQUASHFS_INODE_OFFSET(a)      ((unsigned int) ((a) & 0xffff))
++
++#define SQUASHFS_MKINODE(A, B)                ((squashfs_inode_t)(((squashfs_inode_t) (A)\
++                                      << 16) + (B)))
++
++/* Compute 32 bit VFS inode number from squashfs inode number */
++#define SQUASHFS_MK_VFS_INODE(a, b)   ((unsigned int) (((a) << 8) + \
++                                      ((b) >> 2) + 1))
++/* XXX */
++
++/* Translate between VFS mode and squashfs mode */
++#define SQUASHFS_MODE(a)              ((a) & 0xfff)
++
++/* fragment and fragment table defines */
++#define SQUASHFS_FRAGMENT_BYTES(A)    (A * sizeof(struct squashfs_fragment_entry))
++
++#define SQUASHFS_FRAGMENT_INDEX(A)    (SQUASHFS_FRAGMENT_BYTES(A) / \
++                                      SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A)     (SQUASHFS_FRAGMENT_BYTES(A) % \
++                                              SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEXES(A)  ((SQUASHFS_FRAGMENT_BYTES(A) + \
++                                      SQUASHFS_METADATA_SIZE - 1) / \
++                                      SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEX_BYTES(A)      (SQUASHFS_FRAGMENT_INDEXES(A) *\
++                                              sizeof(long long))
++
++/* cached data constants for filesystem */
++#define SQUASHFS_CACHED_BLKS          8
++
++#define SQUASHFS_MAX_FILE_SIZE_LOG    64
++
++#define SQUASHFS_MAX_FILE_SIZE                ((long long) 1 << \
++                                      (SQUASHFS_MAX_FILE_SIZE_LOG - 2))
++
++#define SQUASHFS_MARKER_BYTE          0xff
++
++/* meta index cache */
++#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
++#define SQUASHFS_META_ENTRIES 31
++#define SQUASHFS_META_NUMBER  8
++#define SQUASHFS_SLOTS                4
++
++struct meta_entry {
++      long long               data_block;
++      unsigned int            index_block;
++      unsigned short          offset;
++      unsigned short          pad;
++};
++
++struct meta_index {
++      unsigned int            inode_number;
++      unsigned int            offset;
++      unsigned short          entries;
++      unsigned short          skip;
++      unsigned short          locked;
++      unsigned short          pad;
++      struct meta_entry       meta_entry[SQUASHFS_META_ENTRIES];
++};
++
++
++/*
++ * definitions for structures on disk
++ */
++
++typedef long long             squashfs_block_t;
++typedef long long             squashfs_inode_t;
++
++struct squashfs_super_block {
++      unsigned int            s_magic;
++      unsigned int            inodes;
++      unsigned int            bytes_used_2;
++      unsigned int            uid_start_2;
++      unsigned int            guid_start_2;
++      unsigned int            inode_table_start_2;
++      unsigned int            directory_table_start_2;
++      unsigned int            s_major:16;
++      unsigned int            s_minor:16;
++      unsigned int            block_size_1:16;
++      unsigned int            block_log:16;
++      unsigned int            flags:8;
++      unsigned int            no_uids:8;
++      unsigned int            no_guids:8;
++      unsigned int            mkfs_time /* time of filesystem creation */;
++      squashfs_inode_t        root_inode;
++      unsigned int            block_size;
++      unsigned int            fragments;
++      unsigned int            fragment_table_start_2;
++      long long               bytes_used;
++      long long               uid_start;
++      long long               guid_start;
++      long long               inode_table_start;
++      long long               directory_table_start;
++      long long               fragment_table_start;
++      long long               unused;
++} __attribute__ ((packed));
++
++struct squashfs_dir_index {
++      unsigned int            index;
++      unsigned int            start_block;
++      unsigned char           size;
++      unsigned char           name[0];
++} __attribute__ ((packed));
++
++#define SQUASHFS_BASE_INODE_HEADER            \
++      unsigned int            inode_type:4;   \
++      unsigned int            mode:12;        \
++      unsigned int            uid:8;          \
++      unsigned int            guid:8;         \
++      unsigned int            mtime;          \
++      unsigned int            inode_number;
++
++struct squashfs_base_inode_header {
++      SQUASHFS_BASE_INODE_HEADER;
++} __attribute__ ((packed));
++
++struct squashfs_ipc_inode_header {
++      SQUASHFS_BASE_INODE_HEADER;
++      unsigned int            nlink;
++} __attribute__ ((packed));
++
++struct squashfs_dev_inode_header {
++      SQUASHFS_BASE_INODE_HEADER;
++      unsigned int            nlink;
++      unsigned short          rdev;
++} __attribute__ ((packed));
++      
++struct squashfs_symlink_inode_header {
++      SQUASHFS_BASE_INODE_HEADER;
++      unsigned int            nlink;
++      unsigned short          symlink_size;
++      char                    symlink[0];
++} __attribute__ ((packed));
++
++struct squashfs_reg_inode_header {
++      SQUASHFS_BASE_INODE_HEADER;
++      squashfs_block_t        start_block;
++      unsigned int            fragment;
++      unsigned int            offset;
++      unsigned int            file_size;
++      unsigned short          block_list[0];
++} __attribute__ ((packed));
++
++struct squashfs_lreg_inode_header {
++      SQUASHFS_BASE_INODE_HEADER;
++      unsigned int            nlink;
++      squashfs_block_t        start_block;
++      unsigned int            fragment;
++      unsigned int            offset;
++      long long               file_size;
++      unsigned short          block_list[0];
++} __attribute__ ((packed));
++
++struct squashfs_dir_inode_header {
++      SQUASHFS_BASE_INODE_HEADER;
++      unsigned int            nlink;
++      unsigned int            file_size:19;
++      unsigned int            offset:13;
++      unsigned int            start_block;
++      unsigned int            parent_inode;
++} __attribute__  ((packed));
++
++struct squashfs_ldir_inode_header {
++      SQUASHFS_BASE_INODE_HEADER;
++      unsigned int            nlink;
++      unsigned int            file_size:27;
++      unsigned int            offset:13;
++      unsigned int            start_block;
++      unsigned int            i_count:16;
++      unsigned int            parent_inode;
++      struct squashfs_dir_index       index[0];
++} __attribute__  ((packed));
++
++union squashfs_inode_header {
++      struct squashfs_base_inode_header       base;
++      struct squashfs_dev_inode_header        dev;
++      struct squashfs_symlink_inode_header    symlink;
++      struct squashfs_reg_inode_header        reg;
++      struct squashfs_lreg_inode_header       lreg;
++      struct squashfs_dir_inode_header        dir;
++      struct squashfs_ldir_inode_header       ldir;
++      struct squashfs_ipc_inode_header        ipc;
++};
++      
++struct squashfs_dir_entry {
++      unsigned int            offset:13;
++      unsigned int            type:3;
++      unsigned int            size:8;
++      int                     inode_number:16;
++      char                    name[0];
++} __attribute__ ((packed));
++
++struct squashfs_dir_header {
++      unsigned int            count:8;
++      unsigned int            start_block;
++      unsigned int            inode_number;
++} __attribute__ ((packed));
++
++struct squashfs_fragment_entry {
++      long long               start_block;
++      unsigned int            size;
++      unsigned int            unused;
++} __attribute__ ((packed));
++
++extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen);
++extern int squashfs_uncompress_init(void);
++extern int squashfs_uncompress_exit(void);
++
++/*
++ * macros to convert each packed bitfield structure from little endian to big
++ * endian and vice versa.  These are needed when creating or using a filesystem
++ * on a machine with different byte ordering to the target architecture.
++ *
++ */
++
++#define SQUASHFS_SWAP_START \
++      int bits;\
++      int b_pos;\
++      unsigned long long val;\
++      unsigned char *s;\
++      unsigned char *d;
++
++#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\
++      SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\
++      SQUASHFS_SWAP((s)->inodes, d, 32, 32);\
++      SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\
++      SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\
++      SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\
++      SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\
++      SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\
++      SQUASHFS_SWAP((s)->s_major, d, 224, 16);\
++      SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\
++      SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\
++      SQUASHFS_SWAP((s)->block_log, d, 272, 16);\
++      SQUASHFS_SWAP((s)->flags, d, 288, 8);\
++      SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\
++      SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\
++      SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\
++      SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\
++      SQUASHFS_SWAP((s)->block_size, d, 408, 32);\
++      SQUASHFS_SWAP((s)->fragments, d, 440, 32);\
++      SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\
++      SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\
++      SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\
++      SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\
++      SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\
++      SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\
++      SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\
++      SQUASHFS_SWAP((s)->unused, d, 888, 64);\
++}
++
++#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
++      SQUASHFS_MEMSET(s, d, n);\
++      SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
++      SQUASHFS_SWAP((s)->mode, d, 4, 12);\
++      SQUASHFS_SWAP((s)->uid, d, 16, 8);\
++      SQUASHFS_SWAP((s)->guid, d, 24, 8);\
++      SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
++      SQUASHFS_SWAP((s)->inode_number, d, 64, 32);
++
++#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
++}
++
++#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++                      sizeof(struct squashfs_ipc_inode_header))\
++      SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++}
++
++#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++                      sizeof(struct squashfs_dev_inode_header)); \
++      SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++      SQUASHFS_SWAP((s)->rdev, d, 128, 16);\
++}
++
++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++                      sizeof(struct squashfs_symlink_inode_header));\
++      SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++      SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\
++}
++
++#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++                      sizeof(struct squashfs_reg_inode_header));\
++      SQUASHFS_SWAP((s)->start_block, d, 96, 64);\
++      SQUASHFS_SWAP((s)->fragment, d, 160, 32);\
++      SQUASHFS_SWAP((s)->offset, d, 192, 32);\
++      SQUASHFS_SWAP((s)->file_size, d, 224, 32);\
++}
++
++#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++                      sizeof(struct squashfs_lreg_inode_header));\
++      SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++      SQUASHFS_SWAP((s)->start_block, d, 128, 64);\
++      SQUASHFS_SWAP((s)->fragment, d, 192, 32);\
++      SQUASHFS_SWAP((s)->offset, d, 224, 32);\
++      SQUASHFS_SWAP((s)->file_size, d, 256, 64);\
++}
++
++#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++                      sizeof(struct squashfs_dir_inode_header));\
++      SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++      SQUASHFS_SWAP((s)->file_size, d, 128, 19);\
++      SQUASHFS_SWAP((s)->offset, d, 147, 13);\
++      SQUASHFS_SWAP((s)->start_block, d, 160, 32);\
++      SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\
++}
++
++#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++                      sizeof(struct squashfs_ldir_inode_header));\
++      SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++      SQUASHFS_SWAP((s)->file_size, d, 128, 27);\
++      SQUASHFS_SWAP((s)->offset, d, 155, 13);\
++      SQUASHFS_SWAP((s)->start_block, d, 168, 32);\
++      SQUASHFS_SWAP((s)->i_count, d, 200, 16);\
++      SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\
++}
++
++#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\
++      SQUASHFS_SWAP((s)->index, d, 0, 32);\
++      SQUASHFS_SWAP((s)->start_block, d, 32, 32);\
++      SQUASHFS_SWAP((s)->size, d, 64, 8);\
++}
++
++#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\
++      SQUASHFS_SWAP((s)->count, d, 0, 8);\
++      SQUASHFS_SWAP((s)->start_block, d, 8, 32);\
++      SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\
++}
++
++#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\
++      SQUASHFS_SWAP((s)->offset, d, 0, 13);\
++      SQUASHFS_SWAP((s)->type, d, 13, 3);\
++      SQUASHFS_SWAP((s)->size, d, 16, 8);\
++      SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\
++}
++
++#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\
++      SQUASHFS_SWAP((s)->start_block, d, 0, 64);\
++      SQUASHFS_SWAP((s)->size, d, 64, 32);\
++}
++
++#define SQUASHFS_SWAP_SHORTS(s, d, n) {\
++      int entry;\
++      int bit_position;\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, n * 2);\
++      for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
++                      16)\
++              SQUASHFS_SWAP(s[entry], d, bit_position, 16);\
++}
++
++#define SQUASHFS_SWAP_INTS(s, d, n) {\
++      int entry;\
++      int bit_position;\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, n * 4);\
++      for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
++                      32)\
++              SQUASHFS_SWAP(s[entry], d, bit_position, 32);\
++}
++
++#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\
++      int entry;\
++      int bit_position;\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, n * 8);\
++      for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
++                      64)\
++              SQUASHFS_SWAP(s[entry], d, bit_position, 64);\
++}
++
++#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\
++      int entry;\
++      int bit_position;\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, n * bits / 8);\
++      for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
++                      bits)\
++              SQUASHFS_SWAP(s[entry], d, bit_position, bits);\
++}
++
++#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
++
++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
++
++struct squashfs_base_inode_header_1 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:4; /* index into uid table */
++      unsigned int            guid:4; /* index into guid table */
++} __attribute__ ((packed));
++
++struct squashfs_ipc_inode_header_1 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:4; /* index into uid table */
++      unsigned int            guid:4; /* index into guid table */
++      unsigned int            type:4;
++      unsigned int            offset:4;
++} __attribute__ ((packed));
++
++struct squashfs_dev_inode_header_1 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:4; /* index into uid table */
++      unsigned int            guid:4; /* index into guid table */
++      unsigned short          rdev;
++} __attribute__ ((packed));
++      
++struct squashfs_symlink_inode_header_1 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:4; /* index into uid table */
++      unsigned int            guid:4; /* index into guid table */
++      unsigned short          symlink_size;
++      char                    symlink[0];
++} __attribute__ ((packed));
++
++struct squashfs_reg_inode_header_1 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:4; /* index into uid table */
++      unsigned int            guid:4; /* index into guid table */
++      unsigned int            mtime;
++      unsigned int            start_block;
++      unsigned int            file_size:32;
++      unsigned short          block_list[0];
++} __attribute__ ((packed));
++
++struct squashfs_dir_inode_header_1 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:4; /* index into uid table */
++      unsigned int            guid:4; /* index into guid table */
++      unsigned int            file_size:19;
++      unsigned int            offset:13;
++      unsigned int            mtime;
++      unsigned int            start_block:24;
++} __attribute__  ((packed));
++
++#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \
++      SQUASHFS_MEMSET(s, d, n);\
++      SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
++      SQUASHFS_SWAP((s)->mode, d, 4, 12);\
++      SQUASHFS_SWAP((s)->uid, d, 16, 4);\
++      SQUASHFS_SWAP((s)->guid, d, 20, 4);
++
++#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\
++}
++
++#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
++                      sizeof(struct squashfs_ipc_inode_header_1));\
++      SQUASHFS_SWAP((s)->type, d, 24, 4);\
++      SQUASHFS_SWAP((s)->offset, d, 28, 4);\
++}
++
++#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
++                      sizeof(struct squashfs_dev_inode_header_1));\
++      SQUASHFS_SWAP((s)->rdev, d, 24, 16);\
++}
++
++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
++                      sizeof(struct squashfs_symlink_inode_header_1));\
++      SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\
++}
++
++#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
++                      sizeof(struct squashfs_reg_inode_header_1));\
++      SQUASHFS_SWAP((s)->mtime, d, 24, 32);\
++      SQUASHFS_SWAP((s)->start_block, d, 56, 32);\
++      SQUASHFS_SWAP((s)->file_size, d, 88, 32);\
++}
++
++#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
++                      sizeof(struct squashfs_dir_inode_header_1));\
++      SQUASHFS_SWAP((s)->file_size, d, 24, 19);\
++      SQUASHFS_SWAP((s)->offset, d, 43, 13);\
++      SQUASHFS_SWAP((s)->mtime, d, 56, 32);\
++      SQUASHFS_SWAP((s)->start_block, d, 88, 24);\
++}
++
++#endif
++
++#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
++
++struct squashfs_dir_index_2 {
++      unsigned int            index:27;
++      unsigned int            start_block:29;
++      unsigned char           size;
++      unsigned char           name[0];
++} __attribute__ ((packed));
++
++struct squashfs_base_inode_header_2 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:8; /* index into uid table */
++      unsigned int            guid:8; /* index into guid table */
++} __attribute__ ((packed));
++
++struct squashfs_ipc_inode_header_2 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:8; /* index into uid table */
++      unsigned int            guid:8; /* index into guid table */
++} __attribute__ ((packed));
++
++struct squashfs_dev_inode_header_2 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:8; /* index into uid table */
++      unsigned int            guid:8; /* index into guid table */
++      unsigned short          rdev;
++} __attribute__ ((packed));
++      
++struct squashfs_symlink_inode_header_2 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:8; /* index into uid table */
++      unsigned int            guid:8; /* index into guid table */
++      unsigned short          symlink_size;
++      char                    symlink[0];
++} __attribute__ ((packed));
++
++struct squashfs_reg_inode_header_2 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:8; /* index into uid table */
++      unsigned int            guid:8; /* index into guid table */
++      unsigned int            mtime;
++      unsigned int            start_block;
++      unsigned int            fragment;
++      unsigned int            offset;
++      unsigned int            file_size:32;
++      unsigned short          block_list[0];
++} __attribute__ ((packed));
++
++struct squashfs_dir_inode_header_2 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:8; /* index into uid table */
++      unsigned int            guid:8; /* index into guid table */
++      unsigned int            file_size:19;
++      unsigned int            offset:13;
++      unsigned int            mtime;
++      unsigned int            start_block:24;
++} __attribute__  ((packed));
++
++struct squashfs_ldir_inode_header_2 {
++      unsigned int            inode_type:4;
++      unsigned int            mode:12; /* protection */
++      unsigned int            uid:8; /* index into uid table */
++      unsigned int            guid:8; /* index into guid table */
++      unsigned int            file_size:27;
++      unsigned int            offset:13;
++      unsigned int            mtime;
++      unsigned int            start_block:24;
++      unsigned int            i_count:16;
++      struct squashfs_dir_index_2     index[0];
++} __attribute__  ((packed));
++
++union squashfs_inode_header_2 {
++      struct squashfs_base_inode_header_2     base;
++      struct squashfs_dev_inode_header_2      dev;
++      struct squashfs_symlink_inode_header_2  symlink;
++      struct squashfs_reg_inode_header_2      reg;
++      struct squashfs_dir_inode_header_2      dir;
++      struct squashfs_ldir_inode_header_2     ldir;
++      struct squashfs_ipc_inode_header_2      ipc;
++};
++      
++struct squashfs_dir_header_2 {
++      unsigned int            count:8;
++      unsigned int            start_block:24;
++} __attribute__ ((packed));
++
++struct squashfs_dir_entry_2 {
++      unsigned int            offset:13;
++      unsigned int            type:3;
++      unsigned int            size:8;
++      char                    name[0];
++} __attribute__ ((packed));
++
++struct squashfs_fragment_entry_2 {
++      unsigned int            start_block;
++      unsigned int            size;
++} __attribute__ ((packed));
++
++#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
++      SQUASHFS_MEMSET(s, d, n);\
++      SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
++      SQUASHFS_SWAP((s)->mode, d, 4, 12);\
++      SQUASHFS_SWAP((s)->uid, d, 16, 8);\
++      SQUASHFS_SWAP((s)->guid, d, 24, 8);\
++
++#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
++}
++
++#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \
++      SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2))
++
++#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
++                      sizeof(struct squashfs_dev_inode_header_2)); \
++      SQUASHFS_SWAP((s)->rdev, d, 32, 16);\
++}
++
++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
++                      sizeof(struct squashfs_symlink_inode_header_2));\
++      SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\
++}
++
++#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
++                      sizeof(struct squashfs_reg_inode_header_2));\
++      SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
++      SQUASHFS_SWAP((s)->start_block, d, 64, 32);\
++      SQUASHFS_SWAP((s)->fragment, d, 96, 32);\
++      SQUASHFS_SWAP((s)->offset, d, 128, 32);\
++      SQUASHFS_SWAP((s)->file_size, d, 160, 32);\
++}
++
++#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
++                      sizeof(struct squashfs_dir_inode_header_2));\
++      SQUASHFS_SWAP((s)->file_size, d, 32, 19);\
++      SQUASHFS_SWAP((s)->offset, d, 51, 13);\
++      SQUASHFS_SWAP((s)->mtime, d, 64, 32);\
++      SQUASHFS_SWAP((s)->start_block, d, 96, 24);\
++}
++
++#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
++                      sizeof(struct squashfs_ldir_inode_header_2));\
++      SQUASHFS_SWAP((s)->file_size, d, 32, 27);\
++      SQUASHFS_SWAP((s)->offset, d, 59, 13);\
++      SQUASHFS_SWAP((s)->mtime, d, 72, 32);\
++      SQUASHFS_SWAP((s)->start_block, d, 104, 24);\
++      SQUASHFS_SWAP((s)->i_count, d, 128, 16);\
++}
++
++#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\
++      SQUASHFS_SWAP((s)->index, d, 0, 27);\
++      SQUASHFS_SWAP((s)->start_block, d, 27, 29);\
++      SQUASHFS_SWAP((s)->size, d, 56, 8);\
++}
++#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\
++      SQUASHFS_SWAP((s)->count, d, 0, 8);\
++      SQUASHFS_SWAP((s)->start_block, d, 8, 24);\
++}
++
++#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\
++      SQUASHFS_SWAP((s)->offset, d, 0, 13);\
++      SQUASHFS_SWAP((s)->type, d, 13, 3);\
++      SQUASHFS_SWAP((s)->size, d, 16, 8);\
++}
++
++#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\
++      SQUASHFS_SWAP_START\
++      SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\
++      SQUASHFS_SWAP((s)->start_block, d, 0, 32);\
++      SQUASHFS_SWAP((s)->size, d, 32, 32);\
++}
++
++#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n)
++
++/* fragment and fragment table defines */
++#define SQUASHFS_FRAGMENT_BYTES_2(A)  (A * sizeof(struct squashfs_fragment_entry_2))
++
++#define SQUASHFS_FRAGMENT_INDEX_2(A)  (SQUASHFS_FRAGMENT_BYTES_2(A) / \
++                                      SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A)   (SQUASHFS_FRAGMENT_BYTES_2(A) % \
++                                              SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEXES_2(A)        ((SQUASHFS_FRAGMENT_BYTES_2(A) + \
++                                      SQUASHFS_METADATA_SIZE - 1) / \
++                                      SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A)    (SQUASHFS_FRAGMENT_INDEXES_2(A) *\
++                                              sizeof(int))
++
++#endif
++
++#ifdef __KERNEL__
++
++/*
++ * macros used to swap each structure entry, taking into account
++ * bitfields and different bitfield placing conventions on differing
++ * architectures
++ */
++
++#include <asm/byteorder.h>
++
++#ifdef __BIG_ENDIAN
++      /* convert from little endian to big endian */
++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
++              tbits, b_pos)
++#else
++      /* convert from big endian to little endian */ 
++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
++              tbits, 64 - tbits - b_pos)
++#endif
++
++#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
++      b_pos = pos % 8;\
++      val = 0;\
++      s = (unsigned char *)p + (pos / 8);\
++      d = ((unsigned char *) &val) + 7;\
++      for(bits = 0; bits < (tbits + b_pos); bits += 8) \
++              *d-- = *s++;\
++      value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\
++}
++
++#define SQUASHFS_MEMSET(s, d, n)      memset(s, 0, n);
++
++#endif
++#endif
+diff --new-file -urp linux-2.6.18/include/linux/squashfs_fs_i.h linux-2.6.18-squashfs3.1/include/linux/squashfs_fs_i.h
+--- linux-2.6.18/include/linux/squashfs_fs_i.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-squashfs3.1/include/linux/squashfs_fs_i.h     2006-08-21 00:13:19.000000000 +0100
+@@ -0,0 +1,45 @@
++#ifndef SQUASHFS_FS_I
++#define SQUASHFS_FS_I
++/*
++ * Squashfs
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006
++ * Phillip Lougher <phillip@lougher.org.uk>
++ *
++ * 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,
++ * or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * squashfs_fs_i.h
++ */
++
++struct squashfs_inode_info {
++      long long       start_block;
++      unsigned int    offset;
++      union {
++              struct {
++                      long long       fragment_start_block;
++                      unsigned int    fragment_size;
++                      unsigned int    fragment_offset;
++                      long long       block_list_start;
++              } s1;
++              struct {
++                      long long       directory_index_start;
++                      unsigned int    directory_index_offset;
++                      unsigned int    directory_index_count;
++                      unsigned int    parent_inode;
++              } s2;
++      } u;
++      struct inode    vfs_inode;
++};
++#endif
+diff --new-file -urp linux-2.6.18/include/linux/squashfs_fs_sb.h linux-2.6.18-squashfs3.1/include/linux/squashfs_fs_sb.h
+--- linux-2.6.18/include/linux/squashfs_fs_sb.h        1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.18-squashfs3.1/include/linux/squashfs_fs_sb.h    2006-08-21 00:16:48.000000000 +0100
+@@ -0,0 +1,75 @@
++#ifndef SQUASHFS_FS_SB
++#define SQUASHFS_FS_SB
++/*
++ * Squashfs
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006
++ * Phillip Lougher <phillip@lougher.org.uk>
++ *
++ * 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,
++ * or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * squashfs_fs_sb.h
++ */
++
++#include <linux/squashfs_fs.h>
++
++struct squashfs_cache {
++      long long       block;
++      int             length;
++      long long       next_index;
++      char            *data;
++};
++
++struct squashfs_fragment_cache {
++      long long       block;
++      int             length;
++      unsigned int    locked;
++      char            *data;
++};
++
++struct squashfs_sb_info {
++      struct squashfs_super_block     sblk;
++      int                     devblksize;
++      int                     devblksize_log2;
++      int                     swap;
++      struct squashfs_cache   *block_cache;
++      struct squashfs_fragment_cache  *fragment;
++      int                     next_cache;
++      int                     next_fragment;
++      int                     next_meta_index;
++      unsigned int            *uid;
++      unsigned int            *guid;
++      long long               *fragment_index;
++      unsigned int            *fragment_index_2;
++      unsigned int            read_size;
++      char                    *read_data;
++      char                    *read_page;
++      struct semaphore        read_data_mutex;
++      struct semaphore        read_page_mutex;
++      struct semaphore        block_cache_mutex;
++      struct semaphore        fragment_mutex;
++      struct semaphore        meta_index_mutex;
++      wait_queue_head_t       waitq;
++      wait_queue_head_t       fragment_wait_queue;
++      struct meta_index       *meta_index;
++      z_stream                stream;
++      struct inode            *(*iget)(struct super_block *s,  squashfs_inode_t
++                              inode);
++      long long               (*read_blocklist)(struct inode *inode, int
++                              index, int readahead_blks, char *block_list,
++                              unsigned short **block_p, unsigned int *bsize);
++      int                     (*read_fragment_index_table)(struct super_block *s);
++};
++#endif
+diff --new-file -urp linux-2.6.18/init/do_mounts_rd.c linux-2.6.18-squashfs3.1/init/do_mounts_rd.c
+--- linux-2.6.18/init/do_mounts_rd.c   2006-08-11 00:03:15.000000000 +0100
++++ linux-2.6.18-squashfs3.1/init/do_mounts_rd.c       2006-08-21 00:13:19.000000000 +0100
+@@ -5,6 +5,7 @@
+ #include <linux/ext2_fs.h>
+ #include <linux/romfs_fs.h>
+ #include <linux/cramfs_fs.h>
++#include <linux/squashfs_fs.h>
+ #include <linux/initrd.h>
+ #include <linux/string.h>
+@@ -39,6 +40,7 @@ static int __init crd_load(int in_fd, in
+  * numbers could not be found.
+  *
+  * We currently check for the following magic numbers:
++ *      squashfs
+  *    minix
+  *    ext2
+  *    romfs
+@@ -53,6 +55,7 @@ identify_ramdisk_image(int fd, int start
+       struct ext2_super_block *ext2sb;
+       struct romfs_super_block *romfsb;
+       struct cramfs_super *cramfsb;
++      struct squashfs_super_block *squashfsb;
+       int nblocks = -1;
+       unsigned char *buf;
+@@ -64,6 +67,7 @@ identify_ramdisk_image(int fd, int start
+       ext2sb = (struct ext2_super_block *) buf;
+       romfsb = (struct romfs_super_block *) buf;
+       cramfsb = (struct cramfs_super *) buf;
++      squashfsb = (struct squashfs_super_block *) buf;
+       memset(buf, 0xe5, size);
+       /*
+@@ -101,6 +105,18 @@ identify_ramdisk_image(int fd, int start
+               goto done;
+       }
++      /* squashfs is at block zero too */
++      if (squashfsb->s_magic == SQUASHFS_MAGIC) {
++              printk(KERN_NOTICE
++                     "RAMDISK: squashfs filesystem found at block %d\n",
++                     start_block);
++              if (squashfsb->s_major < 3)
++                      nblocks = (squashfsb->bytes_used_2+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
++              else
++                      nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
++              goto done;
++      }
++
+       /*
+        * Read block 1 to test for minix and ext2 superblock
+        */
diff --git a/packages/linux/linux-magicbox_2.6.18.6.bb b/packages/linux/linux-magicbox_2.6.18.6.bb
new file mode 100644 (file)
index 0000000..8898045
--- /dev/null
@@ -0,0 +1,77 @@
+SECTION = "kernel"
+DESCRIPTION = "Linux kernel for Magicbox ver 1.1 and 2.0 router boards"
+LICENSE = "GPL"
+PR = "r0"
+#DEPENDS = "u-boot"
+
+KERNEL_CCSUFFIX = "-3.4.4"
+
+SRC_URI = "${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/linux-${PV}.tar.bz2 \
+          file://000-fix-makefile.patch;patch=1 \
+          file://001-magicbox-board-2.6.18.patch;patch=1 \
+          file://002-magicbox-mtd-map-2.6.18.patch;patch=1 \
+          file://010-load-ramdisk-even-if-rootdev-equals-ramdisk.patch;patch=1 \
+          file://magicbox2-ide-cf_2.6.18.patch;patch=1 \
+          file://squashfs3.1-patch;patch=1 \
+          file://kernel-2.6.18-layer7-2.6.patch;patch=1 \
+          file://config-2.6.18-magicbox2\
+"
+
+
+S = "${WORKDIR}/linux-${PV}"
+
+inherit kernel
+
+
+FILES_kernel-image = "/boot/zImage.elf"
+
+export OS = "Linux"
+ARCH = "ppc"
+KERNEL_IMAGETYPE = "zImage"
+KERNEL_OUTPUT = "arch/ppc/boot/images/zImage.elf"
+
+
+
+
+do_configure_prepend() {
+       install -m 0644 ${WORKDIR}/config-2.6.18-magicbox2 ${S}/.config
+}
+
+
+do_stage_append () {
+#need ppc platforms includes + friends in order for external kernel modules to compile as headers as still split
+
+       install -d ${STAGING_KERNEL_DIR}/arch/
+       cp -a arch/ppc ${STAGING_KERNEL_DIR}/arch/
+       cp -a arch/powerpc ${STAGING_KERNEL_DIR}/arch/
+
+       cp -a include/asm-powerpc ${STAGING_KERNEL_DIR}/include/
+       cp -a include/asm-ppc ${STAGING_KERNEL_DIR}/include/
+}
+
+
+
+do_install_append () {
+        install -d  ${DEPLOY_DIR}/images
+        install -m 0755 arch/ppc/boot/images/zImage.elf 
+${DEPLOY_DIR}/images/${KERNEL_IMAGETYPE}-${PV}-${MACHINE}-${DATETIME}.elf
+        install -m 0755 vmlinux ${DEPLOY_DIR}/images/
+        powerpc-${TARGET_OS}-objcopy -O binary -R .note -R .comment -S ${DEPLOY_DIR}/images/vmlinux ${DEPLOY_DIR}/images/linux.bin
+        gzip -f -9 ${DEPLOY_DIR}/images/linux.bin
+        mkimage -A ppc -O linux -T kernel -C gzip -a 0 -e 0 -n "ppc405"+${PV} -d ${DEPLOY_DIR}/images/linux.bin.gz ${DEPLOY_DIR}/images/uImage-${PV}-${MACHINE}-${DATETIME}.bin        
+        rm ${DEPLOY_DIR}/images/vmlinux
+        rm ${DEPLOY_DIR}/images/linux.bin.gz
+
+
+}
+
+
+pkg_postinst_kernel () {
+        true
+}
+
+pkg_postrm_kernel () {
+        true
+}
+
+