diff options
author | matteo <matteo@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2008-06-12 21:13:40 +0000 |
---|---|---|
committer | matteo <matteo@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2008-06-12 21:13:40 +0000 |
commit | cc8d0a8850bff29fb230afbedadc390285f8c5ef (patch) | |
tree | 06b836bbd4cb93f4e1f75e482693485bdeed5e2d /target/linux/avr32 | |
parent | e54d9e35f2bf169ef906a0e84e3b52139e8d5a7f (diff) |
avr32: upgrade to 2.6.25.6
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@11450 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/avr32')
-rw-r--r-- | target/linux/avr32/Makefile | 2 | ||||
-rw-r--r-- | target/linux/avr32/config-default | 66 | ||||
-rw-r--r-- | target/linux/avr32/patches/100-git_sync.patch | 50762 | ||||
-rw-r--r-- | target/linux/avr32/patches/120-cpufreq_panic.patch | 25 |
4 files changed, 39979 insertions, 10876 deletions
diff --git a/target/linux/avr32/Makefile b/target/linux/avr32/Makefile index 5a081f124d..96c5a104b2 100644 --- a/target/linux/avr32/Makefile +++ b/target/linux/avr32/Makefile @@ -10,7 +10,7 @@ ARCH:=avr32 BOARD:=avr32 BOARDNAME:=Atmel AVR32 FEATURES:=squashfs -LINUX_VERSION:=2.6.24.7 +LINUX_VERSION:=2.6.25.6 include $(INCLUDE_DIR)/target.mk diff --git a/target/linux/avr32/config-default b/target/linux/avr32/config-default index ad676449fe..3fbfb59e89 100644 --- a/target/linux/avr32/config-default +++ b/target/linux/avr32/config-default @@ -7,10 +7,13 @@ CONFIG_AP700X_16_BIT_SMC=y # CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set # CONFIG_ARCH_SPARSEMEM_ENABLE is not set # CONFIG_ARCH_SUPPORTS_MSI is not set -CONFIG_ARCH_SUPPORTS_OPROFILE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_AT32AP700X_WDT=m # CONFIG_ATMEL_PWM is not set # CONFIG_ATMEL_SSC is not set -# CONFIG_ATMEL_TCLIB is not set +CONFIG_ATMEL_TCB_CLKSRC=y +CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0 +CONFIG_ATMEL_TCLIB=y CONFIG_AVR32=y CONFIG_BASE_SMALL=0 CONFIG_BITREVERSE=y @@ -19,25 +22,38 @@ CONFIG_BOARD_ATNGW100=y # CONFIG_BOARD_ATSTK1000 is not set # CONFIG_BROADCOM_PHY is not set # CONFIG_BT is not set +CONFIG_CLASSIC_RCU=y CONFIG_CPU_AT32AP7000=y CONFIG_CPU_AT32AP700X=y # CONFIG_CPU_FREQ is not set +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_GF128MUL=m # CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_DW_DMAC=y +# CONFIG_E1000E_ENABLED is not set CONFIG_ENTRY_ADDRESS=0x90000000 # CONFIG_FIXED_PHY is not set CONFIG_FS_POSIX_ACL=y +CONFIG_GENERIC_ALLOCATOR=y CONFIG_GENERIC_BUG=y CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_GENERIC_GPIO=y -# CONFIG_GEN_RTC is not set # CONFIG_GPIO_DEV is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set CONFIG_HARDIRQS_SW_RESEND=y CONFIG_HAS_DMA=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y # CONFIG_HAVE_ARCH_BOOTMEM_NODE is not set +CONFIG_HAVE_GPIO_LIB=y +# CONFIG_HAVE_IDE is not set +CONFIG_HAVE_KPROBES=y +# CONFIG_HAVE_KRETPROBES is not set +CONFIG_HAVE_OPROFILE=y # CONFIG_HW_RANDOM is not set CONFIG_I2C=y # CONFIG_I2C_ALGOBIT is not set @@ -47,14 +63,23 @@ CONFIG_I2C_BOARDINFO=y # CONFIG_IBM_NEW_EMAC_RGMII is not set # CONFIG_IBM_NEW_EMAC_TAH is not set # CONFIG_IBM_NEW_EMAC_ZMII is not set -# CONFIG_IDE is not set CONFIG_INITRAMFS_SOURCE="" # CONFIG_LEDS_ALIX is not set CONFIG_LEDS_GPIO=y CONFIG_LOADER_U_BOOT=y CONFIG_LOAD_ADDRESS=0x10000000 +CONFIG_LZO_COMPRESS=m +CONFIG_LZO_DECOMPRESS=m CONFIG_MACB=y # CONFIG_MDIO_BITBANG is not set +# CONFIG_MEMSTICK is not set +CONFIG_MMC=m +CONFIG_MMC_ATMELMCI=m +CONFIG_MMC_BLOCK=m +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_SPI is not set +# CONFIG_MMC_UNSAFE_RESUME is not set CONFIG_MTD=y # CONFIG_MTD_ABSENT is not set CONFIG_MTD_BLKDEVS=y @@ -104,16 +129,40 @@ CONFIG_MTD_PHYSMAP_START=0x80000000 # CONFIG_NMI_DEBUGGING is not set CONFIG_NO_HZ=y # CONFIG_OWNERSHIP_TRACE is not set -# CONFIG_PATA_AT32 is not set CONFIG_PERFORMANCE_COUNTERS=y CONFIG_PHYLIB=y CONFIG_PHYS_OFFSET=0x10000000 CONFIG_PLATFORM_AT32AP=y # CONFIG_QSEMI_PHY is not set -# CONFIG_RTC is not set +# CONFIG_REALTEK_PHY is not set +CONFIG_RTC_CLASS=m +CONFIG_RTC_DRV_AT32AP700X=m +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_X1205 is not set +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_LIB=m CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_SCHED_HRTICK is not set CONFIG_SCSI_WAIT_SCAN=m +# CONFIG_SDIO_UART is not set # CONFIG_SERIAL_8250 is not set CONFIG_SERIAL_ATMEL=y CONFIG_SERIAL_ATMEL_CONSOLE=y @@ -122,6 +171,7 @@ CONFIG_SERIAL_ATMEL_PDC=y CONFIG_SLABINFO=y # CONFIG_SMSC_PHY is not set # CONFIG_SND_ATMEL_AC97 is not set +# CONFIG_SOFT_WATCHDOG is not set # CONFIG_SPARSEMEM_STATIC is not set # CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set CONFIG_SPI=y @@ -133,11 +183,11 @@ CONFIG_SPI_MASTER=y CONFIG_SSB_POSSIBLE=y CONFIG_SUBARCH_AVR32B=y CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_THERMAL is not set CONFIG_TICK_ONESHOT=y # CONFIG_USB_ARCH_HAS_EHCI is not set # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set -# CONFIG_USER_NS is not set # CONFIG_VGASTATE is not set -# CONFIG_WATCHDOG is not set +CONFIG_VIDEO_V4L2_COMMON=m CONFIG_ZONE_DMA_FLAG=0 diff --git a/target/linux/avr32/patches/100-git_sync.patch b/target/linux/avr32/patches/100-git_sync.patch index 9c2d5ddf42..a840e45f38 100644 --- a/target/linux/avr32/patches/100-git_sync.patch +++ b/target/linux/avr32/patches/100-git_sync.patch @@ -1,5 +1,423 @@ ---- /dev/null -+++ b/arch/avr32/boards/atngw100/Kconfig +diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/at91cap9_devices.c avr32-2.6/arch/arm/mach-at91/at91cap9_devices.c +--- linux-2.6.25.6/arch/arm/mach-at91/at91cap9_devices.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/arm/mach-at91/at91cap9_devices.c 2008-06-12 15:09:38.603815938 +0200 +@@ -278,20 +278,25 @@ + * -------------------------------------------------------------------- */ + + #if defined(CONFIG_MTD_NAND_AT91) || defined(CONFIG_MTD_NAND_AT91_MODULE) +-static struct at91_nand_data nand_data; ++static struct atmel_nand_data nand_data; + + #define NAND_BASE AT91_CHIPSELECT_3 + + static struct resource nand_resources[] = { +- { ++ [0] = { + .start = NAND_BASE, + .end = NAND_BASE + SZ_256M - 1, + .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91_BASE_SYS + AT91_ECC, ++ .end = AT91_BASE_SYS + AT91_ECC + SZ_512 - 1, ++ .flags = IORESOURCE_MEM, + } + }; + + static struct platform_device at91cap9_nand_device = { +- .name = "at91_nand", ++ .name = "atmel_nand", + .id = -1, + .dev = { + .platform_data = &nand_data, +@@ -300,7 +305,7 @@ + .num_resources = ARRAY_SIZE(nand_resources), + }; + +-void __init at91_add_device_nand(struct at91_nand_data *data) ++void __init at91_add_device_nand(struct atmel_nand_data *data) + { + unsigned long csa, mode; + +@@ -341,7 +346,7 @@ + platform_device_register(&at91cap9_nand_device); + } + #else +-void __init at91_add_device_nand(struct at91_nand_data *data) {} ++void __init at91_add_device_nand(struct atmel_nand_data *data) {} + #endif + + /* -------------------------------------------------------------------- +diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/at91rm9200_devices.c avr32-2.6/arch/arm/mach-at91/at91rm9200_devices.c +--- linux-2.6.25.6/arch/arm/mach-at91/at91rm9200_devices.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/arm/mach-at91/at91rm9200_devices.c 2008-06-12 15:09:38.603815938 +0200 +@@ -369,7 +369,7 @@ + * -------------------------------------------------------------------- */ + + #if defined(CONFIG_MTD_NAND_AT91) || defined(CONFIG_MTD_NAND_AT91_MODULE) +-static struct at91_nand_data nand_data; ++static struct atmel_nand_data nand_data; + + #define NAND_BASE AT91_CHIPSELECT_3 + +@@ -382,7 +382,7 @@ + }; + + static struct platform_device at91rm9200_nand_device = { +- .name = "at91_nand", ++ .name = "atmel_nand", + .id = -1, + .dev = { + .platform_data = &nand_data, +@@ -391,7 +391,7 @@ + .num_resources = ARRAY_SIZE(nand_resources), + }; + +-void __init at91_add_device_nand(struct at91_nand_data *data) ++void __init at91_add_device_nand(struct atmel_nand_data *data) + { + unsigned int csa; + +@@ -429,7 +429,7 @@ + platform_device_register(&at91rm9200_nand_device); + } + #else +-void __init at91_add_device_nand(struct at91_nand_data *data) {} ++void __init at91_add_device_nand(struct atmel_nand_data *data) {} + #endif + + +diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/at91sam9260_devices.c avr32-2.6/arch/arm/mach-at91/at91sam9260_devices.c +--- linux-2.6.25.6/arch/arm/mach-at91/at91sam9260_devices.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/arm/mach-at91/at91sam9260_devices.c 2008-06-12 15:09:38.603815938 +0200 +@@ -283,20 +283,25 @@ + * -------------------------------------------------------------------- */ + + #if defined(CONFIG_MTD_NAND_AT91) || defined(CONFIG_MTD_NAND_AT91_MODULE) +-static struct at91_nand_data nand_data; ++static struct atmel_nand_data nand_data; + + #define NAND_BASE AT91_CHIPSELECT_3 + + static struct resource nand_resources[] = { +- { ++ [0] = { + .start = NAND_BASE, + .end = NAND_BASE + SZ_256M - 1, + .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91_BASE_SYS + AT91_ECC, ++ .end = AT91_BASE_SYS + AT91_ECC + SZ_512 - 1, ++ .flags = IORESOURCE_MEM, + } + }; + + static struct platform_device at91sam9260_nand_device = { +- .name = "at91_nand", ++ .name = "atmel_nand", + .id = -1, + .dev = { + .platform_data = &nand_data, +@@ -305,7 +310,7 @@ + .num_resources = ARRAY_SIZE(nand_resources), + }; + +-void __init at91_add_device_nand(struct at91_nand_data *data) ++void __init at91_add_device_nand(struct atmel_nand_data *data) + { + unsigned long csa, mode; + +@@ -346,7 +351,7 @@ + platform_device_register(&at91sam9260_nand_device); + } + #else +-void __init at91_add_device_nand(struct at91_nand_data *data) {} ++void __init at91_add_device_nand(struct atmel_nand_data *data) {} + #endif + + +diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/at91sam9261_devices.c avr32-2.6/arch/arm/mach-at91/at91sam9261_devices.c +--- linux-2.6.25.6/arch/arm/mach-at91/at91sam9261_devices.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/arm/mach-at91/at91sam9261_devices.c 2008-06-12 15:09:38.607815889 +0200 +@@ -199,7 +199,7 @@ + * -------------------------------------------------------------------- */ + + #if defined(CONFIG_MTD_NAND_AT91) || defined(CONFIG_MTD_NAND_AT91_MODULE) +-static struct at91_nand_data nand_data; ++static struct atmel_nand_data nand_data; + + #define NAND_BASE AT91_CHIPSELECT_3 + +@@ -211,8 +211,8 @@ + } + }; + +-static struct platform_device at91_nand_device = { +- .name = "at91_nand", ++static struct platform_device atmel_nand_device = { ++ .name = "atmel_nand", + .id = -1, + .dev = { + .platform_data = &nand_data, +@@ -221,7 +221,7 @@ + .num_resources = ARRAY_SIZE(nand_resources), + }; + +-void __init at91_add_device_nand(struct at91_nand_data *data) ++void __init at91_add_device_nand(struct atmel_nand_data *data) + { + unsigned long csa, mode; + +@@ -262,11 +262,11 @@ + at91_set_A_periph(AT91_PIN_PC1, 0); /* NANDWE */ + + nand_data = *data; +- platform_device_register(&at91_nand_device); ++ platform_device_register(&atmel_nand_device); + } + + #else +-void __init at91_add_device_nand(struct at91_nand_data *data) {} ++void __init at91_add_device_nand(struct atmel_nand_data *data) {} + #endif + + +@@ -539,6 +539,20 @@ + at91_set_B_periph(AT91_PIN_PB28, 0); /* LCDD23 */ + #endif + ++#ifdef CONFIG_FB_INTSRAM ++ { ++ void __iomem *fb; ++ struct resource *fb_res = &lcdc_resources[2]; ++ size_t fb_len = fb_res->end - fb_res->start + 1; ++ ++ fb = ioremap_writecombine(fb_res->start, fb_len); ++ if (fb) { ++ memset(fb, 0, fb_len); ++ iounmap(fb, fb_len); ++ } ++ } ++#endif ++ + lcdc_data = *data; + platform_device_register(&at91_lcdc_device); + } +diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/at91sam9263_devices.c avr32-2.6/arch/arm/mach-at91/at91sam9263_devices.c +--- linux-2.6.25.6/arch/arm/mach-at91/at91sam9263_devices.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/arm/mach-at91/at91sam9263_devices.c 2008-06-12 15:09:38.607815889 +0200 +@@ -353,20 +353,25 @@ + * -------------------------------------------------------------------- */ + + #if defined(CONFIG_MTD_NAND_AT91) || defined(CONFIG_MTD_NAND_AT91_MODULE) +-static struct at91_nand_data nand_data; ++static struct atmel_nand_data nand_data; + + #define NAND_BASE AT91_CHIPSELECT_3 + + static struct resource nand_resources[] = { +- { ++ [0] = { + .start = NAND_BASE, + .end = NAND_BASE + SZ_256M - 1, + .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91_BASE_SYS + AT91_ECC0, ++ .end = AT91_BASE_SYS + AT91_ECC0 + SZ_512 - 1, ++ .flags = IORESOURCE_MEM, + } + }; + + static struct platform_device at91sam9263_nand_device = { +- .name = "at91_nand", ++ .name = "atmel_nand", + .id = -1, + .dev = { + .platform_data = &nand_data, +@@ -375,7 +380,7 @@ + .num_resources = ARRAY_SIZE(nand_resources), + }; + +-void __init at91_add_device_nand(struct at91_nand_data *data) ++void __init at91_add_device_nand(struct atmel_nand_data *data) + { + unsigned long csa, mode; + +@@ -416,7 +421,7 @@ + platform_device_register(&at91sam9263_nand_device); + } + #else +-void __init at91_add_device_nand(struct at91_nand_data *data) {} ++void __init at91_add_device_nand(struct atmel_nand_data *data) {} + #endif + + +diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/at91sam9rl_devices.c avr32-2.6/arch/arm/mach-at91/at91sam9rl_devices.c +--- linux-2.6.25.6/arch/arm/mach-at91/at91sam9rl_devices.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/arm/mach-at91/at91sam9rl_devices.c 2008-06-12 15:09:38.607815889 +0200 +@@ -100,20 +100,25 @@ + * -------------------------------------------------------------------- */ + + #if defined(CONFIG_MTD_NAND_AT91) || defined(CONFIG_MTD_NAND_AT91_MODULE) +-static struct at91_nand_data nand_data; ++static struct atmel_nand_data nand_data; + + #define NAND_BASE AT91_CHIPSELECT_3 + + static struct resource nand_resources[] = { +- { ++ [0] = { + .start = NAND_BASE, + .end = NAND_BASE + SZ_256M - 1, + .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91_BASE_SYS + AT91_ECC, ++ .end = AT91_BASE_SYS + AT91_ECC + SZ_512 - 1, ++ .flags = IORESOURCE_MEM, + } + }; + +-static struct platform_device at91_nand_device = { +- .name = "at91_nand", ++static struct platform_device atmel_nand_device = { ++ .name = "atmel_nand", + .id = -1, + .dev = { + .platform_data = &nand_data, +@@ -122,7 +127,7 @@ + .num_resources = ARRAY_SIZE(nand_resources), + }; + +-void __init at91_add_device_nand(struct at91_nand_data *data) ++void __init at91_add_device_nand(struct atmel_nand_data *data) + { + unsigned long csa; + +@@ -159,11 +164,11 @@ + at91_set_A_periph(AT91_PIN_PB5, 0); /* NANDWE */ + + nand_data = *data; +- platform_device_register(&at91_nand_device); ++ platform_device_register(&atmel_nand_device); + } + + #else +-void __init at91_add_device_nand(struct at91_nand_data *data) {} ++void __init at91_add_device_nand(struct atmel_nand_data *data) {} + #endif + + +@@ -376,6 +381,20 @@ + at91_set_B_periph(AT91_PIN_PC24, 0); /* LCDD22 */ + at91_set_B_periph(AT91_PIN_PC25, 0); /* LCDD23 */ + ++#ifdef CONFIG_FB_INTSRAM ++ { ++ void __iomem *fb; ++ struct resource *fb_res = &lcdc_resources[2]; ++ size_t fb_len = fb_res->end - fb_res->start + 1; ++ ++ fb = ioremap_writecombine(fb_res->start, fb_len); ++ if (fb) { ++ memset(fb, 0, fb_len); ++ iounmap(fb, fb_len); ++ } ++ } ++#endif ++ + lcdc_data = *data; + platform_device_register(&at91_lcdc_device); + } +diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/board-cap9adk.c avr32-2.6/arch/arm/mach-at91/board-cap9adk.c +--- linux-2.6.25.6/arch/arm/mach-at91/board-cap9adk.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/arm/mach-at91/board-cap9adk.c 2008-06-12 15:09:38.607815889 +0200 +@@ -175,7 +175,7 @@ + return cap9adk_nand_partitions; + } + +-static struct at91_nand_data __initdata cap9adk_nand_data = { ++static struct atmel_nand_data __initdata cap9adk_nand_data = { + .ale = 21, + .cle = 22, + // .det_pin = ... not connected +diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/board-dk.c avr32-2.6/arch/arm/mach-at91/board-dk.c +--- linux-2.6.25.6/arch/arm/mach-at91/board-dk.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/arm/mach-at91/board-dk.c 2008-06-12 15:09:38.611815840 +0200 +@@ -151,7 +151,7 @@ + return dk_nand_partition; + } + +-static struct at91_nand_data __initdata dk_nand_data = { ++static struct atmel_nand_data __initdata dk_nand_data = { + .ale = 22, + .cle = 21, + .det_pin = AT91_PIN_PB1, +diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/board-kb9202.c avr32-2.6/arch/arm/mach-at91/board-kb9202.c +--- linux-2.6.25.6/arch/arm/mach-at91/board-kb9202.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/arm/mach-at91/board-kb9202.c 2008-06-12 15:09:38.611815840 +0200 +@@ -102,7 +102,7 @@ + return kb9202_nand_partition; + } + +-static struct at91_nand_data __initdata kb9202_nand_data = { ++static struct atmel_nand_data __initdata kb9202_nand_data = { + .ale = 22, + .cle = 21, + // .det_pin = ... not there +diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/board-sam9260ek.c avr32-2.6/arch/arm/mach-at91/board-sam9260ek.c +--- linux-2.6.25.6/arch/arm/mach-at91/board-sam9260ek.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/arm/mach-at91/board-sam9260ek.c 2008-06-12 15:09:38.611815840 +0200 +@@ -146,7 +146,7 @@ + return ek_nand_partition; + } + +-static struct at91_nand_data __initdata ek_nand_data = { ++static struct atmel_nand_data __initdata ek_nand_data = { + .ale = 21, + .cle = 22, + // .det_pin = ... not connected +diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/board-sam9261ek.c avr32-2.6/arch/arm/mach-at91/board-sam9261ek.c +--- linux-2.6.25.6/arch/arm/mach-at91/board-sam9261ek.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/arm/mach-at91/board-sam9261ek.c 2008-06-12 15:09:38.611815840 +0200 +@@ -189,7 +189,7 @@ + return ek_nand_partition; + } + +-static struct at91_nand_data __initdata ek_nand_data = { ++static struct atmel_nand_data __initdata ek_nand_data = { + .ale = 22, + .cle = 21, + // .det_pin = ... not connected +diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/board-sam9263ek.c avr32-2.6/arch/arm/mach-at91/board-sam9263ek.c +--- linux-2.6.25.6/arch/arm/mach-at91/board-sam9263ek.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/arm/mach-at91/board-sam9263ek.c 2008-06-12 15:09:38.611815840 +0200 +@@ -192,7 +192,7 @@ + return ek_nand_partition; + } + +-static struct at91_nand_data __initdata ek_nand_data = { ++static struct atmel_nand_data __initdata ek_nand_data = { + .ale = 21, + .cle = 22, + // .det_pin = ... not connected +diff --exclude=.git -urN linux-2.6.25.6/arch/arm/mach-at91/board-sam9rlek.c avr32-2.6/arch/arm/mach-at91/board-sam9rlek.c +--- linux-2.6.25.6/arch/arm/mach-at91/board-sam9rlek.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/arm/mach-at91/board-sam9rlek.c 2008-06-12 15:09:38.611815840 +0200 +@@ -93,7 +93,7 @@ + return ek_nand_partition; + } + +-static struct at91_nand_data __initdata ek_nand_data = { ++static struct atmel_nand_data __initdata ek_nand_data = { + .ale = 21, + .cle = 22, + // .det_pin = ... not connected +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/boards/atngw100/Kconfig avr32-2.6/arch/avr32/boards/atngw100/Kconfig +--- linux-2.6.25.6/arch/avr32/boards/atngw100/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/arch/avr32/boards/atngw100/Kconfig 2008-06-12 15:09:38.711815728 +0200 @@ -0,0 +1,12 @@ +# NGW100 customization + @@ -13,18 +431,24 @@ + + Choose 'Y' here if you're having i2c-related problems and + want to rule out the i2c bus driver. ---- a/arch/avr32/boards/atngw100/setup.c -+++ b/arch/avr32/boards/atngw100/setup.c -@@ -20,7 +20,7 @@ - #include <asm/io.h> - #include <asm/setup.h> - --#include <asm/arch/at32ap7000.h> -+#include <asm/arch/at32ap700x.h> - #include <asm/arch/board.h> +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/boards/atngw100/setup.c avr32-2.6/arch/avr32/boards/atngw100/setup.c +--- linux-2.6.25.6/arch/avr32/boards/atngw100/setup.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/boards/atngw100/setup.c 2008-06-12 15:09:38.711815728 +0200 +@@ -25,6 +25,13 @@ #include <asm/arch/init.h> #include <asm/arch/portmux.h> -@@ -37,11 +37,16 @@ + ++/* Oscillator frequencies. These are board-specific */ ++unsigned long at32_board_osc_rates[3] = { ++ [0] = 32768, /* 32.768 kHz on RTC osc */ ++ [1] = 20000000, /* 20 MHz on osc0 */ ++ [2] = 12000000, /* 12 MHz on osc1 */ ++}; ++ + /* Initialized by bootloader-specific startup code. */ + struct tag *bootloader_tags __initdata; + +@@ -37,11 +44,16 @@ static struct spi_board_info spi0_board_info[] __initdata = { { .modalias = "mtd_dataflash", @@ -42,7 +466,7 @@ /* * The next two functions should go away as the boot loader is * supposed to initialize the macb address registers with a valid -@@ -124,6 +129,7 @@ +@@ -124,6 +136,7 @@ } }; @@ -50,7 +474,7 @@ static struct i2c_gpio_platform_data i2c_gpio_data = { .sda_pin = GPIO_PIN_PA(6), .scl_pin = GPIO_PIN_PA(7), -@@ -139,6 +145,7 @@ +@@ -139,6 +152,7 @@ .platform_data = &i2c_gpio_data, }, }; @@ -58,7 +482,7 @@ static int __init atngw100_init(void) { -@@ -157,6 +164,7 @@ +@@ -157,6 +171,7 @@ set_hw_addr(at32_add_device_eth(1, ð_data[1])); at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info)); @@ -66,7 +490,7 @@ at32_add_device_usba(0, NULL); for (i = 0; i < ARRAY_SIZE(ngw_leds); i++) { -@@ -165,11 +173,15 @@ +@@ -165,11 +180,15 @@ } platform_device_register(&ngw_gpio_leds); @@ -82,64 +506,101 @@ return 0; } ---- a/arch/avr32/boards/atstk1000/atstk1000.h -+++ b/arch/avr32/boards/atstk1000/atstk1000.h -@@ -12,4 +12,6 @@ +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/boards/atstk1000/atstk1002.c avr32-2.6/arch/avr32/boards/atstk1000/atstk1002.c +--- linux-2.6.25.6/arch/avr32/boards/atstk1000/atstk1002.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/boards/atstk1000/atstk1002.c 2008-06-12 15:09:38.711815728 +0200 +@@ -1,7 +1,7 @@ + /* +- * ATSTK1002 daughterboard-specific init code ++ * ATSTK1002/ATSTK1006 daughterboard-specific init code + * +- * Copyright (C) 2005-2006 Atmel Corporation ++ * Copyright (C) 2005-2007 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as +@@ -28,6 +28,80 @@ - extern struct atmel_lcdfb_info atstk1000_lcdc_data; + #include "atstk1000.h" -+void atstk1000_setup_j2_leds(void); ++/* Oscillator frequencies. These are board specific */ ++unsigned long at32_board_osc_rates[3] = { ++ [0] = 32768, /* 32.768 kHz on RTC osc */ ++ [1] = 20000000, /* 20 MHz on osc0 */ ++ [2] = 12000000, /* 12 MHz on osc1 */ ++}; + - #endif /* __ARCH_AVR32_BOARDS_ATSTK1000_ATSTK1000_H */ ---- a/arch/avr32/boards/atstk1000/atstk1002.c -+++ b/arch/avr32/boards/atstk1000/atstk1002.c -@@ -11,7 +11,6 @@ - #include <linux/etherdevice.h> - #include <linux/init.h> - #include <linux/kernel.h> --#include <linux/leds.h> - #include <linux/platform_device.h> - #include <linux/string.h> - #include <linux/types.h> -@@ -22,7 +21,7 @@ - - #include <asm/io.h> - #include <asm/setup.h> --#include <asm/arch/at32ap7000.h> -+#include <asm/arch/at32ap700x.h> - #include <asm/arch/board.h> - #include <asm/arch/init.h> - #include <asm/arch/portmux.h> -@@ -49,18 +48,16 @@ - }, - }; - --#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM --#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM -+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC - static struct at73c213_board_info at73c213_data = { - .ssc_id = 0, - .shortname = "AVR32 STK1000 external DAC", - }; - #endif --#endif - --#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM -+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM - static struct spi_board_info spi0_board_info[] __initdata = { --#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM -+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC - { - /* AT73C213 */ - .modalias = "at73c213", -@@ -80,12 +77,25 @@ - }; - #endif ++/* ++ * The ATSTK1006 daughterboard is very similar to the ATSTK1002. Both ++ * have the AT32AP7000 chip on board; the difference is that the ++ * STK1006 has 128 MB SDRAM (the STK1002 uses the 8 MB SDRAM chip on ++ * the STK1000 motherboard) and 256 MB NAND flash (the STK1002 has ++ * none.) ++ * ++ * The RAM difference is handled by the boot loader, so the only ++ * difference we end up handling here is the NAND flash. ++ */ ++#ifdef CONFIG_BOARD_ATSTK1006 ++#include <linux/mtd/partitions.h> ++#include <asm/arch/smc.h> ++ ++static struct smc_timing nand_timing __initdata = { ++ .ncs_read_setup = 0, ++ .nrd_setup = 10, ++ .ncs_write_setup = 0, ++ .nwe_setup = 10, ++ ++ .ncs_read_pulse = 30, ++ .nrd_pulse = 15, ++ .ncs_write_pulse = 30, ++ .nwe_pulse = 15, ++ ++ .read_cycle = 30, ++ .write_cycle = 30, ++ ++ .ncs_read_recover = 0, ++ .nrd_recover = 15, ++ .ncs_write_recover = 0, ++ /* WE# high -> RE# low min 60 ns */ ++ .nwe_recover = 50, ++}; ++ ++static struct smc_config nand_config __initdata = { ++ .bus_width = 1, ++ .nrd_controlled = 1, ++ .nwe_controlled = 1, ++ .nwait_mode = 0, ++ .byte_write = 0, ++ .tdf_cycles = 2, ++ .tdf_mode = 0, ++}; ++ ++static struct mtd_partition nand_partitions[] = { ++ { ++ .name = "main", ++ .offset = 0x00000000, ++ .size = MTDPART_SIZ_FULL, ++ }, ++}; ++ ++static struct mtd_partition *nand_part_info(int size, int *num_partitions) ++{ ++ *num_partitions = ARRAY_SIZE(nand_partitions); ++ return nand_partitions; ++} ++ ++static struct atmel_nand_data atstk1006_nand_data __initdata = { ++ .cle = 21, ++ .ale = 22, ++ .rdy_pin = GPIO_PIN_PB(30), ++ .enable_pin = GPIO_PIN_PB(29), ++ .partition_info = nand_part_info, ++}; ++#endif --#ifdef CONFIG_BOARD_ATSTK1002_SPI1 -+#ifdef CONFIG_BOARD_ATSTK100X_SPI1 - static struct spi_board_info spi1_board_info[] __initdata = { { - /* patch in custom entries here */ + struct eth_addr { + u8 addr[6]; +@@ -83,6 +157,19 @@ } }; #endif @@ -159,125 +620,21 @@ /* * The next two functions should go away as the boot loader is * supposed to initialize the macb address registers with a valid -@@ -141,68 +151,8 @@ - clk_put(pclk); - } - --#ifdef CONFIG_BOARD_ATSTK1002_J2_LED -- --static struct gpio_led stk_j2_led[] = { --#ifdef CONFIG_BOARD_ATSTK1002_J2_LED8 --#define LEDSTRING "J2 jumpered to LED8" -- { .name = "led0:amber", .gpio = GPIO_PIN_PB( 8), }, -- { .name = "led1:amber", .gpio = GPIO_PIN_PB( 9), }, -- { .name = "led2:amber", .gpio = GPIO_PIN_PB(10), }, -- { .name = "led3:amber", .gpio = GPIO_PIN_PB(13), }, -- { .name = "led4:amber", .gpio = GPIO_PIN_PB(14), }, -- { .name = "led5:amber", .gpio = GPIO_PIN_PB(15), }, -- { .name = "led6:amber", .gpio = GPIO_PIN_PB(16), }, -- { .name = "led7:amber", .gpio = GPIO_PIN_PB(30), -- .default_trigger = "heartbeat", }, --#else /* RGB */ --#define LEDSTRING "J2 jumpered to RGB LEDs" -- { .name = "r1:red", .gpio = GPIO_PIN_PB( 8), }, -- { .name = "g1:green", .gpio = GPIO_PIN_PB(10), }, -- { .name = "b1:blue", .gpio = GPIO_PIN_PB(14), }, -- -- { .name = "r2:red", .gpio = GPIO_PIN_PB( 9), -- .default_trigger = "heartbeat", }, -- { .name = "g2:green", .gpio = GPIO_PIN_PB(13), }, -- { .name = "b2:blue", .gpio = GPIO_PIN_PB(15), -- .default_trigger = "heartbeat", }, -- /* PB16, PB30 unused */ --#endif --}; -- --static struct gpio_led_platform_data stk_j2_led_data = { -- .num_leds = ARRAY_SIZE(stk_j2_led), -- .leds = stk_j2_led, --}; -- --static struct platform_device stk_j2_led_dev = { -- .name = "leds-gpio", -- .id = 2, /* gpio block J2 */ -- .dev = { -- .platform_data = &stk_j2_led_data, -- }, --}; -- --static void setup_j2_leds(void) --{ -- unsigned i; -- -- for (i = 0; i < ARRAY_SIZE(stk_j2_led); i++) -- at32_select_gpio(stk_j2_led[i].gpio, AT32_GPIOF_OUTPUT); -- -- printk("STK1002: " LEDSTRING "\n"); -- platform_device_register(&stk_j2_led_dev); --} -- --#else --static void setup_j2_leds(void) --{ --} --#endif -- --#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM --#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM --static void __init at73c213_set_clk(struct at73c213_board_info *info) -+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC -+static void __init atstk1002_setup_extdac(void) - { - struct clk *gclk; - struct clk *pll; -@@ -220,7 +170,7 @@ - } - - at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0); -- info->dac_clk = gclk; -+ at73c213_data.dac_clk = gclk; - - err_set_clk: - clk_put(pll); -@@ -229,12 +179,16 @@ - err_gclk: - return; - } --#endif --#endif -+#else -+static void __init atstk1002_setup_extdac(void) -+{ -+ -+} -+#endif /* CONFIG_BOARD_ATSTK1000_EXTDAC */ - - void __init setup_board(void) - { --#ifdef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM -+#ifdef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM - at32_map_usart(0, 1); /* USART 0/B: /dev/ttyS1, IRDA */ - #else - at32_map_usart(1, 0); /* USART 1/A: /dev/ttyS0, DB9 */ -@@ -271,7 +225,7 @@ +@@ -212,6 +299,12 @@ at32_add_system_devices(); --#ifdef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM -+#ifdef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM ++#ifdef CONFIG_BOARD_ATSTK1006 ++ smc_set_timing(&nand_config, &nand_timing); ++ smc_set_configuration(3, &nand_config); ++ at32_add_device_nand(0, &atstk1006_nand_data); ++#endif ++ + #ifdef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM at32_add_device_usart(1); #else - at32_add_device_usart(0); -@@ -281,12 +235,16 @@ - #ifndef CONFIG_BOARD_ATSTK1002_SW6_CUSTOM - set_hw_addr(at32_add_device_eth(0, ð_data[0])); - #endif --#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM -+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM - at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info)); - #endif --#ifdef CONFIG_BOARD_ATSTK1002_SPI1 -+#ifdef CONFIG_BOARD_ATSTK100X_SPI1 +@@ -228,16 +321,30 @@ + #ifdef CONFIG_BOARD_ATSTK100X_SPI1 at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info)); #endif + at32_add_device_twi(0, NULL, 0); @@ -287,102 +644,48 @@ #ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM set_hw_addr(at32_add_device_eth(1, ð_data[1])); #else -@@ -294,18 +252,23 @@ - fbmem_start, fbmem_size); + at32_add_device_lcdc(0, &atstk1000_lcdc_data, +- fbmem_start, fbmem_size); ++ fbmem_start, fbmem_size, 0); #endif at32_add_device_usba(0, NULL); --#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM -- at32_add_device_ssc(0, ATMEL_SSC_TX); +#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_AC97 + at32_add_device_ac97c(0); +#else + at32_add_device_abdac(0); - #endif -- -- setup_j2_leds(); -- --#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM --#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM -- at73c213_set_clk(&at73c213_data); -+#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM -+ at32_add_device_ssc(0, ATMEL_SSC_TX); ++#endif + #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM + at32_add_device_ssc(0, ATMEL_SSC_TX); #endif + at32_add_device_cf(0, 2, &cf0_data); +#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_PSIF + at32_add_device_psif(0); + at32_add_device_psif(1); - #endif - -+ atstk1000_setup_j2_leds(); -+ atstk1002_setup_extdac(); -+ - return 0; - } - postcore_initcall(atstk1002_init); ---- /dev/null -+++ b/arch/avr32/boards/atstk1000/atstk1003.c -@@ -0,0 +1,185 @@ -+/* -+ * ATSTK1003 daughterboard-specific init code -+ * -+ * Copyright (C) 2007 Atmel Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#include <linux/clk.h> -+#include <linux/err.h> -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/platform_device.h> -+#include <linux/string.h> -+#include <linux/types.h> -+ -+#include <linux/spi/at73c213.h> -+#include <linux/spi/spi.h> -+ -+#include <asm/setup.h> -+ -+#include <asm/arch/at32ap700x.h> -+#include <asm/arch/board.h> -+#include <asm/arch/init.h> -+#include <asm/arch/portmux.h> -+ -+#include "atstk1000.h" -+ -+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC -+static struct at73c213_board_info at73c213_data = { -+ .ssc_id = 0, -+ .shortname = "AVR32 STK1000 external DAC", -+}; -+#endif -+ -+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM -+static struct spi_board_info spi0_board_info[] __initdata = { -+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC -+ { -+ /* AT73C213 */ -+ .modalias = "at73c213", -+ .max_speed_hz = 200000, -+ .chip_select = 0, -+ .mode = SPI_MODE_1, -+ .platform_data = &at73c213_data, -+ }, +#endif -+ /* -+ * We can control the LTV350QV LCD panel, but it isn't much -+ * point since we don't have an LCD controller... -+ */ + + atstk1000_setup_j2_leds(); + atstk1002_setup_extdac(); +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/boards/atstk1000/atstk1003.c avr32-2.6/arch/avr32/boards/atstk1000/atstk1003.c +--- linux-2.6.25.6/arch/avr32/boards/atstk1000/atstk1003.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/boards/atstk1000/atstk1003.c 2008-06-12 15:09:38.711815728 +0200 +@@ -27,6 +27,13 @@ + + #include "atstk1000.h" + ++/* Oscillator frequencies. These are board specific */ ++unsigned long at32_board_osc_rates[3] = { ++ [0] = 32768, /* 32.768 kHz on RTC osc */ ++ [1] = 20000000, /* 20 MHz on osc0 */ ++ [2] = 12000000, /* 12 MHz on osc1 */ +}; -+#endif -+ -+#ifdef CONFIG_BOARD_ATSTK100X_SPI1 -+static struct spi_board_info spi1_board_info[] __initdata = { { -+ /* patch in custom entries here */ -+} }; -+#endif + + #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC + static struct at73c213_board_info at73c213_data = { + .ssc_id = 0, +@@ -59,6 +66,19 @@ + } }; + #endif + +static struct cf_platform_data __initdata cf0_data = { +#ifdef CONFIG_BOARD_ATSTK1000_CF_HACKS + .detect_pin = CONFIG_BOARD_ATSTK1000_CF_DETECT_PIN, @@ -396,399 +699,94 @@ + .cs = 4, +}; + -+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC -+static void __init atstk1003_setup_extdac(void) -+{ -+ struct clk *gclk; -+ struct clk *pll; -+ -+ gclk = clk_get(NULL, "gclk0"); -+ if (IS_ERR(gclk)) -+ goto err_gclk; -+ pll = clk_get(NULL, "pll0"); -+ if (IS_ERR(pll)) -+ goto err_pll; -+ -+ if (clk_set_parent(gclk, pll)) { -+ pr_debug("STK1000: failed to set pll0 as parent for DAC clock\n"); -+ goto err_set_clk; -+ } -+ -+ at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0); -+ at73c213_data.dac_clk = gclk; -+ -+err_set_clk: -+ clk_put(pll); -+err_pll: -+ clk_put(gclk); -+err_gclk: -+ return; -+} -+#else -+static void __init atstk1003_setup_extdac(void) -+{ -+ -+} -+#endif /* CONFIG_BOARD_ATSTK1000_EXTDAC */ -+ -+void __init setup_board(void) -+{ -+#ifdef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM -+ at32_map_usart(0, 1); /* USART 0/B: /dev/ttyS1, IRDA */ -+#else -+ at32_map_usart(1, 0); /* USART 1/A: /dev/ttyS0, DB9 */ -+#endif -+ /* USART 2/unused: expansion connector */ -+ at32_map_usart(3, 2); /* USART 3/C: /dev/ttyS2, DB9 */ -+ -+ at32_setup_serial_console(0); -+} -+ -+static int __init atstk1003_init(void) -+{ -+ /* -+ * ATSTK1000 uses 32-bit SDRAM interface. Reserve the -+ * SDRAM-specific pins so that nobody messes with them. -+ */ -+ at32_reserve_pin(GPIO_PIN_PE(0)); /* DATA[16] */ -+ at32_reserve_pin(GPIO_PIN_PE(1)); /* DATA[17] */ -+ at32_reserve_pin(GPIO_PIN_PE(2)); /* DATA[18] */ -+ at32_reserve_pin(GPIO_PIN_PE(3)); /* DATA[19] */ -+ at32_reserve_pin(GPIO_PIN_PE(4)); /* DATA[20] */ -+ at32_reserve_pin(GPIO_PIN_PE(5)); /* DATA[21] */ -+ at32_reserve_pin(GPIO_PIN_PE(6)); /* DATA[22] */ -+ at32_reserve_pin(GPIO_PIN_PE(7)); /* DATA[23] */ -+ at32_reserve_pin(GPIO_PIN_PE(8)); /* DATA[24] */ -+ at32_reserve_pin(GPIO_PIN_PE(9)); /* DATA[25] */ -+ at32_reserve_pin(GPIO_PIN_PE(10)); /* DATA[26] */ -+ at32_reserve_pin(GPIO_PIN_PE(11)); /* DATA[27] */ -+ at32_reserve_pin(GPIO_PIN_PE(12)); /* DATA[28] */ -+ at32_reserve_pin(GPIO_PIN_PE(13)); /* DATA[29] */ -+ at32_reserve_pin(GPIO_PIN_PE(14)); /* DATA[30] */ -+ at32_reserve_pin(GPIO_PIN_PE(15)); /* DATA[31] */ -+ at32_reserve_pin(GPIO_PIN_PE(26)); /* SDCS */ -+ -+ at32_add_system_devices(); -+ -+#ifdef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM -+ at32_add_device_usart(1); -+#else -+ at32_add_device_usart(0); -+#endif -+ at32_add_device_usart(2); -+ -+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM -+ at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info)); -+#endif -+#ifdef CONFIG_BOARD_ATSTK100X_SPI1 -+ at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info)); -+#endif -+#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM + #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC + static void __init atstk1003_setup_extdac(void) + { +@@ -147,12 +167,22 @@ + at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info)); + #endif + #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM +- at32_add_device_mci(0); + at32_add_device_mci(0, NULL); -+#endif -+ at32_add_device_usba(0, NULL); + #endif + at32_add_device_usba(0, NULL); +#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_AC97 + at32_add_device_ac97c(0); +#else + at32_add_device_abdac(0); +#endif -+#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM -+ at32_add_device_ssc(0, ATMEL_SSC_TX); -+#endif + #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM + at32_add_device_ssc(0, ATMEL_SSC_TX); + #endif + at32_add_device_cf(0, 2, &cf0_data); +#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_PSIF + at32_add_device_psif(0); + at32_add_device_psif(1); +#endif -+ -+ atstk1000_setup_j2_leds(); -+ atstk1003_setup_extdac(); -+ -+ return 0; -+} -+postcore_initcall(atstk1003_init); ---- /dev/null -+++ b/arch/avr32/boards/atstk1000/atstk1004.c -@@ -0,0 +1,156 @@ -+/* -+ * ATSTK1003 daughterboard-specific init code -+ * -+ * Copyright (C) 2007 Atmel Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#include <linux/clk.h> -+#include <linux/err.h> -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/platform_device.h> -+#include <linux/string.h> -+#include <linux/types.h> -+ -+#include <linux/spi/at73c213.h> -+#include <linux/spi/spi.h> -+ -+#include <video/atmel_lcdc.h> -+ -+#include <asm/setup.h> -+ -+#include <asm/arch/at32ap700x.h> -+#include <asm/arch/board.h> -+#include <asm/arch/init.h> -+#include <asm/arch/portmux.h> -+ -+#include "atstk1000.h" -+ -+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC -+static struct at73c213_board_info at73c213_data = { -+ .ssc_id = 0, -+ .shortname = "AVR32 STK1000 external DAC", -+}; -+#endif -+ -+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM -+static struct spi_board_info spi0_board_info[] __initdata = { -+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC -+ { -+ /* AT73C213 */ -+ .modalias = "at73c213", -+ .max_speed_hz = 200000, -+ .chip_select = 0, -+ .mode = SPI_MODE_1, -+ .platform_data = &at73c213_data, -+ }, -+#endif -+ { -+ /* QVGA display */ -+ .modalias = "ltv350qv", -+ .max_speed_hz = 16000000, -+ .chip_select = 1, -+ .mode = SPI_MODE_3, -+ }, + + atstk1000_setup_j2_leds(); + atstk1003_setup_extdac(); +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/boards/atstk1000/atstk1004.c avr32-2.6/arch/avr32/boards/atstk1000/atstk1004.c +--- linux-2.6.25.6/arch/avr32/boards/atstk1000/atstk1004.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/boards/atstk1000/atstk1004.c 2008-06-12 15:09:38.715815679 +0200 +@@ -29,6 +29,13 @@ + + #include "atstk1000.h" + ++/* Oscillator frequencies. These are board specific */ ++unsigned long at32_board_osc_rates[3] = { ++ [0] = 32768, /* 32.768 kHz on RTC osc */ ++ [1] = 20000000, /* 20 MHz on osc0 */ ++ [2] = 12000000, /* 12 MHz on osc1 */ +}; -+#endif -+ -+#ifdef CONFIG_BOARD_ATSTK100X_SPI1 -+static struct spi_board_info spi1_board_info[] __initdata = { { -+ /* patch in custom entries here */ -+} }; -+#endif -+ -+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC -+static void __init atstk1004_setup_extdac(void) -+{ -+ struct clk *gclk; -+ struct clk *pll; -+ -+ gclk = clk_get(NULL, "gclk0"); -+ if (IS_ERR(gclk)) -+ goto err_gclk; -+ pll = clk_get(NULL, "pll0"); -+ if (IS_ERR(pll)) -+ goto err_pll; -+ -+ if (clk_set_parent(gclk, pll)) { -+ pr_debug("STK1000: failed to set pll0 as parent for DAC clock\n"); -+ goto err_set_clk; -+ } -+ -+ at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0); -+ at73c213_data.dac_clk = gclk; -+ -+err_set_clk: -+ clk_put(pll); -+err_pll: -+ clk_put(gclk); -+err_gclk: -+ return; -+} -+#else -+static void __init atstk1004_setup_extdac(void) -+{ -+ -+} -+#endif /* CONFIG_BOARD_ATSTK1000_EXTDAC */ + -+void __init setup_board(void) -+{ -+#ifdef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM -+ at32_map_usart(0, 1); /* USART 0/B: /dev/ttyS1, IRDA */ -+#else -+ at32_map_usart(1, 0); /* USART 1/A: /dev/ttyS0, DB9 */ -+#endif -+ /* USART 2/unused: expansion connector */ -+ at32_map_usart(3, 2); /* USART 3/C: /dev/ttyS2, DB9 */ -+ -+ at32_setup_serial_console(0); -+} -+ -+static int __init atstk1004_init(void) -+{ -+ at32_add_system_devices(); -+ -+#ifdef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM -+ at32_add_device_usart(1); -+#else -+ at32_add_device_usart(0); -+#endif -+ at32_add_device_usart(2); -+ -+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM -+ at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info)); -+#endif -+#ifdef CONFIG_BOARD_ATSTK100X_SPI1 -+ at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info)); -+#endif -+#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM + #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC + static struct at73c213_board_info at73c213_data = { + .ssc_id = 0, +@@ -130,14 +137,23 @@ + at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info)); + #endif + #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM +- at32_add_device_mci(0); + at32_add_device_mci(0, NULL); -+#endif -+ at32_add_device_lcdc(0, &atstk1000_lcdc_data, -+ fbmem_start, fbmem_size); -+ at32_add_device_usba(0, NULL); + #endif + at32_add_device_lcdc(0, &atstk1000_lcdc_data, +- fbmem_start, fbmem_size); ++ fbmem_start, fbmem_size, 0); + at32_add_device_usba(0, NULL); +#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_AC97 + at32_add_device_ac97c(0); +#else + at32_add_device_abdac(0); +#endif -+#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM -+ at32_add_device_ssc(0, ATMEL_SSC_TX); -+#endif + #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM + at32_add_device_ssc(0, ATMEL_SSC_TX); + #endif +#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_PSIF + at32_add_device_psif(0); + at32_add_device_psif(1); +#endif -+ -+ atstk1000_setup_j2_leds(); -+ atstk1004_setup_extdac(); -+ -+ return 0; -+} -+postcore_initcall(atstk1004_init); ---- a/arch/avr32/boards/atstk1000/Kconfig -+++ b/arch/avr32/boards/atstk1000/Kconfig -@@ -1,34 +1,53 @@ - # STK1000 customization - --if BOARD_ATSTK1002 -+if BOARD_ATSTK1000 --config BOARD_ATSTK1002_CUSTOM -- bool "Non-default STK-1002 jumper settings" -+choice -+ prompt "ATSTK1000 CPU daughterboard type" -+ default BOARD_ATSTK1002 -+ -+config BOARD_ATSTK1002 -+ bool "ATSTK1002" + atstk1000_setup_j2_leds(); + atstk1004_setup_extdac(); +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/boards/atstk1000/Kconfig avr32-2.6/arch/avr32/boards/atstk1000/Kconfig +--- linux-2.6.25.6/arch/avr32/boards/atstk1000/Kconfig 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/boards/atstk1000/Kconfig 2008-06-12 15:09:38.711815728 +0200 +@@ -18,6 +18,10 @@ + bool "ATSTK1004" + select CPU_AT32AP7002 + ++config BOARD_ATSTK1006 ++ bool "ATSTK1006" + select CPU_AT32AP7000 + -+config BOARD_ATSTK1003 -+ bool "ATSTK1003" -+ select CPU_AT32AP7001 -+ -+config BOARD_ATSTK1004 -+ bool "ATSTK1004" -+ select CPU_AT32AP7002 -+ -+endchoice -+ -+ -+config BOARD_ATSTK100X_CUSTOM -+ bool "Non-default STK1002/STK1003/STK1004 jumper settings" - help - You will normally leave the jumpers on the CPU card at their - default settings. If you need to use certain peripherals, - you will need to change some of those jumpers. - --if BOARD_ATSTK1002_CUSTOM -+if BOARD_ATSTK100X_CUSTOM - --config BOARD_ATSTK1002_SW1_CUSTOM -+config BOARD_ATSTK100X_SW1_CUSTOM - bool "SW1: use SSC1 (not SPI0)" - help - This also prevents using the external DAC as an audio interface, - and means you can't initialize the on-board QVGA display. - --config BOARD_ATSTK1002_SW2_CUSTOM -+config BOARD_ATSTK100X_SW2_CUSTOM - bool "SW2: use IRDA or TIMER0 (not UART-A, MMC/SD, and PS2-A)" - help - If you change this you'll want an updated boot loader putting - the console on UART-C not UART-A. - --config BOARD_ATSTK1002_SW3_CUSTOM -+config BOARD_ATSTK100X_SW3_CUSTOM - bool "SW3: use TIMER1 (not SSC0 and GCLK)" - help - This also prevents using the external DAC as an audio interface. - --config BOARD_ATSTK1002_SW4_CUSTOM -+config BOARD_ATSTK100X_SW4_CUSTOM - bool "SW4: use ISI/Camera (not GPIOs, SPI1, and PS2-B)" - help - To use the camera interface you'll need a custom card (on the -@@ -36,27 +55,29 @@ - - config BOARD_ATSTK1002_SW5_CUSTOM - bool "SW5: use MACB1 (not LCDC)" -+ depends on BOARD_ATSTK1002 - - config BOARD_ATSTK1002_SW6_CUSTOM - bool "SW6: more GPIOs (not MACB0)" -+ depends on BOARD_ATSTK1002 - - endif # custom - --config BOARD_ATSTK1002_SPI1 -+config BOARD_ATSTK100X_SPI1 - bool "Configure SPI1 controller" -- depends on !BOARD_ATSTK1002_SW4_CUSTOM -+ depends on !BOARD_ATSTK100X_SW4_CUSTOM - help - All the signals for the second SPI controller are available on - GPIO lines and accessed through the J1 jumper block. Say "y" - here to configure that SPI controller. - --config BOARD_ATSTK1002_J2_LED -+config BOARD_ATSTK1000_J2_LED - bool -- default BOARD_ATSTK1002_J2_LED8 || BOARD_ATSTK1002_J2_RGB -+ default BOARD_ATSTK1000_J2_LED8 || BOARD_ATSTK1000_J2_RGB - - choice - prompt "LEDs connected to J2:" -- depends on LEDS_GPIO && !BOARD_ATSTK1002_SW4_CUSTOM -+ depends on LEDS_GPIO && !BOARD_ATSTK100X_SW4_CUSTOM - optional - help - Select this if you have jumpered the J2 jumper block to the -@@ -64,16 +85,77 @@ - IDC cable. A default "heartbeat" trigger is provided, but - you can of course override this. - --config BOARD_ATSTK1002_J2_LED8 -+config BOARD_ATSTK1000_J2_LED8 - bool "LED0..LED7" - help - Select this if J2 is jumpered to LED0..LED7 amber leds. + endchoice --config BOARD_ATSTK1002_J2_RGB -+config BOARD_ATSTK1000_J2_RGB - bool "RGB leds" - help - Select this if J2 is jumpered to the RGB leds. - endchoice +@@ -102,4 +106,60 @@ + depends on !BOARD_ATSTK100X_SW1_CUSTOM && !BOARD_ATSTK100X_SW3_CUSTOM + default y --endif # stk 1002 -+config BOARD_ATSTK1000_EXTDAC -+ bool -+ depends on !BOARD_ATSTK100X_SW1_CUSTOM && !BOARD_ATSTK100X_SW3_CUSTOM -+ default y -+ +config BOARD_ATSTK100X_ENABLE_AC97 + bool "Use AC97C instead of ABDAC" + help @@ -845,203 +843,97 @@ + Y if you have level convertion hardware or a PS/2 device capable of + operating on 3.3 volt. + -+endif # stk 1000 ---- a/arch/avr32/boards/atstk1000/Makefile -+++ b/arch/avr32/boards/atstk1000/Makefile -@@ -1,2 +1,4 @@ - obj-y += setup.o flash.o + endif # stk 1000 +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/boards/atstk1000/Makefile avr32-2.6/arch/avr32/boards/atstk1000/Makefile +--- linux-2.6.25.6/arch/avr32/boards/atstk1000/Makefile 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/boards/atstk1000/Makefile 2008-06-12 15:09:38.711815728 +0200 +@@ -2,3 +2,4 @@ obj-$(CONFIG_BOARD_ATSTK1002) += atstk1002.o -+obj-$(CONFIG_BOARD_ATSTK1003) += atstk1003.o -+obj-$(CONFIG_BOARD_ATSTK1004) += atstk1004.o ---- a/arch/avr32/boards/atstk1000/setup.c -+++ b/arch/avr32/boards/atstk1000/setup.c -@@ -10,13 +10,17 @@ - #include <linux/bootmem.h> - #include <linux/fb.h> - #include <linux/init.h> -+#include <linux/platform_device.h> - #include <linux/types.h> - #include <linux/linkage.h> - - #include <video/atmel_lcdc.h> - - #include <asm/setup.h> -+ -+#include <asm/arch/at32ap700x.h> - #include <asm/arch/board.h> -+#include <asm/arch/portmux.h> - - #include "atstk1000.h" - -@@ -61,3 +65,63 @@ - .default_monspecs = &atstk1000_default_monspecs, - .guard_time = 2, - }; -+ -+#ifdef CONFIG_BOARD_ATSTK1000_J2_LED -+#include <linux/leds.h> -+ -+static struct gpio_led stk1000_j2_led[] = { -+#ifdef CONFIG_BOARD_ATSTK1000_J2_LED8 -+#define LEDSTRING "J2 jumpered to LED8" -+ { .name = "led0:amber", .gpio = GPIO_PIN_PB( 8), }, -+ { .name = "led1:amber", .gpio = GPIO_PIN_PB( 9), }, -+ { .name = "led2:amber", .gpio = GPIO_PIN_PB(10), }, -+ { .name = "led3:amber", .gpio = GPIO_PIN_PB(13), }, -+ { .name = "led4:amber", .gpio = GPIO_PIN_PB(14), }, -+ { .name = "led5:amber", .gpio = GPIO_PIN_PB(15), }, -+ { .name = "led6:amber", .gpio = GPIO_PIN_PB(16), }, -+ { .name = "led7:amber", .gpio = GPIO_PIN_PB(30), -+ .default_trigger = "heartbeat", }, -+#else /* RGB */ -+#define LEDSTRING "J2 jumpered to RGB LEDs" -+ { .name = "r1:red", .gpio = GPIO_PIN_PB( 8), }, -+ { .name = "g1:green", .gpio = GPIO_PIN_PB(10), }, -+ { .name = "b1:blue", .gpio = GPIO_PIN_PB(14), }, -+ -+ { .name = "r2:red", .gpio = GPIO_PIN_PB( 9), -+ .default_trigger = "heartbeat", }, -+ { .name = "g2:green", .gpio = GPIO_PIN_PB(13), }, -+ { .name = "b2:blue", .gpio = GPIO_PIN_PB(15), -+ .default_trigger = "heartbeat", }, -+ /* PB16, PB30 unused */ -+#endif -+}; -+ -+static struct gpio_led_platform_data stk1000_j2_led_data = { -+ .num_leds = ARRAY_SIZE(stk1000_j2_led), -+ .leds = stk1000_j2_led, -+}; -+ -+static struct platform_device stk1000_j2_led_dev = { -+ .name = "leds-gpio", -+ .id = 2, /* gpio block J2 */ -+ .dev = { -+ .platform_data = &stk1000_j2_led_data, -+ }, -+}; -+ -+void __init atstk1000_setup_j2_leds(void) -+{ -+ unsigned i; -+ -+ for (i = 0; i < ARRAY_SIZE(stk1000_j2_led); i++) -+ at32_select_gpio(stk1000_j2_led[i].gpio, AT32_GPIOF_OUTPUT); -+ -+ printk("STK1000: " LEDSTRING "\n"); -+ platform_device_register(&stk1000_j2_led_dev); -+} -+#else /* CONFIG_BOARD_ATSTK1000_J2_LED */ -+void __init atstk1000_setup_j2_leds(void) -+{ -+ -+} -+#endif /* CONFIG_BOARD_ATSTK1000_J2_LED */ ---- a/arch/avr32/configs/atngw100_defconfig -+++ b/arch/avr32/configs/atngw100_defconfig -@@ -1,46 +1,52 @@ + obj-$(CONFIG_BOARD_ATSTK1003) += atstk1003.o + obj-$(CONFIG_BOARD_ATSTK1004) += atstk1004.o ++obj-$(CONFIG_BOARD_ATSTK1006) += atstk1002.o +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/configs/atngw100_defconfig avr32-2.6/arch/avr32/configs/atngw100_defconfig +--- linux-2.6.25.6/arch/avr32/configs/atngw100_defconfig 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/configs/atngw100_defconfig 2008-06-12 15:09:38.715815679 +0200 +@@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit --# Linux kernel version: 2.6.22-rc5 --# Sat Jun 23 15:40:05 2007 -+# Linux kernel version: 2.6.24 -+# Thu Mar 6 12:49:54 2008 +-# Linux kernel version: 2.6.24-rc7 +-# Wed Jan 9 23:20:41 2008 ++# Linux kernel version: 2.6.25.4 ++# Wed Jun 11 15:23:36 2008 # CONFIG_AVR32=y CONFIG_GENERIC_GPIO=y - CONFIG_GENERIC_HARDIRQS=y -+CONFIG_STACKTRACE_SUPPORT=y -+CONFIG_LOCKDEP_SUPPORT=y -+CONFIG_TRACE_IRQFLAGS_SUPPORT=y - CONFIG_HARDIRQS_SW_RESEND=y +@@ -13,10 +13,10 @@ CONFIG_GENERIC_IRQ_PROBE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y -+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set + # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set -+CONFIG_ARCH_SUPPORTS_OPROFILE=y +-CONFIG_ARCH_SUPPORTS_OPROFILE=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_BUG=y - CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" - - # --# Code maturity level options -+# General setup - # - 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_IPC_NS is not set - CONFIG_SYSVIPC_SYSCTL=y - CONFIG_POSIX_MQUEUE=y +@@ -37,17 +37,15 @@ CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y # CONFIG_TASKSTATS is not set --# CONFIG_UTS_NS is not set -+# CONFIG_USER_NS is not set -+# CONFIG_PID_NS is not set +-# CONFIG_USER_NS is not set +-# CONFIG_PID_NS is not set # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set CONFIG_LOG_BUF_SHIFT=14 -+# CONFIG_CGROUPS is not set -+CONFIG_FAIR_GROUP_SCHED=y -+CONFIG_FAIR_USER_SCHED=y -+# CONFIG_FAIR_CGROUP_SCHED is not set + # CONFIG_CGROUPS is not set +-CONFIG_FAIR_GROUP_SCHED=y +-CONFIG_FAIR_USER_SCHED=y +-# CONFIG_FAIR_CGROUP_SCHED is not set ++# CONFIG_GROUP_SCHED is not set CONFIG_SYSFS_DEPRECATED=y ++CONFIG_SYSFS_DEPRECATED_V2=y # CONFIG_RELAY is not set ++# CONFIG_NAMESPACES is not set CONFIG_BLK_DEV_INITRD=y -@@ -61,35 +67,28 @@ + CONFIG_INITRAMFS_SOURCE="" + CONFIG_CC_OPTIMIZE_FOR_SIZE=y +@@ -61,11 +59,13 @@ + CONFIG_PRINTK=y + CONFIG_BUG=y + CONFIG_ELF_CORE=y ++# CONFIG_COMPAT_BRK is not set + # CONFIG_BASE_FULL is not set + CONFIG_FUTEX=y CONFIG_ANON_INODES=y CONFIG_EPOLL=y CONFIG_SIGNALFD=y --CONFIG_TIMERFD=y ++CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_VM_EVENT_COUNTERS=y --# CONFIG_SLUB_DEBUG is not set -+CONFIG_SLUB_DEBUG=y +@@ -73,6 +73,14 @@ # CONFIG_SLAB is not set CONFIG_SLUB=y # CONFIG_SLOB is not set -+CONFIG_SLABINFO=y ++CONFIG_PROFILING=y ++# CONFIG_MARKERS is not set ++CONFIG_OPROFILE=m ++CONFIG_HAVE_OPROFILE=y ++CONFIG_KPROBES=y ++CONFIG_HAVE_KPROBES=y ++# CONFIG_HAVE_KRETPROBES is not set ++CONFIG_PROC_PAGE_MONITOR=y + CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set - CONFIG_BASE_SMALL=1 -- --# --# Loadable module support --# - CONFIG_MODULES=y - CONFIG_MODULE_UNLOAD=y - CONFIG_MODULE_FORCE_UNLOAD=y - # CONFIG_MODVERSIONS is not set - # CONFIG_MODULE_SRCVERSION_ALL is not set - CONFIG_KMOD=y -- --# --# Block layer --# - CONFIG_BLOCK=y - # CONFIG_LBD is not set - # CONFIG_BLK_DEV_IO_TRACE is not set - # CONFIG_LSF is not set -+# CONFIG_BLK_DEV_BSG is not set +@@ -101,10 +109,15 @@ + CONFIG_DEFAULT_CFQ=y + # CONFIG_DEFAULT_NOOP is not set + CONFIG_DEFAULT_IOSCHED="cfq" ++CONFIG_CLASSIC_RCU=y # - # IO Schedulers -@@ -107,21 +106,28 @@ - # # System Type and features # +CONFIG_TICK_ONESHOT=y @@ -1051,8 +943,7 @@ CONFIG_SUBARCH_AVR32B=y CONFIG_MMU=y CONFIG_PERFORMANCE_COUNTERS=y - CONFIG_PLATFORM_AT32AP=y -+CONFIG_CPU_AT32AP700X=y +@@ -113,6 +126,7 @@ CONFIG_CPU_AT32AP7000=y # CONFIG_BOARD_ATSTK1000 is not set CONFIG_BOARD_ATNGW100=y @@ -1060,226 +951,234 @@ CONFIG_LOADER_U_BOOT=y # - # Atmel AVR32 AP options - # --# CONFIG_AP7000_32_BIT_SMC is not set --CONFIG_AP7000_16_BIT_SMC=y --# CONFIG_AP7000_8_BIT_SMC is not set -+# CONFIG_AP700X_32_BIT_SMC is not set -+CONFIG_AP700X_16_BIT_SMC=y -+# CONFIG_AP700X_8_BIT_SMC is not set +@@ -121,6 +135,7 @@ + # CONFIG_AP700X_32_BIT_SMC is not set + CONFIG_AP700X_16_BIT_SMC=y + # CONFIG_AP700X_8_BIT_SMC is not set +CONFIG_GPIO_DEV=y CONFIG_LOAD_ADDRESS=0x10000000 CONFIG_ENTRY_ADDRESS=0x90000000 CONFIG_PHYS_OFFSET=0x10000000 -@@ -141,10 +147,14 @@ - CONFIG_FLATMEM=y - CONFIG_FLAT_NODE_MEM_MAP=y - # CONFIG_SPARSEMEM_STATIC is not set -+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set - CONFIG_SPLIT_PTLOCK_CPUS=4 - # CONFIG_RESOURCES_64BIT is not set +@@ -146,16 +161,26 @@ CONFIG_ZONE_DMA_FLAG=0 -+CONFIG_VIRT_TO_BUS=y + CONFIG_VIRT_TO_BUS=y # CONFIG_OWNERSHIP_TRACE is not set -+# CONFIG_NMI_DEBUGGING is not set ++CONFIG_NMI_DEBUGGING=y +CONFIG_DW_DMAC=y # CONFIG_HZ_100 is not set CONFIG_HZ_250=y # CONFIG_HZ_300 is not set -@@ -153,13 +163,31 @@ + # CONFIG_HZ_1000 is not set + CONFIG_HZ=250 ++# CONFIG_SCHED_HRTICK is not set CONFIG_CMDLINE="" # --# Bus options -+# Power management options + # Power management options # --# CONFIG_ARCH_SUPPORTS_MSI is not set ++CONFIG_ARCH_SUSPEND_POSSIBLE=y ++CONFIG_PM=y ++# CONFIG_PM_LEGACY is not set ++# CONFIG_PM_DEBUG is not set ++CONFIG_PM_SLEEP=y ++CONFIG_SUSPEND=y ++CONFIG_SUSPEND_FREEZER=y # --# PCCARD (PCMCIA/CardBus) support -+# CPU Frequency scaling -+# -+CONFIG_CPU_FREQ=y -+CONFIG_CPU_FREQ_TABLE=y -+# CONFIG_CPU_FREQ_DEBUG is not set -+# CONFIG_CPU_FREQ_STAT is not set -+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y -+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set -+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set -+CONFIG_CPU_FREQ_GOV_USERSPACE=y -+CONFIG_CPU_FREQ_GOV_ONDEMAND=y -+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set -+CONFIG_CPU_FREQ_AT32AP=y -+ -+# -+# Bus options - # -+# CONFIG_ARCH_SUPPORTS_MSI is not set - # CONFIG_PCCARD is not set - - # -@@ -213,6 +241,7 @@ - CONFIG_INET_XFRM_MODE_TRANSPORT=y - CONFIG_INET_XFRM_MODE_TUNNEL=y - CONFIG_INET_XFRM_MODE_BEET=y -+# CONFIG_INET_LRO is not set - CONFIG_INET_DIAG=y - CONFIG_INET_TCP_DIAG=y - # CONFIG_TCP_CONG_ADVANCED is not set -@@ -240,6 +269,7 @@ + # CPU Frequency scaling +@@ -164,9 +189,9 @@ + CONFIG_CPU_FREQ_TABLE=y + # CONFIG_CPU_FREQ_DEBUG is not set + # CONFIG_CPU_FREQ_STAT is not set +-CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y ++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set + # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +-# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set ++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y + # CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set + CONFIG_CPU_FREQ_GOV_PERFORMANCE=y + # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +@@ -202,6 +227,7 @@ + CONFIG_XFRM_USER=y + # CONFIG_XFRM_SUB_POLICY is not set + # CONFIG_XFRM_MIGRATE is not set ++# CONFIG_XFRM_STATISTICS is not set + CONFIG_NET_KEY=y + # CONFIG_NET_KEY_MIGRATE is not set + CONFIG_INET=y +@@ -260,82 +286,33 @@ # CONFIG_NETWORK_SECMARK is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set -+CONFIG_BRIDGE_NETFILTER=y +-CONFIG_BRIDGE_NETFILTER=y ++# CONFIG_NETFILTER_ADVANCED is not set # # Core Netfilter Configuration -@@ -252,6 +282,7 @@ - # CONFIG_NF_CONNTRACK_EVENTS is not set - CONFIG_NF_CT_PROTO_GRE=m - # CONFIG_NF_CT_PROTO_SCTP is not set -+# CONFIG_NF_CT_PROTO_UDPLITE is not set - CONFIG_NF_CONNTRACK_AMANDA=m + # +-# CONFIG_NETFILTER_NETLINK is not set +-CONFIG_NF_CONNTRACK_ENABLED=m ++CONFIG_NETFILTER_NETLINK=m ++CONFIG_NETFILTER_NETLINK_LOG=m + CONFIG_NF_CONNTRACK=m +-CONFIG_NF_CT_ACCT=y +-CONFIG_NF_CONNTRACK_MARK=y +-# CONFIG_NF_CONNTRACK_EVENTS is not set +-CONFIG_NF_CT_PROTO_GRE=m +-# CONFIG_NF_CT_PROTO_SCTP is not set +-# CONFIG_NF_CT_PROTO_UDPLITE is not set +-CONFIG_NF_CONNTRACK_AMANDA=m CONFIG_NF_CONNTRACK_FTP=m - CONFIG_NF_CONNTRACK_H323=m -@@ -269,9 +300,11 @@ - CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +-CONFIG_NF_CONNTRACK_H323=m + CONFIG_NF_CONNTRACK_IRC=m +-CONFIG_NF_CONNTRACK_NETBIOS_NS=m +-CONFIG_NF_CONNTRACK_PPTP=m +-CONFIG_NF_CONNTRACK_SANE=m + CONFIG_NF_CONNTRACK_SIP=m +-CONFIG_NF_CONNTRACK_TFTP=m ++CONFIG_NF_CT_NETLINK=m + CONFIG_NETFILTER_XTABLES=y +-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +-# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set +-# CONFIG_NETFILTER_XT_TARGET_DSCP is not set + CONFIG_NETFILTER_XT_TARGET_MARK=m +-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m - # CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set -+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +-# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +-# CONFIG_NETFILTER_XT_TARGET_TRACE is not set CONFIG_NETFILTER_XT_TARGET_TCPMSS=m - CONFIG_NETFILTER_XT_MATCH_COMMENT=m - CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m -+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set - CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +-CONFIG_NETFILTER_XT_MATCH_COMMENT=m +-CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +-# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set +-CONFIG_NETFILTER_XT_MATCH_CONNMARK=m CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m - # CONFIG_NETFILTER_XT_MATCH_DCCP is not set -@@ -284,6 +317,7 @@ +-# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +-# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +-CONFIG_NETFILTER_XT_MATCH_ESP=m +-CONFIG_NETFILTER_XT_MATCH_HELPER=m +-CONFIG_NETFILTER_XT_MATCH_LENGTH=m +-CONFIG_NETFILTER_XT_MATCH_LIMIT=m +-CONFIG_NETFILTER_XT_MATCH_MAC=m CONFIG_NETFILTER_XT_MATCH_MARK=m CONFIG_NETFILTER_XT_MATCH_POLICY=m - CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m -+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set - CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m - CONFIG_NETFILTER_XT_MATCH_QUOTA=m - CONFIG_NETFILTER_XT_MATCH_REALM=m -@@ -292,6 +326,8 @@ - CONFIG_NETFILTER_XT_MATCH_STATISTIC=m - CONFIG_NETFILTER_XT_MATCH_STRING=m - CONFIG_NETFILTER_XT_MATCH_TCPMSS=m -+# CONFIG_NETFILTER_XT_MATCH_TIME is not set -+# CONFIG_NETFILTER_XT_MATCH_U32 is not set - CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +-# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +-CONFIG_NETFILTER_XT_MATCH_QUOTA=m +-CONFIG_NETFILTER_XT_MATCH_REALM=m +-# CONFIG_NETFILTER_XT_MATCH_SCTP is not set + CONFIG_NETFILTER_XT_MATCH_STATE=m +-CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +-CONFIG_NETFILTER_XT_MATCH_STRING=m +-CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +-# CONFIG_NETFILTER_XT_MATCH_TIME is not set +-# CONFIG_NETFILTER_XT_MATCH_U32 is not set +-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m + + # + # IP: Netfilter Configuration + # + CONFIG_NF_CONNTRACK_IPV4=m + CONFIG_NF_CONNTRACK_PROC_COMPAT=y +-# CONFIG_IP_NF_QUEUE is not set + CONFIG_IP_NF_IPTABLES=m +-CONFIG_IP_NF_MATCH_IPRANGE=m +-CONFIG_IP_NF_MATCH_TOS=m +-CONFIG_IP_NF_MATCH_RECENT=m +-CONFIG_IP_NF_MATCH_ECN=m +-CONFIG_IP_NF_MATCH_AH=m +-CONFIG_IP_NF_MATCH_TTL=m +-CONFIG_IP_NF_MATCH_OWNER=m +-CONFIG_IP_NF_MATCH_ADDRTYPE=m + CONFIG_IP_NF_FILTER=m + CONFIG_IP_NF_TARGET_REJECT=m + CONFIG_IP_NF_TARGET_LOG=m +@@ -343,54 +320,25 @@ + CONFIG_NF_NAT=m + CONFIG_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_NF_NAT_SNMP_BASIC=m +-CONFIG_NF_NAT_PROTO_GRE=m + CONFIG_NF_NAT_FTP=m + CONFIG_NF_NAT_IRC=m +-CONFIG_NF_NAT_TFTP=m +-CONFIG_NF_NAT_AMANDA=m +-CONFIG_NF_NAT_PPTP=m +-CONFIG_NF_NAT_H323=m ++# CONFIG_NF_NAT_TFTP is not set ++# CONFIG_NF_NAT_AMANDA is not set ++# CONFIG_NF_NAT_PPTP is not set ++# CONFIG_NF_NAT_H323 is not set + CONFIG_NF_NAT_SIP=m + CONFIG_IP_NF_MANGLE=m +-CONFIG_IP_NF_TARGET_TOS=m +-CONFIG_IP_NF_TARGET_ECN=m +-CONFIG_IP_NF_TARGET_TTL=m +-CONFIG_IP_NF_TARGET_CLUSTERIP=m +-CONFIG_IP_NF_RAW=m +-CONFIG_IP_NF_ARPTABLES=m +-CONFIG_IP_NF_ARPFILTER=m +-CONFIG_IP_NF_ARP_MANGLE=m # -@@ -359,13 +395,19 @@ +-# IPv6: Netfilter Configuration (EXPERIMENTAL) ++# IPv6: Netfilter Configuration + # + CONFIG_NF_CONNTRACK_IPV6=m +-CONFIG_IP6_NF_QUEUE=m + CONFIG_IP6_NF_IPTABLES=m +-CONFIG_IP6_NF_MATCH_RT=m +-CONFIG_IP6_NF_MATCH_OPTS=m +-CONFIG_IP6_NF_MATCH_FRAG=m +-CONFIG_IP6_NF_MATCH_HL=m +-CONFIG_IP6_NF_MATCH_OWNER=m + CONFIG_IP6_NF_MATCH_IPV6HEADER=m +-CONFIG_IP6_NF_MATCH_AH=m +-CONFIG_IP6_NF_MATCH_MH=m +-CONFIG_IP6_NF_MATCH_EUI64=m + CONFIG_IP6_NF_FILTER=m + CONFIG_IP6_NF_TARGET_LOG=m + CONFIG_IP6_NF_TARGET_REJECT=m CONFIG_IP6_NF_MANGLE=m - CONFIG_IP6_NF_TARGET_HL=m - CONFIG_IP6_NF_RAW=m -+ -+# -+# Bridge: Netfilter Configuration -+# -+# CONFIG_BRIDGE_NF_EBTABLES is not set +-CONFIG_IP6_NF_TARGET_HL=m +-CONFIG_IP6_NF_RAW=m +- +-# +-# Bridge: Netfilter Configuration +-# +-# CONFIG_BRIDGE_NF_EBTABLES is not set # CONFIG_IP_DCCP is not set # CONFIG_IP_SCTP is not set # CONFIG_TIPC is not set - # CONFIG_ATM is not set --# CONFIG_BRIDGE is not set -+CONFIG_BRIDGE=m - CONFIG_VLAN_8021Q=m - # CONFIG_DECNET is not set -+CONFIG_LLC=m - # CONFIG_LLC2 is not set - # CONFIG_IPX is not set - # CONFIG_ATALK is not set -@@ -373,10 +415,6 @@ - # CONFIG_LAPB is not set +@@ -407,7 +355,6 @@ # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set -- --# --# QoS and/or fair queueing --# # CONFIG_NET_SCHED is not set - CONFIG_NET_CLS_ROUTE=y +-CONFIG_NET_CLS_ROUTE=y -@@ -384,6 +422,7 @@ - # Network testing # + # Network testing +@@ -415,6 +362,7 @@ # CONFIG_NET_PKTGEN is not set -+# CONFIG_NET_TCPPROBE is not set + # CONFIG_NET_TCPPROBE is not set # CONFIG_HAMRADIO is not set ++# CONFIG_CAN is not set # CONFIG_IRDA is not set # CONFIG_BT is not set -@@ -397,6 +436,7 @@ - # CONFIG_MAC80211 is not set - # CONFIG_IEEE80211 is not set - # CONFIG_RFKILL is not set -+# CONFIG_NET_9P is not set - - # - # Device Drivers -@@ -405,16 +445,13 @@ - # - # Generic Driver Options - # -+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" - CONFIG_STANDALONE=y - # CONFIG_PREVENT_FIRMWARE_BUILD is not set - # CONFIG_FW_LOADER is not set - # CONFIG_DEBUG_DRIVER is not set - # CONFIG_DEBUG_DEVRES is not set - # CONFIG_SYS_HYPERVISOR is not set -- --# --# Connector - unified userspace <-> kernelspace linker --# - # CONFIG_CONNECTOR is not set - CONFIG_MTD=y - # CONFIG_MTD_DEBUG is not set -@@ -434,6 +471,7 @@ - # CONFIG_INFTL is not set - # CONFIG_RFD_FTL is not set - # CONFIG_SSFDC is not set -+# CONFIG_MTD_OOPS is not set - - # - # RAM/ROM/Flash chip drivers -@@ -493,20 +531,8 @@ - # UBI - Unsorted block images - # - # CONFIG_MTD_UBI is not set -- --# --# Parallel port support --# - # CONFIG_PARPORT is not set -- --# --# Plug and Play support --# --# CONFIG_PNPACPI is not set -- --# --# Block devices --# -+CONFIG_BLK_DEV=y - # CONFIG_BLK_DEV_COW_COMMON is not set - CONFIG_BLK_DEV_LOOP=m - # CONFIG_BLK_DEV_CRYPTOLOOP is not set -@@ -517,11 +543,13 @@ - CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 + # CONFIG_AF_RXRPC is not set +@@ -531,11 +479,18 @@ + CONFIG_BLK_DEV_RAM=m + CONFIG_BLK_DEV_RAM_COUNT=16 + CONFIG_BLK_DEV_RAM_SIZE=4096 +-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 ++# CONFIG_BLK_DEV_XIP is not set # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set -- --# --# Misc devices --# --# CONFIG_BLINK is not set +-# CONFIG_MISC_DEVICES is not set +-# CONFIG_IDE is not set +CONFIG_MISC_DEVICES=y +# CONFIG_ATMEL_PWM is not set +CONFIG_ATMEL_TCLIB=y @@ -1287,87 +1186,34 @@ +CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0 +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_ATMEL_SSC is not set - # CONFIG_IDE is not set - - # -@@ -529,30 +557,42 @@ - # - # CONFIG_RAID_ATTRS is not set - # CONFIG_SCSI is not set -+# CONFIG_SCSI_DMA is not set - # CONFIG_SCSI_NETLINK is not set - # CONFIG_ATA is not set -- --# --# Multi-device support (RAID and LVM) --# - # CONFIG_MD is not set -- --# --# Network device support --# - CONFIG_NETDEVICES=y -+# CONFIG_NETDEVICES_MULTIQUEUE is not set - # CONFIG_DUMMY is not set - # CONFIG_BONDING is not set -+# CONFIG_MACVLAN is not set - # CONFIG_EQUALIZER is not set - CONFIG_TUN=m --# CONFIG_PHYLIB is not set -+# CONFIG_VETH is not set -+CONFIG_PHYLIB=y ++# CONFIG_ENCLOSURE_SERVICES is not set ++# CONFIG_HAVE_IDE is not set # --# Ethernet (10 or 100Mbit) -+# MII PHY device drivers - # -+# CONFIG_MARVELL_PHY is not set -+# CONFIG_DAVICOM_PHY is not set -+# CONFIG_QSEMI_PHY is not set -+# CONFIG_LXT_PHY is not set -+# CONFIG_CICADA_PHY is not set -+# CONFIG_VITESSE_PHY is not set -+# CONFIG_SMSC_PHY is not set -+# CONFIG_BROADCOM_PHY is not set -+# CONFIG_ICPLUS_PHY is not set -+# CONFIG_FIXED_PHY is not set -+# CONFIG_MDIO_BITBANG is not set + # SCSI device support +@@ -568,11 +523,13 @@ + # CONFIG_SMSC_PHY is not set + # CONFIG_BROADCOM_PHY is not set + # CONFIG_ICPLUS_PHY is not set ++# CONFIG_REALTEK_PHY is not set + # CONFIG_FIXED_PHY is not set + # CONFIG_MDIO_BITBANG is not set CONFIG_NET_ETHERNET=y --CONFIG_MII=y -+# CONFIG_MII is not set + # CONFIG_MII is not set CONFIG_MACB=y -+# CONFIG_IBM_NEW_EMAC_ZMII is not set -+# CONFIG_IBM_NEW_EMAC_RGMII is not set -+# CONFIG_IBM_NEW_EMAC_TAH is not set -+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set -+# CONFIG_B44 is not set - # CONFIG_NETDEV_1000 is not set - # CONFIG_NETDEV_10000 is not set - -@@ -571,21 +611,14 @@ - CONFIG_PPP_BSDCOMP=m - CONFIG_PPP_MPPE=m - CONFIG_PPPOE=m -+# CONFIG_PPPOL2TP is not set ++# CONFIG_ENC28J60 is not set + # CONFIG_IBM_NEW_EMAC_ZMII is not set + # CONFIG_IBM_NEW_EMAC_RGMII is not set + # CONFIG_IBM_NEW_EMAC_TAH is not set +@@ -599,7 +556,6 @@ + # CONFIG_PPPOL2TP is not set # CONFIG_SLIP is not set CONFIG_SLHC=m - # CONFIG_SHAPER 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 - - # -@@ -615,28 +648,57 @@ +@@ -633,6 +589,7 @@ # CONFIG_SERIAL_ATMEL=y CONFIG_SERIAL_ATMEL_CONSOLE=y @@ -1375,592 +1221,338 @@ # CONFIG_SERIAL_ATMEL_TTYAT is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y - CONFIG_UNIX98_PTYS=y +@@ -640,8 +597,6 @@ # CONFIG_LEGACY_PTYS is not set -- --# --# IPMI --# # CONFIG_IPMI_HANDLER is not set --# CONFIG_WATCHDOG is not set # CONFIG_HW_RANDOM is not set - # CONFIG_RTC is not set - # CONFIG_GEN_RTC is not set +-# CONFIG_RTC is not set +-# CONFIG_GEN_RTC is not set # CONFIG_R3964 is not set # CONFIG_RAW_DRIVER is not set -- --# --# TPM devices --# # CONFIG_TCG_TPM is not set --# CONFIG_I2C is not set -+CONFIG_I2C=m -+CONFIG_I2C_BOARDINFO=y -+CONFIG_I2C_CHARDEV=m +@@ -659,6 +614,7 @@ + # + # I2C Hardware Bus support + # ++CONFIG_I2C_ATMELTWI=m + CONFIG_I2C_GPIO=m + # CONFIG_I2C_OCORES is not set + # CONFIG_I2C_PARPORT_LIGHT is not set +@@ -669,13 +625,12 @@ + # + # Miscellaneous I2C Chip support + # +-# CONFIG_SENSORS_DS1337 is not set +-# CONFIG_SENSORS_DS1374 is not set + # CONFIG_DS1682 is not set + # CONFIG_SENSORS_EEPROM is not set + # CONFIG_SENSORS_PCF8574 is not set +-# CONFIG_SENSORS_PCA9539 is not set ++# CONFIG_PCF8575 is not set + # CONFIG_SENSORS_PCF8591 is not set ++# CONFIG_TPS65010 is not set + # CONFIG_SENSORS_MAX6875 is not set + # CONFIG_SENSORS_TSL2550 is not set + # CONFIG_I2C_DEBUG_CORE is not set +@@ -702,9 +657,27 @@ + # CONFIG_SPI_AT25 is not set + CONFIG_SPI_SPIDEV=m + # CONFIG_SPI_TLE62X0 is not set ++CONFIG_HAVE_GPIO_LIB=y + +# -+# I2C Algorithms ++# GPIO Support +# -+CONFIG_I2C_ALGOBIT=m -+# CONFIG_I2C_ALGOPCF is not set -+# CONFIG_I2C_ALGOPCA is not set ++# CONFIG_DEBUG_GPIO is not set + +# -+# I2C Hardware Bus support ++# I2C GPIO expanders: +# -+CONFIG_I2C_ATMELTWI=m -+CONFIG_I2C_GPIO=m -+# CONFIG_I2C_OCORES is not set -+# CONFIG_I2C_PARPORT_LIGHT is not set -+# CONFIG_I2C_SIMTEC is not set -+# CONFIG_I2C_TAOS_EVM is not set -+# CONFIG_I2C_STUB is not set -+ -+# -+# Miscellaneous I2C Chip support -+# -+# CONFIG_SENSORS_DS1337 is not set -+# CONFIG_SENSORS_DS1374 is not set -+# CONFIG_DS1682 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_MAX6875 is not set -+# CONFIG_SENSORS_TSL2550 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 -@@ -655,13 +717,25 @@ - # SPI Protocol Masters - # - # CONFIG_SPI_AT25 is not set --# CONFIG_SPI_SPIDEV is not set -+CONFIG_SPI_SPIDEV=m -+# CONFIG_SPI_TLE62X0 is not set -+# CONFIG_W1 is not set -+# CONFIG_POWER_SUPPLY is not set -+# CONFIG_HWMON is not set -+CONFIG_WATCHDOG=y -+# CONFIG_WATCHDOG_NOWAYOUT is not set - - # --# Dallas's 1-wire bus -+# Watchdog Device Drivers - # --# CONFIG_W1 is not set --# CONFIG_HWMON is not set -+# CONFIG_SOFT_WATCHDOG is not set -+CONFIG_AT32AP700X_WDT=y ++# CONFIG_GPIO_PCA953X is not set ++# CONFIG_GPIO_PCF857X is not set + +# -+# Sonics Silicon Backplane ++# SPI GPIO expanders: +# -+CONFIG_SSB_POSSIBLE=y -+# CONFIG_SSB is not set - - # - # Multifunction device drivers -@@ -678,23 +752,21 @@ - # - # Graphics support - # -+# CONFIG_VGASTATE is not set -+# CONFIG_VIDEO_OUTPUT_CONTROL is not set -+# CONFIG_FB is not set - # CONFIG_BACKLIGHT_LCD_SUPPORT is not set - - # - # Display device support - # - # CONFIG_DISPLAY_SUPPORT is not set --# CONFIG_VGASTATE is not set --# CONFIG_FB is not set ++# CONFIG_GPIO_MCP23S08 is not set + # CONFIG_W1 is not set + # CONFIG_POWER_SUPPLY is not set + # CONFIG_HWMON is not set ++# CONFIG_THERMAL is not set + CONFIG_WATCHDOG=y + # CONFIG_WATCHDOG_NOWAYOUT is not set +@@ -757,10 +730,6 @@ # - # Sound + # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' # - # CONFIG_SOUND is not set - -# --# USB support +-# USB Gadget Support -# -+CONFIG_USB_SUPPORT=y - # CONFIG_USB_ARCH_HAS_HCD is not set - # CONFIG_USB_ARCH_HAS_OHCI is not set - # CONFIG_USB_ARCH_HAS_EHCI is not set -@@ -706,12 +778,48 @@ + CONFIG_USB_GADGET=y + # CONFIG_USB_GADGET_DEBUG is not set + # CONFIG_USB_GADGET_DEBUG_FILES is not set +@@ -787,21 +756,24 @@ + # CONFIG_USB_FILE_STORAGE_TEST is not set + CONFIG_USB_G_SERIAL=m + # CONFIG_USB_MIDI_GADGET is not set +-CONFIG_MMC=m ++# CONFIG_USB_G_PRINTER is not set ++CONFIG_MMC=y + # CONFIG_MMC_DEBUG is not set + # CONFIG_MMC_UNSAFE_RESUME is not set + # - # USB Gadget Support + # MMC/SD Card Drivers # --# CONFIG_USB_GADGET is not set --# CONFIG_MMC is not set -+CONFIG_USB_GADGET=y -+# CONFIG_USB_GADGET_DEBUG is not set -+# CONFIG_USB_GADGET_DEBUG_FILES is not set -+CONFIG_USB_GADGET_SELECTED=y -+# CONFIG_USB_GADGET_AMD5536UDC is not set -+CONFIG_USB_GADGET_ATMEL_USBA=y -+CONFIG_USB_ATMEL_USBA=y -+# CONFIG_USB_GADGET_FSL_USB2 is not set -+# CONFIG_USB_GADGET_NET2280 is not set -+# CONFIG_USB_GADGET_PXA2XX is not set -+# CONFIG_USB_GADGET_M66592 is not set -+# CONFIG_USB_GADGET_GOKU is not set -+# CONFIG_USB_GADGET_LH7A40X is not set -+# CONFIG_USB_GADGET_OMAP is not set -+# CONFIG_USB_GADGET_S3C2410 is not set -+# CONFIG_USB_GADGET_AT91 is not set -+# CONFIG_USB_GADGET_DUMMY_HCD is not set -+CONFIG_USB_GADGET_DUALSPEED=y -+CONFIG_USB_ZERO=m -+CONFIG_USB_ETH=m -+CONFIG_USB_ETH_RNDIS=y -+CONFIG_USB_GADGETFS=m -+CONFIG_USB_FILE_STORAGE=m -+# CONFIG_USB_FILE_STORAGE_TEST is not set -+CONFIG_USB_G_SERIAL=m -+# CONFIG_USB_MIDI_GADGET is not set -+CONFIG_MMC=y -+# CONFIG_MMC_DEBUG is not set -+# CONFIG_MMC_UNSAFE_RESUME is not set -+ -+# -+# MMC/SD Card Drivers -+# +-CONFIG_MMC_BLOCK=m +CONFIG_MMC_BLOCK=y -+# CONFIG_MMC_BLOCK_BOUNCE is not set -+# CONFIG_SDIO_UART is not set + CONFIG_MMC_BLOCK_BOUNCE=y + # CONFIG_SDIO_UART is not set # --# LED devices -+# MMC/SD Host Controller Drivers + # MMC/SD Host Controller Drivers # +CONFIG_MMC_ATMELMCI=y -+CONFIG_MMC_SPI=m + CONFIG_MMC_SPI=m ++# CONFIG_MEMSTICK is not set CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y -@@ -726,53 +834,71 @@ - CONFIG_LEDS_TRIGGERS=y - CONFIG_LEDS_TRIGGER_TIMER=y - CONFIG_LEDS_TRIGGER_HEARTBEAT=y -- -+CONFIG_RTC_LIB=y -+CONFIG_RTC_CLASS=y -+CONFIG_RTC_HCTOSYS=y -+CONFIG_RTC_HCTOSYS_DEVICE="rtc0" -+# CONFIG_RTC_DEBUG is not set +@@ -844,19 +816,22 @@ + # CONFIG_RTC_DRV_PCF8563 is not set + # CONFIG_RTC_DRV_PCF8583 is not set + # CONFIG_RTC_DRV_M41T80 is not set ++# CONFIG_RTC_DRV_S35390A is not set # --# LED drivers --# -- --# --# LED Triggers --# -- --# --# InfiniBand support -+# RTC interfaces - # -+CONFIG_RTC_INTF_SYSFS=y -+CONFIG_RTC_INTF_PROC=y -+CONFIG_RTC_INTF_DEV=y -+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set -+# CONFIG_RTC_DRV_TEST is not set - - # --# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) -+# I2C RTC drivers + # SPI RTC drivers # -+# CONFIG_RTC_DRV_DS1307 is not set -+# CONFIG_RTC_DRV_DS1374 is not set -+# CONFIG_RTC_DRV_DS1672 is not set -+# CONFIG_RTC_DRV_MAX6900 is not set -+# CONFIG_RTC_DRV_RS5C372 is not set -+# CONFIG_RTC_DRV_ISL1208 is not set -+# CONFIG_RTC_DRV_X1205 is not set -+# CONFIG_RTC_DRV_PCF8563 is not set -+# CONFIG_RTC_DRV_PCF8583 is not set -+# CONFIG_RTC_DRV_M41T80 is not set - - # --# Real Time Clock -+# SPI RTC drivers - # --# CONFIG_RTC_CLASS is not set +-# CONFIG_RTC_DRV_RS5C348 is not set + # CONFIG_RTC_DRV_MAX6902 is not set ++# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set -+# CONFIG_RTC_DRV_MAX6902 is not set # --# DMA Engine support -+# Platform RTC drivers + # Platform RTC drivers # --# CONFIG_DMA_ENGINE is not set -+# CONFIG_RTC_DRV_DS1553 is not set ++# CONFIG_RTC_DRV_DS1511 is not set + # CONFIG_RTC_DRV_DS1553 is not set +-# CONFIG_RTC_DRV_STK17TA8 is not set + # CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set -+# CONFIG_RTC_DRV_DS1742 is not set -+# CONFIG_RTC_DRV_M48T86 is not set -+# CONFIG_RTC_DRV_M48T59 is not set -+# CONFIG_RTC_DRV_V3020 is not set - - # --# DMA Clients -+# on-CPU RTC drivers - # -+CONFIG_RTC_DRV_AT32AP700X=y - - # --# DMA Devices -+# Userspace I/O - # -+# CONFIG_UIO is not set - + # CONFIG_RTC_DRV_M48T86 is not set + # CONFIG_RTC_DRV_M48T59 is not set + # CONFIG_RTC_DRV_V3020 is not set +@@ -874,25 +849,23 @@ # # File systems # --CONFIG_EXT2_FS=y -+CONFIG_EXT2_FS=m +-CONFIG_EXT2_FS=m ++CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XATTR is not set # CONFIG_EXT2_FS_XIP is not set --CONFIG_EXT3_FS=y -+CONFIG_EXT3_FS=m +-CONFIG_EXT3_FS=m ++CONFIG_EXT3_FS=y # CONFIG_EXT3_FS_XATTR is not set # CONFIG_EXT4DEV_FS is not set --CONFIG_JBD=y --# CONFIG_JBD_DEBUG is not set -+CONFIG_JBD=m +-CONFIG_JBD=m ++CONFIG_JBD=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set # CONFIG_FS_POSIX_ACL is not set -@@ -781,7 +907,8 @@ + # CONFIG_XFS_FS is not set + # CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set - # CONFIG_MINIX_FS is not set - # CONFIG_ROMFS_FS is not set --# CONFIG_INOTIFY is not set -+CONFIG_INOTIFY=y -+CONFIG_INOTIFY_USER=y +-# CONFIG_MINIX_FS is not set +-# CONFIG_ROMFS_FS is not set ++# CONFIG_DNOTIFY is not set + CONFIG_INOTIFY=y + CONFIG_INOTIFY_USER=y # CONFIG_QUOTA is not set - # CONFIG_DNOTIFY is not set +-# CONFIG_DNOTIFY is not set # CONFIG_AUTOFS_FS is not set -@@ -814,7 +941,6 @@ + # CONFIG_AUTOFS4_FS is not set + CONFIG_FUSE_FS=m +@@ -923,7 +896,7 @@ CONFIG_TMPFS=y # CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set --CONFIG_RAMFS=y - CONFIG_CONFIGFS_FS=y +-CONFIG_CONFIGFS_FS=m ++CONFIG_CONFIGFS_FS=y # -@@ -830,10 +956,12 @@ - CONFIG_JFFS2_FS=y - CONFIG_JFFS2_FS_DEBUG=0 - CONFIG_JFFS2_FS_WRITEBUFFER=y -+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set - # CONFIG_JFFS2_SUMMARY is not set - # CONFIG_JFFS2_FS_XATTR is not set - # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set - CONFIG_JFFS2_ZLIB=y -+# CONFIG_JFFS2_LZO is not set - CONFIG_JFFS2_RTIME=y + # Miscellaneous filesystems +@@ -948,8 +921,10 @@ # CONFIG_JFFS2_RUBIN is not set # CONFIG_CRAMFS is not set -@@ -842,19 +970,21 @@ + # CONFIG_VXFS_FS is not set ++# CONFIG_MINIX_FS is not set + # CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set ++# CONFIG_ROMFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set -- --# --# Network File Systems --# -+CONFIG_NETWORK_FILESYSTEMS=y - CONFIG_NFS_FS=y - 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_NFSD=m -+CONFIG_NFSD_V3=y -+# CONFIG_NFSD_V3_ACL is not set -+# CONFIG_NFSD_V4 is not set -+CONFIG_NFSD_TCP=y - CONFIG_ROOT_NFS=y - CONFIG_LOCKD=y - CONFIG_LOCKD_V4=y -+CONFIG_EXPORTFS=m - CONFIG_NFS_COMMON=y - CONFIG_SUNRPC=y - # CONFIG_SUNRPC_BIND34 is not set -@@ -871,23 +1001,18 @@ - # 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 is not set - CONFIG_MSDOS_PARTITION=y -- --# --# Native Language Support --# --CONFIG_NLS=y -+CONFIG_NLS=m - CONFIG_NLS_DEFAULT="iso8859-1" --# CONFIG_NLS_CODEPAGE_437 is not set -+CONFIG_NLS_CODEPAGE_437=m - # CONFIG_NLS_CODEPAGE_737 is not set - # CONFIG_NLS_CODEPAGE_775 is not set --CONFIG_NLS_CODEPAGE_850=y -+CONFIG_NLS_CODEPAGE_850=m - # CONFIG_NLS_CODEPAGE_852 is not set - # CONFIG_NLS_CODEPAGE_855 is not set - # CONFIG_NLS_CODEPAGE_857 is not set -@@ -908,7 +1033,7 @@ - # CONFIG_NLS_CODEPAGE_1250 is not set - # CONFIG_NLS_CODEPAGE_1251 is not set - # CONFIG_NLS_ASCII is not set --CONFIG_NLS_ISO8859_1=y -+CONFIG_NLS_ISO8859_1=m - # CONFIG_NLS_ISO8859_2 is not set - # CONFIG_NLS_ISO8859_3 is not set - # CONFIG_NLS_ISO8859_4 is not set -@@ -921,18 +1046,19 @@ - # CONFIG_NLS_ISO8859_15 is not set - # CONFIG_NLS_KOI8_R is not set + CONFIG_NETWORK_FILESYSTEMS=y +@@ -1030,11 +1005,6 @@ # CONFIG_NLS_KOI8_U is not set --CONFIG_NLS_UTF8=y -- --# --# Distributed Lock Manager --# -+CONFIG_NLS_UTF8=m + CONFIG_NLS_UTF8=m # CONFIG_DLM is not set -+CONFIG_INSTRUMENTATION=y -+CONFIG_PROFILING=y -+CONFIG_OPROFILE=m -+CONFIG_KPROBES=y -+# CONFIG_MARKERS is not set +-CONFIG_INSTRUMENTATION=y +-CONFIG_PROFILING=y +-CONFIG_OPROFILE=m +-CONFIG_KPROBES=y +-# CONFIG_MARKERS is not set # # Kernel hacking - # --CONFIG_TRACE_IRQFLAGS_SUPPORT=y - # CONFIG_PRINTK_TIME is not set -+CONFIG_ENABLE_WARN_DEPRECATED=y - CONFIG_ENABLE_MUST_CHECK=y - CONFIG_MAGIC_SYSRQ=y - # CONFIG_UNUSED_SYMBOLS is not set -@@ -941,12 +1067,17 @@ - CONFIG_DEBUG_KERNEL=y - # CONFIG_DEBUG_SHIRQ is not set - CONFIG_DETECT_SOFTLOCKUP=y -+CONFIG_SCHED_DEBUG=y +@@ -1053,6 +1023,7 @@ # CONFIG_SCHEDSTATS is not set # CONFIG_TIMER_STATS is not set -+# CONFIG_SLUB_DEBUG_ON is not set + # CONFIG_SLUB_DEBUG_ON is not set ++# CONFIG_SLUB_STATS is not set # CONFIG_DEBUG_RT_MUTEXES is not set # CONFIG_RT_MUTEX_TESTER is not set # CONFIG_DEBUG_SPINLOCK is not set - # CONFIG_DEBUG_MUTEXES is not set -+# CONFIG_DEBUG_LOCK_ALLOC is not set -+# CONFIG_PROVE_LOCKING is not set -+# CONFIG_LOCK_STAT is not set - # CONFIG_DEBUG_SPINLOCK_SLEEP is not set - # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set - # CONFIG_DEBUG_KOBJECT is not set -@@ -954,21 +1085,21 @@ - # CONFIG_DEBUG_INFO is not set - # CONFIG_DEBUG_VM is not set +@@ -1069,9 +1040,10 @@ # CONFIG_DEBUG_LIST is not set -+# CONFIG_DEBUG_SG is not set + # CONFIG_DEBUG_SG is not set CONFIG_FRAME_POINTER=y - # CONFIG_FORCED_INLINING is not set -+# CONFIG_BOOT_PRINTK_DELAY is not set +-# CONFIG_FORCED_INLINING is not set + # CONFIG_BOOT_PRINTK_DELAY is not set # CONFIG_RCU_TORTURE_TEST is not set -+# CONFIG_LKDTM is not set ++# CONFIG_KPROBES_SANITY_TEST is not set ++# CONFIG_BACKTRACE_SELF_TEST is not set + # CONFIG_LKDTM is not set # CONFIG_FAULT_INJECTION is not set --# CONFIG_KPROBES is not set -+# CONFIG_SAMPLES is not set - - # - # Security options - # - # CONFIG_KEYS is not set - # CONFIG_SECURITY is not set -- --# --# Cryptographic options --# -+# CONFIG_SECURITY_FILE_CAPABILITIES is not set + # CONFIG_SAMPLES is not set +@@ -1084,7 +1056,9 @@ + # CONFIG_SECURITY_FILE_CAPABILITIES is not set CONFIG_CRYPTO=y CONFIG_CRYPTO_ALGAPI=y ++CONFIG_CRYPTO_AEAD=y CONFIG_CRYPTO_BLKCIPHER=y -@@ -989,6 +1120,7 @@ - CONFIG_CRYPTO_CBC=y ++# CONFIG_CRYPTO_SEQIV is not set + CONFIG_CRYPTO_HASH=y + CONFIG_CRYPTO_MANAGER=y + CONFIG_CRYPTO_HMAC=y +@@ -1103,6 +1077,9 @@ CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_LRW is not set -+# CONFIG_CRYPTO_XTS is not set + # CONFIG_CRYPTO_XTS is not set ++# CONFIG_CRYPTO_CTR is not set ++# CONFIG_CRYPTO_GCM is not set ++# CONFIG_CRYPTO_CCM is not set # CONFIG_CRYPTO_CRYPTD is not set CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_FCRYPT is not set -@@ -1002,15 +1134,14 @@ - CONFIG_CRYPTO_ARC4=m +@@ -1117,12 +1094,14 @@ # CONFIG_CRYPTO_KHAZAD is not set # CONFIG_CRYPTO_ANUBIS is not set -+# CONFIG_CRYPTO_SEED is not set + # CONFIG_CRYPTO_SEED is not set ++# CONFIG_CRYPTO_SALSA20 is not set CONFIG_CRYPTO_DEFLATE=y # CONFIG_CRYPTO_MICHAEL_MIC is not set # CONFIG_CRYPTO_CRC32C is not set # CONFIG_CRYPTO_CAMELLIA is not set # CONFIG_CRYPTO_TEST is not set -- --# --# Hardware crypto devices --# -+# CONFIG_CRYPTO_AUTHENC is not set -+CONFIG_CRYPTO_HW=y +-# CONFIG_CRYPTO_AUTHENC is not set ++CONFIG_CRYPTO_AUTHENC=y ++# CONFIG_CRYPTO_LZO is not set + CONFIG_CRYPTO_HW=y # - # Library routines -@@ -1018,8 +1149,9 @@ - CONFIG_BITREVERSE=y - CONFIG_CRC_CCITT=m - # CONFIG_CRC16 is not set --# CONFIG_CRC_ITU_T is not set -+CONFIG_CRC_ITU_T=m - CONFIG_CRC32=y -+CONFIG_CRC7=m +@@ -1137,10 +1116,7 @@ # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y ---- a/arch/avr32/configs/atstk1002_defconfig -+++ b/arch/avr32/configs/atstk1002_defconfig -@@ -1,48 +1,49 @@ +-CONFIG_TEXTSEARCH=y +-CONFIG_TEXTSEARCH_KMP=m +-CONFIG_TEXTSEARCH_BM=m +-CONFIG_TEXTSEARCH_FSM=m ++CONFIG_GENERIC_ALLOCATOR=y + CONFIG_PLIST=y + CONFIG_HAS_IOMEM=y + CONFIG_HAS_IOPORT=y +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/configs/atstk1002_defconfig avr32-2.6/arch/avr32/configs/atstk1002_defconfig +--- linux-2.6.25.6/arch/avr32/configs/atstk1002_defconfig 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/configs/atstk1002_defconfig 2008-06-12 15:09:38.715815679 +0200 +@@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit --# Linux kernel version: 2.6.22-rc5 --# Sat Jun 23 15:32:08 2007 -+# Linux kernel version: 2.6.24 -+# Thu Mar 6 12:49:17 2008 +-# Linux kernel version: 2.6.24-rc7 +-# Wed Jan 9 23:07:43 2008 ++# Linux kernel version: 2.6.25.4 ++# Wed Jun 11 15:29:18 2008 # CONFIG_AVR32=y CONFIG_GENERIC_GPIO=y - CONFIG_GENERIC_HARDIRQS=y -+CONFIG_STACKTRACE_SUPPORT=y -+CONFIG_LOCKDEP_SUPPORT=y -+CONFIG_TRACE_IRQFLAGS_SUPPORT=y - CONFIG_HARDIRQS_SW_RESEND=y +@@ -13,10 +13,10 @@ CONFIG_GENERIC_IRQ_PROBE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y -+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set + # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set -+CONFIG_ARCH_SUPPORTS_OPROFILE=y +-CONFIG_ARCH_SUPPORTS_OPROFILE=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_BUG=y - CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" - - # --# Code maturity level options -+# General setup - # - 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_IPC_NS is not set - CONFIG_SYSVIPC_SYSCTL=y +@@ -36,15 +36,15 @@ CONFIG_POSIX_MQUEUE=y --CONFIG_BSD_PROCESS_ACCT=y --CONFIG_BSD_PROCESS_ACCT_V3=y --CONFIG_TASKSTATS=y --CONFIG_TASK_DELAY_ACCT=y --# CONFIG_TASK_XACCT is not set --# CONFIG_UTS_NS is not set --CONFIG_AUDIT=y -+# CONFIG_BSD_PROCESS_ACCT is not set -+# CONFIG_TASKSTATS is not set -+# CONFIG_USER_NS is not set -+# CONFIG_PID_NS is not set -+# CONFIG_AUDIT is not set + # CONFIG_BSD_PROCESS_ACCT is not set + # CONFIG_TASKSTATS is not set +-# CONFIG_USER_NS is not set +-# CONFIG_PID_NS is not set + # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set CONFIG_LOG_BUF_SHIFT=14 -+# CONFIG_CGROUPS is not set -+# CONFIG_FAIR_GROUP_SCHED is not set + # CONFIG_CGROUPS is not set +-# CONFIG_FAIR_GROUP_SCHED is not set ++# CONFIG_GROUP_SCHED is not set CONFIG_SYSFS_DEPRECATED=y ++CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_RELAY=y ++# CONFIG_NAMESPACES is not set CONFIG_BLK_DEV_INITRD=y -@@ -63,35 +64,28 @@ + CONFIG_INITRAMFS_SOURCE="" + CONFIG_CC_OPTIMIZE_FOR_SIZE=y +@@ -58,11 +58,13 @@ + CONFIG_PRINTK=y + CONFIG_BUG=y + CONFIG_ELF_CORE=y ++# CONFIG_COMPAT_BRK is not set + # CONFIG_BASE_FULL is not set + CONFIG_FUTEX=y CONFIG_ANON_INODES=y CONFIG_EPOLL=y CONFIG_SIGNALFD=y --CONFIG_TIMERFD=y ++CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_VM_EVENT_COUNTERS=y --# CONFIG_SLUB_DEBUG is not set -+CONFIG_SLUB_DEBUG=y +@@ -70,6 +72,14 @@ # CONFIG_SLAB is not set CONFIG_SLUB=y # CONFIG_SLOB is not set -+CONFIG_SLABINFO=y ++CONFIG_PROFILING=y ++# CONFIG_MARKERS is not set ++CONFIG_OPROFILE=m ++CONFIG_HAVE_OPROFILE=y ++CONFIG_KPROBES=y ++CONFIG_HAVE_KPROBES=y ++# CONFIG_HAVE_KRETPROBES is not set ++CONFIG_PROC_PAGE_MONITOR=y + CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set - CONFIG_BASE_SMALL=1 -- --# --# 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 is not set -- --# --# Block layer --# - CONFIG_BLOCK=y - # CONFIG_LBD is not set - # CONFIG_BLK_DEV_IO_TRACE is not set - # CONFIG_LSF is not set -+# CONFIG_BLK_DEV_BSG is not set - - # - # IO Schedulers -@@ -99,32 +93,49 @@ - CONFIG_IOSCHED_NOOP=y - # CONFIG_IOSCHED_AS is not set - # CONFIG_IOSCHED_DEADLINE is not set --# CONFIG_IOSCHED_CFQ is not set -+CONFIG_IOSCHED_CFQ=y - # 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" -+CONFIG_DEFAULT_CFQ=y -+# CONFIG_DEFAULT_NOOP is not set -+CONFIG_DEFAULT_IOSCHED="cfq" +@@ -98,10 +108,15 @@ + CONFIG_DEFAULT_CFQ=y + # CONFIG_DEFAULT_NOOP is not set + CONFIG_DEFAULT_IOSCHED="cfq" ++CONFIG_CLASSIC_RCU=y # # System Type and features @@ -1972,422 +1564,138 @@ CONFIG_SUBARCH_AVR32B=y CONFIG_MMU=y CONFIG_PERFORMANCE_COUNTERS=y - CONFIG_PLATFORM_AT32AP=y -+CONFIG_CPU_AT32AP700X=y - CONFIG_CPU_AT32AP7000=y --CONFIG_BOARD_ATSTK1002=y - CONFIG_BOARD_ATSTK1000=y - # CONFIG_BOARD_ATNGW100 is not set -+CONFIG_BOARD_ATSTK1002=y -+# CONFIG_BOARD_ATSTK1003 is not set -+# CONFIG_BOARD_ATSTK1004 is not set -+# CONFIG_BOARD_ATSTK100X_CUSTOM is not set -+# CONFIG_BOARD_ATSTK100X_SPI1 is not set -+# CONFIG_BOARD_ATSTK1000_J2_LED is not set -+# CONFIG_BOARD_ATSTK1000_J2_LED8 is not set -+# CONFIG_BOARD_ATSTK1000_J2_RGB is not set -+CONFIG_BOARD_ATSTK1000_EXTDAC=y +@@ -113,12 +128,16 @@ + CONFIG_BOARD_ATSTK1002=y + # CONFIG_BOARD_ATSTK1003 is not set + # CONFIG_BOARD_ATSTK1004 is not set ++# CONFIG_BOARD_ATSTK1006 is not set + # CONFIG_BOARD_ATSTK100X_CUSTOM is not set + # CONFIG_BOARD_ATSTK100X_SPI1 is not set + # CONFIG_BOARD_ATSTK1000_J2_LED is not set + # CONFIG_BOARD_ATSTK1000_J2_LED8 is not set + # CONFIG_BOARD_ATSTK1000_J2_RGB is not set + CONFIG_BOARD_ATSTK1000_EXTDAC=y +# CONFIG_BOARD_ATSTK100X_ENABLE_AC97 is not set +# CONFIG_BOARD_ATSTK1000_CF_HACKS is not set +# CONFIG_BOARD_ATSTK100X_ENABLE_PSIF is not set CONFIG_LOADER_U_BOOT=y # - # Atmel AVR32 AP options - # --# CONFIG_AP7000_32_BIT_SMC is not set --CONFIG_AP7000_16_BIT_SMC=y --# CONFIG_AP7000_8_BIT_SMC is not set -+# CONFIG_AP700X_32_BIT_SMC is not set -+CONFIG_AP700X_16_BIT_SMC=y -+# CONFIG_AP700X_8_BIT_SMC is not set +@@ -127,6 +146,7 @@ + # CONFIG_AP700X_32_BIT_SMC is not set + CONFIG_AP700X_16_BIT_SMC=y + # CONFIG_AP700X_8_BIT_SMC is not set +CONFIG_GPIO_DEV=y CONFIG_LOAD_ADDRESS=0x10000000 CONFIG_ENTRY_ADDRESS=0x90000000 CONFIG_PHYS_OFFSET=0x10000000 -@@ -144,10 +155,14 @@ - CONFIG_FLATMEM=y - CONFIG_FLAT_NODE_MEM_MAP=y - # CONFIG_SPARSEMEM_STATIC is not set -+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set - CONFIG_SPLIT_PTLOCK_CPUS=4 - # CONFIG_RESOURCES_64BIT is not set +@@ -152,16 +172,26 @@ CONFIG_ZONE_DMA_FLAG=0 -+CONFIG_VIRT_TO_BUS=y + CONFIG_VIRT_TO_BUS=y # CONFIG_OWNERSHIP_TRACE is not set +CONFIG_NMI_DEBUGGING=y +CONFIG_DW_DMAC=y # CONFIG_HZ_100 is not set CONFIG_HZ_250=y # CONFIG_HZ_300 is not set -@@ -156,13 +171,31 @@ + # CONFIG_HZ_1000 is not set + CONFIG_HZ=250 ++# CONFIG_SCHED_HRTICK is not set CONFIG_CMDLINE="" # --# Bus options -+# Power management options - # --# CONFIG_ARCH_SUPPORTS_MSI is not set - - # --# PCCARD (PCMCIA/CardBus) support -+# CPU Frequency scaling -+# -+CONFIG_CPU_FREQ=y -+CONFIG_CPU_FREQ_TABLE=y -+# CONFIG_CPU_FREQ_DEBUG is not set -+# CONFIG_CPU_FREQ_STAT is not set -+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y -+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set -+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set -+CONFIG_CPU_FREQ_GOV_USERSPACE=y -+CONFIG_CPU_FREQ_GOV_ONDEMAND=y -+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set -+CONFIG_CPU_FREQ_AT32AP=y -+ -+# -+# Bus options + # Power management options # -+# CONFIG_ARCH_SUPPORTS_MSI is not set - # CONFIG_PCCARD is not set ++CONFIG_ARCH_SUSPEND_POSSIBLE=y ++CONFIG_PM=y ++# CONFIG_PM_LEGACY is not set ++# CONFIG_PM_DEBUG is not set ++CONFIG_PM_SLEEP=y ++CONFIG_SUSPEND=y ++CONFIG_SUSPEND_FREEZER=y # -@@ -182,7 +215,12 @@ - CONFIG_PACKET=y - CONFIG_PACKET_MMAP=y - CONFIG_UNIX=y --# CONFIG_NET_KEY is not set -+CONFIG_XFRM=y -+CONFIG_XFRM_USER=m -+# CONFIG_XFRM_SUB_POLICY is not set -+# CONFIG_XFRM_MIGRATE is not set -+CONFIG_NET_KEY=m -+# CONFIG_NET_KEY_MIGRATE is not set + # CPU Frequency scaling +@@ -170,9 +200,9 @@ + CONFIG_CPU_FREQ_TABLE=y + # CONFIG_CPU_FREQ_DEBUG is not set + # CONFIG_CPU_FREQ_STAT is not set +-CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y ++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set + # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +-# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set ++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y + # CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set + CONFIG_CPU_FREQ_GOV_PERFORMANCE=y + # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +@@ -208,6 +238,7 @@ + CONFIG_XFRM_USER=m + # CONFIG_XFRM_SUB_POLICY is not set + # CONFIG_XFRM_MIGRATE is not set ++# CONFIG_XFRM_STATISTICS is not set + CONFIG_NET_KEY=m + # CONFIG_NET_KEY_MIGRATE is not set CONFIG_INET=y - # CONFIG_IP_MULTICAST is not set - # CONFIG_IP_ADVANCED_ROUTER is not set -@@ -191,36 +229,52 @@ - CONFIG_IP_PNP_DHCP=y - # CONFIG_IP_PNP_BOOTP is not set - # CONFIG_IP_PNP_RARP is not set --# CONFIG_NET_IPIP is not set --# CONFIG_NET_IPGRE is not set -+CONFIG_NET_IPIP=m -+CONFIG_NET_IPGRE=m - # CONFIG_ARPD is not set - # CONFIG_SYN_COOKIES is not set --# CONFIG_INET_AH is not set --# CONFIG_INET_ESP is not set -+CONFIG_INET_AH=m -+CONFIG_INET_ESP=m - # 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_XFRM_MODE_BEET is not set -+CONFIG_INET_TUNNEL=m -+CONFIG_INET_XFRM_MODE_TRANSPORT=m -+CONFIG_INET_XFRM_MODE_TUNNEL=m -+CONFIG_INET_XFRM_MODE_BEET=m -+# CONFIG_INET_LRO is not set - CONFIG_INET_DIAG=y - CONFIG_INET_TCP_DIAG=y - # CONFIG_TCP_CONG_ADVANCED is not set - CONFIG_TCP_CONG_CUBIC=y - CONFIG_DEFAULT_TCP_CONG="cubic" - # CONFIG_TCP_MD5SIG is not set --# CONFIG_IPV6 is not set --# CONFIG_INET6_XFRM_TUNNEL is not set --# CONFIG_INET6_TUNNEL is not set -+CONFIG_IPV6=m -+# CONFIG_IPV6_PRIVACY is not set -+# CONFIG_IPV6_ROUTER_PREF is not set -+# CONFIG_IPV6_OPTIMISTIC_DAD is not set -+CONFIG_INET6_AH=m -+CONFIG_INET6_ESP=m -+CONFIG_INET6_IPCOMP=m -+# CONFIG_IPV6_MIP6 is not set -+CONFIG_INET6_XFRM_TUNNEL=m -+CONFIG_INET6_TUNNEL=m -+CONFIG_INET6_XFRM_MODE_TRANSPORT=m -+CONFIG_INET6_XFRM_MODE_TUNNEL=m -+CONFIG_INET6_XFRM_MODE_BEET=m -+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set -+CONFIG_IPV6_SIT=m -+CONFIG_IPV6_TUNNEL=m -+# CONFIG_IPV6_MULTIPLE_TABLES is not set - # CONFIG_NETWORK_SECMARK is not set - # CONFIG_NETFILTER is not set - # CONFIG_IP_DCCP is not set - # CONFIG_IP_SCTP is not set - # CONFIG_TIPC is not set - # CONFIG_ATM is not set --# CONFIG_BRIDGE is not set -+CONFIG_BRIDGE=m - # CONFIG_VLAN_8021Q is not set - # CONFIG_DECNET is not set -+CONFIG_LLC=m - # CONFIG_LLC2 is not set - # CONFIG_IPX is not set - # CONFIG_ATALK is not set -@@ -228,16 +282,13 @@ - # CONFIG_LAPB is not set - # CONFIG_ECONET is not set - # CONFIG_WAN_ROUTER is not set -- --# --# QoS and/or fair queueing --# - # CONFIG_NET_SCHED is not set - - # - # Network testing - # +@@ -279,6 +310,7 @@ # CONFIG_NET_PKTGEN is not set -+# CONFIG_NET_TCPPROBE is not set + # CONFIG_NET_TCPPROBE is not set # CONFIG_HAMRADIO is not set ++# CONFIG_CAN is not set # CONFIG_IRDA is not set # CONFIG_BT is not set -@@ -251,6 +302,7 @@ - # CONFIG_MAC80211 is not set - # CONFIG_IEEE80211 is not set - # CONFIG_RFKILL is not set -+# CONFIG_NET_9P is not set - - # - # Device Drivers -@@ -259,16 +311,13 @@ - # - # Generic Driver Options - # -+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" - CONFIG_STANDALONE=y - # CONFIG_PREVENT_FIRMWARE_BUILD is not set - # CONFIG_FW_LOADER is not set - # CONFIG_DEBUG_DRIVER is not set - # CONFIG_DEBUG_DEVRES is not set - # CONFIG_SYS_HYPERVISOR is not set -- --# --# Connector - unified userspace <-> kernelspace linker --# - # CONFIG_CONNECTOR is not set - CONFIG_MTD=y - # CONFIG_MTD_DEBUG is not set -@@ -288,6 +337,7 @@ - # CONFIG_INFTL is not set - # CONFIG_RFD_FTL is not set - # CONFIG_SSFDC is not set -+# CONFIG_MTD_OOPS is not set - - # - # RAM/ROM/Flash chip drivers -@@ -327,6 +377,8 @@ - # - # Self-contained MTD device drivers - # -+CONFIG_MTD_DATAFLASH=m -+CONFIG_MTD_M25P80=m - # CONFIG_MTD_SLRAM is not set - # CONFIG_MTD_PHRAM is not set - # CONFIG_MTD_MTDRAM is not set -@@ -345,20 +397,8 @@ - # UBI - Unsorted block images - # - # CONFIG_MTD_UBI is not set -- --# --# Parallel port support --# - # CONFIG_PARPORT is not set -- --# --# Plug and Play support --# --# CONFIG_PNPACPI is not set -- --# --# Block devices --# -+CONFIG_BLK_DEV=y - # CONFIG_BLK_DEV_COW_COMMON is not set - CONFIG_BLK_DEV_LOOP=m - # CONFIG_BLK_DEV_CRYPTOLOOP is not set -@@ -369,42 +409,91 @@ - CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 + # CONFIG_AF_RXRPC is not set +@@ -395,13 +427,18 @@ + CONFIG_BLK_DEV_RAM=m + CONFIG_BLK_DEV_RAM_COUNT=16 + CONFIG_BLK_DEV_RAM_SIZE=4096 +-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 ++# CONFIG_BLK_DEV_XIP is not set # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set -- --# --# Misc devices --# --# CONFIG_BLINK is not set -+CONFIG_MISC_DEVICES=y + CONFIG_MISC_DEVICES=y +CONFIG_ATMEL_PWM=m +CONFIG_ATMEL_TCLIB=y +CONFIG_ATMEL_TCB_CLKSRC=y +CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0 -+# CONFIG_EEPROM_93CX6 is not set -+CONFIG_ATMEL_SSC=m - # CONFIG_IDE is not set + # CONFIG_EEPROM_93CX6 is not set + CONFIG_ATMEL_SSC=m +-# CONFIG_IDE is not set ++# CONFIG_ENCLOSURE_SERVICES is not set ++# CONFIG_HAVE_IDE is not set # # SCSI device support - # - # CONFIG_RAID_ATTRS is not set --# CONFIG_SCSI is not set -+CONFIG_SCSI=m -+CONFIG_SCSI_DMA=y -+# CONFIG_SCSI_TGT is not set - # CONFIG_SCSI_NETLINK is not set --# CONFIG_ATA is not set -+# CONFIG_SCSI_PROC_FS is not set - - # --# Multi-device support (RAID and LVM) -+# SCSI support type (disk, tape, CD-ROM) - # --# CONFIG_MD is not set -+CONFIG_BLK_DEV_SD=m -+# CONFIG_CHR_DEV_ST is not set -+# CONFIG_CHR_DEV_OSST is not set -+CONFIG_BLK_DEV_SR=m -+# CONFIG_BLK_DEV_SR_VENDOR is not set -+# CONFIG_CHR_DEV_SG is not set -+# CONFIG_CHR_DEV_SCH is not set -+ -+# -+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -+# -+# CONFIG_SCSI_MULTI_LUN is not set -+# CONFIG_SCSI_CONSTANTS is not set -+# CONFIG_SCSI_LOGGING is not set -+# CONFIG_SCSI_SCAN_ASYNC is not set -+CONFIG_SCSI_WAIT_SCAN=m - - # --# Network device support -+# SCSI Transports - # -+# CONFIG_SCSI_SPI_ATTRS is not set -+# CONFIG_SCSI_FC_ATTRS is not set -+# CONFIG_SCSI_ISCSI_ATTRS is not set -+# CONFIG_SCSI_SAS_LIBSAS is not set -+# CONFIG_SCSI_SRP_ATTRS is not set -+# CONFIG_SCSI_LOWLEVEL is not set -+CONFIG_ATA=m -+# CONFIG_ATA_NONSTANDARD is not set -+CONFIG_PATA_AT32=m -+# CONFIG_PATA_PLATFORM is not set -+# CONFIG_MD is not set - CONFIG_NETDEVICES=y --CONFIG_DUMMY=y -+# CONFIG_NETDEVICES_MULTIQUEUE is not set -+# CONFIG_DUMMY is not set - # CONFIG_BONDING is not set -+# CONFIG_MACVLAN is not set - # CONFIG_EQUALIZER is not set - CONFIG_TUN=m --# CONFIG_PHYLIB is not set -+# CONFIG_VETH is not set -+CONFIG_PHYLIB=y - - # --# Ethernet (10 or 100Mbit) -+# MII PHY device drivers - # -+# CONFIG_MARVELL_PHY is not set -+# CONFIG_DAVICOM_PHY is not set -+# CONFIG_QSEMI_PHY is not set -+# CONFIG_LXT_PHY is not set -+# CONFIG_CICADA_PHY is not set -+# CONFIG_VITESSE_PHY is not set -+# CONFIG_SMSC_PHY is not set -+# CONFIG_BROADCOM_PHY is not set -+# CONFIG_ICPLUS_PHY is not set -+# CONFIG_FIXED_PHY is not set -+# CONFIG_MDIO_BITBANG is not set +@@ -444,6 +481,7 @@ + # CONFIG_SCSI_LOWLEVEL is not set + CONFIG_ATA=m + # CONFIG_ATA_NONSTANDARD is not set ++# CONFIG_SATA_MV is not set + CONFIG_PATA_AT32=m + # CONFIG_PATA_PLATFORM is not set + # CONFIG_MD is not set +@@ -469,11 +507,13 @@ + # CONFIG_SMSC_PHY is not set + # CONFIG_BROADCOM_PHY is not set + # CONFIG_ICPLUS_PHY is not set ++# CONFIG_REALTEK_PHY is not set + # CONFIG_FIXED_PHY is not set + # CONFIG_MDIO_BITBANG is not set CONFIG_NET_ETHERNET=y --CONFIG_MII=y -+# CONFIG_MII is not set + # CONFIG_MII is not set CONFIG_MACB=y -+# CONFIG_IBM_NEW_EMAC_ZMII is not set -+# CONFIG_IBM_NEW_EMAC_RGMII is not set -+# CONFIG_IBM_NEW_EMAC_TAH is not set -+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set -+# CONFIG_B44 is not set - # CONFIG_NETDEV_1000 is not set - # CONFIG_NETDEV_10000 is not set - -@@ -423,27 +512,54 @@ - CONFIG_PPP_BSDCOMP=m - # CONFIG_PPP_MPPE is not set - # CONFIG_PPPOE is not set -+# CONFIG_PPPOL2TP is not set ++# CONFIG_ENC28J60 is not set + # CONFIG_IBM_NEW_EMAC_ZMII is not set + # CONFIG_IBM_NEW_EMAC_RGMII is not set + # CONFIG_IBM_NEW_EMAC_TAH is not set +@@ -500,7 +540,6 @@ + # CONFIG_PPPOL2TP is not set # CONFIG_SLIP is not set CONFIG_SLHC=m - # CONFIG_SHAPER 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 -+CONFIG_INPUT=m -+# CONFIG_INPUT_FF_MEMLESS is not set -+CONFIG_INPUT_POLLDEV=m -+ -+# -+# Userland interfaces -+# -+CONFIG_INPUT_MOUSEDEV=m -+CONFIG_INPUT_MOUSEDEV_PSAUX=y -+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -+# CONFIG_INPUT_JOYDEV is not set -+CONFIG_INPUT_EVDEV=m -+# CONFIG_INPUT_EVBUG is not set -+ -+# -+# Input Device Drivers -+# -+CONFIG_INPUT_KEYBOARD=y -+# CONFIG_KEYBOARD_ATKBD is not set -+# CONFIG_KEYBOARD_SUNKBD is not set -+# CONFIG_KEYBOARD_LKKBD is not set -+# CONFIG_KEYBOARD_XTKBD is not set -+# CONFIG_KEYBOARD_NEWTON is not set -+# CONFIG_KEYBOARD_STOWAWAY is not set -+CONFIG_KEYBOARD_GPIO=m -+CONFIG_INPUT_MOUSE=y -+# CONFIG_MOUSE_PS2 is not set -+# CONFIG_MOUSE_SERIAL is not set -+# CONFIG_MOUSE_VSXXXAA is not set -+CONFIG_MOUSE_GPIO=m -+# CONFIG_INPUT_JOYSTICK is not set -+# CONFIG_INPUT_TABLET is not set -+# CONFIG_INPUT_TOUCHSCREEN is not set -+# CONFIG_INPUT_MISC is not set - - # - # Hardware I/O ports -@@ -467,40 +583,94 @@ +@@ -568,6 +607,7 @@ # CONFIG_SERIAL_ATMEL=y CONFIG_SERIAL_ATMEL_CONSOLE=y @@ -2395,347 +1703,672 @@ # CONFIG_SERIAL_ATMEL_TTYAT is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y - CONFIG_UNIX98_PTYS=y +@@ -575,8 +615,6 @@ # CONFIG_LEGACY_PTYS is not set -- --# --# IPMI --# # CONFIG_IPMI_HANDLER is not set --# CONFIG_WATCHDOG is not set # CONFIG_HW_RANDOM is not set - # CONFIG_RTC is not set - # CONFIG_GEN_RTC is not set +-# CONFIG_RTC is not set +-# CONFIG_GEN_RTC is not set # CONFIG_R3964 is not set # CONFIG_RAW_DRIVER is not set -+# CONFIG_TCG_TPM is not set -+CONFIG_I2C=m -+CONFIG_I2C_BOARDINFO=y -+CONFIG_I2C_CHARDEV=m + # CONFIG_TCG_TPM is not set +@@ -594,6 +632,7 @@ + # + # I2C Hardware Bus support + # ++CONFIG_I2C_ATMELTWI=m + CONFIG_I2C_GPIO=m + # CONFIG_I2C_OCORES is not set + # CONFIG_I2C_PARPORT_LIGHT is not set +@@ -604,13 +643,12 @@ + # + # Miscellaneous I2C Chip support + # +-# CONFIG_SENSORS_DS1337 is not set +-# CONFIG_SENSORS_DS1374 is not set + # CONFIG_DS1682 is not set + # CONFIG_SENSORS_EEPROM is not set + # CONFIG_SENSORS_PCF8574 is not set +-# CONFIG_SENSORS_PCA9539 is not set ++# CONFIG_PCF8575 is not set + # CONFIG_SENSORS_PCF8591 is not set ++# CONFIG_TPS65010 is not set + # CONFIG_SENSORS_MAX6875 is not set + # CONFIG_SENSORS_TSL2550 is not set + # CONFIG_I2C_DEBUG_CORE is not set +@@ -637,9 +675,27 @@ + # CONFIG_SPI_AT25 is not set + CONFIG_SPI_SPIDEV=m + # CONFIG_SPI_TLE62X0 is not set ++CONFIG_HAVE_GPIO_LIB=y + +# -+# I2C Algorithms ++# GPIO Support +# -+CONFIG_I2C_ALGOBIT=m -+# CONFIG_I2C_ALGOPCF is not set -+# CONFIG_I2C_ALGOPCA is not set ++# CONFIG_DEBUG_GPIO is not set + +# -+# I2C Hardware Bus support ++# I2C GPIO expanders: +# -+CONFIG_I2C_ATMELTWI=m -+CONFIG_I2C_GPIO=m -+# CONFIG_I2C_OCORES is not set -+# CONFIG_I2C_PARPORT_LIGHT is not set -+# CONFIG_I2C_SIMTEC is not set -+# CONFIG_I2C_TAOS_EVM is not set -+# CONFIG_I2C_STUB is not set ++# CONFIG_GPIO_PCA953X is not set ++# CONFIG_GPIO_PCF857X is not set + +# -+# Miscellaneous I2C Chip support ++# SPI GPIO expanders: +# -+# CONFIG_SENSORS_DS1337 is not set -+# CONFIG_SENSORS_DS1374 is not set -+# CONFIG_DS1682 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_MAX6875 is not set -+# CONFIG_SENSORS_TSL2550 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 ++# CONFIG_GPIO_MCP23S08 is not set + # CONFIG_W1 is not set + # CONFIG_POWER_SUPPLY is not set + # CONFIG_HWMON is not set ++# CONFIG_THERMAL is not set + CONFIG_WATCHDOG=y + # CONFIG_WATCHDOG_NOWAYOUT is not set +@@ -732,12 +788,18 @@ # --# TPM devices -+# SPI support + # Generic devices # --# CONFIG_TCG_TPM is not set --# CONFIG_I2C is not set -+CONFIG_SPI=y -+# CONFIG_SPI_DEBUG is not set -+CONFIG_SPI_MASTER=y ++CONFIG_SND_AC97_CODEC=m + # CONFIG_SND_DUMMY is not set + # CONFIG_SND_MTPAV is not set + # CONFIG_SND_SERIAL_U16550 is not set + # CONFIG_SND_MPU401 is not set # --# SPI support -+# SPI Master Controller Drivers ++# AVR32 devices ++# ++CONFIG_SND_ATMEL_AC97=m ++ ++# + # SPI devices # --# CONFIG_SPI is not set --# CONFIG_SPI_MASTER is not set -+CONFIG_SPI_ATMEL=y -+# CONFIG_SPI_BITBANG is not set - + CONFIG_SND_AT73C213=m +@@ -753,9 +815,14 @@ # --# Dallas's 1-wire bus -+# SPI Protocol Masters + # -+# CONFIG_SPI_AT25 is not set -+CONFIG_SPI_SPIDEV=m -+# CONFIG_SPI_TLE62X0 is not set - # CONFIG_W1 is not set -+# CONFIG_POWER_SUPPLY is not set - # CONFIG_HWMON is not set -+CONFIG_WATCHDOG=y -+# CONFIG_WATCHDOG_NOWAYOUT is not set -+ ++# ALSA SoC audio for Freescale SOCs +# -+# Watchdog Device Drivers -+# -+# CONFIG_SOFT_WATCHDOG is not set -+CONFIG_AT32AP700X_WDT=y + +# -+# Sonics Silicon Backplane -+# -+CONFIG_SSB_POSSIBLE=y -+# CONFIG_SSB is not set + # Open Sound System + # + # CONFIG_SOUND_PRIME is not set ++CONFIG_AC97_BUS=m + # CONFIG_HID_SUPPORT is not set + CONFIG_USB_SUPPORT=y + # CONFIG_USB_ARCH_HAS_HCD is not set +@@ -765,10 +832,6 @@ + # + # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' + # +- +-# +-# USB Gadget Support +-# + CONFIG_USB_GADGET=y + # CONFIG_USB_GADGET_DEBUG is not set + # CONFIG_USB_GADGET_DEBUG_FILES is not set +@@ -796,27 +859,31 @@ + # CONFIG_USB_FILE_STORAGE_TEST is not set + CONFIG_USB_G_SERIAL=m + # CONFIG_USB_MIDI_GADGET is not set +-CONFIG_MMC=m ++# CONFIG_USB_G_PRINTER is not set ++CONFIG_MMC=y + # CONFIG_MMC_DEBUG is not set + # CONFIG_MMC_UNSAFE_RESUME is not set # - # Multifunction device drivers -@@ -517,23 +687,104 @@ + # MMC/SD Card Drivers # - # Graphics support +-CONFIG_MMC_BLOCK=m ++CONFIG_MMC_BLOCK=y + CONFIG_MMC_BLOCK_BOUNCE=y + # CONFIG_SDIO_UART is not set + # --# CONFIG_BACKLIGHT_LCD_SUPPORT is not set -+# CONFIG_VGASTATE is not set -+# CONFIG_VIDEO_OUTPUT_CONTROL is not set -+CONFIG_FB=y -+# CONFIG_FIRMWARE_EDID is not set -+# CONFIG_FB_DDC is not set -+CONFIG_FB_CFB_FILLRECT=y -+CONFIG_FB_CFB_COPYAREA=y -+CONFIG_FB_CFB_IMAGEBLIT=y -+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set -+# CONFIG_FB_SYS_FILLRECT is not set -+# CONFIG_FB_SYS_COPYAREA is not set -+# CONFIG_FB_SYS_IMAGEBLIT is not set -+# CONFIG_FB_SYS_FOPS is not set -+CONFIG_FB_DEFERRED_IO=y -+# CONFIG_FB_SVGALIB is not set -+# CONFIG_FB_MACMODES is not set -+# CONFIG_FB_BACKLIGHT is not set -+# CONFIG_FB_MODE_HELPERS is not set -+# CONFIG_FB_TILEBLITTING is not set -+ -+# -+# Frame buffer hardware drivers -+# -+# CONFIG_FB_S1D13XXX is not set -+CONFIG_FB_ATMEL=y -+# CONFIG_FB_VIRTUAL is not set -+CONFIG_BACKLIGHT_LCD_SUPPORT=y -+CONFIG_LCD_CLASS_DEVICE=y -+CONFIG_LCD_LTV350QV=y -+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set + # MMC/SD Host Controller Drivers + # ++CONFIG_MMC_ATMELMCI=y + CONFIG_MMC_SPI=m ++# CONFIG_MEMSTICK is not set + CONFIG_NEW_LEDS=y + CONFIG_LEDS_CLASS=m # - # Display device support + # LED drivers # - # CONFIG_DISPLAY_SUPPORT is not set --# CONFIG_VGASTATE is not set --# CONFIG_FB is not set -+# CONFIG_LOGO is not set ++CONFIG_LEDS_ATMEL_PWM=m + CONFIG_LEDS_GPIO=m + + # +@@ -853,19 +920,22 @@ + # CONFIG_RTC_DRV_PCF8563 is not set + # CONFIG_RTC_DRV_PCF8583 is not set + # CONFIG_RTC_DRV_M41T80 is not set ++# CONFIG_RTC_DRV_S35390A is not set # - # Sound + # SPI RTC drivers # --# CONFIG_SOUND is not set -+CONFIG_SOUND=m +-# CONFIG_RTC_DRV_RS5C348 is not set + # CONFIG_RTC_DRV_MAX6902 is not set ++# CONFIG_RTC_DRV_R9701 is not set ++# CONFIG_RTC_DRV_RS5C348 is not set + + # + # Platform RTC drivers + # ++# CONFIG_RTC_DRV_DS1511 is not set + # CONFIG_RTC_DRV_DS1553 is not set +-# CONFIG_RTC_DRV_STK17TA8 is not set + # CONFIG_RTC_DRV_DS1742 is not set ++# CONFIG_RTC_DRV_STK17TA8 is not set + # CONFIG_RTC_DRV_M48T86 is not set + # CONFIG_RTC_DRV_M48T59 is not set + # CONFIG_RTC_DRV_V3020 is not set +@@ -883,13 +953,13 @@ + # + # File systems + # +-CONFIG_EXT2_FS=m ++CONFIG_EXT2_FS=y + # CONFIG_EXT2_FS_XATTR is not set + # CONFIG_EXT2_FS_XIP is not set +-CONFIG_EXT3_FS=m ++CONFIG_EXT3_FS=y + # CONFIG_EXT3_FS_XATTR is not set + # CONFIG_EXT4DEV_FS is not set +-CONFIG_JBD=m ++CONFIG_JBD=y + # CONFIG_JBD_DEBUG is not set + # CONFIG_REISERFS_FS is not set + # CONFIG_JFS_FS is not set +@@ -897,12 +967,10 @@ + # CONFIG_XFS_FS is not set + # CONFIG_GFS2_FS is not set + # CONFIG_OCFS2_FS is not set +-CONFIG_MINIX_FS=m +-# CONFIG_ROMFS_FS is not set ++# CONFIG_DNOTIFY is not set + CONFIG_INOTIFY=y + CONFIG_INOTIFY_USER=y + # CONFIG_QUOTA is not set +-# CONFIG_DNOTIFY is not set + # CONFIG_AUTOFS_FS is not set + # CONFIG_AUTOFS4_FS is not set + CONFIG_FUSE_FS=m +@@ -933,7 +1001,7 @@ + CONFIG_TMPFS=y + # CONFIG_TMPFS_POSIX_ACL is not set + # CONFIG_HUGETLB_PAGE is not set +-# CONFIG_CONFIGFS_FS is not set ++CONFIG_CONFIGFS_FS=y + + # + # Miscellaneous filesystems +@@ -957,8 +1025,10 @@ + # CONFIG_JFFS2_RUBIN is not set + # CONFIG_CRAMFS is not set + # CONFIG_VXFS_FS is not set ++CONFIG_MINIX_FS=m + # CONFIG_HPFS_FS is not set + # CONFIG_QNX4FS_FS is not set ++# CONFIG_ROMFS_FS is not set + # CONFIG_SYSV_FS is not set + # CONFIG_UFS_FS is not set + CONFIG_NETWORK_FILESYSTEMS=y +@@ -1028,11 +1098,6 @@ + # CONFIG_NLS_KOI8_U is not set + CONFIG_NLS_UTF8=m + # CONFIG_DLM is not set +-CONFIG_INSTRUMENTATION=y +-CONFIG_PROFILING=y +-CONFIG_OPROFILE=m +-CONFIG_KPROBES=y +-# CONFIG_MARKERS is not set + + # + # Kernel hacking +@@ -1051,6 +1116,7 @@ + # CONFIG_SCHEDSTATS is not set + # CONFIG_TIMER_STATS is not set + # CONFIG_SLUB_DEBUG_ON is not set ++# CONFIG_SLUB_STATS is not set + # CONFIG_DEBUG_RT_MUTEXES is not set + # CONFIG_RT_MUTEX_TESTER is not set + # CONFIG_DEBUG_SPINLOCK is not set +@@ -1067,9 +1133,10 @@ + # CONFIG_DEBUG_LIST is not set + # CONFIG_DEBUG_SG is not set + CONFIG_FRAME_POINTER=y +-CONFIG_FORCED_INLINING=y + # CONFIG_BOOT_PRINTK_DELAY is not set + # CONFIG_RCU_TORTURE_TEST is not set ++# CONFIG_KPROBES_SANITY_TEST is not set ++# CONFIG_BACKTRACE_SELF_TEST is not set + # CONFIG_LKDTM is not set + # CONFIG_FAULT_INJECTION is not set + # CONFIG_SAMPLES is not set +@@ -1082,7 +1149,9 @@ + # CONFIG_SECURITY_FILE_CAPABILITIES is not set + CONFIG_CRYPTO=y + CONFIG_CRYPTO_ALGAPI=m ++CONFIG_CRYPTO_AEAD=m + CONFIG_CRYPTO_BLKCIPHER=m ++# CONFIG_CRYPTO_SEQIV is not set + CONFIG_CRYPTO_HASH=m + CONFIG_CRYPTO_MANAGER=m + CONFIG_CRYPTO_HMAC=m +@@ -1101,6 +1170,9 @@ + # CONFIG_CRYPTO_PCBC is not set + # CONFIG_CRYPTO_LRW is not set + # CONFIG_CRYPTO_XTS is not set ++# CONFIG_CRYPTO_CTR is not set ++# CONFIG_CRYPTO_GCM is not set ++# CONFIG_CRYPTO_CCM is not set + # CONFIG_CRYPTO_CRYPTD is not set + CONFIG_CRYPTO_DES=m + # CONFIG_CRYPTO_FCRYPT is not set +@@ -1115,12 +1187,14 @@ + # CONFIG_CRYPTO_KHAZAD is not set + # CONFIG_CRYPTO_ANUBIS is not set + # CONFIG_CRYPTO_SEED is not set ++# CONFIG_CRYPTO_SALSA20 is not set + CONFIG_CRYPTO_DEFLATE=m + # CONFIG_CRYPTO_MICHAEL_MIC is not set + # CONFIG_CRYPTO_CRC32C is not set + # CONFIG_CRYPTO_CAMELLIA is not set + # CONFIG_CRYPTO_TEST is not set +-# CONFIG_CRYPTO_AUTHENC is not set ++CONFIG_CRYPTO_AUTHENC=m ++# CONFIG_CRYPTO_LZO is not set + # CONFIG_CRYPTO_HW is not set + + # +@@ -1135,6 +1209,7 @@ + # CONFIG_LIBCRC32C is not set + CONFIG_ZLIB_INFLATE=y + CONFIG_ZLIB_DEFLATE=y ++CONFIG_GENERIC_ALLOCATOR=y + CONFIG_PLIST=y + CONFIG_HAS_IOMEM=y + CONFIG_HAS_IOPORT=y +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/configs/atstk1003_defconfig avr32-2.6/arch/avr32/configs/atstk1003_defconfig +--- linux-2.6.25.6/arch/avr32/configs/atstk1003_defconfig 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/configs/atstk1003_defconfig 2008-06-12 15:09:38.715815679 +0200 +@@ -1,7 +1,7 @@ + # + # Automatically generated make config: don't edit +-# Linux kernel version: 2.6.24-rc7 +-# Wed Jan 9 22:54:34 2008 ++# Linux kernel version: 2.6.25.4 ++# Wed Jun 11 15:33:36 2008 + # + CONFIG_AVR32=y + CONFIG_GENERIC_GPIO=y +@@ -13,10 +13,10 @@ + CONFIG_GENERIC_IRQ_PROBE=y + CONFIG_RWSEM_GENERIC_SPINLOCK=y + CONFIG_GENERIC_TIME=y ++CONFIG_GENERIC_CLOCKEVENTS=y + # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set + # CONFIG_ARCH_HAS_ILOG2_U32 is not set + # CONFIG_ARCH_HAS_ILOG2_U64 is not set +-CONFIG_ARCH_SUPPORTS_OPROFILE=y + CONFIG_GENERIC_HWEIGHT=y + CONFIG_GENERIC_CALIBRATE_DELAY=y + CONFIG_GENERIC_BUG=y +@@ -39,17 +39,15 @@ + CONFIG_TASKSTATS=y + CONFIG_TASK_DELAY_ACCT=y + # CONFIG_TASK_XACCT is not set +-# CONFIG_USER_NS is not set +-# CONFIG_PID_NS is not set + CONFIG_AUDIT=y + # CONFIG_IKCONFIG is not set + CONFIG_LOG_BUF_SHIFT=14 + # CONFIG_CGROUPS is not set +-CONFIG_FAIR_GROUP_SCHED=y +-CONFIG_FAIR_USER_SCHED=y +-# CONFIG_FAIR_CGROUP_SCHED is not set ++# CONFIG_GROUP_SCHED is not set + CONFIG_SYSFS_DEPRECATED=y ++CONFIG_SYSFS_DEPRECATED_V2=y + CONFIG_RELAY=y ++# CONFIG_NAMESPACES is not set + CONFIG_BLK_DEV_INITRD=y + CONFIG_INITRAMFS_SOURCE="" + CONFIG_CC_OPTIMIZE_FOR_SIZE=y +@@ -63,11 +61,13 @@ + CONFIG_PRINTK=y + CONFIG_BUG=y + CONFIG_ELF_CORE=y ++# CONFIG_COMPAT_BRK is not set + # CONFIG_BASE_FULL is not set + CONFIG_FUTEX=y + CONFIG_ANON_INODES=y + CONFIG_EPOLL=y + CONFIG_SIGNALFD=y ++CONFIG_TIMERFD=y + CONFIG_EVENTFD=y + CONFIG_SHMEM=y + CONFIG_VM_EVENT_COUNTERS=y +@@ -75,6 +75,14 @@ + # CONFIG_SLAB is not set + CONFIG_SLUB=y + # CONFIG_SLOB is not set ++CONFIG_PROFILING=y ++# CONFIG_MARKERS is not set ++CONFIG_OPROFILE=m ++CONFIG_HAVE_OPROFILE=y ++CONFIG_KPROBES=y ++CONFIG_HAVE_KPROBES=y ++# CONFIG_HAVE_KRETPROBES is not set ++CONFIG_PROC_PAGE_MONITOR=y + CONFIG_SLABINFO=y + CONFIG_RT_MUTEXES=y + # CONFIG_TINY_SHMEM is not set +@@ -103,10 +111,15 @@ + CONFIG_DEFAULT_CFQ=y + # CONFIG_DEFAULT_NOOP is not set + CONFIG_DEFAULT_IOSCHED="cfq" ++CONFIG_CLASSIC_RCU=y + + # + # System Type and features + # ++CONFIG_TICK_ONESHOT=y ++CONFIG_NO_HZ=y ++CONFIG_HIGH_RES_TIMERS=y ++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y + CONFIG_SUBARCH_AVR32B=y + CONFIG_MMU=y + CONFIG_PERFORMANCE_COUNTERS=y +@@ -118,12 +131,16 @@ + # CONFIG_BOARD_ATSTK1002 is not set + CONFIG_BOARD_ATSTK1003=y + # CONFIG_BOARD_ATSTK1004 is not set ++# CONFIG_BOARD_ATSTK1006 is not set + # CONFIG_BOARD_ATSTK100X_CUSTOM is not set + # CONFIG_BOARD_ATSTK100X_SPI1 is not set + # CONFIG_BOARD_ATSTK1000_J2_LED is not set + # CONFIG_BOARD_ATSTK1000_J2_LED8 is not set + # CONFIG_BOARD_ATSTK1000_J2_RGB is not set + CONFIG_BOARD_ATSTK1000_EXTDAC=y ++# CONFIG_BOARD_ATSTK100X_ENABLE_AC97 is not set ++# CONFIG_BOARD_ATSTK1000_CF_HACKS is not set ++# CONFIG_BOARD_ATSTK100X_ENABLE_PSIF is not set + CONFIG_LOADER_U_BOOT=y + + # +@@ -132,6 +149,7 @@ + # CONFIG_AP700X_32_BIT_SMC is not set + CONFIG_AP700X_16_BIT_SMC=y + # CONFIG_AP700X_8_BIT_SMC is not set ++CONFIG_GPIO_DEV=y + CONFIG_LOAD_ADDRESS=0x10000000 + CONFIG_ENTRY_ADDRESS=0x90000000 + CONFIG_PHYS_OFFSET=0x10000000 +@@ -157,16 +175,26 @@ + CONFIG_ZONE_DMA_FLAG=0 + CONFIG_VIRT_TO_BUS=y + # CONFIG_OWNERSHIP_TRACE is not set ++CONFIG_NMI_DEBUGGING=y ++CONFIG_DW_DMAC=y + # CONFIG_HZ_100 is not set + CONFIG_HZ_250=y + # CONFIG_HZ_300 is not set + # CONFIG_HZ_1000 is not set + CONFIG_HZ=250 ++# CONFIG_SCHED_HRTICK is not set + CONFIG_CMDLINE="" + + # + # Power management options + # ++CONFIG_ARCH_SUSPEND_POSSIBLE=y ++CONFIG_PM=y ++# CONFIG_PM_LEGACY is not set ++# CONFIG_PM_DEBUG is not set ++CONFIG_PM_SLEEP=y ++CONFIG_SUSPEND=y ++CONFIG_SUSPEND_FREEZER=y + + # + # CPU Frequency scaling +@@ -175,9 +203,9 @@ + CONFIG_CPU_FREQ_TABLE=y + # CONFIG_CPU_FREQ_DEBUG is not set + # CONFIG_CPU_FREQ_STAT is not set +-CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y ++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set + # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +-# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set ++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y + # CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set + CONFIG_CPU_FREQ_GOV_PERFORMANCE=y + # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +@@ -260,6 +288,7 @@ + # CONFIG_NET_PKTGEN is not set + # CONFIG_NET_TCPPROBE is not set + # CONFIG_HAMRADIO is not set ++# CONFIG_CAN is not set + # CONFIG_IRDA is not set + # CONFIG_BT is not set + # CONFIG_AF_RXRPC is not set +@@ -376,13 +405,18 @@ + CONFIG_BLK_DEV_RAM=m + CONFIG_BLK_DEV_RAM_COUNT=16 + CONFIG_BLK_DEV_RAM_SIZE=4096 +-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 ++# CONFIG_BLK_DEV_XIP is not set + # CONFIG_CDROM_PKTCDVD is not set + # CONFIG_ATA_OVER_ETH is not set + CONFIG_MISC_DEVICES=y ++CONFIG_ATMEL_PWM=m ++CONFIG_ATMEL_TCLIB=y ++CONFIG_ATMEL_TCB_CLKSRC=y ++CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0 + # CONFIG_EEPROM_93CX6 is not set + CONFIG_ATMEL_SSC=m +-# CONFIG_IDE is not set ++# CONFIG_ENCLOSURE_SERVICES is not set ++# CONFIG_HAVE_IDE is not set + + # + # SCSI device support +@@ -427,6 +461,7 @@ + # CONFIG_SCSI_DEBUG is not set + CONFIG_ATA=m + # CONFIG_ATA_NONSTANDARD is not set ++# CONFIG_SATA_MV is not set + CONFIG_PATA_AT32=m + # CONFIG_PATA_PLATFORM is not set + # CONFIG_MD is not set +@@ -460,7 +495,6 @@ + # CONFIG_PPPOL2TP is not set + # CONFIG_SLIP is not set + CONFIG_SLHC=m +-# CONFIG_SHAPER is not set + # CONFIG_NETCONSOLE is not set + # CONFIG_NETPOLL is not set + # CONFIG_NET_POLL_CONTROLLER is not set +@@ -528,6 +562,7 @@ + # + CONFIG_SERIAL_ATMEL=y + CONFIG_SERIAL_ATMEL_CONSOLE=y ++CONFIG_SERIAL_ATMEL_PDC=y + # CONFIG_SERIAL_ATMEL_TTYAT is not set + CONFIG_SERIAL_CORE=y + CONFIG_SERIAL_CORE_CONSOLE=y +@@ -535,8 +570,6 @@ + # CONFIG_LEGACY_PTYS is not set + # CONFIG_IPMI_HANDLER is not set + # CONFIG_HW_RANDOM is not set +-# CONFIG_RTC is not set +-# CONFIG_GEN_RTC is not set + # CONFIG_R3964 is not set + # CONFIG_RAW_DRIVER is not set + # CONFIG_TCG_TPM is not set +@@ -554,6 +587,7 @@ + # + # I2C Hardware Bus support + # ++CONFIG_I2C_ATMELTWI=m + CONFIG_I2C_GPIO=m + # CONFIG_I2C_OCORES is not set + # CONFIG_I2C_PARPORT_LIGHT is not set +@@ -564,13 +598,12 @@ + # + # Miscellaneous I2C Chip support + # +-# CONFIG_SENSORS_DS1337 is not set +-# CONFIG_SENSORS_DS1374 is not set + # CONFIG_DS1682 is not set + # CONFIG_SENSORS_EEPROM is not set + # CONFIG_SENSORS_PCF8574 is not set +-# CONFIG_SENSORS_PCA9539 is not set ++# CONFIG_PCF8575 is not set + # CONFIG_SENSORS_PCF8591 is not set ++# CONFIG_TPS65010 is not set + # CONFIG_SENSORS_MAX6875 is not set + # CONFIG_SENSORS_TSL2550 is not set + # CONFIG_I2C_DEBUG_CORE is not set +@@ -597,9 +630,27 @@ + # CONFIG_SPI_AT25 is not set + CONFIG_SPI_SPIDEV=m + # CONFIG_SPI_TLE62X0 is not set ++CONFIG_HAVE_GPIO_LIB=y + +# -+# Advanced Linux Sound Architecture ++# GPIO Support +# -+CONFIG_SND=m -+CONFIG_SND_TIMER=m -+CONFIG_SND_PCM=m -+# CONFIG_SND_SEQUENCER is not set -+CONFIG_SND_OSSEMUL=y -+CONFIG_SND_MIXER_OSS=m -+CONFIG_SND_PCM_OSS=m -+CONFIG_SND_PCM_OSS_PLUGINS=y -+# CONFIG_SND_DYNAMIC_MINORS is not set -+# CONFIG_SND_SUPPORT_OLD_API is not set -+# CONFIG_SND_VERBOSE_PROCFS is not set -+# CONFIG_SND_VERBOSE_PRINTK is not set -+# CONFIG_SND_DEBUG is not set ++# CONFIG_DEBUG_GPIO is not set + +# -+# Generic devices ++# I2C GPIO expanders: +# -+CONFIG_SND_AC97_CODEC=m -+# CONFIG_SND_DUMMY is not set -+# CONFIG_SND_MTPAV is not set -+# CONFIG_SND_SERIAL_U16550 is not set -+# CONFIG_SND_MPU401 is not set ++# CONFIG_GPIO_PCA953X is not set ++# CONFIG_GPIO_PCF857X is not set + +# -+# AVR32 devices ++# SPI GPIO expanders: +# -+CONFIG_SND_ATMEL_AC97=m ++# CONFIG_GPIO_MCP23S08 is not set + # CONFIG_W1 is not set + # CONFIG_POWER_SUPPLY is not set + # CONFIG_HWMON is not set ++# CONFIG_THERMAL is not set + CONFIG_WATCHDOG=y + # CONFIG_WATCHDOG_NOWAYOUT is not set +@@ -665,12 +716,18 @@ # --# USB support -+# SPI devices + # Generic devices # -+CONFIG_SND_AT73C213=m -+CONFIG_SND_AT73C213_TARGET_BITRATE=48000 -+ -+# -+# System on Chip audio support ++CONFIG_SND_AC97_CODEC=m + # CONFIG_SND_DUMMY is not set + # CONFIG_SND_MTPAV is not set + # CONFIG_SND_SERIAL_U16550 is not set + # CONFIG_SND_MPU401 is not set + + # ++# AVR32 devices +# -+# CONFIG_SND_SOC is not set ++CONFIG_SND_ATMEL_AC97=m + +# -+# SoC Audio support for SuperH + # SPI devices + # + CONFIG_SND_AT73C213=m +@@ -686,9 +743,14 @@ + # + + # ++# ALSA SoC audio for Freescale SOCs +# + +# -+# Open Sound System -+# -+CONFIG_SOUND_PRIME=m -+# CONFIG_SOUND_MSNDCLAS is not set -+# CONFIG_SOUND_MSNDPIN is not set -+CONFIG_SOUND_AT32_ABDAC=m + # Open Sound System + # + # CONFIG_SOUND_PRIME is not set +CONFIG_AC97_BUS=m -+# CONFIG_HID_SUPPORT is not set -+CONFIG_USB_SUPPORT=y + # CONFIG_HID_SUPPORT is not set + CONFIG_USB_SUPPORT=y # CONFIG_USB_ARCH_HAS_HCD is not set - # CONFIG_USB_ARCH_HAS_OHCI is not set - # CONFIG_USB_ARCH_HAS_EHCI is not set -@@ -545,63 +796,137 @@ +@@ -698,10 +760,6 @@ # - # USB Gadget Support + # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' # --# CONFIG_USB_GADGET is not set --# CONFIG_MMC is not set - -# --# LED devices +-# USB Gadget Support -# --# CONFIG_NEW_LEDS is not set -+CONFIG_USB_GADGET=y -+# CONFIG_USB_GADGET_DEBUG is not set -+# CONFIG_USB_GADGET_DEBUG_FILES is not set -+# CONFIG_USB_GADGET_DEBUG_FS is not set -+CONFIG_USB_GADGET_SELECTED=y -+# CONFIG_USB_GADGET_AMD5536UDC is not set -+CONFIG_USB_GADGET_ATMEL_USBA=y -+CONFIG_USB_ATMEL_USBA=y -+# CONFIG_USB_GADGET_FSL_USB2 is not set -+# CONFIG_USB_GADGET_NET2280 is not set -+# CONFIG_USB_GADGET_PXA2XX is not set -+# CONFIG_USB_GADGET_M66592 is not set -+# CONFIG_USB_GADGET_GOKU is not set -+# CONFIG_USB_GADGET_LH7A40X is not set -+# CONFIG_USB_GADGET_OMAP is not set -+# CONFIG_USB_GADGET_S3C2410 is not set -+# CONFIG_USB_GADGET_AT91 is not set -+# CONFIG_USB_GADGET_DUMMY_HCD is not set -+CONFIG_USB_GADGET_DUALSPEED=y -+CONFIG_USB_ZERO=m -+CONFIG_USB_ETH=m -+CONFIG_USB_ETH_RNDIS=y -+CONFIG_USB_GADGETFS=m -+CONFIG_USB_FILE_STORAGE=m -+# CONFIG_USB_FILE_STORAGE_TEST is not set -+CONFIG_USB_G_SERIAL=m -+# CONFIG_USB_MIDI_GADGET is not set + CONFIG_USB_GADGET=y + # CONFIG_USB_GADGET_DEBUG is not set + # CONFIG_USB_GADGET_DEBUG_FILES is not set +@@ -729,27 +787,31 @@ + # CONFIG_USB_FILE_STORAGE_TEST is not set + CONFIG_USB_G_SERIAL=m + # CONFIG_USB_MIDI_GADGET is not set +-CONFIG_MMC=m ++# CONFIG_USB_G_PRINTER is not set +CONFIG_MMC=y -+# CONFIG_MMC_DEBUG is not set -+# CONFIG_MMC_UNSAFE_RESUME is not set -+ -+# -+# MMC/SD Card Drivers -+# -+CONFIG_MMC_BLOCK=y -+# CONFIG_MMC_BLOCK_BOUNCE is not set -+# CONFIG_SDIO_UART is not set -+ -+# -+# MMC/SD Host Controller Drivers -+# -+CONFIG_MMC_ATMELMCI=y -+CONFIG_MMC_SPI=m -+CONFIG_NEW_LEDS=y -+CONFIG_LEDS_CLASS=m + # CONFIG_MMC_DEBUG is not set + # CONFIG_MMC_UNSAFE_RESUME is not set # - # LED drivers + # MMC/SD Card Drivers # -+CONFIG_LEDS_ATMEL_PWM=m -+CONFIG_LEDS_GPIO=m +-CONFIG_MMC_BLOCK=m ++CONFIG_MMC_BLOCK=y + # CONFIG_MMC_BLOCK_BOUNCE is not set + # CONFIG_SDIO_UART is not set # - # LED Triggers + # MMC/SD Host Controller Drivers # -+CONFIG_LEDS_TRIGGERS=y -+CONFIG_LEDS_TRIGGER_TIMER=m -+CONFIG_LEDS_TRIGGER_HEARTBEAT=m -+CONFIG_RTC_LIB=y -+CONFIG_RTC_CLASS=y -+CONFIG_RTC_HCTOSYS=y -+CONFIG_RTC_HCTOSYS_DEVICE="rtc0" -+# CONFIG_RTC_DEBUG is not set ++CONFIG_MMC_ATMELMCI=y + CONFIG_MMC_SPI=m ++# CONFIG_MEMSTICK is not set + CONFIG_NEW_LEDS=y + CONFIG_LEDS_CLASS=y # --# InfiniBand support -+# RTC interfaces + # LED drivers # -+CONFIG_RTC_INTF_SYSFS=y -+CONFIG_RTC_INTF_PROC=y -+CONFIG_RTC_INTF_DEV=y -+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set -+# CONFIG_RTC_DRV_TEST is not set ++CONFIG_LEDS_ATMEL_PWM=m + CONFIG_LEDS_GPIO=y # --# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) -+# I2C RTC drivers - # -+# CONFIG_RTC_DRV_DS1307 is not set -+# CONFIG_RTC_DRV_DS1374 is not set -+# CONFIG_RTC_DRV_DS1672 is not set -+# CONFIG_RTC_DRV_MAX6900 is not set -+# CONFIG_RTC_DRV_RS5C372 is not set -+# CONFIG_RTC_DRV_ISL1208 is not set -+# CONFIG_RTC_DRV_X1205 is not set -+# CONFIG_RTC_DRV_PCF8563 is not set -+# CONFIG_RTC_DRV_PCF8583 is not set -+# CONFIG_RTC_DRV_M41T80 is not set +@@ -786,19 +848,22 @@ + # CONFIG_RTC_DRV_PCF8563 is not set + # CONFIG_RTC_DRV_PCF8583 is not set + # CONFIG_RTC_DRV_M41T80 is not set ++# CONFIG_RTC_DRV_S35390A is not set # --# Real Time Clock -+# SPI RTC drivers + # SPI RTC drivers # --# CONFIG_RTC_CLASS is not set +-# CONFIG_RTC_DRV_RS5C348 is not set + # CONFIG_RTC_DRV_MAX6902 is not set ++# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set -+# CONFIG_RTC_DRV_MAX6902 is not set # --# DMA Engine support -+# Platform RTC drivers + # Platform RTC drivers # --# CONFIG_DMA_ENGINE is not set -+# CONFIG_RTC_DRV_DS1553 is not set ++# CONFIG_RTC_DRV_DS1511 is not set + # CONFIG_RTC_DRV_DS1553 is not set +-# CONFIG_RTC_DRV_STK17TA8 is not set + # CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set -+# CONFIG_RTC_DRV_DS1742 is not set -+# CONFIG_RTC_DRV_M48T86 is not set -+# CONFIG_RTC_DRV_M48T59 is not set -+# CONFIG_RTC_DRV_V3020 is not set - - # --# DMA Clients -+# on-CPU RTC drivers - # -+CONFIG_RTC_DRV_AT32AP700X=y - - # --# DMA Devices -+# Userspace I/O - # -+# CONFIG_UIO is not set - + # CONFIG_RTC_DRV_M48T86 is not set + # CONFIG_RTC_DRV_M48T59 is not set + # CONFIG_RTC_DRV_V3020 is not set +@@ -816,13 +881,13 @@ # # File systems # @@ -2743,218 +2376,369 @@ +CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XATTR is not set # CONFIG_EXT2_FS_XIP is not set --# CONFIG_EXT3_FS is not set +-CONFIG_EXT3_FS=m +CONFIG_EXT3_FS=y -+# CONFIG_EXT3_FS_XATTR is not set + # CONFIG_EXT3_FS_XATTR is not set # CONFIG_EXT4DEV_FS is not set +-CONFIG_JBD=m +CONFIG_JBD=y -+# CONFIG_JBD_DEBUG is not set + # CONFIG_JBD_DEBUG is not set # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set - # CONFIG_FS_POSIX_ACL is not set +@@ -830,12 +895,10 @@ # CONFIG_XFS_FS is not set # CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set --CONFIG_MINIX_FS=m -+# CONFIG_MINIX_FS is not set - # CONFIG_ROMFS_FS is not set +-# CONFIG_MINIX_FS is not set +-# CONFIG_ROMFS_FS is not set ++# CONFIG_DNOTIFY is not set CONFIG_INOTIFY=y CONFIG_INOTIFY_USER=y -@@ -609,7 +934,7 @@ - # CONFIG_DNOTIFY is not set + # CONFIG_QUOTA is not set +-# CONFIG_DNOTIFY is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set --# CONFIG_FUSE_FS is not set -+CONFIG_FUSE_FS=m - - # - # CD-ROM/DVD Filesystems -@@ -637,8 +962,7 @@ + CONFIG_FUSE_FS=m +@@ -866,7 +929,7 @@ CONFIG_TMPFS=y # CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set --CONFIG_RAMFS=y -CONFIG_CONFIGFS_FS=m +CONFIG_CONFIGFS_FS=y # # Miscellaneous filesystems -@@ -652,11 +976,12 @@ - # CONFIG_EFS_FS is not set - CONFIG_JFFS2_FS=y - CONFIG_JFFS2_FS_DEBUG=0 --CONFIG_JFFS2_FS_WRITEBUFFER=y -+# CONFIG_JFFS2_FS_WRITEBUFFER is not set - # CONFIG_JFFS2_SUMMARY is not set - # CONFIG_JFFS2_FS_XATTR is not set - # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set - CONFIG_JFFS2_ZLIB=y -+# CONFIG_JFFS2_LZO is not set - CONFIG_JFFS2_RTIME=y +@@ -891,8 +954,10 @@ # CONFIG_JFFS2_RUBIN is not set # CONFIG_CRAMFS is not set -@@ -665,10 +990,7 @@ + # CONFIG_VXFS_FS is not set ++# CONFIG_MINIX_FS is not set + # CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set ++# CONFIG_ROMFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set -- --# --# Network File Systems --# -+CONFIG_NETWORK_FILESYSTEMS=y - CONFIG_NFS_FS=y - CONFIG_NFS_V3=y - # CONFIG_NFS_V3_ACL is not set -@@ -688,17 +1010,12 @@ - # 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 is not set - CONFIG_MSDOS_PARTITION=y -- --# --# Native Language Support --# - CONFIG_NLS=m - CONFIG_NLS_DEFAULT="iso8859-1" - CONFIG_NLS_CODEPAGE_437=m -@@ -739,17 +1056,18 @@ - # CONFIG_NLS_KOI8_R is not set + # CONFIG_NETWORK_FILESYSTEMS is not set +@@ -943,11 +1008,6 @@ # CONFIG_NLS_KOI8_U is not set CONFIG_NLS_UTF8=m -- --# --# Distributed Lock Manager --# # CONFIG_DLM is not set -+CONFIG_INSTRUMENTATION=y -+CONFIG_PROFILING=y -+CONFIG_OPROFILE=m -+CONFIG_KPROBES=y -+# CONFIG_MARKERS is not set +-CONFIG_INSTRUMENTATION=y +-CONFIG_PROFILING=y +-CONFIG_OPROFILE=m +-CONFIG_KPROBES=y +-# CONFIG_MARKERS is not set # # Kernel hacking - # --CONFIG_TRACE_IRQFLAGS_SUPPORT=y - # CONFIG_PRINTK_TIME is not set -+CONFIG_ENABLE_WARN_DEPRECATED=y - CONFIG_ENABLE_MUST_CHECK=y - CONFIG_MAGIC_SYSRQ=y - # CONFIG_UNUSED_SYMBOLS is not set -@@ -758,12 +1076,17 @@ - CONFIG_DEBUG_KERNEL=y - # CONFIG_DEBUG_SHIRQ is not set - CONFIG_DETECT_SOFTLOCKUP=y -+CONFIG_SCHED_DEBUG=y +@@ -965,6 +1025,7 @@ + CONFIG_SCHED_DEBUG=y # CONFIG_SCHEDSTATS is not set # CONFIG_TIMER_STATS is not set -+# CONFIG_SLUB_DEBUG_ON is not set ++# CONFIG_SLUB_STATS is not set # CONFIG_DEBUG_RT_MUTEXES is not set # CONFIG_RT_MUTEX_TESTER is not set # CONFIG_DEBUG_SPINLOCK is not set - # CONFIG_DEBUG_MUTEXES is not set -+# CONFIG_DEBUG_LOCK_ALLOC is not set -+# CONFIG_PROVE_LOCKING is not set -+# CONFIG_LOCK_STAT is not set - # CONFIG_DEBUG_SPINLOCK_SLEEP is not set - # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set - # CONFIG_DEBUG_KOBJECT is not set -@@ -771,22 +1094,63 @@ - # CONFIG_DEBUG_INFO is not set - # CONFIG_DEBUG_VM is not set +@@ -981,9 +1042,10 @@ # CONFIG_DEBUG_LIST is not set -+# CONFIG_DEBUG_SG is not set + # CONFIG_DEBUG_SG is not set CONFIG_FRAME_POINTER=y - CONFIG_FORCED_INLINING=y -+# CONFIG_BOOT_PRINTK_DELAY is not set +-CONFIG_FORCED_INLINING=y + # CONFIG_BOOT_PRINTK_DELAY is not set # CONFIG_RCU_TORTURE_TEST is not set -+# CONFIG_LKDTM is not set ++# CONFIG_KPROBES_SANITY_TEST is not set ++# CONFIG_BACKTRACE_SELF_TEST is not set + # CONFIG_LKDTM is not set # CONFIG_FAULT_INJECTION is not set --# CONFIG_KPROBES is not set -+# CONFIG_SAMPLES is not set + # CONFIG_SAMPLES is not set +@@ -1009,6 +1071,7 @@ + CONFIG_AUDIT_GENERIC=y + CONFIG_ZLIB_INFLATE=y + CONFIG_ZLIB_DEFLATE=y ++CONFIG_GENERIC_ALLOCATOR=y + CONFIG_PLIST=y + CONFIG_HAS_IOMEM=y + CONFIG_HAS_IOPORT=y +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/configs/atstk1004_defconfig avr32-2.6/arch/avr32/configs/atstk1004_defconfig +--- linux-2.6.25.6/arch/avr32/configs/atstk1004_defconfig 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/configs/atstk1004_defconfig 2008-06-12 15:09:38.719815350 +0200 +@@ -1,7 +1,7 @@ + # + # Automatically generated make config: don't edit +-# Linux kernel version: 2.6.24-rc7 +-# Wed Jan 9 23:04:20 2008 ++# Linux kernel version: 2.6.25.4 ++# Wed Jun 11 15:37:49 2008 + # + CONFIG_AVR32=y + CONFIG_GENERIC_GPIO=y +@@ -13,10 +13,10 @@ + CONFIG_GENERIC_IRQ_PROBE=y + CONFIG_RWSEM_GENERIC_SPINLOCK=y + CONFIG_GENERIC_TIME=y ++CONFIG_GENERIC_CLOCKEVENTS=y + # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set + # CONFIG_ARCH_HAS_ILOG2_U32 is not set + # CONFIG_ARCH_HAS_ILOG2_U64 is not set +-CONFIG_ARCH_SUPPORTS_OPROFILE=y + CONFIG_GENERIC_HWEIGHT=y + CONFIG_GENERIC_CALIBRATE_DELAY=y + CONFIG_GENERIC_BUG=y +@@ -34,15 +34,15 @@ + # CONFIG_POSIX_MQUEUE is not set + # CONFIG_BSD_PROCESS_ACCT is not set + # CONFIG_TASKSTATS is not set +-# CONFIG_USER_NS is not set +-# CONFIG_PID_NS is not set + # CONFIG_AUDIT is not set + # CONFIG_IKCONFIG is not set + CONFIG_LOG_BUF_SHIFT=14 + # CONFIG_CGROUPS is not set +-# CONFIG_FAIR_GROUP_SCHED is not set ++# CONFIG_GROUP_SCHED is not set + CONFIG_SYSFS_DEPRECATED=y ++CONFIG_SYSFS_DEPRECATED_V2=y + # CONFIG_RELAY is not set ++# CONFIG_NAMESPACES is not set + # CONFIG_BLK_DEV_INITRD is not set + CONFIG_CC_OPTIMIZE_FOR_SIZE=y + CONFIG_SYSCTL=y +@@ -54,24 +54,37 @@ + CONFIG_PRINTK=y + CONFIG_BUG=y + CONFIG_ELF_CORE=y ++# CONFIG_COMPAT_BRK is not set + # CONFIG_BASE_FULL is not set + # CONFIG_FUTEX is not set + # CONFIG_EPOLL is not set + # CONFIG_SIGNALFD is not set ++# CONFIG_TIMERFD is not set + # CONFIG_EVENTFD is not set + CONFIG_SHMEM=y + CONFIG_VM_EVENT_COUNTERS=y + # CONFIG_SLAB is not set + # CONFIG_SLUB is not set + CONFIG_SLOB=y ++# CONFIG_PROFILING is not set ++# CONFIG_MARKERS is not set ++CONFIG_HAVE_OPROFILE=y ++CONFIG_HAVE_KPROBES=y ++# CONFIG_HAVE_KRETPROBES is not set ++# CONFIG_PROC_PAGE_MONITOR is not set + # CONFIG_TINY_SHMEM is not set + CONFIG_BASE_SMALL=1 + # CONFIG_MODULES is not set + # CONFIG_BLOCK is not set ++CONFIG_CLASSIC_RCU=y # - # Security options + # System Type and features + # ++# CONFIG_TICK_ONESHOT is not set ++# CONFIG_NO_HZ is not set ++# CONFIG_HIGH_RES_TIMERS is not set ++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y + CONFIG_SUBARCH_AVR32B=y + CONFIG_MMU=y + CONFIG_PERFORMANCE_COUNTERS=y +@@ -83,10 +96,14 @@ + # CONFIG_BOARD_ATSTK1002 is not set + # CONFIG_BOARD_ATSTK1003 is not set + CONFIG_BOARD_ATSTK1004=y ++# CONFIG_BOARD_ATSTK1006 is not set + # CONFIG_BOARD_ATSTK100X_CUSTOM is not set + # CONFIG_BOARD_ATSTK100X_SPI1 is not set + # CONFIG_BOARD_ATSTK1000_J2_LED is not set + CONFIG_BOARD_ATSTK1000_EXTDAC=y ++# CONFIG_BOARD_ATSTK100X_ENABLE_AC97 is not set ++# CONFIG_BOARD_ATSTK1000_CF_HACKS is not set ++# CONFIG_BOARD_ATSTK100X_ENABLE_PSIF is not set + CONFIG_LOADER_U_BOOT=y + + # +@@ -95,6 +112,7 @@ + # CONFIG_AP700X_32_BIT_SMC is not set + CONFIG_AP700X_16_BIT_SMC=y + # CONFIG_AP700X_8_BIT_SMC is not set ++# CONFIG_GPIO_DEV is not set + CONFIG_LOAD_ADDRESS=0x10000000 + CONFIG_ENTRY_ADDRESS=0x90000000 + CONFIG_PHYS_OFFSET=0x10000000 +@@ -120,34 +138,26 @@ + CONFIG_ZONE_DMA_FLAG=0 + CONFIG_VIRT_TO_BUS=y + # CONFIG_OWNERSHIP_TRACE is not set ++# CONFIG_NMI_DEBUGGING is not set ++CONFIG_DW_DMAC=y + # CONFIG_HZ_100 is not set + CONFIG_HZ_250=y + # CONFIG_HZ_300 is not set + # CONFIG_HZ_1000 is not set + CONFIG_HZ=250 ++# CONFIG_SCHED_HRTICK is not set + CONFIG_CMDLINE="" + + # + # Power management options + # ++CONFIG_ARCH_SUSPEND_POSSIBLE=y ++# CONFIG_PM is not set + + # + # CPU Frequency scaling + # +-CONFIG_CPU_FREQ=y +-CONFIG_CPU_FREQ_TABLE=y +-# CONFIG_CPU_FREQ_DEBUG is not set +-# CONFIG_CPU_FREQ_STAT is not set +-CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +-# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +-# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +-# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +-CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +-# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +-CONFIG_CPU_FREQ_GOV_USERSPACE=y +-CONFIG_CPU_FREQ_GOV_ONDEMAND=y +-# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +-CONFIG_CPU_FREQ_AT32AP=y ++# CONFIG_CPU_FREQ is not set + + # + # Bus options +@@ -222,6 +232,7 @@ + # + # CONFIG_NET_PKTGEN is not set + # CONFIG_HAMRADIO is not set ++# CONFIG_CAN is not set + # CONFIG_IRDA is not set + # CONFIG_BT is not set + # CONFIG_AF_RXRPC is not set +@@ -321,6 +332,7 @@ + # CONFIG_MTD_UBI is not set + # CONFIG_PARPORT is not set + # CONFIG_MISC_DEVICES is not set ++# CONFIG_HAVE_IDE is not set + + # + # SCSI device support +@@ -358,6 +370,7 @@ + # + CONFIG_SERIAL_ATMEL=y + CONFIG_SERIAL_ATMEL_CONSOLE=y ++# CONFIG_SERIAL_ATMEL_PDC is not set + # CONFIG_SERIAL_ATMEL_TTYAT is not set + CONFIG_SERIAL_CORE=y + CONFIG_SERIAL_CORE_CONSOLE=y +@@ -365,8 +378,6 @@ + # CONFIG_LEGACY_PTYS is not set + # CONFIG_IPMI_HANDLER is not set + # CONFIG_HW_RANDOM is not set +-# CONFIG_RTC is not set +-# CONFIG_GEN_RTC is not set + # CONFIG_R3964 is not set + # CONFIG_TCG_TPM is not set + # CONFIG_I2C is not set +@@ -389,9 +400,24 @@ + # CONFIG_SPI_AT25 is not set + # CONFIG_SPI_SPIDEV is not set + # CONFIG_SPI_TLE62X0 is not set ++CONFIG_HAVE_GPIO_LIB=y ++ ++# ++# GPIO Support ++# ++ ++# ++# I2C GPIO expanders: ++# ++ ++# ++# SPI GPIO expanders: ++# ++# CONFIG_GPIO_MCP23S08 is not set + # CONFIG_W1 is not set + # CONFIG_POWER_SUPPLY is not set + # CONFIG_HWMON is not set ++# CONFIG_THERMAL is not set + CONFIG_WATCHDOG=y + # CONFIG_WATCHDOG_NOWAYOUT is not set + +@@ -471,10 +497,6 @@ + # + # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' # - # CONFIG_KEYS is not set - # CONFIG_SECURITY is not set - -# --# Cryptographic options +-# USB Gadget Support -# --# CONFIG_CRYPTO is not set -+# CONFIG_SECURITY_FILE_CAPABILITIES is not set -+CONFIG_CRYPTO=y -+CONFIG_CRYPTO_ALGAPI=m -+CONFIG_CRYPTO_BLKCIPHER=m -+CONFIG_CRYPTO_HASH=m -+CONFIG_CRYPTO_MANAGER=m -+CONFIG_CRYPTO_HMAC=m -+# CONFIG_CRYPTO_XCBC is not set -+# CONFIG_CRYPTO_NULL is not set -+# CONFIG_CRYPTO_MD4 is not set -+CONFIG_CRYPTO_MD5=m -+CONFIG_CRYPTO_SHA1=m -+# 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_GF128MUL is not set -+# CONFIG_CRYPTO_ECB is not set -+CONFIG_CRYPTO_CBC=m -+# CONFIG_CRYPTO_PCBC is not set -+# CONFIG_CRYPTO_LRW is not set -+# CONFIG_CRYPTO_XTS is not set -+# CONFIG_CRYPTO_CRYPTD is not set -+CONFIG_CRYPTO_DES=m -+# CONFIG_CRYPTO_FCRYPT is not set -+# CONFIG_CRYPTO_BLOWFISH is not set -+# CONFIG_CRYPTO_TWOFISH is not set -+# CONFIG_CRYPTO_SERPENT is not set -+# CONFIG_CRYPTO_AES is not set -+# CONFIG_CRYPTO_CAST5 is not set -+# CONFIG_CRYPTO_CAST6 is not set -+# CONFIG_CRYPTO_TEA is not set -+# CONFIG_CRYPTO_ARC4 is not set -+# CONFIG_CRYPTO_KHAZAD is not set -+# CONFIG_CRYPTO_ANUBIS is not set -+# CONFIG_CRYPTO_SEED is not set -+CONFIG_CRYPTO_DEFLATE=m -+# CONFIG_CRYPTO_MICHAEL_MIC is not set -+# CONFIG_CRYPTO_CRC32C is not set -+# CONFIG_CRYPTO_CAMELLIA is not set -+# CONFIG_CRYPTO_TEST is not set -+# CONFIG_CRYPTO_AUTHENC is not set -+# CONFIG_CRYPTO_HW is not set + CONFIG_USB_GADGET=y + # CONFIG_USB_GADGET_DEBUG_FILES is not set + CONFIG_USB_GADGET_SELECTED=y +@@ -499,7 +521,9 @@ + # CONFIG_USB_FILE_STORAGE is not set + # CONFIG_USB_G_SERIAL is not set + # CONFIG_USB_MIDI_GADGET is not set ++# CONFIG_USB_G_PRINTER is not set + # CONFIG_MMC is not set ++# CONFIG_MEMSTICK is not set + # CONFIG_NEW_LEDS is not set + CONFIG_RTC_LIB=y + CONFIG_RTC_CLASS=y +@@ -519,15 +543,17 @@ + # + # SPI RTC drivers + # +-# CONFIG_RTC_DRV_RS5C348 is not set + # CONFIG_RTC_DRV_MAX6902 is not set ++# CONFIG_RTC_DRV_R9701 is not set ++# CONFIG_RTC_DRV_RS5C348 is not set # - # Library routines -@@ -794,10 +1158,10 @@ - CONFIG_BITREVERSE=y - CONFIG_CRC_CCITT=m - # CONFIG_CRC16 is not set --# CONFIG_CRC_ITU_T is not set -+CONFIG_CRC_ITU_T=m - CONFIG_CRC32=y -+CONFIG_CRC7=m + # Platform RTC drivers + # ++# CONFIG_RTC_DRV_DS1511 is not set + # CONFIG_RTC_DRV_DS1553 is not set +-# CONFIG_RTC_DRV_STK17TA8 is not set + # CONFIG_RTC_DRV_DS1742 is not set ++# CONFIG_RTC_DRV_STK17TA8 is not set + # CONFIG_RTC_DRV_M48T86 is not set + # CONFIG_RTC_DRV_M48T59 is not set + # CONFIG_RTC_DRV_V3020 is not set +@@ -545,9 +571,9 @@ + # + # File systems + # ++# CONFIG_DNOTIFY is not set + # CONFIG_INOTIFY is not set + # CONFIG_QUOTA is not set +-# CONFIG_DNOTIFY is not set + # CONFIG_AUTOFS_FS is not set + # CONFIG_AUTOFS4_FS is not set + # CONFIG_FUSE_FS is not set +@@ -580,7 +606,6 @@ + # CONFIG_NETWORK_FILESYSTEMS is not set + # CONFIG_NLS is not set + # CONFIG_DLM is not set +-# CONFIG_INSTRUMENTATION is not set + + # + # Kernel hacking +@@ -616,6 +641,7 @@ # CONFIG_LIBCRC32C is not set --CONFIG_AUDIT_GENERIC=y CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y - CONFIG_PLIST=y ---- /dev/null -+++ b/arch/avr32/configs/atstk1003_defconfig -@@ -0,0 +1,1041 @@ ++CONFIG_GENERIC_ALLOCATOR=y + CONFIG_HAS_IOMEM=y + CONFIG_HAS_IOPORT=y + CONFIG_HAS_DMA=y +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/configs/atstk1006_defconfig avr32-2.6/arch/avr32/configs/atstk1006_defconfig +--- linux-2.6.25.6/arch/avr32/configs/atstk1006_defconfig 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/arch/avr32/configs/atstk1006_defconfig 2008-06-12 15:09:38.719815350 +0200 +@@ -0,0 +1,1235 @@ +# +# Automatically generated make config: don't edit -+# Linux kernel version: 2.6.24 -+# Thu Mar 6 12:50:27 2008 ++# Linux kernel version: 2.6.25.4 ++# Wed Jun 11 15:40:45 2008 +# +CONFIG_AVR32=y +CONFIG_GENERIC_GPIO=y @@ -2970,7 +2754,6 @@ +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set -+CONFIG_ARCH_SUPPORTS_OPROFILE=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_BUG=y @@ -2988,22 +2771,17 @@ +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y -+CONFIG_BSD_PROCESS_ACCT=y -+CONFIG_BSD_PROCESS_ACCT_V3=y -+CONFIG_TASKSTATS=y -+CONFIG_TASK_DELAY_ACCT=y -+# CONFIG_TASK_XACCT is not set -+# CONFIG_USER_NS is not set -+# CONFIG_PID_NS is not set -+CONFIG_AUDIT=y ++# CONFIG_BSD_PROCESS_ACCT is not set ++# CONFIG_TASKSTATS is not set ++# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CGROUPS is not set -+CONFIG_FAIR_GROUP_SCHED=y -+CONFIG_FAIR_USER_SCHED=y -+# CONFIG_FAIR_CGROUP_SCHED is not set ++# CONFIG_GROUP_SCHED is not set +CONFIG_SYSFS_DEPRECATED=y ++CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_RELAY=y ++# CONFIG_NAMESPACES is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y @@ -3017,18 +2795,28 @@ +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y ++# CONFIG_COMPAT_BRK is not set +# CONFIG_BASE_FULL is not set +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y ++CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y -+# CONFIG_SLUB_DEBUG is not set ++CONFIG_SLUB_DEBUG=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set ++CONFIG_PROFILING=y ++# CONFIG_MARKERS is not set ++CONFIG_OPROFILE=m ++CONFIG_HAVE_OPROFILE=y ++CONFIG_KPROBES=y ++CONFIG_HAVE_KPROBES=y ++# CONFIG_HAVE_KRETPROBES is not set ++CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set @@ -3057,6 +2845,7 @@ +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" ++CONFIG_CLASSIC_RCU=y + +# +# System Type and features @@ -3070,12 +2859,13 @@ +CONFIG_PERFORMANCE_COUNTERS=y +CONFIG_PLATFORM_AT32AP=y +CONFIG_CPU_AT32AP700X=y -+CONFIG_CPU_AT32AP7001=y ++CONFIG_CPU_AT32AP7000=y +CONFIG_BOARD_ATSTK1000=y +# CONFIG_BOARD_ATNGW100 is not set +# CONFIG_BOARD_ATSTK1002 is not set -+CONFIG_BOARD_ATSTK1003=y ++# CONFIG_BOARD_ATSTK1003 is not set +# CONFIG_BOARD_ATSTK1004 is not set ++CONFIG_BOARD_ATSTK1006=y +# CONFIG_BOARD_ATSTK100X_CUSTOM is not set +# CONFIG_BOARD_ATSTK100X_SPI1 is not set +# CONFIG_BOARD_ATSTK1000_J2_LED is not set @@ -3126,11 +2916,19 @@ +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 ++# CONFIG_SCHED_HRTICK is not set +CONFIG_CMDLINE="" + +# +# Power management options +# ++CONFIG_ARCH_SUSPEND_POSSIBLE=y ++CONFIG_PM=y ++# CONFIG_PM_LEGACY is not set ++# CONFIG_PM_DEBUG is not set ++CONFIG_PM_SLEEP=y ++CONFIG_SUSPEND=y ++CONFIG_SUSPEND_FREEZER=y + +# +# CPU Frequency scaling @@ -3139,9 +2937,9 @@ +CONFIG_CPU_FREQ_TABLE=y +# CONFIG_CPU_FREQ_DEBUG is not set +# CONFIG_CPU_FREQ_STAT is not set -+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y ++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set ++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set @@ -3173,42 +2971,67 @@ +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y -+# CONFIG_NET_KEY is not set ++CONFIG_XFRM=y ++CONFIG_XFRM_USER=m ++# CONFIG_XFRM_SUB_POLICY is not set ++# CONFIG_XFRM_MIGRATE is not set ++# CONFIG_XFRM_STATISTICS is not set ++CONFIG_NET_KEY=m ++# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y -+# CONFIG_IP_PNP is not set -+# CONFIG_NET_IPIP is not set -+# CONFIG_NET_IPGRE is not set ++CONFIG_IP_PNP=y ++CONFIG_IP_PNP_DHCP=y ++# CONFIG_IP_PNP_BOOTP is not set ++# CONFIG_IP_PNP_RARP is not set ++CONFIG_NET_IPIP=m ++CONFIG_NET_IPGRE=m +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set -+# CONFIG_INET_AH is not set -+# CONFIG_INET_ESP is not set ++CONFIG_INET_AH=m ++CONFIG_INET_ESP=m +# 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_XFRM_MODE_BEET is not set ++CONFIG_INET_TUNNEL=m ++CONFIG_INET_XFRM_MODE_TRANSPORT=m ++CONFIG_INET_XFRM_MODE_TUNNEL=m ++CONFIG_INET_XFRM_MODE_BEET=m +# CONFIG_INET_LRO is not set -+# CONFIG_INET_DIAG is not set ++CONFIG_INET_DIAG=y ++CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set -+# CONFIG_IPV6 is not set -+# CONFIG_INET6_XFRM_TUNNEL is not set -+# CONFIG_INET6_TUNNEL is not set ++CONFIG_IPV6=m ++# CONFIG_IPV6_PRIVACY is not set ++# CONFIG_IPV6_ROUTER_PREF is not set ++# CONFIG_IPV6_OPTIMISTIC_DAD is not set ++CONFIG_INET6_AH=m ++CONFIG_INET6_ESP=m ++CONFIG_INET6_IPCOMP=m ++# CONFIG_IPV6_MIP6 is not set ++CONFIG_INET6_XFRM_TUNNEL=m ++CONFIG_INET6_TUNNEL=m ++CONFIG_INET6_XFRM_MODE_TRANSPORT=m ++CONFIG_INET6_XFRM_MODE_TUNNEL=m ++CONFIG_INET6_XFRM_MODE_BEET=m ++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set ++CONFIG_IPV6_SIT=m ++CONFIG_IPV6_TUNNEL=m ++# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set -+# CONFIG_BRIDGE is not set ++CONFIG_BRIDGE=m +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set ++CONFIG_LLC=m +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set @@ -3224,6 +3047,7 @@ +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_TCPPROBE is not set +# CONFIG_HAMRADIO is not set ++# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set @@ -3324,13 +3148,32 @@ +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set -+# CONFIG_MTD_NAND is not set ++CONFIG_MTD_NAND=y ++# CONFIG_MTD_NAND_VERIFY_WRITE is not set ++# CONFIG_MTD_NAND_ECC_SMC is not set ++# CONFIG_MTD_NAND_MUSEUM_IDS is not set ++CONFIG_MTD_NAND_IDS=y ++# CONFIG_MTD_NAND_DISKONCHIP is not set ++CONFIG_MTD_NAND_ATMEL=y ++CONFIG_MTD_NAND_ATMEL_ECC_HW=y ++# CONFIG_MTD_NAND_ATMEL_ECC_SOFT is not set ++# CONFIG_MTD_NAND_ATMEL_ECC_NONE is not set ++# CONFIG_MTD_NAND_NANDSIM is not set ++# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_ONENAND is not set + +# +# UBI - Unsorted block images +# -+# CONFIG_MTD_UBI is not set ++CONFIG_MTD_UBI=m ++CONFIG_MTD_UBI_WL_THRESHOLD=4096 ++CONFIG_MTD_UBI_BEB_RESERVE=1 ++CONFIG_MTD_UBI_GLUEBI=y ++ ++# ++# UBI debugging options ++# ++# CONFIG_MTD_UBI_DEBUG is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set @@ -3340,7 +3183,7 @@ +CONFIG_BLK_DEV_RAM=m +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 -+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 ++# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y @@ -3350,7 +3193,8 @@ +CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0 +# CONFIG_EEPROM_93CX6 is not set +CONFIG_ATMEL_SSC=m -+# CONFIG_IDE is not set ++# CONFIG_ENCLOSURE_SERVICES is not set ++# CONFIG_HAVE_IDE is not set + +# +# SCSI device support @@ -3390,11 +3234,10 @@ +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set -+CONFIG_SCSI_LOWLEVEL=y -+# CONFIG_ISCSI_TCP is not set -+# CONFIG_SCSI_DEBUG is not set ++# CONFIG_SCSI_LOWLEVEL is not set +CONFIG_ATA=m +# CONFIG_ATA_NONSTANDARD is not set ++# CONFIG_SATA_MV is not set +CONFIG_PATA_AT32=m +# CONFIG_PATA_PLATFORM is not set +# CONFIG_MD is not set @@ -3404,9 +3247,34 @@ +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set -+# CONFIG_TUN is not set ++CONFIG_TUN=m +# CONFIG_VETH is not set -+# CONFIG_NET_ETHERNET is not set ++CONFIG_PHYLIB=y ++ ++# ++# MII PHY device drivers ++# ++# CONFIG_MARVELL_PHY is not set ++# CONFIG_DAVICOM_PHY is not set ++# CONFIG_QSEMI_PHY is not set ++# CONFIG_LXT_PHY is not set ++# CONFIG_CICADA_PHY is not set ++# CONFIG_VITESSE_PHY is not set ++# CONFIG_SMSC_PHY is not set ++# CONFIG_BROADCOM_PHY is not set ++# CONFIG_ICPLUS_PHY is not set ++# CONFIG_REALTEK_PHY is not set ++# CONFIG_FIXED_PHY is not set ++# CONFIG_MDIO_BITBANG is not set ++CONFIG_NET_ETHERNET=y ++# CONFIG_MII is not set ++CONFIG_MACB=y ++# CONFIG_ENC28J60 is not set ++# CONFIG_IBM_NEW_EMAC_ZMII is not set ++# CONFIG_IBM_NEW_EMAC_RGMII is not set ++# CONFIG_IBM_NEW_EMAC_TAH is not set ++# CONFIG_IBM_NEW_EMAC_EMAC4 is not set ++# CONFIG_B44 is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set + @@ -3428,7 +3296,6 @@ +# CONFIG_PPPOL2TP is not set +# CONFIG_SLIP is not set +CONFIG_SLHC=m -+# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set @@ -3450,7 +3317,7 @@ +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set -+# CONFIG_INPUT_EVDEV is not set ++CONFIG_INPUT_EVDEV=m +# CONFIG_INPUT_EVBUG is not set + +# @@ -3504,8 +3371,6 @@ +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set -+# CONFIG_RTC is not set -+# CONFIG_GEN_RTC is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set @@ -3534,13 +3399,12 @@ +# +# Miscellaneous I2C Chip support +# -+# CONFIG_SENSORS_DS1337 is not set -+# CONFIG_SENSORS_DS1374 is not set +# CONFIG_DS1682 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set -+# CONFIG_SENSORS_PCA9539 is not set ++# CONFIG_PCF8575 is not set +# CONFIG_SENSORS_PCF8591 is not set ++# CONFIG_TPS65010 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_I2C_DEBUG_CORE is not set @@ -3567,9 +3431,27 @@ +# CONFIG_SPI_AT25 is not set +CONFIG_SPI_SPIDEV=m +# CONFIG_SPI_TLE62X0 is not set ++CONFIG_HAVE_GPIO_LIB=y ++ ++# ++# GPIO Support ++# ++# CONFIG_DEBUG_GPIO is not set ++ ++# ++# I2C GPIO expanders: ++# ++# CONFIG_GPIO_PCA953X is not set ++# CONFIG_GPIO_PCF857X is not set ++ ++# ++# SPI GPIO expanders: ++# ++# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set ++# CONFIG_THERMAL is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + @@ -3602,13 +3484,40 @@ +# +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set -+# CONFIG_FB is not set -+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set ++CONFIG_FB=y ++# CONFIG_FIRMWARE_EDID is not set ++# CONFIG_FB_DDC is not set ++CONFIG_FB_CFB_FILLRECT=y ++CONFIG_FB_CFB_COPYAREA=y ++CONFIG_FB_CFB_IMAGEBLIT=y ++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set ++# CONFIG_FB_SYS_FILLRECT is not set ++# CONFIG_FB_SYS_COPYAREA is not set ++# CONFIG_FB_SYS_IMAGEBLIT is not set ++# CONFIG_FB_SYS_FOPS is not set ++CONFIG_FB_DEFERRED_IO=y ++# CONFIG_FB_SVGALIB is not set ++# CONFIG_FB_MACMODES is not set ++# CONFIG_FB_BACKLIGHT is not set ++# CONFIG_FB_MODE_HELPERS is not set ++# CONFIG_FB_TILEBLITTING is not set ++ ++# ++# Frame buffer hardware drivers ++# ++# CONFIG_FB_S1D13XXX is not set ++CONFIG_FB_ATMEL=y ++# CONFIG_FB_VIRTUAL is not set ++CONFIG_BACKLIGHT_LCD_SUPPORT=y ++CONFIG_LCD_CLASS_DEVICE=y ++CONFIG_LCD_LTV350QV=y ++# CONFIG_BACKLIGHT_CLASS_DEVICE is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set ++# CONFIG_LOGO is not set + +# +# Sound @@ -3627,8 +3536,8 @@ +CONFIG_SND_PCM_OSS=m +CONFIG_SND_PCM_OSS_PLUGINS=y +# CONFIG_SND_DYNAMIC_MINORS is not set -+CONFIG_SND_SUPPORT_OLD_API=y -+CONFIG_SND_VERBOSE_PROCFS=y ++# CONFIG_SND_SUPPORT_OLD_API is not set ++# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + @@ -3662,6 +3571,10 @@ +# + +# ++# ALSA SoC audio for Freescale SOCs ++# ++ ++# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set @@ -3675,14 +3588,10 @@ +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# -+ -+# -+# USB Gadget Support -+# +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set -+CONFIG_USB_GADGET_DEBUG_FS=y ++# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_AMD5536UDC is not set +CONFIG_USB_GADGET_ATMEL_USBA=y @@ -3706,6 +3615,7 @@ +# CONFIG_USB_FILE_STORAGE_TEST is not set +CONFIG_USB_G_SERIAL=m +# CONFIG_USB_MIDI_GADGET is not set ++# CONFIG_USB_G_PRINTER is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set @@ -3714,7 +3624,7 @@ +# MMC/SD Card Drivers +# +CONFIG_MMC_BLOCK=y -+# CONFIG_MMC_BLOCK_BOUNCE is not set ++CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_SDIO_UART is not set + +# @@ -3722,21 +3632,22 @@ +# +CONFIG_MMC_ATMELMCI=y +CONFIG_MMC_SPI=m ++# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y -+CONFIG_LEDS_CLASS=y ++CONFIG_LEDS_CLASS=m + +# +# LED drivers +# +CONFIG_LEDS_ATMEL_PWM=m -+CONFIG_LEDS_GPIO=y ++CONFIG_LEDS_GPIO=m + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y -+CONFIG_LEDS_TRIGGER_TIMER=y -+CONFIG_LEDS_TRIGGER_HEARTBEAT=y ++CONFIG_LEDS_TRIGGER_TIMER=m ++CONFIG_LEDS_TRIGGER_HEARTBEAT=m +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y @@ -3765,19 +3676,22 @@ +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set ++# CONFIG_RTC_DRV_S35390A is not set + +# +# SPI RTC drivers +# -+# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6902 is not set ++# CONFIG_RTC_DRV_R9701 is not set ++# CONFIG_RTC_DRV_RS5C348 is not set + +# +# Platform RTC drivers +# ++# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set -+# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_DS1742 is not set ++# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_V3020 is not set @@ -3790,18 +3704,18 @@ +# +# Userspace I/O +# -+CONFIG_UIO=m ++# CONFIG_UIO is not set + +# +# File systems +# -+CONFIG_EXT2_FS=m ++CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set -+CONFIG_EXT3_FS=m ++CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_XATTR is not set +# CONFIG_EXT4DEV_FS is not set -+CONFIG_JBD=m ++CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set @@ -3809,12 +3723,10 @@ +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set -+# CONFIG_MINIX_FS is not set -+# CONFIG_ROMFS_FS is not set ++# CONFIG_DNOTIFY is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set -+# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=m @@ -3859,8 +3771,7 @@ +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 -+CONFIG_JFFS2_FS_WRITEBUFFER=y -+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set ++# CONFIG_JFFS2_FS_WRITEBUFFER is not set +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set @@ -3870,11 +3781,32 @@ +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set ++CONFIG_MINIX_FS=m +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set ++# CONFIG_ROMFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set -+# CONFIG_NETWORK_FILESYSTEMS is not set ++CONFIG_NETWORK_FILESYSTEMS=y ++CONFIG_NFS_FS=y ++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_ROOT_NFS=y ++CONFIG_LOCKD=y ++CONFIG_LOCKD_V4=y ++CONFIG_NFS_COMMON=y ++CONFIG_SUNRPC=y ++# CONFIG_SUNRPC_BIND34 is not set ++# 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 + +# +# Partition Types @@ -3922,11 +3854,6 @@ +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=m +# CONFIG_DLM is not set -+CONFIG_INSTRUMENTATION=y -+CONFIG_PROFILING=y -+CONFIG_OPROFILE=m -+CONFIG_KPROBES=y -+# CONFIG_MARKERS is not set + +# +# Kernel hacking @@ -3944,6 +3871,8 @@ +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set ++# CONFIG_SLUB_DEBUG_ON is not set ++# CONFIG_SLUB_STATS is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set @@ -3960,9 +3889,10 @@ +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +CONFIG_FRAME_POINTER=y -+CONFIG_FORCED_INLINING=y +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set ++# CONFIG_KPROBES_SANITY_TEST is not set ++# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_LKDTM is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_SAMPLES is not set @@ -3973,7 +3903,55 @@ +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set -+# CONFIG_CRYPTO is not set ++CONFIG_CRYPTO=y ++CONFIG_CRYPTO_ALGAPI=m ++CONFIG_CRYPTO_AEAD=m ++CONFIG_CRYPTO_BLKCIPHER=m ++# CONFIG_CRYPTO_SEQIV is not set ++CONFIG_CRYPTO_HASH=m ++CONFIG_CRYPTO_MANAGER=m ++CONFIG_CRYPTO_HMAC=m ++# CONFIG_CRYPTO_XCBC is not set ++# CONFIG_CRYPTO_NULL is not set ++# CONFIG_CRYPTO_MD4 is not set ++CONFIG_CRYPTO_MD5=m ++CONFIG_CRYPTO_SHA1=m ++# 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_GF128MUL is not set ++# CONFIG_CRYPTO_ECB is not set ++CONFIG_CRYPTO_CBC=m ++# CONFIG_CRYPTO_PCBC is not set ++# CONFIG_CRYPTO_LRW is not set ++# CONFIG_CRYPTO_XTS is not set ++# CONFIG_CRYPTO_CTR is not set ++# CONFIG_CRYPTO_GCM is not set ++# CONFIG_CRYPTO_CCM is not set ++# CONFIG_CRYPTO_CRYPTD is not set ++CONFIG_CRYPTO_DES=m ++# CONFIG_CRYPTO_FCRYPT is not set ++# CONFIG_CRYPTO_BLOWFISH is not set ++# CONFIG_CRYPTO_TWOFISH is not set ++# CONFIG_CRYPTO_SERPENT is not set ++# CONFIG_CRYPTO_AES is not set ++# CONFIG_CRYPTO_CAST5 is not set ++# CONFIG_CRYPTO_CAST6 is not set ++# CONFIG_CRYPTO_TEA is not set ++# CONFIG_CRYPTO_ARC4 is not set ++# CONFIG_CRYPTO_KHAZAD is not set ++# CONFIG_CRYPTO_ANUBIS is not set ++# CONFIG_CRYPTO_SEED is not set ++# CONFIG_CRYPTO_SALSA20 is not set ++CONFIG_CRYPTO_DEFLATE=m ++# CONFIG_CRYPTO_MICHAEL_MIC is not set ++# CONFIG_CRYPTO_CRC32C is not set ++# CONFIG_CRYPTO_CAMELLIA is not set ++# CONFIG_CRYPTO_TEST is not set ++CONFIG_CRYPTO_AUTHENC=m ++# CONFIG_CRYPTO_LZO is not set ++# CONFIG_CRYPTO_HW is not set + +# +# Library routines @@ -3985,657 +3963,16 @@ +CONFIG_CRC32=y +CONFIG_CRC7=m +# CONFIG_LIBCRC32C is not set -+CONFIG_AUDIT_GENERIC=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y ++CONFIG_GENERIC_ALLOCATOR=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y ---- /dev/null -+++ b/arch/avr32/configs/atstk1004_defconfig -@@ -0,0 +1,639 @@ -+# -+# Automatically generated make config: don't edit -+# Linux kernel version: 2.6.24 -+# Thu Mar 6 12:51:05 2008 -+# -+CONFIG_AVR32=y -+CONFIG_GENERIC_GPIO=y -+CONFIG_GENERIC_HARDIRQS=y -+CONFIG_STACKTRACE_SUPPORT=y -+CONFIG_LOCKDEP_SUPPORT=y -+CONFIG_TRACE_IRQFLAGS_SUPPORT=y -+CONFIG_HARDIRQS_SW_RESEND=y -+CONFIG_GENERIC_IRQ_PROBE=y -+CONFIG_RWSEM_GENERIC_SPINLOCK=y -+CONFIG_GENERIC_TIME=y -+CONFIG_GENERIC_CLOCKEVENTS=y -+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -+# CONFIG_ARCH_HAS_ILOG2_U32 is not set -+# CONFIG_ARCH_HAS_ILOG2_U64 is not set -+CONFIG_ARCH_SUPPORTS_OPROFILE=y -+CONFIG_GENERIC_HWEIGHT=y -+CONFIG_GENERIC_CALIBRATE_DELAY=y -+CONFIG_GENERIC_BUG=y -+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" -+ -+# -+# General setup -+# -+CONFIG_EXPERIMENTAL=y -+CONFIG_BROKEN_ON_SMP=y -+CONFIG_INIT_ENV_ARG_LIMIT=32 -+CONFIG_LOCALVERSION="" -+# CONFIG_LOCALVERSION_AUTO is not set -+# CONFIG_SYSVIPC is not set -+# CONFIG_POSIX_MQUEUE is not set -+# CONFIG_BSD_PROCESS_ACCT is not set -+# CONFIG_TASKSTATS is not set -+# CONFIG_USER_NS is not set -+# CONFIG_PID_NS is not set -+# CONFIG_AUDIT is not set -+# CONFIG_IKCONFIG is not set -+CONFIG_LOG_BUF_SHIFT=14 -+# CONFIG_CGROUPS is not set -+# CONFIG_FAIR_GROUP_SCHED is not set -+CONFIG_SYSFS_DEPRECATED=y -+# CONFIG_RELAY is not set -+# CONFIG_BLK_DEV_INITRD is not set -+CONFIG_CC_OPTIMIZE_FOR_SIZE=y -+CONFIG_SYSCTL=y -+CONFIG_EMBEDDED=y -+# CONFIG_SYSCTL_SYSCALL is not set -+CONFIG_KALLSYMS=y -+# CONFIG_KALLSYMS_EXTRA_PASS is not set -+CONFIG_HOTPLUG=y -+CONFIG_PRINTK=y -+CONFIG_BUG=y -+CONFIG_ELF_CORE=y -+# CONFIG_BASE_FULL is not set -+# CONFIG_FUTEX is not set -+# CONFIG_EPOLL is not set -+# CONFIG_SIGNALFD is not set -+# CONFIG_EVENTFD is not set -+CONFIG_SHMEM=y -+CONFIG_VM_EVENT_COUNTERS=y -+# CONFIG_SLAB is not set -+# CONFIG_SLUB is not set -+CONFIG_SLOB=y -+# CONFIG_TINY_SHMEM is not set -+CONFIG_BASE_SMALL=1 -+# CONFIG_MODULES is not set -+# CONFIG_BLOCK is not set -+ -+# -+# System Type and features -+# -+CONFIG_TICK_ONESHOT=y -+CONFIG_NO_HZ=y -+CONFIG_HIGH_RES_TIMERS=y -+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y -+CONFIG_SUBARCH_AVR32B=y -+CONFIG_MMU=y -+CONFIG_PERFORMANCE_COUNTERS=y -+CONFIG_PLATFORM_AT32AP=y -+CONFIG_CPU_AT32AP700X=y -+CONFIG_CPU_AT32AP7002=y -+CONFIG_BOARD_ATSTK1000=y -+# CONFIG_BOARD_ATNGW100 is not set -+# CONFIG_BOARD_ATSTK1002 is not set -+# CONFIG_BOARD_ATSTK1003 is not set -+CONFIG_BOARD_ATSTK1004=y -+# CONFIG_BOARD_ATSTK100X_CUSTOM is not set -+# CONFIG_BOARD_ATSTK100X_SPI1 is not set -+# CONFIG_BOARD_ATSTK1000_J2_LED is not set -+CONFIG_BOARD_ATSTK1000_EXTDAC=y -+# CONFIG_BOARD_ATSTK100X_ENABLE_AC97 is not set -+# CONFIG_BOARD_ATSTK1000_CF_HACKS is not set -+# CONFIG_BOARD_ATSTK100X_ENABLE_PSIF is not set -+CONFIG_LOADER_U_BOOT=y -+ -+# -+# Atmel AVR32 AP options -+# -+# CONFIG_AP700X_32_BIT_SMC is not set -+CONFIG_AP700X_16_BIT_SMC=y -+# CONFIG_AP700X_8_BIT_SMC is not set -+# CONFIG_GPIO_DEV is not set -+CONFIG_LOAD_ADDRESS=0x10000000 -+CONFIG_ENTRY_ADDRESS=0x90000000 -+CONFIG_PHYS_OFFSET=0x10000000 -+CONFIG_PREEMPT_NONE=y -+# CONFIG_PREEMPT_VOLUNTARY is not set -+# CONFIG_PREEMPT is not set -+# CONFIG_HAVE_ARCH_BOOTMEM_NODE is not set -+# CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set -+# CONFIG_NEED_NODE_MEMMAP_SIZE is not set -+CONFIG_ARCH_FLATMEM_ENABLE=y -+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set -+# CONFIG_ARCH_SPARSEMEM_ENABLE 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_SPARSEMEM_VMEMMAP_ENABLE is not set -+CONFIG_SPLIT_PTLOCK_CPUS=4 -+# CONFIG_RESOURCES_64BIT is not set -+CONFIG_ZONE_DMA_FLAG=0 -+CONFIG_VIRT_TO_BUS=y -+# CONFIG_OWNERSHIP_TRACE is not set -+# CONFIG_NMI_DEBUGGING is not set -+# CONFIG_DW_DMAC is not set -+# CONFIG_HZ_100 is not set -+CONFIG_HZ_250=y -+# CONFIG_HZ_300 is not set -+# CONFIG_HZ_1000 is not set -+CONFIG_HZ=250 -+CONFIG_CMDLINE="" -+ -+# -+# Power management options -+# -+ -+# -+# CPU Frequency scaling -+# -+CONFIG_CPU_FREQ=y -+CONFIG_CPU_FREQ_TABLE=y -+# CONFIG_CPU_FREQ_DEBUG is not set -+# CONFIG_CPU_FREQ_STAT is not set -+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y -+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set -+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set -+CONFIG_CPU_FREQ_GOV_USERSPACE=y -+CONFIG_CPU_FREQ_GOV_ONDEMAND=y -+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set -+CONFIG_CPU_FREQ_AT32AP=y -+ -+# -+# Bus options -+# -+# CONFIG_ARCH_SUPPORTS_MSI is not set -+# CONFIG_PCCARD is not set -+ -+# -+# Executable file formats -+# -+CONFIG_BINFMT_ELF=y -+# CONFIG_BINFMT_MISC is not set -+ -+# -+# Networking -+# -+CONFIG_NET=y -+ -+# -+# Networking options -+# -+CONFIG_PACKET=y -+CONFIG_PACKET_MMAP=y -+CONFIG_UNIX=y -+# CONFIG_NET_KEY is not set -+CONFIG_INET=y -+# CONFIG_IP_MULTICAST is not set -+# CONFIG_IP_ADVANCED_ROUTER is not set -+CONFIG_IP_FIB_HASH=y -+# CONFIG_IP_PNP is not set -+# CONFIG_NET_IPIP is not set -+# CONFIG_NET_IPGRE is not set -+# CONFIG_ARPD is not set -+# CONFIG_SYN_COOKIES is not set -+# 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_XFRM_MODE_BEET is not set -+# CONFIG_INET_LRO is not set -+# CONFIG_INET_DIAG is not set -+# CONFIG_TCP_CONG_ADVANCED is not set -+CONFIG_TCP_CONG_CUBIC=y -+CONFIG_DEFAULT_TCP_CONG="cubic" -+# CONFIG_TCP_MD5SIG 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 is not set -+# CONFIG_IP_DCCP is not set -+# CONFIG_IP_SCTP is not set -+# CONFIG_TIPC is not set -+# CONFIG_ATM is not set -+# CONFIG_BRIDGE is not set -+# CONFIG_VLAN_8021Q is not set -+# CONFIG_DECNET is not set -+# 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 -+# CONFIG_NET_SCHED is not set -+ -+# -+# Network testing -+# -+# CONFIG_NET_PKTGEN is not set -+# CONFIG_HAMRADIO is not set -+# CONFIG_IRDA is not set -+# CONFIG_BT is not set -+# CONFIG_AF_RXRPC is not set -+ -+# -+# Wireless -+# -+# CONFIG_CFG80211 is not set -+# CONFIG_WIRELESS_EXT is not set -+# CONFIG_MAC80211 is not set -+# CONFIG_IEEE80211 is not set -+# CONFIG_RFKILL is not set -+# CONFIG_NET_9P is not set -+ -+# -+# Device Drivers -+# -+ -+# -+# Generic Driver Options -+# -+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -+CONFIG_STANDALONE=y -+# CONFIG_PREVENT_FIRMWARE_BUILD is not set -+# CONFIG_FW_LOADER is not set -+# CONFIG_SYS_HYPERVISOR is not set -+# CONFIG_CONNECTOR is not set -+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=y -+ -+# -+# User Modules And Translation Layers -+# -+CONFIG_MTD_CHAR=y -+# CONFIG_MTD_OOPS 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 -+ -+# -+# Mapping drivers for chip access -+# -+# CONFIG_MTD_COMPLEX_MAPPINGS is not set -+CONFIG_MTD_PHYSMAP=y -+CONFIG_MTD_PHYSMAP_START=0x8000000 -+CONFIG_MTD_PHYSMAP_LEN=0x0 -+CONFIG_MTD_PHYSMAP_BANKWIDTH=2 -+# CONFIG_MTD_PLATRAM is not set -+ -+# -+# Self-contained MTD device drivers -+# -+# CONFIG_MTD_DATAFLASH is not set -+# CONFIG_MTD_M25P80 is not set -+# CONFIG_MTD_SLRAM is not set -+# CONFIG_MTD_PHRAM is not set -+# CONFIG_MTD_MTDRAM 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 -+# CONFIG_MTD_NAND is not set -+# CONFIG_MTD_ONENAND is not set -+ -+# -+# UBI - Unsorted block images -+# -+# CONFIG_MTD_UBI is not set -+# CONFIG_PARPORT is not set -+CONFIG_MISC_DEVICES=y -+# CONFIG_ATMEL_PWM is not set -+CONFIG_ATMEL_TCLIB=y -+CONFIG_ATMEL_TCB_CLKSRC=y -+CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0 -+# CONFIG_EEPROM_93CX6 is not set -+# CONFIG_ATMEL_SSC is not set -+ -+# -+# SCSI device support -+# -+# CONFIG_SCSI_DMA is not set -+# CONFIG_SCSI_NETLINK is not set -+# CONFIG_NETDEVICES is not set -+# CONFIG_ISDN is not set -+# 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 is not set -+ -+# -+# Non-8250 serial port support -+# -+CONFIG_SERIAL_ATMEL=y -+CONFIG_SERIAL_ATMEL_CONSOLE=y -+# CONFIG_SERIAL_ATMEL_PDC is not set -+# CONFIG_SERIAL_ATMEL_TTYAT is not set -+CONFIG_SERIAL_CORE=y -+CONFIG_SERIAL_CORE_CONSOLE=y -+CONFIG_UNIX98_PTYS=y -+# CONFIG_LEGACY_PTYS is not set -+# CONFIG_IPMI_HANDLER is not set -+# CONFIG_HW_RANDOM is not set -+# CONFIG_RTC is not set -+# CONFIG_GEN_RTC is not set -+# CONFIG_R3964 is not set -+# CONFIG_TCG_TPM is not set -+# CONFIG_I2C is not set -+ -+# -+# SPI support -+# -+CONFIG_SPI=y -+CONFIG_SPI_MASTER=y -+ -+# -+# SPI Master Controller Drivers -+# -+CONFIG_SPI_ATMEL=y -+# CONFIG_SPI_BITBANG is not set -+ -+# -+# SPI Protocol Masters -+# -+# CONFIG_SPI_AT25 is not set -+# CONFIG_SPI_SPIDEV is not set -+# CONFIG_SPI_TLE62X0 is not set -+# CONFIG_W1 is not set -+# CONFIG_POWER_SUPPLY is not set -+# CONFIG_HWMON is not set -+CONFIG_WATCHDOG=y -+# CONFIG_WATCHDOG_NOWAYOUT is not set -+ -+# -+# Watchdog Device Drivers -+# -+# CONFIG_SOFT_WATCHDOG is not set -+CONFIG_AT32AP700X_WDT=y -+ -+# -+# Sonics Silicon Backplane -+# -+CONFIG_SSB_POSSIBLE=y -+# CONFIG_SSB is not set -+ -+# -+# Multifunction device drivers -+# -+# CONFIG_MFD_SM501 is not set -+ -+# -+# Multimedia devices -+# -+# CONFIG_VIDEO_DEV is not set -+# CONFIG_DVB_CORE is not set -+# CONFIG_DAB is not set -+ -+# -+# Graphics support -+# -+# CONFIG_VGASTATE is not set -+# CONFIG_VIDEO_OUTPUT_CONTROL is not set -+CONFIG_FB=y -+# CONFIG_FIRMWARE_EDID is not set -+# CONFIG_FB_DDC is not set -+CONFIG_FB_CFB_FILLRECT=y -+CONFIG_FB_CFB_COPYAREA=y -+CONFIG_FB_CFB_IMAGEBLIT=y -+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set -+# CONFIG_FB_SYS_FILLRECT is not set -+# CONFIG_FB_SYS_COPYAREA is not set -+# CONFIG_FB_SYS_IMAGEBLIT is not set -+# CONFIG_FB_SYS_FOPS is not set -+CONFIG_FB_DEFERRED_IO=y -+# CONFIG_FB_SVGALIB is not set -+# CONFIG_FB_MACMODES is not set -+# CONFIG_FB_BACKLIGHT is not set -+# CONFIG_FB_MODE_HELPERS is not set -+# CONFIG_FB_TILEBLITTING is not set -+ -+# -+# Frame buffer hardware drivers -+# -+# CONFIG_FB_S1D13XXX is not set -+CONFIG_FB_ATMEL=y -+# CONFIG_FB_VIRTUAL is not set -+CONFIG_BACKLIGHT_LCD_SUPPORT=y -+CONFIG_LCD_CLASS_DEVICE=y -+CONFIG_LCD_LTV350QV=y -+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set -+ -+# -+# Display device support -+# -+# CONFIG_DISPLAY_SUPPORT is not set -+# CONFIG_LOGO is not set -+ -+# -+# Sound -+# -+# CONFIG_SOUND is not set -+CONFIG_USB_SUPPORT=y -+# CONFIG_USB_ARCH_HAS_HCD is not set -+# CONFIG_USB_ARCH_HAS_OHCI is not set -+# CONFIG_USB_ARCH_HAS_EHCI is not set -+ -+# -+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -+# -+ -+# -+# USB Gadget Support -+# -+CONFIG_USB_GADGET=y -+# CONFIG_USB_GADGET_DEBUG_FILES is not set -+CONFIG_USB_GADGET_SELECTED=y -+# CONFIG_USB_GADGET_AMD5536UDC is not set -+CONFIG_USB_GADGET_ATMEL_USBA=y -+CONFIG_USB_ATMEL_USBA=y -+# CONFIG_USB_GADGET_FSL_USB2 is not set -+# CONFIG_USB_GADGET_NET2280 is not set -+# CONFIG_USB_GADGET_PXA2XX is not set -+# CONFIG_USB_GADGET_M66592 is not set -+# CONFIG_USB_GADGET_GOKU is not set -+# CONFIG_USB_GADGET_LH7A40X is not set -+# CONFIG_USB_GADGET_OMAP is not set -+# CONFIG_USB_GADGET_S3C2410 is not set -+# CONFIG_USB_GADGET_AT91 is not set -+# CONFIG_USB_GADGET_DUMMY_HCD is not set -+CONFIG_USB_GADGET_DUALSPEED=y -+# CONFIG_USB_ZERO is not set -+CONFIG_USB_ETH=y -+# CONFIG_USB_ETH_RNDIS is not set -+# CONFIG_USB_GADGETFS is not set -+# CONFIG_USB_FILE_STORAGE is not set -+# CONFIG_USB_G_SERIAL is not set -+# CONFIG_USB_MIDI_GADGET is not set -+# CONFIG_MMC is not set -+# CONFIG_NEW_LEDS is not set -+CONFIG_RTC_LIB=y -+CONFIG_RTC_CLASS=y -+CONFIG_RTC_HCTOSYS=y -+CONFIG_RTC_HCTOSYS_DEVICE="rtc0" -+# CONFIG_RTC_DEBUG is not set -+ -+# -+# RTC interfaces -+# -+CONFIG_RTC_INTF_SYSFS=y -+# CONFIG_RTC_INTF_PROC is not set -+CONFIG_RTC_INTF_DEV=y -+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set -+# CONFIG_RTC_DRV_TEST is not set -+ -+# -+# SPI RTC drivers -+# -+# CONFIG_RTC_DRV_RS5C348 is not set -+# CONFIG_RTC_DRV_MAX6902 is not set -+ -+# -+# Platform RTC drivers -+# -+# CONFIG_RTC_DRV_DS1553 is not set -+# CONFIG_RTC_DRV_STK17TA8 is not set -+# CONFIG_RTC_DRV_DS1742 is not set -+# CONFIG_RTC_DRV_M48T86 is not set -+# CONFIG_RTC_DRV_M48T59 is not set -+# CONFIG_RTC_DRV_V3020 is not set -+ -+# -+# on-CPU RTC drivers -+# -+CONFIG_RTC_DRV_AT32AP700X=y -+ -+# -+# Userspace I/O -+# -+# CONFIG_UIO is not set -+ -+# -+# File systems -+# -+# CONFIG_INOTIFY is not set -+# CONFIG_QUOTA is not set -+# CONFIG_DNOTIFY is not set -+# CONFIG_AUTOFS_FS is not set -+# CONFIG_AUTOFS4_FS is not set -+# CONFIG_FUSE_FS is not set -+ -+# -+# Pseudo filesystems -+# -+CONFIG_PROC_FS=y -+CONFIG_PROC_KCORE=y -+CONFIG_PROC_SYSCTL=y -+CONFIG_SYSFS=y -+CONFIG_TMPFS=y -+# CONFIG_TMPFS_POSIX_ACL is not set -+# CONFIG_HUGETLB_PAGE is not set -+# CONFIG_CONFIGFS_FS is not set -+ -+# -+# Miscellaneous filesystems -+# -+CONFIG_JFFS2_FS=y -+CONFIG_JFFS2_FS_DEBUG=0 -+# CONFIG_JFFS2_FS_WRITEBUFFER is not set -+# CONFIG_JFFS2_SUMMARY is not set -+# CONFIG_JFFS2_FS_XATTR is not set -+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set -+CONFIG_JFFS2_ZLIB=y -+# CONFIG_JFFS2_LZO is not set -+CONFIG_JFFS2_RTIME=y -+# CONFIG_JFFS2_RUBIN is not set -+# CONFIG_NETWORK_FILESYSTEMS is not set -+# CONFIG_NLS is not set -+# CONFIG_DLM is not set -+# CONFIG_INSTRUMENTATION is not set -+ -+# -+# Kernel hacking -+# -+# CONFIG_PRINTK_TIME is not set -+CONFIG_ENABLE_WARN_DEPRECATED=y -+CONFIG_ENABLE_MUST_CHECK=y -+CONFIG_MAGIC_SYSRQ=y -+# CONFIG_UNUSED_SYMBOLS is not set -+# CONFIG_DEBUG_FS is not set -+# CONFIG_HEADERS_CHECK is not set -+# CONFIG_DEBUG_KERNEL is not set -+# CONFIG_DEBUG_BUGVERBOSE is not set -+# CONFIG_SAMPLES is not set -+ -+# -+# Security options -+# -+# CONFIG_KEYS is not set -+# CONFIG_SECURITY is not set -+# CONFIG_SECURITY_FILE_CAPABILITIES is not set -+# CONFIG_CRYPTO is not set -+ -+# -+# Library routines -+# -+CONFIG_BITREVERSE=y -+# CONFIG_CRC_CCITT is not set -+# CONFIG_CRC16 is not set -+# CONFIG_CRC_ITU_T is not set -+CONFIG_CRC32=y -+# CONFIG_CRC7 is not set -+# CONFIG_LIBCRC32C is not set -+CONFIG_ZLIB_INFLATE=y -+CONFIG_ZLIB_DEFLATE=y -+CONFIG_HAS_IOMEM=y -+CONFIG_HAS_IOPORT=y -+CONFIG_HAS_DMA=y ---- /dev/null -+++ b/arch/avr32/drivers/dw-dmac.c +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/drivers/dw-dmac.c avr32-2.6/arch/avr32/drivers/dw-dmac.c +--- linux-2.6.25.6/arch/avr32/drivers/dw-dmac.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/arch/avr32/drivers/dw-dmac.c 2008-06-12 15:09:38.719815350 +0200 @@ -0,0 +1,761 @@ +/* + * Driver for the Synopsys DesignWare DMA Controller @@ -5398,8 +4735,9 @@ +MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller driver"); +MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>"); +MODULE_LICENSE("GPL"); ---- /dev/null -+++ b/arch/avr32/drivers/dw-dmac.h +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/drivers/dw-dmac.h avr32-2.6/arch/avr32/drivers/dw-dmac.h +--- linux-2.6.25.6/arch/avr32/drivers/dw-dmac.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/arch/avr32/drivers/dw-dmac.h 2008-06-12 15:09:38.719815350 +0200 @@ -0,0 +1,42 @@ +/* + * Driver for the Synopsys DesignWare DMA Controller @@ -5443,13 +4781,15 @@ +#define DW_DMAC_CHAN_DSR 0x050 + +#endif /* __AVR32_DW_DMAC_H__ */ ---- /dev/null -+++ b/arch/avr32/drivers/Makefile +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/drivers/Makefile avr32-2.6/arch/avr32/drivers/Makefile +--- linux-2.6.25.6/arch/avr32/drivers/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/arch/avr32/drivers/Makefile 2008-06-12 15:09:38.719815350 +0200 @@ -0,0 +1 @@ +obj-$(CONFIG_DW_DMAC) += dw-dmac.o ---- a/arch/avr32/Kconfig -+++ b/arch/avr32/Kconfig -@@ -45,6 +45,9 @@ +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/Kconfig avr32-2.6/arch/avr32/Kconfig +--- linux-2.6.25.6/arch/avr32/Kconfig 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/Kconfig 2008-06-12 15:09:38.711815728 +0200 +@@ -47,6 +47,9 @@ config GENERIC_TIME def_bool y @@ -5459,17 +4799,7 @@ config RWSEM_XCHGADD_ALGORITHM def_bool n -@@ -54,6 +57,9 @@ - config ARCH_HAS_ILOG2_U64 - def_bool n - -+config ARCH_SUPPORTS_OPROFILE -+ def_bool y -+ - config GENERIC_HWEIGHT - def_bool y - -@@ -68,6 +74,8 @@ +@@ -70,6 +73,8 @@ menu "System Type and features" @@ -5478,51 +4808,15 @@ config SUBARCH_AVR32B bool config MMU -@@ -81,19 +89,23 @@ +@@ -83,6 +88,7 @@ select MMU select PERFORMANCE_COUNTERS + select HAVE_GPIO_LIB ++ select GENERIC_ALLOCATOR --choice -- prompt "AVR32 CPU type" -- default CPU_AT32AP7000 -+# -+# CPU types -+# - --config CPU_AT32AP7000 -- bool "AT32AP7000" -+# AP7000 derivatives -+config CPU_AT32AP700X -+ bool - select PLATFORM_AT32AP --endchoice -- --# --# CPU Daughterboards for ATSTK1000 --config BOARD_ATSTK1002 -+config CPU_AT32AP7000 -+ bool -+ select CPU_AT32AP700X -+config CPU_AT32AP7001 -+ bool -+ select CPU_AT32AP700X -+config CPU_AT32AP7002 - bool -+ select CPU_AT32AP700X - - choice - prompt "AVR32 board type" -@@ -101,15 +113,18 @@ - - config BOARD_ATSTK1000 - bool "ATSTK1000 evaluation board" -- select BOARD_ATSTK1002 if CPU_AT32AP7000 - - config BOARD_ATNGW100 - bool "ATNGW100 Network Gateway" -+ select CPU_AT32AP7000 - endchoice - + # + # CPU types +@@ -117,6 +123,9 @@ if BOARD_ATSTK1000 source "arch/avr32/boards/atstk1000/Kconfig" endif @@ -5532,39 +4826,10 @@ choice prompt "Boot loader type" -@@ -123,15 +138,15 @@ - - config LOAD_ADDRESS - hex -- default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y -+ default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP700X=y - - config ENTRY_ADDRESS - hex -- default 0x90000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y -+ default 0x90000000 if LOADER_U_BOOT=y && CPU_AT32AP700X=y +@@ -180,6 +189,10 @@ + be dumped to the console when a Non-Maskable Interrupt + happens. - config PHYS_OFFSET - hex -- default 0x10000000 if CPU_AT32AP7000=y -+ default 0x10000000 if CPU_AT32AP700X=y - - source "kernel/Kconfig.preempt" - -@@ -163,6 +178,20 @@ - enabling Nexus-compliant debuggers to keep track of the PID of the - currently executing task. - -+config NMI_DEBUGGING -+ bool "NMI Debugging" -+ default n -+ help -+ Say Y here and pass the nmi_debug command-line parameter to -+ the kernel to turn on NMI debugging. Depending on the value -+ of the nmi_debug option, various pieces of information will -+ be dumped to the console when a Non-Maskable Interrupt -+ happens. -+ +config DW_DMAC + tristate "Synopsys DesignWare DMA Controller support" + default y if CPU_AT32AP7000 @@ -5572,228 +4837,43 @@ # FPU emulation goes here source "kernel/Kconfig.hz" -@@ -219,6 +248,8 @@ +@@ -196,6 +209,11 @@ - source "fs/Kconfig" - -+source "kernel/Kconfig.instrumentation" -+ - source "arch/avr32/Kconfig.debug" + menu "Power management options" - source "security/Kconfig" ---- a/arch/avr32/Kconfig.debug -+++ b/arch/avr32/Kconfig.debug -@@ -6,14 +6,4 @@ - - source "lib/Kconfig.debug" - --config KPROBES -- bool "Kprobes" -- depends on DEBUG_KERNEL -- help -- Kprobes allows you to trap at almost any kernel address and -- execute a callback function. register_kprobe() establishes -- a probepoint and specifies the callback. Kprobes is useful -- for kernel debugging, non-intrusive instrumentation and testing. -- If in doubt, say "N". -- - endmenu ---- a/arch/avr32/kernel/cpu.c -+++ b/arch/avr32/kernel/cpu.c -@@ -13,6 +13,7 @@ - #include <linux/percpu.h> - #include <linux/param.h> - #include <linux/errno.h> -+#include <linux/clk.h> - - #include <asm/setup.h> - #include <asm/sysreg.h> -@@ -187,9 +188,20 @@ - - subsys_initcall(topology_init); - -+struct chip_id_map { -+ u16 mid; -+ u16 pn; -+ const char *name; -+}; -+ -+static const struct chip_id_map chip_names[] = { -+ { .mid = 0x1f, .pn = 0x1e82, .name = "AT32AP700x" }, -+}; -+#define NR_CHIP_NAMES ARRAY_SIZE(chip_names) -+ - static const char *cpu_names[] = { - "Morgan", -- "AP7000", -+ "AP7", - }; - #define NR_CPU_NAMES ARRAY_SIZE(cpu_names) - -@@ -206,12 +218,32 @@ - "MPU" - }; - -+static const char *cpu_feature_flags[] = { -+ "rmw", "dsp", "simd", "ocd", "perfctr", "java", "fpu", -+}; -+ -+static const char *get_chip_name(struct avr32_cpuinfo *cpu) -+{ -+ unsigned int i; -+ unsigned int mid = avr32_get_manufacturer_id(cpu); -+ unsigned int pn = avr32_get_product_number(cpu); -+ -+ for (i = 0; i < NR_CHIP_NAMES; i++) { -+ if (chip_names[i].mid == mid && chip_names[i].pn == pn) -+ return chip_names[i].name; -+ } ++config ARCH_SUSPEND_POSSIBLE ++ def_bool y + -+ return "(unknown)"; -+} ++source "kernel/power/Kconfig" + - void __init setup_processor(void) - { - unsigned long config0, config1; - unsigned long features; - unsigned cpu_id, cpu_rev, arch_id, arch_rev, mmu_type; -+ unsigned device_id; - unsigned tmp; -+ unsigned i; - - config0 = sysreg_read(CONFIG0); - config1 = sysreg_read(CONFIG1); -@@ -221,11 +253,14 @@ - arch_rev = SYSREG_BFEXT(AR, config0); - mmu_type = SYSREG_BFEXT(MMUT, config0); - -+ device_id = ocd_read(DID); -+ - boot_cpu_data.arch_type = arch_id; - boot_cpu_data.cpu_type = cpu_id; - boot_cpu_data.arch_revision = arch_rev; - boot_cpu_data.cpu_revision = cpu_rev; - boot_cpu_data.tlb_config = mmu_type; -+ boot_cpu_data.device_id = device_id; - - tmp = SYSREG_BFEXT(ILSZ, config1); - if (tmp) { -@@ -247,41 +282,34 @@ - return; - } + menu "CPU Frequency scaling" -- printk ("CPU: %s [%02x] revision %d (%s revision %d)\n", -+ printk ("CPU: %s chip revision %c\n", get_chip_name(&boot_cpu_data), -+ avr32_get_chip_revision(&boot_cpu_data) + 'A'); -+ printk ("CPU: %s [%02x] core revision %d (%s arch revision %d)\n", - cpu_names[cpu_id], cpu_id, cpu_rev, - arch_names[arch_id], arch_rev); - printk ("CPU: MMU configuration: %s\n", mmu_types[mmu_type]); - - printk ("CPU: features:"); - features = 0; -- if (config0 & SYSREG_BIT(CONFIG0_R)) { -+ if (config0 & SYSREG_BIT(CONFIG0_R)) - features |= AVR32_FEATURE_RMW; -- printk(" rmw"); -- } -- if (config0 & SYSREG_BIT(CONFIG0_D)) { -+ if (config0 & SYSREG_BIT(CONFIG0_D)) - features |= AVR32_FEATURE_DSP; -- printk(" dsp"); -- } -- if (config0 & SYSREG_BIT(CONFIG0_S)) { -+ if (config0 & SYSREG_BIT(CONFIG0_S)) - features |= AVR32_FEATURE_SIMD; -- printk(" simd"); -- } -- if (config0 & SYSREG_BIT(CONFIG0_O)) { -+ if (config0 & SYSREG_BIT(CONFIG0_O)) - features |= AVR32_FEATURE_OCD; -- printk(" ocd"); -- } -- if (config0 & SYSREG_BIT(CONFIG0_P)) { -+ if (config0 & SYSREG_BIT(CONFIG0_P)) - features |= AVR32_FEATURE_PCTR; -- printk(" perfctr"); -- } -- if (config0 & SYSREG_BIT(CONFIG0_J)) { -+ if (config0 & SYSREG_BIT(CONFIG0_J)) - features |= AVR32_FEATURE_JAVA; -- printk(" java"); -- } -- if (config0 & SYSREG_BIT(CONFIG0_F)) { -+ if (config0 & SYSREG_BIT(CONFIG0_F)) - features |= AVR32_FEATURE_FPU; -- printk(" fpu"); -- } -+ -+ for (i = 0; i < ARRAY_SIZE(cpu_feature_flags); i++) -+ if (features & (1 << i)) -+ printk(" %s", cpu_feature_flags[i]); + source "drivers/cpufreq/Kconfig" +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/kernel/avr32_ksyms.c avr32-2.6/arch/avr32/kernel/avr32_ksyms.c +--- linux-2.6.25.6/arch/avr32/kernel/avr32_ksyms.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/kernel/avr32_ksyms.c 2008-06-12 15:03:55.883815569 +0200 +@@ -29,7 +29,9 @@ + */ + EXPORT_SYMBOL(memset); + EXPORT_SYMBOL(memcpy); + - printk("\n"); - boot_cpu_data.features = features; - } -@@ -291,6 +319,8 @@ - { - unsigned int icache_size, dcache_size; - unsigned int cpu = smp_processor_id(); -+ unsigned int freq; -+ unsigned int i; - - icache_size = boot_cpu_data.icache.ways * - boot_cpu_data.icache.sets * -@@ -301,15 +331,21 @@ - - seq_printf(m, "processor\t: %d\n", cpu); - -+ seq_printf(m, "chip type\t: %s revision %c\n", -+ get_chip_name(&boot_cpu_data), -+ avr32_get_chip_revision(&boot_cpu_data) + 'A'); - if (boot_cpu_data.arch_type < NR_ARCH_NAMES) -- seq_printf(m, "cpu family\t: %s revision %d\n", -+ seq_printf(m, "cpu arch\t: %s revision %d\n", - arch_names[boot_cpu_data.arch_type], - boot_cpu_data.arch_revision); - if (boot_cpu_data.cpu_type < NR_CPU_NAMES) -- seq_printf(m, "cpu type\t: %s revision %d\n", -+ seq_printf(m, "cpu core\t: %s revision %d\n", - cpu_names[boot_cpu_data.cpu_type], - boot_cpu_data.cpu_revision); - -+ freq = (clk_get_rate(boot_cpu_data.clk) + 500) / 1000; -+ seq_printf(m, "cpu MHz\t\t: %u.%03u\n", freq / 1000, freq % 1000); -+ - seq_printf(m, "i-cache\t\t: %dK (%u ways x %u sets x %u)\n", - icache_size >> 10, - boot_cpu_data.icache.ways, -@@ -320,7 +356,13 @@ - boot_cpu_data.dcache.ways, - boot_cpu_data.dcache.sets, - boot_cpu_data.dcache.linesz); -- seq_printf(m, "bogomips\t: %lu.%02lu\n", -+ -+ seq_printf(m, "features\t:"); -+ for (i = 0; i < ARRAY_SIZE(cpu_feature_flags); i++) -+ if (boot_cpu_data.features & (1 << i)) -+ seq_printf(m, " %s", cpu_feature_flags[i]); -+ -+ seq_printf(m, "\nbogomips\t: %lu.%02lu\n", - boot_cpu_data.loops_per_jiffy / (500000/HZ), - (boot_cpu_data.loops_per_jiffy / (5000/HZ)) % 100); - -@@ -343,7 +385,7 @@ - - } + EXPORT_SYMBOL(clear_page); ++EXPORT_SYMBOL(copy_page); --struct seq_operations cpuinfo_op = { -+const struct seq_operations cpuinfo_op = { - .start = c_start, - .next = c_next, - .stop = c_stop, ---- /dev/null -+++ b/arch/avr32/kernel/dma-controller.c + /* + * Userspace access stuff. +@@ -41,6 +43,8 @@ + EXPORT_SYMBOL(__strncpy_from_user); + EXPORT_SYMBOL(clear_user); + EXPORT_SYMBOL(__clear_user); ++EXPORT_SYMBOL(strnlen_user); ++ + EXPORT_SYMBOL(csum_partial); + EXPORT_SYMBOL(csum_partial_copy_generic); + +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/kernel/dma-controller.c avr32-2.6/arch/avr32/kernel/dma-controller.c +--- linux-2.6.25.6/arch/avr32/kernel/dma-controller.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/arch/avr32/kernel/dma-controller.c 2008-06-12 15:09:38.719815350 +0200 @@ -0,0 +1,34 @@ +/* + * Preliminary DMA controller framework for AVR32 @@ -5829,8 +4909,9 @@ + return NULL; +} +EXPORT_SYMBOL(find_dma_controller); ---- a/arch/avr32/kernel/entry-avr32b.S -+++ b/arch/avr32/kernel/entry-avr32b.S +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/kernel/entry-avr32b.S avr32-2.6/arch/avr32/kernel/entry-avr32b.S +--- linux-2.6.25.6/arch/avr32/kernel/entry-avr32b.S 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/kernel/entry-avr32b.S 2008-06-12 15:03:55.883815569 +0200 @@ -741,26 +741,6 @@ .section .irq.text,"ax",@progbits @@ -5858,330 +4939,21 @@ .global irq_level0 .global irq_level1 .global irq_level2 ---- a/arch/avr32/kernel/irq.c -+++ b/arch/avr32/kernel/irq.c -@@ -25,6 +25,17 @@ - printk("unexpected IRQ %u\n", irq); - } - -+/* May be overridden by platform code */ -+int __weak nmi_enable(void) -+{ -+ return -ENOSYS; -+} -+ -+void __weak nmi_disable(void) -+{ -+ -+} -+ - #ifdef CONFIG_PROC_FS - int show_interrupts(struct seq_file *p, void *v) - { ---- a/arch/avr32/kernel/kprobes.c -+++ b/arch/avr32/kernel/kprobes.c -@@ -48,6 +48,7 @@ - void __kprobes arch_arm_kprobe(struct kprobe *p) - { - pr_debug("arming kprobe at %p\n", p->addr); -+ ocd_enable(NULL); - *p->addr = BREAKPOINT_INSTRUCTION; - flush_icache_range((unsigned long)p->addr, - (unsigned long)p->addr + sizeof(kprobe_opcode_t)); -@@ -56,6 +57,7 @@ - void __kprobes arch_disarm_kprobe(struct kprobe *p) - { - pr_debug("disarming kprobe at %p\n", p->addr); -+ ocd_disable(NULL); - *p->addr = p->opcode; - flush_icache_range((unsigned long)p->addr, - (unsigned long)p->addr + sizeof(kprobe_opcode_t)); -@@ -260,9 +262,6 @@ - - int __init arch_init_kprobes(void) - { -- printk("KPROBES: Enabling monitor mode (MM|DBE)...\n"); -- ocd_write(DC, (1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT)); -- - /* TODO: Register kretprobe trampoline */ - return 0; - } ---- a/arch/avr32/kernel/Makefile -+++ b/arch/avr32/kernel/Makefile -@@ -6,9 +6,11 @@ - - obj-$(CONFIG_SUBARCH_AVR32B) += entry-avr32b.o - obj-y += syscall_table.o syscall-stubs.o irq.o --obj-y += setup.o traps.o semaphore.o ptrace.o -+obj-y += setup.o traps.o semaphore.o ocd.o ptrace.o +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/kernel/Makefile avr32-2.6/arch/avr32/kernel/Makefile +--- linux-2.6.25.6/arch/avr32/kernel/Makefile 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/kernel/Makefile 2008-06-12 15:09:38.719815350 +0200 +@@ -9,6 +9,7 @@ + obj-y += setup.o traps.o semaphore.o ocd.o ptrace.o obj-y += signal.o sys_avr32.o process.o time.o obj-y += init_task.o switch_to.o cpu.o +obj-y += dma-controller.o obj-$(CONFIG_MODULES) += module.o avr32_ksyms.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_STACKTRACE) += stacktrace.o -+obj-$(CONFIG_NMI_DEBUGGING) += nmi_debug.o ---- /dev/null -+++ b/arch/avr32/kernel/nmi_debug.c -@@ -0,0 +1,82 @@ -+/* -+ * Copyright (C) 2007 Atmel Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#include <linux/delay.h> -+#include <linux/kdebug.h> -+#include <linux/notifier.h> -+#include <linux/sched.h> -+ -+#include <asm/irq.h> -+ -+enum nmi_action { -+ NMI_SHOW_STATE = 1 << 0, -+ NMI_SHOW_REGS = 1 << 1, -+ NMI_DIE = 1 << 2, -+ NMI_DEBOUNCE = 1 << 3, -+}; -+ -+static unsigned long nmi_actions; -+ -+static int nmi_debug_notify(struct notifier_block *self, -+ unsigned long val, void *data) -+{ -+ struct die_args *args = data; -+ -+ if (likely(val != DIE_NMI)) -+ return NOTIFY_DONE; -+ -+ if (nmi_actions & NMI_SHOW_STATE) -+ show_state(); -+ if (nmi_actions & NMI_SHOW_REGS) -+ show_regs(args->regs); -+ if (nmi_actions & NMI_DEBOUNCE) -+ mdelay(10); -+ if (nmi_actions & NMI_DIE) -+ return NOTIFY_BAD; -+ -+ return NOTIFY_OK; -+} -+ -+static struct notifier_block nmi_debug_nb = { -+ .notifier_call = nmi_debug_notify, -+}; -+ -+static int __init nmi_debug_setup(char *str) -+{ -+ char *p, *sep; -+ -+ register_die_notifier(&nmi_debug_nb); -+ if (nmi_enable()) { -+ printk(KERN_WARNING "Unable to enable NMI.\n"); -+ return 0; -+ } -+ -+ if (*str != '=') -+ return 0; -+ -+ for (p = str + 1; *p; p = sep + 1) { -+ sep = strchr(p, ','); -+ if (sep) -+ *sep = 0; -+ if (strcmp(p, "state") == 0) -+ nmi_actions |= NMI_SHOW_STATE; -+ else if (strcmp(p, "regs") == 0) -+ nmi_actions |= NMI_SHOW_REGS; -+ else if (strcmp(p, "debounce") == 0) -+ nmi_actions |= NMI_DEBOUNCE; -+ else if (strcmp(p, "die") == 0) -+ nmi_actions |= NMI_DIE; -+ else -+ printk(KERN_WARNING "NMI: Unrecognized action `%s'\n", -+ p); -+ if (!sep) -+ break; -+ } -+ -+ return 0; -+} -+__setup("nmi_debug", nmi_debug_setup); ---- /dev/null -+++ b/arch/avr32/kernel/ocd.c -@@ -0,0 +1,163 @@ -+/* -+ * Copyright (C) 2007 Atmel Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#include <linux/init.h> -+#include <linux/sched.h> -+#include <linux/spinlock.h> -+ -+#include <asm/ocd.h> -+ -+static long ocd_count; -+static spinlock_t ocd_lock; -+ -+/** -+ * ocd_enable - enable on-chip debugging -+ * @child: task to be debugged -+ * -+ * If @child is non-NULL, ocd_enable() first checks if debugging has -+ * already been enabled for @child, and if it has, does nothing. -+ * -+ * If @child is NULL (e.g. when debugging the kernel), or debugging -+ * has not already been enabled for it, ocd_enable() increments the -+ * reference count and enables the debugging hardware. -+ */ -+void ocd_enable(struct task_struct *child) -+{ -+ u32 dc; -+ -+ if (child) -+ pr_debug("ocd_enable: child=%s [%u]\n", -+ child->comm, child->pid); -+ else -+ pr_debug("ocd_enable (no child)\n"); -+ -+ if (!child || !test_and_set_tsk_thread_flag(child, TIF_DEBUG)) { -+ spin_lock(&ocd_lock); -+ ocd_count++; -+ dc = ocd_read(DC); -+ dc |= (1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT); -+ ocd_write(DC, dc); -+ spin_unlock(&ocd_lock); -+ } -+} -+ -+/** -+ * ocd_disable - disable on-chip debugging -+ * @child: task that was being debugged, but isn't anymore -+ * -+ * If @child is non-NULL, ocd_disable() checks if debugging is enabled -+ * for @child, and if it isn't, does nothing. -+ * -+ * If @child is NULL (e.g. when debugging the kernel), or debugging is -+ * enabled, ocd_disable() decrements the reference count, and if it -+ * reaches zero, disables the debugging hardware. -+ */ -+void ocd_disable(struct task_struct *child) -+{ -+ u32 dc; -+ -+ if (!child) -+ pr_debug("ocd_disable (no child)\n"); -+ else if (test_tsk_thread_flag(child, TIF_DEBUG)) -+ pr_debug("ocd_disable: child=%s [%u]\n", -+ child->comm, child->pid); -+ -+ if (!child || test_and_clear_tsk_thread_flag(child, TIF_DEBUG)) { -+ spin_lock(&ocd_lock); -+ ocd_count--; -+ -+ WARN_ON(ocd_count < 0); -+ -+ if (ocd_count <= 0) { -+ dc = ocd_read(DC); -+ dc &= ~((1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT)); -+ ocd_write(DC, dc); -+ } -+ spin_unlock(&ocd_lock); -+ } -+} -+ -+#ifdef CONFIG_DEBUG_FS -+#include <linux/debugfs.h> -+#include <linux/module.h> -+ -+static struct dentry *ocd_debugfs_root; -+static struct dentry *ocd_debugfs_DC; -+static struct dentry *ocd_debugfs_DS; -+static struct dentry *ocd_debugfs_count; -+ -+static u64 ocd_DC_get(void *data) -+{ -+ return ocd_read(DC); -+} -+static void ocd_DC_set(void *data, u64 val) -+{ -+ ocd_write(DC, val); -+} -+DEFINE_SIMPLE_ATTRIBUTE(fops_DC, ocd_DC_get, ocd_DC_set, "0x%08llx\n"); -+ -+static u64 ocd_DS_get(void *data) -+{ -+ return ocd_read(DS); -+} -+DEFINE_SIMPLE_ATTRIBUTE(fops_DS, ocd_DS_get, NULL, "0x%08llx\n"); -+ -+static u64 ocd_count_get(void *data) -+{ -+ return ocd_count; -+} -+DEFINE_SIMPLE_ATTRIBUTE(fops_count, ocd_count_get, NULL, "%lld\n"); -+ -+static void ocd_debugfs_init(void) -+{ -+ struct dentry *root; -+ -+ root = debugfs_create_dir("ocd", NULL); -+ if (IS_ERR(root) || !root) -+ goto err_root; -+ ocd_debugfs_root = root; -+ -+ ocd_debugfs_DC = debugfs_create_file("DC", S_IRUSR | S_IWUSR, -+ root, NULL, &fops_DC); -+ if (!ocd_debugfs_DC) -+ goto err_DC; -+ -+ ocd_debugfs_DS = debugfs_create_file("DS", S_IRUSR, root, -+ NULL, &fops_DS); -+ if (!ocd_debugfs_DS) -+ goto err_DS; -+ -+ ocd_debugfs_count = debugfs_create_file("count", S_IRUSR, root, -+ NULL, &fops_count); -+ if (!ocd_debugfs_count) -+ goto err_count; -+ -+ return; -+ -+err_count: -+ debugfs_remove(ocd_debugfs_DS); -+err_DS: -+ debugfs_remove(ocd_debugfs_DC); -+err_DC: -+ debugfs_remove(ocd_debugfs_root); -+err_root: -+ printk(KERN_WARNING "OCD: Failed to create debugfs entries\n"); -+} -+#else -+static inline void ocd_debugfs_init(void) -+{ -+ -+} -+#endif -+ -+static int __init ocd_init(void) -+{ -+ spin_lock_init(&ocd_lock); -+ ocd_debugfs_init(); -+ return 0; -+} -+arch_initcall(ocd_init); ---- a/arch/avr32/kernel/process.c -+++ b/arch/avr32/kernel/process.c -@@ -11,17 +11,18 @@ - #include <linux/fs.h> - #include <linux/ptrace.h> - #include <linux/reboot.h> -+#include <linux/tick.h> - #include <linux/uaccess.h> - #include <linux/unistd.h> - +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/kernel/process.c avr32-2.6/arch/avr32/kernel/process.c +--- linux-2.6.25.6/arch/avr32/kernel/process.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/kernel/process.c 2008-06-12 15:03:55.887814682 +0200 +@@ -18,11 +18,11 @@ #include <asm/sysreg.h> #include <asm/ocd.h> @@ -6195,61 +4967,19 @@ /* * This file handles the architecture-dependent parts of process handling.. */ -@@ -30,8 +31,10 @@ - { - /* endless idle loop with no priority at all */ - while (1) { -+ tick_nohz_stop_sched_tick(); - while (!need_resched()) - cpu_idle_sleep(); -+ tick_nohz_restart_sched_tick(); - preempt_enable_no_resched(); - schedule(); - preempt_disable(); -@@ -103,7 +106,7 @@ - */ - void exit_thread(void) - { -- /* nothing to do */ -+ ocd_disable(current); - } - - void flush_thread(void) -@@ -345,6 +348,10 @@ - p->thread.cpu_context.ksp = (unsigned long)childregs; - p->thread.cpu_context.pc = (unsigned long)ret_from_fork; - -+ clear_tsk_thread_flag(p, TIF_DEBUG); -+ if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG)) -+ ocd_enable(p); -+ - return 0; - } +@@ -54,6 +54,8 @@ ---- a/arch/avr32/kernel/ptrace.c -+++ b/arch/avr32/kernel/ptrace.c -@@ -58,6 +58,7 @@ + void machine_power_off(void) { - clear_tsk_thread_flag(child, TIF_SINGLE_STEP); - clear_tsk_thread_flag(child, TIF_BREAKPOINT); -+ ocd_disable(child); ++ if (pm_power_off) ++ pm_power_off(); } - /* -@@ -144,10 +145,6 @@ - { - int ret; - -- pr_debug("ptrace: Enabling monitor mode...\n"); -- ocd_write(DC, ocd_read(DC) | (1 << OCD_DC_MM_BIT) -- | (1 << OCD_DC_DBE_BIT)); -- - switch (request) { - /* Read the word at location addr in the child process */ - case PTRACE_PEEKTEXT: ---- a/arch/avr32/kernel/setup.c -+++ b/arch/avr32/kernel/setup.c -@@ -273,6 +273,8 @@ + void machine_restart(char *cmd) +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/kernel/setup.c avr32-2.6/arch/avr32/kernel/setup.c +--- linux-2.6.25.6/arch/avr32/kernel/setup.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/kernel/setup.c 2008-06-12 15:03:55.887814682 +0200 +@@ -274,6 +274,8 @@ printk(KERN_WARNING "Failed to allocate framebuffer memory\n"); fbmem_size = 0; @@ -6258,30 +4988,22 @@ } } ---- a/arch/avr32/kernel/signal.c -+++ b/arch/avr32/kernel/signal.c -@@ -270,19 +270,12 @@ - if (!user_mode(regs)) - return 0; +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/kernel/signal.c avr32-2.6/arch/avr32/kernel/signal.c +--- linux-2.6.25.6/arch/avr32/kernel/signal.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/kernel/signal.c 2008-06-12 15:09:38.719815350 +0200 +@@ -93,6 +93,9 @@ + if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) + goto badframe; -- if (try_to_freeze()) { -- signr = 0; -- if (!signal_pending(current)) -- goto no_signal; -- } -- - if (test_thread_flag(TIF_RESTORE_SIGMASK)) - oldset = ¤t->saved_sigmask; - else if (!oldset) - oldset = ¤t->blocked; - - signr = get_signal_to_deliver(&info, &ka, regs, NULL); --no_signal: - if (syscall) { - switch (regs->r12) { - case -ERESTART_RESTARTBLOCK: ---- a/arch/avr32/kernel/time.c -+++ b/arch/avr32/kernel/time.c ++ if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT) ++ goto badframe; ++ + pr_debug("Context restored: pc = %08lx, lr = %08lx, sp = %08lx\n", + regs->pc, regs->lr, regs->sp); + +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/kernel/time.c avr32-2.6/arch/avr32/kernel/time.c +--- linux-2.6.25.6/arch/avr32/kernel/time.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/kernel/time.c 2008-06-12 15:03:55.887814682 +0200 @@ -1,16 +1,12 @@ /* * Copyright (C) 2004-2007 Atmel Corporation @@ -6564,7 +5286,7 @@ + comparator.min_delta_ns = clockevent_delta2ns(50, &comparator) + 1; -static struct sysdev_class timer_class = { -- set_kset_name("timer"), +- .name = "timer", -}; + sysreg_write(COMPARE, 0); + timer_irqaction.dev_id = &comparator; @@ -6592,2400 +5314,286 @@ } - -device_initcall(init_timer_sysfs); ---- a/arch/avr32/kernel/traps.c -+++ b/arch/avr32/kernel/traps.c -@@ -9,6 +9,7 @@ - #include <linux/bug.h> +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/lib/io-readsb.S avr32-2.6/arch/avr32/lib/io-readsb.S +--- linux-2.6.25.6/arch/avr32/lib/io-readsb.S 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/lib/io-readsb.S 2008-06-12 15:09:38.719815350 +0200 +@@ -41,7 +41,7 @@ + 2: sub r10, -4 + reteq r12 + +-3: ld.uh r8, r12[0] ++3: ld.ub r8, r12[0] + sub r10, 1 + st.b r11++, r8 + brne 3b +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/at32ap700x.c avr32-2.6/arch/avr32/mach-at32ap/at32ap700x.c +--- linux-2.6.25.6/arch/avr32/mach-at32ap/at32ap700x.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/mach-at32ap/at32ap700x.c 2008-06-12 15:09:38.723815860 +0200 +@@ -6,11 +6,13 @@ + * published by the Free Software Foundation. + */ + #include <linux/clk.h> ++#include <linux/delay.h> + #include <linux/fb.h> #include <linux/init.h> - #include <linux/kallsyms.h> -+#include <linux/kdebug.h> - #include <linux/module.h> - #include <linux/notifier.h> - #include <linux/sched.h> -@@ -107,9 +108,23 @@ + #include <linux/platform_device.h> + #include <linux/dma-mapping.h> + #include <linux/spi/spi.h> ++#include <linux/usb/atmel_usba_udc.h> - asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs) - { -- printk(KERN_ALERT "Got Non-Maskable Interrupt, dumping regs\n"); -- show_regs_log_lvl(regs, KERN_ALERT); -- show_stack_log_lvl(current, regs->sp, regs, KERN_ALERT); -+ int ret; -+ -+ nmi_enter(); -+ -+ ret = notify_die(DIE_NMI, "NMI", regs, 0, ecr, SIGINT); -+ switch (ret) { -+ case NOTIFY_OK: -+ case NOTIFY_STOP: -+ return; -+ case NOTIFY_BAD: -+ die("Fatal Non-Maskable Interrupt", regs, SIGINT); -+ default: -+ break; -+ } -+ -+ printk(KERN_ALERT "Got NMI, but nobody cared. Disabling...\n"); -+ nmi_disable(); - } + #include <asm/io.h> + #include <asm/irq.h> +@@ -18,6 +20,7 @@ + #include <asm/arch/at32ap700x.h> + #include <asm/arch/board.h> + #include <asm/arch/portmux.h> ++#include <asm/arch/sram.h> + + #include <video/atmel_lcdc.h> + +@@ -91,25 +94,18 @@ + + static DEFINE_SPINLOCK(pm_lock); - asmlinkage void do_critical_exception(unsigned long ecr, struct pt_regs *regs) ---- a/arch/avr32/mach-at32ap/at32ap7000.c -+++ /dev/null -@@ -1,1730 +0,0 @@ --/* -- * Copyright (C) 2005-2006 Atmel Corporation -- * -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License version 2 as -- * published by the Free Software Foundation. -- */ --#include <linux/clk.h> --#include <linux/fb.h> --#include <linux/init.h> --#include <linux/platform_device.h> --#include <linux/dma-mapping.h> --#include <linux/spi/spi.h> -- --#include <asm/io.h> -- --#include <asm/arch/at32ap7000.h> --#include <asm/arch/board.h> --#include <asm/arch/portmux.h> -- --#include <video/atmel_lcdc.h> -- --#include "clock.h" --#include "hmatrix.h" --#include "pio.h" --#include "pm.h" -- -- --#define PBMEM(base) \ -- { \ -- .start = base, \ -- .end = base + 0x3ff, \ -- .flags = IORESOURCE_MEM, \ -- } --#define IRQ(num) \ -- { \ -- .start = num, \ -- .end = num, \ -- .flags = IORESOURCE_IRQ, \ -- } --#define NAMED_IRQ(num, _name) \ -- { \ -- .start = num, \ -- .end = num, \ -- .name = _name, \ -- .flags = IORESOURCE_IRQ, \ -- } -- --/* REVISIT these assume *every* device supports DMA, but several -- * don't ... tc, smc, pio, rtc, watchdog, pwm, ps2, and more. -- */ --#define DEFINE_DEV(_name, _id) \ --static u64 _name##_id##_dma_mask = DMA_32BIT_MASK; \ --static struct platform_device _name##_id##_device = { \ -- .name = #_name, \ -- .id = _id, \ -- .dev = { \ -- .dma_mask = &_name##_id##_dma_mask, \ -- .coherent_dma_mask = DMA_32BIT_MASK, \ -- }, \ -- .resource = _name##_id##_resource, \ -- .num_resources = ARRAY_SIZE(_name##_id##_resource), \ --} --#define DEFINE_DEV_DATA(_name, _id) \ --static u64 _name##_id##_dma_mask = DMA_32BIT_MASK; \ --static struct platform_device _name##_id##_device = { \ -- .name = #_name, \ -- .id = _id, \ -- .dev = { \ -- .dma_mask = &_name##_id##_dma_mask, \ -- .platform_data = &_name##_id##_data, \ -- .coherent_dma_mask = DMA_32BIT_MASK, \ -- }, \ -- .resource = _name##_id##_resource, \ -- .num_resources = ARRAY_SIZE(_name##_id##_resource), \ --} -- --#define select_peripheral(pin, periph, flags) \ -- at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags) -- --#define DEV_CLK(_name, devname, bus, _index) \ --static struct clk devname##_##_name = { \ -- .name = #_name, \ -- .dev = &devname##_device.dev, \ -- .parent = &bus##_clk, \ -- .mode = bus##_clk_mode, \ -- .get_rate = bus##_clk_get_rate, \ -- .index = _index, \ --} -- --static DEFINE_SPINLOCK(pm_lock); -- -unsigned long at32ap7000_osc_rates[3] = { - [0] = 32768, - /* FIXME: these are ATSTK1002-specific */ - [1] = 20000000, - [2] = 12000000, -}; -- --static unsigned long osc_get_rate(struct clk *clk) --{ ++static struct clk osc0; ++static struct clk osc1; + + static unsigned long osc_get_rate(struct clk *clk) + { - return at32ap7000_osc_rates[clk->index]; --} -- --static unsigned long pll_get_rate(struct clk *clk, unsigned long control) --{ -- unsigned long div, mul, rate; -- ++ return at32_board_osc_rates[clk->index]; + } + + static unsigned long pll_get_rate(struct clk *clk, unsigned long control) + { + unsigned long div, mul, rate; + - if (!(control & PM_BIT(PLLEN))) - return 0; - -- div = PM_BFEXT(PLLDIV, control) + 1; -- mul = PM_BFEXT(PLLMUL, control) + 1; -- -- rate = clk->parent->get_rate(clk->parent); -- rate = (rate + div / 2) / div; -- rate *= mul; -- -- return rate; --} -- --static unsigned long pll0_get_rate(struct clk *clk) --{ -- u32 control; -- -- control = pm_readl(PLL0); -- -- return pll_get_rate(clk, control); --} -- --static unsigned long pll1_get_rate(struct clk *clk) --{ -- u32 control; -- -- control = pm_readl(PLL1); -- -- return pll_get_rate(clk, control); --} -- --/* -- * The AT32AP7000 has five primary clock sources: One 32kHz -- * oscillator, two crystal oscillators and two PLLs. -- */ --static struct clk osc32k = { -- .name = "osc32k", -- .get_rate = osc_get_rate, -- .users = 1, -- .index = 0, --}; --static struct clk osc0 = { -- .name = "osc0", -- .get_rate = osc_get_rate, -- .users = 1, -- .index = 1, --}; --static struct clk osc1 = { -- .name = "osc1", -- .get_rate = osc_get_rate, -- .index = 2, --}; --static struct clk pll0 = { -- .name = "pll0", -- .get_rate = pll0_get_rate, -- .parent = &osc0, --}; --static struct clk pll1 = { -- .name = "pll1", -- .get_rate = pll1_get_rate, -- .parent = &osc0, --}; -- --/* -- * The main clock can be either osc0 or pll0. The boot loader may -- * have chosen one for us, so we don't really know which one until we -- * have a look at the SM. -- */ --static struct clk *main_clock; -- --/* -- * Synchronous clocks are generated from the main clock. The clocks -- * must satisfy the constraint -- * fCPU >= fHSB >= fPB -- * i.e. each clock must not be faster than its parent. -- */ --static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift) --{ -- return main_clock->get_rate(main_clock) >> shift; --}; -- --static void cpu_clk_mode(struct clk *clk, int enabled) --{ -- unsigned long flags; -- u32 mask; -- -- spin_lock_irqsave(&pm_lock, flags); -- mask = pm_readl(CPU_MASK); -- if (enabled) -- mask |= 1 << clk->index; -- else -- mask &= ~(1 << clk->index); -- pm_writel(CPU_MASK, mask); -- spin_unlock_irqrestore(&pm_lock, flags); --} -- --static unsigned long cpu_clk_get_rate(struct clk *clk) --{ -- unsigned long cksel, shift = 0; -- -- cksel = pm_readl(CKSEL); -- if (cksel & PM_BIT(CPUDIV)) -- shift = PM_BFEXT(CPUSEL, cksel) + 1; -- -- return bus_clk_get_rate(clk, shift); --} -- --static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply) --{ -- u32 control; -- unsigned long parent_rate, child_div, actual_rate, div; -- -- parent_rate = clk->parent->get_rate(clk->parent); -- control = pm_readl(CKSEL); -- -- if (control & PM_BIT(HSBDIV)) -- child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1); -- else -- child_div = 1; -- -- if (rate > 3 * (parent_rate / 4) || child_div == 1) { -- actual_rate = parent_rate; -- control &= ~PM_BIT(CPUDIV); -- } else { -- unsigned int cpusel; -- div = (parent_rate + rate / 2) / rate; -- if (div > child_div) -- div = child_div; -- cpusel = (div > 1) ? (fls(div) - 2) : 0; -- control = PM_BIT(CPUDIV) | PM_BFINS(CPUSEL, cpusel, control); -- actual_rate = parent_rate / (1 << (cpusel + 1)); -- } -- -- pr_debug("clk %s: new rate %lu (actual rate %lu)\n", -- clk->name, rate, actual_rate); -- -- if (apply) -- pm_writel(CKSEL, control); -- -- return actual_rate; --} -- --static void hsb_clk_mode(struct clk *clk, int enabled) --{ -- unsigned long flags; -- u32 mask; -- -- spin_lock_irqsave(&pm_lock, flags); -- mask = pm_readl(HSB_MASK); -- if (enabled) -- mask |= 1 << clk->index; -- else -- mask &= ~(1 << clk->index); -- pm_writel(HSB_MASK, mask); -- spin_unlock_irqrestore(&pm_lock, flags); --} -- --static unsigned long hsb_clk_get_rate(struct clk *clk) --{ -- unsigned long cksel, shift = 0; -- -- cksel = pm_readl(CKSEL); -- if (cksel & PM_BIT(HSBDIV)) -- shift = PM_BFEXT(HSBSEL, cksel) + 1; -- -- return bus_clk_get_rate(clk, shift); --} -- --static void pba_clk_mode(struct clk *clk, int enabled) --{ -- unsigned long flags; -- u32 mask; -- -- spin_lock_irqsave(&pm_lock, flags); -- mask = pm_readl(PBA_MASK); -- if (enabled) -- mask |= 1 << clk->index; -- else -- mask &= ~(1 << clk->index); -- pm_writel(PBA_MASK, mask); -- spin_unlock_irqrestore(&pm_lock, flags); --} -- --static unsigned long pba_clk_get_rate(struct clk *clk) --{ -- unsigned long cksel, shift = 0; -- -- cksel = pm_readl(CKSEL); -- if (cksel & PM_BIT(PBADIV)) -- shift = PM_BFEXT(PBASEL, cksel) + 1; -- -- return bus_clk_get_rate(clk, shift); --} -- --static void pbb_clk_mode(struct clk *clk, int enabled) --{ -- unsigned long flags; -- u32 mask; -- -- spin_lock_irqsave(&pm_lock, flags); -- mask = pm_readl(PBB_MASK); -- if (enabled) -- mask |= 1 << clk->index; -- else -- mask &= ~(1 << clk->index); -- pm_writel(PBB_MASK, mask); -- spin_unlock_irqrestore(&pm_lock, flags); --} -- --static unsigned long pbb_clk_get_rate(struct clk *clk) --{ -- unsigned long cksel, shift = 0; -- -- cksel = pm_readl(CKSEL); -- if (cksel & PM_BIT(PBBDIV)) -- shift = PM_BFEXT(PBBSEL, cksel) + 1; -- -- return bus_clk_get_rate(clk, shift); --} -- --static struct clk cpu_clk = { -- .name = "cpu", -- .get_rate = cpu_clk_get_rate, -- .set_rate = cpu_clk_set_rate, -- .users = 1, --}; --static struct clk hsb_clk = { -- .name = "hsb", -- .parent = &cpu_clk, -- .get_rate = hsb_clk_get_rate, --}; --static struct clk pba_clk = { -- .name = "pba", -- .parent = &hsb_clk, -- .mode = hsb_clk_mode, -- .get_rate = pba_clk_get_rate, -- .index = 1, --}; --static struct clk pbb_clk = { -- .name = "pbb", -- .parent = &hsb_clk, -- .mode = hsb_clk_mode, -- .get_rate = pbb_clk_get_rate, -- .users = 1, -- .index = 2, --}; -- --/* -------------------------------------------------------------------- -- * Generic Clock operations -- * -------------------------------------------------------------------- */ -- --static void genclk_mode(struct clk *clk, int enabled) --{ -- u32 control; -- -- control = pm_readl(GCCTRL(clk->index)); -- if (enabled) -- control |= PM_BIT(CEN); -- else -- control &= ~PM_BIT(CEN); -- pm_writel(GCCTRL(clk->index), control); --} -- --static unsigned long genclk_get_rate(struct clk *clk) --{ -- u32 control; -- unsigned long div = 1; -- -- control = pm_readl(GCCTRL(clk->index)); -- if (control & PM_BIT(DIVEN)) -- div = 2 * (PM_BFEXT(DIV, control) + 1); -- -- return clk->parent->get_rate(clk->parent) / div; --} -- --static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply) --{ -- u32 control; -- unsigned long parent_rate, actual_rate, div; -- -- parent_rate = clk->parent->get_rate(clk->parent); -- control = pm_readl(GCCTRL(clk->index)); -- -- if (rate > 3 * parent_rate / 4) { -- actual_rate = parent_rate; -- control &= ~PM_BIT(DIVEN); -- } else { -- div = (parent_rate + rate) / (2 * rate) - 1; -- control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN); -- actual_rate = parent_rate / (2 * (div + 1)); -- } -- -- dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n", -- clk->name, rate, actual_rate); -- -- if (apply) -- pm_writel(GCCTRL(clk->index), control); -- -- return actual_rate; --} -- --int genclk_set_parent(struct clk *clk, struct clk *parent) --{ -- u32 control; -- -- dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n", -- clk->name, parent->name, clk->parent->name); -- -- control = pm_readl(GCCTRL(clk->index)); -- -- if (parent == &osc1 || parent == &pll1) -- control |= PM_BIT(OSCSEL); -- else if (parent == &osc0 || parent == &pll0) -- control &= ~PM_BIT(OSCSEL); -- else -- return -EINVAL; -- -- if (parent == &pll0 || parent == &pll1) -- control |= PM_BIT(PLLSEL); -- else -- control &= ~PM_BIT(PLLSEL); -- -- pm_writel(GCCTRL(clk->index), control); -- clk->parent = parent; -- -- return 0; --} -- --static void __init genclk_init_parent(struct clk *clk) --{ -- u32 control; -- struct clk *parent; -- -- BUG_ON(clk->index > 7); -- -- control = pm_readl(GCCTRL(clk->index)); -- if (control & PM_BIT(OSCSEL)) -- parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1; -- else -- parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0; -- -- clk->parent = parent; --} -- --/* -------------------------------------------------------------------- -- * System peripherals -- * -------------------------------------------------------------------- */ --static struct resource at32_pm0_resource[] = { -- { -- .start = 0xfff00000, -- .end = 0xfff0007f, -- .flags = IORESOURCE_MEM, -- }, -- IRQ(20), --}; -- --static struct resource at32ap700x_rtc0_resource[] = { -- { -- .start = 0xfff00080, -- .end = 0xfff000af, -- .flags = IORESOURCE_MEM, -- }, -- IRQ(21), --}; -- --static struct resource at32_wdt0_resource[] = { -- { -- .start = 0xfff000b0, -- .end = 0xfff000cf, -- .flags = IORESOURCE_MEM, -- }, --}; -- --static struct resource at32_eic0_resource[] = { -- { -- .start = 0xfff00100, -- .end = 0xfff0013f, -- .flags = IORESOURCE_MEM, -- }, -- IRQ(19), --}; -- --DEFINE_DEV(at32_pm, 0); --DEFINE_DEV(at32ap700x_rtc, 0); --DEFINE_DEV(at32_wdt, 0); --DEFINE_DEV(at32_eic, 0); -- --/* -- * Peripheral clock for PM, RTC, WDT and EIC. PM will ensure that this -- * is always running. -- */ --static struct clk at32_pm_pclk = { -- .name = "pclk", -- .dev = &at32_pm0_device.dev, -- .parent = &pbb_clk, -- .mode = pbb_clk_mode, -- .get_rate = pbb_clk_get_rate, -- .users = 1, -- .index = 0, --}; -- --static struct resource intc0_resource[] = { -- PBMEM(0xfff00400), --}; --struct platform_device at32_intc0_device = { -- .name = "intc", -- .id = 0, -- .resource = intc0_resource, -- .num_resources = ARRAY_SIZE(intc0_resource), --}; --DEV_CLK(pclk, at32_intc0, pbb, 1); -- --static struct clk ebi_clk = { -- .name = "ebi", -- .parent = &hsb_clk, -- .mode = hsb_clk_mode, -- .get_rate = hsb_clk_get_rate, -- .users = 1, --}; --static struct clk hramc_clk = { -- .name = "hramc", -- .parent = &hsb_clk, -- .mode = hsb_clk_mode, -- .get_rate = hsb_clk_get_rate, -- .users = 1, -- .index = 3, --}; -- --static struct resource smc0_resource[] = { -- PBMEM(0xfff03400), --}; --DEFINE_DEV(smc, 0); --DEV_CLK(pclk, smc0, pbb, 13); --DEV_CLK(mck, smc0, hsb, 0); -- --static struct platform_device pdc_device = { -- .name = "pdc", -- .id = 0, --}; --DEV_CLK(hclk, pdc, hsb, 4); --DEV_CLK(pclk, pdc, pba, 16); -- --static struct clk pico_clk = { -- .name = "pico", -- .parent = &cpu_clk, -- .mode = cpu_clk_mode, -- .get_rate = cpu_clk_get_rate, -- .users = 1, --}; -- --static struct resource dmaca0_resource[] = { -- { -- .start = 0xff200000, -- .end = 0xff20ffff, -- .flags = IORESOURCE_MEM, -- }, -- IRQ(2), --}; --DEFINE_DEV(dmaca, 0); --DEV_CLK(hclk, dmaca0, hsb, 10); -- --/* -------------------------------------------------------------------- -- * HMATRIX -- * -------------------------------------------------------------------- */ -- --static struct clk hmatrix_clk = { -- .name = "hmatrix_clk", -- .parent = &pbb_clk, -- .mode = pbb_clk_mode, -- .get_rate = pbb_clk_get_rate, -- .index = 2, -- .users = 1, --}; --#define HMATRIX_BASE ((void __iomem *)0xfff00800) -- --#define hmatrix_readl(reg) \ -- __raw_readl((HMATRIX_BASE) + HMATRIX_##reg) --#define hmatrix_writel(reg,value) \ -- __raw_writel((value), (HMATRIX_BASE) + HMATRIX_##reg) -- --/* -- * Set bits in the HMATRIX Special Function Register (SFR) used by the -- * External Bus Interface (EBI). This can be used to enable special -- * features like CompactFlash support, NAND Flash support, etc. on -- * certain chipselects. -- */ --static inline void set_ebi_sfr_bits(u32 mask) --{ -- u32 sfr; -- -- clk_enable(&hmatrix_clk); -- sfr = hmatrix_readl(SFR4); -- sfr |= mask; -- hmatrix_writel(SFR4, sfr); -- clk_disable(&hmatrix_clk); --} -- --/* -------------------------------------------------------------------- -- * System Timer/Counter (TC) -- * -------------------------------------------------------------------- */ --static struct resource at32_systc0_resource[] = { -- PBMEM(0xfff00c00), -- IRQ(22), --}; --struct platform_device at32_systc0_device = { -- .name = "systc", -- .id = 0, -- .resource = at32_systc0_resource, -- .num_resources = ARRAY_SIZE(at32_systc0_resource), --}; --DEV_CLK(pclk, at32_systc0, pbb, 3); -- --/* -------------------------------------------------------------------- -- * PIO -- * -------------------------------------------------------------------- */ -- --static struct resource pio0_resource[] = { -- PBMEM(0xffe02800), -- IRQ(13), --}; --DEFINE_DEV(pio, 0); --DEV_CLK(mck, pio0, pba, 10); -- --static struct resource pio1_resource[] = { -- PBMEM(0xffe02c00), -- IRQ(14), --}; --DEFINE_DEV(pio, 1); --DEV_CLK(mck, pio1, pba, 11); -- --static struct resource pio2_resource[] = { -- PBMEM(0xffe03000), -- IRQ(15), --}; --DEFINE_DEV(pio, 2); --DEV_CLK(mck, pio2, pba, 12); -- --static struct resource pio3_resource[] = { -- PBMEM(0xffe03400), -- IRQ(16), --}; --DEFINE_DEV(pio, 3); --DEV_CLK(mck, pio3, pba, 13); -- --static struct resource pio4_resource[] = { -- PBMEM(0xffe03800), -- IRQ(17), --}; --DEFINE_DEV(pio, 4); --DEV_CLK(mck, pio4, pba, 14); -- --void __init at32_add_system_devices(void) --{ -- platform_device_register(&at32_pm0_device); -- platform_device_register(&at32_intc0_device); -- platform_device_register(&at32ap700x_rtc0_device); -- platform_device_register(&at32_wdt0_device); -- platform_device_register(&at32_eic0_device); -- platform_device_register(&smc0_device); -- platform_device_register(&pdc_device); -- platform_device_register(&dmaca0_device); -- -- platform_device_register(&at32_systc0_device); -- -- platform_device_register(&pio0_device); -- platform_device_register(&pio1_device); -- platform_device_register(&pio2_device); -- platform_device_register(&pio3_device); -- platform_device_register(&pio4_device); --} -- --/* -------------------------------------------------------------------- -- * USART -- * -------------------------------------------------------------------- */ -- --static struct atmel_uart_data atmel_usart0_data = { -- .use_dma_tx = 1, -- .use_dma_rx = 1, --}; --static struct resource atmel_usart0_resource[] = { -- PBMEM(0xffe00c00), -- IRQ(6), --}; --DEFINE_DEV_DATA(atmel_usart, 0); --DEV_CLK(usart, atmel_usart0, pba, 3); -- --static struct atmel_uart_data atmel_usart1_data = { -- .use_dma_tx = 1, -- .use_dma_rx = 1, --}; --static struct resource atmel_usart1_resource[] = { -- PBMEM(0xffe01000), -- IRQ(7), --}; --DEFINE_DEV_DATA(atmel_usart, 1); --DEV_CLK(usart, atmel_usart1, pba, 4); -- --static struct atmel_uart_data atmel_usart2_data = { -- .use_dma_tx = 1, -- .use_dma_rx = 1, --}; --static struct resource atmel_usart2_resource[] = { -- PBMEM(0xffe01400), -- IRQ(8), --}; --DEFINE_DEV_DATA(atmel_usart, 2); --DEV_CLK(usart, atmel_usart2, pba, 5); -- --static struct atmel_uart_data atmel_usart3_data = { -- .use_dma_tx = 1, -- .use_dma_rx = 1, --}; --static struct resource atmel_usart3_resource[] = { -- PBMEM(0xffe01800), -- IRQ(9), --}; --DEFINE_DEV_DATA(atmel_usart, 3); --DEV_CLK(usart, atmel_usart3, pba, 6); -- --static inline void configure_usart0_pins(void) --{ -- select_peripheral(PA(8), PERIPH_B, 0); /* RXD */ -- select_peripheral(PA(9), PERIPH_B, 0); /* TXD */ --} -- --static inline void configure_usart1_pins(void) --{ -- select_peripheral(PA(17), PERIPH_A, 0); /* RXD */ -- select_peripheral(PA(18), PERIPH_A, 0); /* TXD */ --} -- --static inline void configure_usart2_pins(void) --{ -- select_peripheral(PB(26), PERIPH_B, 0); /* RXD */ -- select_peripheral(PB(27), PERIPH_B, 0); /* TXD */ --} -- --static inline void configure_usart3_pins(void) --{ -- select_peripheral(PB(18), PERIPH_B, 0); /* RXD */ -- select_peripheral(PB(17), PERIPH_B, 0); /* TXD */ --} -- --static struct platform_device *__initdata at32_usarts[4]; -- --void __init at32_map_usart(unsigned int hw_id, unsigned int line) --{ -- struct platform_device *pdev; -- -- switch (hw_id) { -- case 0: -- pdev = &atmel_usart0_device; -- configure_usart0_pins(); -- break; -- case 1: -- pdev = &atmel_usart1_device; -- configure_usart1_pins(); -- break; -- case 2: -- pdev = &atmel_usart2_device; -- configure_usart2_pins(); -- break; -- case 3: -- pdev = &atmel_usart3_device; -- configure_usart3_pins(); -- break; -- default: -- return; -- } -- -- if (PXSEG(pdev->resource[0].start) == P4SEG) { -- /* Addresses in the P4 segment are permanently mapped 1:1 */ -- struct atmel_uart_data *data = pdev->dev.platform_data; -- data->regs = (void __iomem *)pdev->resource[0].start; -- } -- -- pdev->id = line; -- at32_usarts[line] = pdev; --} -- --struct platform_device *__init at32_add_device_usart(unsigned int id) --{ -- platform_device_register(at32_usarts[id]); -- return at32_usarts[id]; --} -- --struct platform_device *atmel_default_console_device; -- --void __init at32_setup_serial_console(unsigned int usart_id) --{ -- atmel_default_console_device = at32_usarts[usart_id]; --} -- --/* -------------------------------------------------------------------- -- * Ethernet -- * -------------------------------------------------------------------- */ -- --static struct eth_platform_data macb0_data; --static struct resource macb0_resource[] = { -- PBMEM(0xfff01800), -- IRQ(25), --}; --DEFINE_DEV_DATA(macb, 0); --DEV_CLK(hclk, macb0, hsb, 8); --DEV_CLK(pclk, macb0, pbb, 6); -- --static struct eth_platform_data macb1_data; --static struct resource macb1_resource[] = { -- PBMEM(0xfff01c00), -- IRQ(26), --}; --DEFINE_DEV_DATA(macb, 1); --DEV_CLK(hclk, macb1, hsb, 9); --DEV_CLK(pclk, macb1, pbb, 7); -- --struct platform_device *__init --at32_add_device_eth(unsigned int id, struct eth_platform_data *data) --{ -- struct platform_device *pdev; -- -- switch (id) { -- case 0: -- pdev = &macb0_device; -- -- select_peripheral(PC(3), PERIPH_A, 0); /* TXD0 */ -- select_peripheral(PC(4), PERIPH_A, 0); /* TXD1 */ -- select_peripheral(PC(7), PERIPH_A, 0); /* TXEN */ -- select_peripheral(PC(8), PERIPH_A, 0); /* TXCK */ -- select_peripheral(PC(9), PERIPH_A, 0); /* RXD0 */ -- select_peripheral(PC(10), PERIPH_A, 0); /* RXD1 */ -- select_peripheral(PC(13), PERIPH_A, 0); /* RXER */ -- select_peripheral(PC(15), PERIPH_A, 0); /* RXDV */ -- select_peripheral(PC(16), PERIPH_A, 0); /* MDC */ -- select_peripheral(PC(17), PERIPH_A, 0); /* MDIO */ -- -- if (!data->is_rmii) { -- select_peripheral(PC(0), PERIPH_A, 0); /* COL */ -- select_peripheral(PC(1), PERIPH_A, 0); /* CRS */ -- select_peripheral(PC(2), PERIPH_A, 0); /* TXER */ -- select_peripheral(PC(5), PERIPH_A, 0); /* TXD2 */ -- select_peripheral(PC(6), PERIPH_A, 0); /* TXD3 */ -- select_peripheral(PC(11), PERIPH_A, 0); /* RXD2 */ -- select_peripheral(PC(12), PERIPH_A, 0); /* RXD3 */ -- select_peripheral(PC(14), PERIPH_A, 0); /* RXCK */ -- select_peripheral(PC(18), PERIPH_A, 0); /* SPD */ -- } -- break; -- -- case 1: -- pdev = &macb1_device; -- -- select_peripheral(PD(13), PERIPH_B, 0); /* TXD0 */ -- select_peripheral(PD(14), PERIPH_B, 0); /* TXD1 */ -- select_peripheral(PD(11), PERIPH_B, 0); /* TXEN */ -- select_peripheral(PD(12), PERIPH_B, 0); /* TXCK */ -- select_peripheral(PD(10), PERIPH_B, 0); /* RXD0 */ -- select_peripheral(PD(6), PERIPH_B, 0); /* RXD1 */ -- select_peripheral(PD(5), PERIPH_B, 0); /* RXER */ -- select_peripheral(PD(4), PERIPH_B, 0); /* RXDV */ -- select_peripheral(PD(3), PERIPH_B, 0); /* MDC */ -- select_peripheral(PD(2), PERIPH_B, 0); /* MDIO */ -- -- if (!data->is_rmii) { -- select_peripheral(PC(19), PERIPH_B, 0); /* COL */ -- select_peripheral(PC(23), PERIPH_B, 0); /* CRS */ -- select_peripheral(PC(26), PERIPH_B, 0); /* TXER */ -- select_peripheral(PC(27), PERIPH_B, 0); /* TXD2 */ -- select_peripheral(PC(28), PERIPH_B, 0); /* TXD3 */ -- select_peripheral(PC(29), PERIPH_B, 0); /* RXD2 */ -- select_peripheral(PC(30), PERIPH_B, 0); /* RXD3 */ -- select_peripheral(PC(24), PERIPH_B, 0); /* RXCK */ -- select_peripheral(PD(15), PERIPH_B, 0); /* SPD */ -- } -- break; -- -- default: -- return NULL; -- } -- -- memcpy(pdev->dev.platform_data, data, sizeof(struct eth_platform_data)); -- platform_device_register(pdev); -- -- return pdev; --} -- --/* -------------------------------------------------------------------- -- * SPI -- * -------------------------------------------------------------------- */ --static struct resource atmel_spi0_resource[] = { -- PBMEM(0xffe00000), -- IRQ(3), --}; --DEFINE_DEV(atmel_spi, 0); --DEV_CLK(spi_clk, atmel_spi0, pba, 0); -- --static struct resource atmel_spi1_resource[] = { -- PBMEM(0xffe00400), -- IRQ(4), --}; --DEFINE_DEV(atmel_spi, 1); --DEV_CLK(spi_clk, atmel_spi1, pba, 1); -- --static void __init --at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b, -- unsigned int n, const u8 *pins) --{ -- unsigned int pin, mode; -- -- for (; n; n--, b++) { -- b->bus_num = bus_num; -- if (b->chip_select >= 4) -- continue; -- pin = (unsigned)b->controller_data; -- if (!pin) { -- pin = pins[b->chip_select]; -- b->controller_data = (void *)pin; -- } -- mode = AT32_GPIOF_OUTPUT; -- if (!(b->mode & SPI_CS_HIGH)) -- mode |= AT32_GPIOF_HIGH; -- at32_select_gpio(pin, mode); -- } --} -- --struct platform_device *__init --at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n) --{ -- /* -- * Manage the chipselects as GPIOs, normally using the same pins -- * the SPI controller expects; but boards can use other pins. -- */ -- static u8 __initdata spi0_pins[] = -- { GPIO_PIN_PA(3), GPIO_PIN_PA(4), -- GPIO_PIN_PA(5), GPIO_PIN_PA(20), }; -- static u8 __initdata spi1_pins[] = -- { GPIO_PIN_PB(2), GPIO_PIN_PB(3), -- GPIO_PIN_PB(4), GPIO_PIN_PA(27), }; -- struct platform_device *pdev; -- -- switch (id) { -- case 0: -- pdev = &atmel_spi0_device; -- select_peripheral(PA(0), PERIPH_A, 0); /* MISO */ -- select_peripheral(PA(1), PERIPH_A, 0); /* MOSI */ -- select_peripheral(PA(2), PERIPH_A, 0); /* SCK */ -- at32_spi_setup_slaves(0, b, n, spi0_pins); -- break; -- -- case 1: -- pdev = &atmel_spi1_device; -- select_peripheral(PB(0), PERIPH_B, 0); /* MISO */ -- select_peripheral(PB(1), PERIPH_B, 0); /* MOSI */ -- select_peripheral(PB(5), PERIPH_B, 0); /* SCK */ -- at32_spi_setup_slaves(1, b, n, spi1_pins); -- break; -- -- default: -- return NULL; -- } -- -- spi_register_board_info(b, n); -- platform_device_register(pdev); -- return pdev; --} -- --/* -------------------------------------------------------------------- -- * TWI -- * -------------------------------------------------------------------- */ --static struct resource atmel_twi0_resource[] __initdata = { -- PBMEM(0xffe00800), -- IRQ(5), --}; --static struct clk atmel_twi0_pclk = { -- .name = "twi_pclk", -- .parent = &pba_clk, -- .mode = pba_clk_mode, -- .get_rate = pba_clk_get_rate, -- .index = 2, --}; -- --struct platform_device *__init at32_add_device_twi(unsigned int id) --{ -- struct platform_device *pdev; -- -- if (id != 0) -- return NULL; -- -- pdev = platform_device_alloc("atmel_twi", id); -- if (!pdev) -- return NULL; -- -- if (platform_device_add_resources(pdev, atmel_twi0_resource, -- ARRAY_SIZE(atmel_twi0_resource))) -- goto err_add_resources; -- -- select_peripheral(PA(6), PERIPH_A, 0); /* SDA */ -- select_peripheral(PA(7), PERIPH_A, 0); /* SDL */ -- -- atmel_twi0_pclk.dev = &pdev->dev; -- -- platform_device_add(pdev); -- return pdev; -- --err_add_resources: -- platform_device_put(pdev); -- return NULL; --} -- --/* -------------------------------------------------------------------- -- * MMC -- * -------------------------------------------------------------------- */ --static struct resource atmel_mci0_resource[] __initdata = { -- PBMEM(0xfff02400), -- IRQ(28), --}; --static struct clk atmel_mci0_pclk = { -- .name = "mci_clk", -- .parent = &pbb_clk, -- .mode = pbb_clk_mode, -- .get_rate = pbb_clk_get_rate, -- .index = 9, --}; -- --struct platform_device *__init at32_add_device_mci(unsigned int id) --{ -- struct platform_device *pdev; -- -- if (id != 0) -- return NULL; -- -- pdev = platform_device_alloc("atmel_mci", id); -- if (!pdev) -- return NULL; -- -- if (platform_device_add_resources(pdev, atmel_mci0_resource, -- ARRAY_SIZE(atmel_mci0_resource))) -- goto err_add_resources; -- -- select_peripheral(PA(10), PERIPH_A, 0); /* CLK */ -- select_peripheral(PA(11), PERIPH_A, 0); /* CMD */ -- select_peripheral(PA(12), PERIPH_A, 0); /* DATA0 */ -- select_peripheral(PA(13), PERIPH_A, 0); /* DATA1 */ -- select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */ -- select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */ -- -- atmel_mci0_pclk.dev = &pdev->dev; -- -- platform_device_add(pdev); -- return pdev; -- --err_add_resources: -- platform_device_put(pdev); -- return NULL; --} -- --/* -------------------------------------------------------------------- -- * LCDC -- * -------------------------------------------------------------------- */ --static struct atmel_lcdfb_info atmel_lcdfb0_data; --static struct resource atmel_lcdfb0_resource[] = { -- { -- .start = 0xff000000, -- .end = 0xff000fff, -- .flags = IORESOURCE_MEM, -- }, -- IRQ(1), -- { -- /* Placeholder for pre-allocated fb memory */ -- .start = 0x00000000, -- .end = 0x00000000, -- .flags = 0, -- }, --}; --DEFINE_DEV_DATA(atmel_lcdfb, 0); --DEV_CLK(hck1, atmel_lcdfb0, hsb, 7); --static struct clk atmel_lcdfb0_pixclk = { -- .name = "lcdc_clk", -- .dev = &atmel_lcdfb0_device.dev, -- .mode = genclk_mode, -- .get_rate = genclk_get_rate, -- .set_rate = genclk_set_rate, -- .set_parent = genclk_set_parent, -- .index = 7, --}; -- --struct platform_device *__init --at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data, -- unsigned long fbmem_start, unsigned long fbmem_len) --{ -- struct platform_device *pdev; -- struct atmel_lcdfb_info *info; -- struct fb_monspecs *monspecs; -- struct fb_videomode *modedb; -- unsigned int modedb_size; -- -- /* -- * Do a deep copy of the fb data, monspecs and modedb. Make -- * sure all allocations are done before setting up the -- * portmux. -- */ -- monspecs = kmemdup(data->default_monspecs, -- sizeof(struct fb_monspecs), GFP_KERNEL); -- if (!monspecs) -- return NULL; -- -- modedb_size = sizeof(struct fb_videomode) * monspecs->modedb_len; -- modedb = kmemdup(monspecs->modedb, modedb_size, GFP_KERNEL); -- if (!modedb) -- goto err_dup_modedb; -- monspecs->modedb = modedb; -- -- switch (id) { -- case 0: -- pdev = &atmel_lcdfb0_device; -- select_peripheral(PC(19), PERIPH_A, 0); /* CC */ -- select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC */ -- select_peripheral(PC(21), PERIPH_A, 0); /* PCLK */ -- select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC */ -- select_peripheral(PC(23), PERIPH_A, 0); /* DVAL */ -- select_peripheral(PC(24), PERIPH_A, 0); /* MODE */ -- select_peripheral(PC(25), PERIPH_A, 0); /* PWR */ -- select_peripheral(PC(26), PERIPH_A, 0); /* DATA0 */ -- select_peripheral(PC(27), PERIPH_A, 0); /* DATA1 */ -- select_peripheral(PC(28), PERIPH_A, 0); /* DATA2 */ -- select_peripheral(PC(29), PERIPH_A, 0); /* DATA3 */ -- select_peripheral(PC(30), PERIPH_A, 0); /* DATA4 */ -- select_peripheral(PC(31), PERIPH_A, 0); /* DATA5 */ -- select_peripheral(PD(0), PERIPH_A, 0); /* DATA6 */ -- select_peripheral(PD(1), PERIPH_A, 0); /* DATA7 */ -- select_peripheral(PD(2), PERIPH_A, 0); /* DATA8 */ -- select_peripheral(PD(3), PERIPH_A, 0); /* DATA9 */ -- select_peripheral(PD(4), PERIPH_A, 0); /* DATA10 */ -- select_peripheral(PD(5), PERIPH_A, 0); /* DATA11 */ -- select_peripheral(PD(6), PERIPH_A, 0); /* DATA12 */ -- select_peripheral(PD(7), PERIPH_A, 0); /* DATA13 */ -- select_peripheral(PD(8), PERIPH_A, 0); /* DATA14 */ -- select_peripheral(PD(9), PERIPH_A, 0); /* DATA15 */ -- select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */ -- select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */ -- select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */ -- select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */ -- select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */ -- select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */ -- select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */ -- select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */ -- -- clk_set_parent(&atmel_lcdfb0_pixclk, &pll0); -- clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0)); -- break; -- -- default: -- goto err_invalid_id; -- } -- -- if (fbmem_len) { -- pdev->resource[2].start = fbmem_start; -- pdev->resource[2].end = fbmem_start + fbmem_len - 1; -- pdev->resource[2].flags = IORESOURCE_MEM; -- } -- -- info = pdev->dev.platform_data; -- memcpy(info, data, sizeof(struct atmel_lcdfb_info)); -- info->default_monspecs = monspecs; -- -- platform_device_register(pdev); -- return pdev; -- --err_invalid_id: -- kfree(modedb); --err_dup_modedb: -- kfree(monspecs); -- return NULL; --} -- --/* -------------------------------------------------------------------- -- * SSC -- * -------------------------------------------------------------------- */ --static struct resource ssc0_resource[] = { -- PBMEM(0xffe01c00), -- IRQ(10), --}; --DEFINE_DEV(ssc, 0); --DEV_CLK(pclk, ssc0, pba, 7); -- --static struct resource ssc1_resource[] = { -- PBMEM(0xffe02000), -- IRQ(11), --}; --DEFINE_DEV(ssc, 1); --DEV_CLK(pclk, ssc1, pba, 8); -- --static struct resource ssc2_resource[] = { -- PBMEM(0xffe02400), -- IRQ(12), --}; --DEFINE_DEV(ssc, 2); --DEV_CLK(pclk, ssc2, pba, 9); -- --struct platform_device *__init --at32_add_device_ssc(unsigned int id, unsigned int flags) --{ -- struct platform_device *pdev; -- -- switch (id) { -- case 0: -- pdev = &ssc0_device; -- if (flags & ATMEL_SSC_RF) -- select_peripheral(PA(21), PERIPH_A, 0); /* RF */ -- if (flags & ATMEL_SSC_RK) -- select_peripheral(PA(22), PERIPH_A, 0); /* RK */ -- if (flags & ATMEL_SSC_TK) -- select_peripheral(PA(23), PERIPH_A, 0); /* TK */ -- if (flags & ATMEL_SSC_TF) -- select_peripheral(PA(24), PERIPH_A, 0); /* TF */ -- if (flags & ATMEL_SSC_TD) -- select_peripheral(PA(25), PERIPH_A, 0); /* TD */ -- if (flags & ATMEL_SSC_RD) -- select_peripheral(PA(26), PERIPH_A, 0); /* RD */ -- break; -- case 1: -- pdev = &ssc1_device; -- if (flags & ATMEL_SSC_RF) -- select_peripheral(PA(0), PERIPH_B, 0); /* RF */ -- if (flags & ATMEL_SSC_RK) -- select_peripheral(PA(1), PERIPH_B, 0); /* RK */ -- if (flags & ATMEL_SSC_TK) -- select_peripheral(PA(2), PERIPH_B, 0); /* TK */ -- if (flags & ATMEL_SSC_TF) -- select_peripheral(PA(3), PERIPH_B, 0); /* TF */ -- if (flags & ATMEL_SSC_TD) -- select_peripheral(PA(4), PERIPH_B, 0); /* TD */ -- if (flags & ATMEL_SSC_RD) -- select_peripheral(PA(5), PERIPH_B, 0); /* RD */ -- break; -- case 2: -- pdev = &ssc2_device; -- if (flags & ATMEL_SSC_TD) -- select_peripheral(PB(13), PERIPH_A, 0); /* TD */ -- if (flags & ATMEL_SSC_RD) -- select_peripheral(PB(14), PERIPH_A, 0); /* RD */ -- if (flags & ATMEL_SSC_TK) -- select_peripheral(PB(15), PERIPH_A, 0); /* TK */ -- if (flags & ATMEL_SSC_TF) -- select_peripheral(PB(16), PERIPH_A, 0); /* TF */ -- if (flags & ATMEL_SSC_RF) -- select_peripheral(PB(17), PERIPH_A, 0); /* RF */ -- if (flags & ATMEL_SSC_RK) -- select_peripheral(PB(18), PERIPH_A, 0); /* RK */ -- break; -- default: -- return NULL; -- } -- -- platform_device_register(pdev); -- return pdev; --} -- --/* -------------------------------------------------------------------- -- * USB Device Controller -- * -------------------------------------------------------------------- */ --static struct resource usba0_resource[] __initdata = { -- { -- .start = 0xff300000, -- .end = 0xff3fffff, -- .flags = IORESOURCE_MEM, -- }, { -- .start = 0xfff03000, -- .end = 0xfff033ff, -- .flags = IORESOURCE_MEM, -- }, -- IRQ(31), --}; --static struct clk usba0_pclk = { -- .name = "pclk", -- .parent = &pbb_clk, -- .mode = pbb_clk_mode, -- .get_rate = pbb_clk_get_rate, -- .index = 12, --}; --static struct clk usba0_hclk = { -- .name = "hclk", -- .parent = &hsb_clk, -- .mode = hsb_clk_mode, -- .get_rate = hsb_clk_get_rate, -- .index = 6, --}; -- --struct platform_device *__init --at32_add_device_usba(unsigned int id, struct usba_platform_data *data) --{ -- struct platform_device *pdev; -- -- if (id != 0) -- return NULL; -- -- pdev = platform_device_alloc("atmel_usba_udc", 0); -- if (!pdev) -- return NULL; -- -- if (platform_device_add_resources(pdev, usba0_resource, -- ARRAY_SIZE(usba0_resource))) -- goto out_free_pdev; -- -- if (data) { -- if (platform_device_add_data(pdev, data, sizeof(*data))) -- goto out_free_pdev; -- -- if (data->vbus_pin != GPIO_PIN_NONE) -- at32_select_gpio(data->vbus_pin, 0); -- } -- -- usba0_pclk.dev = &pdev->dev; -- usba0_hclk.dev = &pdev->dev; -- -- platform_device_add(pdev); -- -- return pdev; -- --out_free_pdev: -- platform_device_put(pdev); -- return NULL; --} -- --/* -------------------------------------------------------------------- -- * IDE / CompactFlash -- * -------------------------------------------------------------------- */ --static struct resource at32_smc_cs4_resource[] __initdata = { -- { -- .start = 0x04000000, -- .end = 0x07ffffff, -- .flags = IORESOURCE_MEM, -- }, -- IRQ(~0UL), /* Magic IRQ will be overridden */ --}; --static struct resource at32_smc_cs5_resource[] __initdata = { -- { -- .start = 0x20000000, -- .end = 0x23ffffff, -- .flags = IORESOURCE_MEM, -- }, -- IRQ(~0UL), /* Magic IRQ will be overridden */ --}; -- --static int __init at32_init_ide_or_cf(struct platform_device *pdev, -- unsigned int cs, unsigned int extint) --{ -- static unsigned int extint_pin_map[4] __initdata = { -- GPIO_PIN_PB(25), -- GPIO_PIN_PB(26), -- GPIO_PIN_PB(27), -- GPIO_PIN_PB(28), -- }; -- static bool common_pins_initialized __initdata = false; -- unsigned int extint_pin; -- int ret; -- -- if (extint >= ARRAY_SIZE(extint_pin_map)) -- return -EINVAL; -- extint_pin = extint_pin_map[extint]; -- -- switch (cs) { -- case 4: -- ret = platform_device_add_resources(pdev, -- at32_smc_cs4_resource, -- ARRAY_SIZE(at32_smc_cs4_resource)); -- if (ret) -- return ret; -- -- select_peripheral(PE(21), PERIPH_A, 0); /* NCS4 -> OE_N */ -- set_ebi_sfr_bits(HMATRIX_BIT(CS4A)); -- break; -- case 5: -- ret = platform_device_add_resources(pdev, -- at32_smc_cs5_resource, -- ARRAY_SIZE(at32_smc_cs5_resource)); -- if (ret) -- return ret; -- -- select_peripheral(PE(22), PERIPH_A, 0); /* NCS5 -> OE_N */ -- set_ebi_sfr_bits(HMATRIX_BIT(CS5A)); -- break; -- default: -- return -EINVAL; -- } -- -- if (!common_pins_initialized) { -- select_peripheral(PE(19), PERIPH_A, 0); /* CFCE1 -> CS0_N */ -- select_peripheral(PE(20), PERIPH_A, 0); /* CFCE2 -> CS1_N */ -- select_peripheral(PE(23), PERIPH_A, 0); /* CFRNW -> DIR */ -- select_peripheral(PE(24), PERIPH_A, 0); /* NWAIT <- IORDY */ -- common_pins_initialized = true; -- } -- -- at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH); -- -- pdev->resource[1].start = EIM_IRQ_BASE + extint; -- pdev->resource[1].end = pdev->resource[1].start; -- -- return 0; --} -- --struct platform_device *__init --at32_add_device_ide(unsigned int id, unsigned int extint, -- struct ide_platform_data *data) --{ -- struct platform_device *pdev; -- -- pdev = platform_device_alloc("at32_ide", id); -- if (!pdev) -- goto fail; -- -- if (platform_device_add_data(pdev, data, -- sizeof(struct ide_platform_data))) -- goto fail; -- -- if (at32_init_ide_or_cf(pdev, data->cs, extint)) -- goto fail; -- -- platform_device_add(pdev); -- return pdev; -- --fail: -- platform_device_put(pdev); -- return NULL; --} -- --struct platform_device *__init --at32_add_device_cf(unsigned int id, unsigned int extint, -- struct cf_platform_data *data) --{ -- struct platform_device *pdev; -- -- pdev = platform_device_alloc("at32_cf", id); -- if (!pdev) -- goto fail; -- -- if (platform_device_add_data(pdev, data, -- sizeof(struct cf_platform_data))) -- goto fail; -- -- if (at32_init_ide_or_cf(pdev, data->cs, extint)) -- goto fail; -- -- if (data->detect_pin != GPIO_PIN_NONE) -- at32_select_gpio(data->detect_pin, AT32_GPIOF_DEGLITCH); -- if (data->reset_pin != GPIO_PIN_NONE) -- at32_select_gpio(data->reset_pin, 0); -- if (data->vcc_pin != GPIO_PIN_NONE) -- at32_select_gpio(data->vcc_pin, 0); -- /* READY is used as extint, so we can't select it as gpio */ -- -- platform_device_add(pdev); -- return pdev; -- --fail: -- platform_device_put(pdev); -- return NULL; --} -- --/* -------------------------------------------------------------------- -- * AC97C -- * -------------------------------------------------------------------- */ --static struct resource atmel_ac97c0_resource[] __initdata = { -- PBMEM(0xfff02800), -- IRQ(29), --}; --static struct clk atmel_ac97c0_pclk = { -- .name = "pclk", -- .parent = &pbb_clk, -- .mode = pbb_clk_mode, -- .get_rate = pbb_clk_get_rate, -- .index = 10, --}; -- --struct platform_device *__init at32_add_device_ac97c(unsigned int id) --{ -- struct platform_device *pdev; -- -- if (id != 0) -- return NULL; -- -- pdev = platform_device_alloc("atmel_ac97c", id); -- if (!pdev) -- return NULL; -- -- if (platform_device_add_resources(pdev, atmel_ac97c0_resource, -- ARRAY_SIZE(atmel_ac97c0_resource))) -- goto err_add_resources; -- -- select_peripheral(PB(20), PERIPH_B, 0); /* SYNC */ -- select_peripheral(PB(21), PERIPH_B, 0); /* SDO */ -- select_peripheral(PB(22), PERIPH_B, 0); /* SDI */ -- select_peripheral(PB(23), PERIPH_B, 0); /* SCLK */ -- -- atmel_ac97c0_pclk.dev = &pdev->dev; -- -- platform_device_add(pdev); -- return pdev; -- --err_add_resources: -- platform_device_put(pdev); -- return NULL; --} -- --/* -------------------------------------------------------------------- -- * ABDAC -- * -------------------------------------------------------------------- */ --static struct resource abdac0_resource[] __initdata = { -- PBMEM(0xfff02000), -- IRQ(27), --}; --static struct clk abdac0_pclk = { -- .name = "pclk", -- .parent = &pbb_clk, -- .mode = pbb_clk_mode, -- .get_rate = pbb_clk_get_rate, -- .index = 8, --}; --static struct clk abdac0_sample_clk = { -- .name = "sample_clk", -- .mode = genclk_mode, -- .get_rate = genclk_get_rate, -- .set_rate = genclk_set_rate, -- .set_parent = genclk_set_parent, -- .index = 6, --}; -- --struct platform_device *__init at32_add_device_abdac(unsigned int id) --{ -- struct platform_device *pdev; -- -- if (id != 0) -- return NULL; -- -- pdev = platform_device_alloc("abdac", id); -- if (!pdev) -- return NULL; -- -- if (platform_device_add_resources(pdev, abdac0_resource, -- ARRAY_SIZE(abdac0_resource))) -- goto err_add_resources; -- -- select_peripheral(PB(20), PERIPH_A, 0); /* DATA1 */ -- select_peripheral(PB(21), PERIPH_A, 0); /* DATA0 */ -- select_peripheral(PB(22), PERIPH_A, 0); /* DATAN1 */ -- select_peripheral(PB(23), PERIPH_A, 0); /* DATAN0 */ -- -- abdac0_pclk.dev = &pdev->dev; -- abdac0_sample_clk.dev = &pdev->dev; -- -- platform_device_add(pdev); -- return pdev; -- --err_add_resources: -- platform_device_put(pdev); -- return NULL; --} -- --/* -------------------------------------------------------------------- -- * GCLK -- * -------------------------------------------------------------------- */ --static struct clk gclk0 = { -- .name = "gclk0", -- .mode = genclk_mode, -- .get_rate = genclk_get_rate, -- .set_rate = genclk_set_rate, -- .set_parent = genclk_set_parent, -- .index = 0, --}; --static struct clk gclk1 = { -- .name = "gclk1", -- .mode = genclk_mode, -- .get_rate = genclk_get_rate, -- .set_rate = genclk_set_rate, -- .set_parent = genclk_set_parent, -- .index = 1, --}; --static struct clk gclk2 = { -- .name = "gclk2", -- .mode = genclk_mode, -- .get_rate = genclk_get_rate, -- .set_rate = genclk_set_rate, -- .set_parent = genclk_set_parent, -- .index = 2, --}; --static struct clk gclk3 = { -- .name = "gclk3", -- .mode = genclk_mode, -- .get_rate = genclk_get_rate, -- .set_rate = genclk_set_rate, -- .set_parent = genclk_set_parent, -- .index = 3, --}; --static struct clk gclk4 = { -- .name = "gclk4", -- .mode = genclk_mode, -- .get_rate = genclk_get_rate, -- .set_rate = genclk_set_rate, -- .set_parent = genclk_set_parent, -- .index = 4, --}; -- --struct clk *at32_clock_list[] = { -- &osc32k, -- &osc0, -- &osc1, -- &pll0, -- &pll1, -- &cpu_clk, -- &hsb_clk, -- &pba_clk, -- &pbb_clk, -- &at32_pm_pclk, -- &at32_intc0_pclk, -- &hmatrix_clk, -- &ebi_clk, -- &hramc_clk, -- &smc0_pclk, -- &smc0_mck, -- &pdc_hclk, -- &pdc_pclk, -- &dmaca0_hclk, -- &pico_clk, -- &pio0_mck, -- &pio1_mck, -- &pio2_mck, -- &pio3_mck, -- &pio4_mck, -- &at32_systc0_pclk, -- &atmel_usart0_usart, -- &atmel_usart1_usart, -- &atmel_usart2_usart, -- &atmel_usart3_usart, -- &macb0_hclk, -- &macb0_pclk, -- &macb1_hclk, -- &macb1_pclk, -- &atmel_spi0_spi_clk, -- &atmel_spi1_spi_clk, -- &atmel_twi0_pclk, -- &atmel_mci0_pclk, -- &atmel_lcdfb0_hck1, -- &atmel_lcdfb0_pixclk, -- &ssc0_pclk, -- &ssc1_pclk, -- &ssc2_pclk, -- &usba0_hclk, -- &usba0_pclk, -- &atmel_ac97c0_pclk, -- &abdac0_pclk, -- &abdac0_sample_clk, -- &gclk0, -- &gclk1, -- &gclk2, -- &gclk3, -- &gclk4, --}; --unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list); -- --void __init at32_portmux_init(void) --{ -- at32_init_pio(&pio0_device); -- at32_init_pio(&pio1_device); -- at32_init_pio(&pio2_device); -- at32_init_pio(&pio3_device); -- at32_init_pio(&pio4_device); --} -- --void __init at32_clock_init(void) --{ -- u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0; -- int i; -- -- if (pm_readl(MCCTRL) & PM_BIT(PLLSEL)) { -- main_clock = &pll0; -- cpu_clk.parent = &pll0; -- } else { -- main_clock = &osc0; -- cpu_clk.parent = &osc0; -- } -- -- if (pm_readl(PLL0) & PM_BIT(PLLOSC)) -- pll0.parent = &osc1; -- if (pm_readl(PLL1) & PM_BIT(PLLOSC)) -- pll1.parent = &osc1; -- -- genclk_init_parent(&gclk0); -- genclk_init_parent(&gclk1); -- genclk_init_parent(&gclk2); -- genclk_init_parent(&gclk3); -- genclk_init_parent(&gclk4); -- genclk_init_parent(&atmel_lcdfb0_pixclk); -- genclk_init_parent(&abdac0_sample_clk); -- -- /* -- * Turn on all clocks that have at least one user already, and -- * turn off everything else. We only do this for module -- * clocks, and even though it isn't particularly pretty to -- * check the address of the mode function, it should do the -- * trick... -- */ -- for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) { -- struct clk *clk = at32_clock_list[i]; -- -- if (clk->users == 0) -- continue; -- -- if (clk->mode == &cpu_clk_mode) -- cpu_mask |= 1 << clk->index; -- else if (clk->mode == &hsb_clk_mode) -- hsb_mask |= 1 << clk->index; -- else if (clk->mode == &pba_clk_mode) -- pba_mask |= 1 << clk->index; -- else if (clk->mode == &pbb_clk_mode) -- pbb_mask |= 1 << clk->index; -- } -- -- pm_writel(CPU_MASK, cpu_mask); -- pm_writel(HSB_MASK, hsb_mask); -- pm_writel(PBA_MASK, pba_mask); -- pm_writel(PBB_MASK, pbb_mask); --} ---- /dev/null -+++ b/arch/avr32/mach-at32ap/at32ap700x.c -@@ -0,0 +1,1944 @@ -+/* -+ * Copyright (C) 2005-2006 Atmel Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#include <linux/clk.h> -+#include <linux/fb.h> -+#include <linux/init.h> -+#include <linux/platform_device.h> -+#include <linux/dma-mapping.h> -+#include <linux/spi/spi.h> -+#include <linux/usb/atmel_usba_udc.h> -+ -+#include <asm/io.h> -+#include <asm/irq.h> -+ -+#include <asm/arch/at32ap700x.h> -+#include <asm/arch/board.h> -+#include <asm/arch/portmux.h> -+ -+#include <video/atmel_lcdc.h> -+ -+#include "clock.h" -+#include "hmatrix.h" -+#include "pio.h" -+#include "pm.h" -+ -+ -+#define PBMEM(base) \ -+ { \ -+ .start = base, \ -+ .end = base + 0x3ff, \ -+ .flags = IORESOURCE_MEM, \ -+ } -+#define IRQ(num) \ -+ { \ -+ .start = num, \ -+ .end = num, \ -+ .flags = IORESOURCE_IRQ, \ -+ } -+#define NAMED_IRQ(num, _name) \ -+ { \ -+ .start = num, \ -+ .end = num, \ -+ .name = _name, \ -+ .flags = IORESOURCE_IRQ, \ -+ } -+ -+/* REVISIT these assume *every* device supports DMA, but several -+ * don't ... tc, smc, pio, rtc, watchdog, pwm, ps2, and more. -+ */ -+#define DEFINE_DEV(_name, _id) \ -+static u64 _name##_id##_dma_mask = DMA_32BIT_MASK; \ -+static struct platform_device _name##_id##_device = { \ -+ .name = #_name, \ -+ .id = _id, \ -+ .dev = { \ -+ .dma_mask = &_name##_id##_dma_mask, \ -+ .coherent_dma_mask = DMA_32BIT_MASK, \ -+ }, \ -+ .resource = _name##_id##_resource, \ -+ .num_resources = ARRAY_SIZE(_name##_id##_resource), \ -+} -+#define DEFINE_DEV_DATA(_name, _id) \ -+static u64 _name##_id##_dma_mask = DMA_32BIT_MASK; \ -+static struct platform_device _name##_id##_device = { \ -+ .name = #_name, \ -+ .id = _id, \ -+ .dev = { \ -+ .dma_mask = &_name##_id##_dma_mask, \ -+ .platform_data = &_name##_id##_data, \ -+ .coherent_dma_mask = DMA_32BIT_MASK, \ -+ }, \ -+ .resource = _name##_id##_resource, \ -+ .num_resources = ARRAY_SIZE(_name##_id##_resource), \ -+} -+ -+#define select_peripheral(pin, periph, flags) \ -+ at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags) -+ -+#define DEV_CLK(_name, devname, bus, _index) \ -+static struct clk devname##_##_name = { \ -+ .name = #_name, \ -+ .dev = &devname##_device.dev, \ -+ .parent = &bus##_clk, \ -+ .mode = bus##_clk_mode, \ -+ .get_rate = bus##_clk_get_rate, \ -+ .index = _index, \ -+} -+ -+static DEFINE_SPINLOCK(pm_lock); -+ -+unsigned long at32ap7000_osc_rates[3] = { -+ [0] = 32768, -+ /* FIXME: these are ATSTK1002-specific */ -+ [1] = 20000000, -+ [2] = 12000000, -+}; -+ -+static unsigned long osc_get_rate(struct clk *clk) -+{ -+ return at32ap7000_osc_rates[clk->index]; -+} -+ -+static unsigned long pll_get_rate(struct clk *clk, unsigned long control) -+{ -+ unsigned long div, mul, rate; -+ -+ if (!(control & PM_BIT(PLLEN))) -+ return 0; -+ -+ div = PM_BFEXT(PLLDIV, control) + 1; -+ mul = PM_BFEXT(PLLMUL, control) + 1; + div = PM_BFEXT(PLLDIV, control) + 1; + mul = PM_BFEXT(PLLMUL, control) + 1; + +@@ -120,6 +116,71 @@ + return rate; + } + ++static long pll_set_rate(struct clk *clk, unsigned long rate, ++ u32 *pll_ctrl) ++{ ++ unsigned long mul; ++ unsigned long mul_best_fit = 0; ++ unsigned long div; ++ unsigned long div_min; ++ unsigned long div_max; ++ unsigned long div_best_fit = 0; ++ unsigned long base; ++ unsigned long pll_in; ++ unsigned long actual = 0; ++ unsigned long rate_error; ++ unsigned long rate_error_prev = ~0UL; ++ u32 ctrl; ++ ++ /* Rate must be between 80 MHz and 200 Mhz. */ ++ if (rate < 80000000UL || rate > 200000000UL) ++ return -EINVAL; + -+ rate = clk->parent->get_rate(clk->parent); -+ rate = (rate + div / 2) / div; -+ rate *= mul; ++ ctrl = PM_BF(PLLOPT, 4); ++ base = clk->parent->get_rate(clk->parent); + -+ return rate; -+} ++ /* PLL input frequency must be between 6 MHz and 32 MHz. */ ++ div_min = DIV_ROUND_UP(base, 32000000UL); ++ div_max = base / 6000000UL; + -+static unsigned long pll0_get_rate(struct clk *clk) -+{ -+ u32 control; ++ if (div_max < div_min) ++ return -EINVAL; + -+ control = pm_readl(PLL0); ++ for (div = div_min; div <= div_max; div++) { ++ pll_in = (base + div / 2) / div; ++ mul = (rate + pll_in / 2) / pll_in; + -+ return pll_get_rate(clk, control); -+} ++ if (mul == 0) ++ continue; + -+static unsigned long pll1_get_rate(struct clk *clk) -+{ -+ u32 control; ++ actual = pll_in * mul; ++ rate_error = abs(actual - rate); + -+ control = pm_readl(PLL1); ++ if (rate_error < rate_error_prev) { ++ mul_best_fit = mul; ++ div_best_fit = div; ++ rate_error_prev = rate_error; ++ } + -+ return pll_get_rate(clk, control); -+} ++ if (rate_error == 0) ++ break; ++ } + -+/* -+ * The AT32AP7000 has five primary clock sources: One 32kHz -+ * oscillator, two crystal oscillators and two PLLs. -+ */ -+static struct clk osc32k = { -+ .name = "osc32k", -+ .get_rate = osc_get_rate, -+ .users = 1, -+ .index = 0, -+}; -+static struct clk osc0 = { -+ .name = "osc0", -+ .get_rate = osc_get_rate, -+ .users = 1, -+ .index = 1, -+}; -+static struct clk osc1 = { -+ .name = "osc1", -+ .get_rate = osc_get_rate, -+ .index = 2, -+}; -+static struct clk pll0 = { -+ .name = "pll0", -+ .get_rate = pll0_get_rate, -+ .parent = &osc0, -+}; -+static struct clk pll1 = { -+ .name = "pll1", -+ .get_rate = pll1_get_rate, -+ .parent = &osc0, -+}; ++ if (div_best_fit == 0) ++ return -EINVAL; + -+/* -+ * The main clock can be either osc0 or pll0. The boot loader may -+ * have chosen one for us, so we don't really know which one until we -+ * have a look at the SM. -+ */ -+static struct clk *main_clock; ++ ctrl |= PM_BF(PLLMUL, mul_best_fit - 1); ++ ctrl |= PM_BF(PLLDIV, div_best_fit - 1); ++ ctrl |= PM_BF(PLLCOUNT, 16); + -+/* -+ * Synchronous clocks are generated from the main clock. The clocks -+ * must satisfy the constraint -+ * fCPU >= fHSB >= fPB -+ * i.e. each clock must not be faster than its parent. -+ */ -+static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift) -+{ -+ return main_clock->get_rate(main_clock) >> shift; -+}; ++ if (clk->parent == &osc1) ++ ctrl |= PM_BIT(PLLOSC); + -+static void cpu_clk_mode(struct clk *clk, int enabled) -+{ -+ unsigned long flags; -+ u32 mask; ++ *pll_ctrl = ctrl; + -+ spin_lock_irqsave(&pm_lock, flags); -+ mask = pm_readl(CPU_MASK); -+ if (enabled) -+ mask |= 1 << clk->index; -+ else -+ mask &= ~(1 << clk->index); -+ pm_writel(CPU_MASK, mask); -+ spin_unlock_irqrestore(&pm_lock, flags); ++ return actual; +} + -+static unsigned long cpu_clk_get_rate(struct clk *clk) + static unsigned long pll0_get_rate(struct clk *clk) + { + u32 control; +@@ -129,6 +190,41 @@ + return pll_get_rate(clk, control); + } + ++static void pll1_mode(struct clk *clk, int enabled) +{ -+ unsigned long cksel, shift = 0; -+ -+ cksel = pm_readl(CKSEL); -+ if (cksel & PM_BIT(CPUDIV)) -+ shift = PM_BFEXT(CPUSEL, cksel) + 1; ++ unsigned long timeout; ++ u32 status; ++ u32 ctrl; + -+ return bus_clk_get_rate(clk, shift); -+} ++ ctrl = pm_readl(PLL1); + -+static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply) -+{ -+ u32 control; -+ unsigned long parent_rate, child_div, actual_rate, div; ++ if (enabled) { ++ if (!PM_BFEXT(PLLMUL, ctrl) && !PM_BFEXT(PLLDIV, ctrl)) { ++ pr_debug("clk %s: failed to enable, rate not set\n", ++ clk->name); ++ return; ++ } + -+ parent_rate = clk->parent->get_rate(clk->parent); -+ control = pm_readl(CKSEL); ++ ctrl |= PM_BIT(PLLEN); ++ pm_writel(PLL1, ctrl); + -+ if (control & PM_BIT(HSBDIV)) -+ child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1); -+ else -+ child_div = 1; ++ /* Wait for PLL lock. */ ++ for (timeout = 10000; timeout; timeout--) { ++ status = pm_readl(ISR); ++ if (status & PM_BIT(LOCK1)) ++ break; ++ udelay(10); ++ } + -+ if (rate > 3 * (parent_rate / 4) || child_div == 1) { -+ actual_rate = parent_rate; -+ control &= ~PM_BIT(CPUDIV); ++ if (!(status & PM_BIT(LOCK1))) ++ printk(KERN_ERR "clk %s: timeout waiting for lock\n", ++ clk->name); + } else { -+ unsigned int cpusel; -+ div = (parent_rate + rate / 2) / rate; -+ if (div > child_div) -+ div = child_div; -+ cpusel = (div > 1) ? (fls(div) - 2) : 0; -+ control = PM_BIT(CPUDIV) | PM_BFINS(CPUSEL, cpusel, control); -+ actual_rate = parent_rate / (1 << (cpusel + 1)); ++ ctrl &= ~PM_BIT(PLLEN); ++ pm_writel(PLL1, ctrl); + } -+ -+ pr_debug("clk %s: new rate %lu (actual rate %lu)\n", -+ clk->name, rate, actual_rate); -+ -+ if (apply) -+ pm_writel(CKSEL, control); -+ -+ return actual_rate; -+} -+ -+static void hsb_clk_mode(struct clk *clk, int enabled) -+{ -+ unsigned long flags; -+ u32 mask; -+ -+ spin_lock_irqsave(&pm_lock, flags); -+ mask = pm_readl(HSB_MASK); -+ if (enabled) -+ mask |= 1 << clk->index; -+ else -+ mask &= ~(1 << clk->index); -+ pm_writel(HSB_MASK, mask); -+ spin_unlock_irqrestore(&pm_lock, flags); -+} -+ -+static unsigned long hsb_clk_get_rate(struct clk *clk) -+{ -+ unsigned long cksel, shift = 0; -+ -+ cksel = pm_readl(CKSEL); -+ if (cksel & PM_BIT(HSBDIV)) -+ shift = PM_BFEXT(HSBSEL, cksel) + 1; -+ -+ return bus_clk_get_rate(clk, shift); -+} -+ -+static void pba_clk_mode(struct clk *clk, int enabled) -+{ -+ unsigned long flags; -+ u32 mask; -+ -+ spin_lock_irqsave(&pm_lock, flags); -+ mask = pm_readl(PBA_MASK); -+ if (enabled) -+ mask |= 1 << clk->index; -+ else -+ mask &= ~(1 << clk->index); -+ pm_writel(PBA_MASK, mask); -+ spin_unlock_irqrestore(&pm_lock, flags); -+} -+ -+static unsigned long pba_clk_get_rate(struct clk *clk) -+{ -+ unsigned long cksel, shift = 0; -+ -+ cksel = pm_readl(CKSEL); -+ if (cksel & PM_BIT(PBADIV)) -+ shift = PM_BFEXT(PBASEL, cksel) + 1; -+ -+ return bus_clk_get_rate(clk, shift); -+} -+ -+static void pbb_clk_mode(struct clk *clk, int enabled) -+{ -+ unsigned long flags; -+ u32 mask; -+ -+ spin_lock_irqsave(&pm_lock, flags); -+ mask = pm_readl(PBB_MASK); -+ if (enabled) -+ mask |= 1 << clk->index; -+ else -+ mask &= ~(1 << clk->index); -+ pm_writel(PBB_MASK, mask); -+ spin_unlock_irqrestore(&pm_lock, flags); -+} -+ -+static unsigned long pbb_clk_get_rate(struct clk *clk) -+{ -+ unsigned long cksel, shift = 0; -+ -+ cksel = pm_readl(CKSEL); -+ if (cksel & PM_BIT(PBBDIV)) -+ shift = PM_BFEXT(PBBSEL, cksel) + 1; -+ -+ return bus_clk_get_rate(clk, shift); -+} -+ -+static struct clk cpu_clk = { -+ .name = "cpu", -+ .get_rate = cpu_clk_get_rate, -+ .set_rate = cpu_clk_set_rate, -+ .users = 1, -+}; -+static struct clk hsb_clk = { -+ .name = "hsb", -+ .parent = &cpu_clk, -+ .get_rate = hsb_clk_get_rate, -+}; -+static struct clk pba_clk = { -+ .name = "pba", -+ .parent = &hsb_clk, -+ .mode = hsb_clk_mode, -+ .get_rate = pba_clk_get_rate, -+ .index = 1, -+}; -+static struct clk pbb_clk = { -+ .name = "pbb", -+ .parent = &hsb_clk, -+ .mode = hsb_clk_mode, -+ .get_rate = pbb_clk_get_rate, -+ .users = 1, -+ .index = 2, -+}; -+ -+/* -------------------------------------------------------------------- -+ * Generic Clock operations -+ * -------------------------------------------------------------------- */ -+ -+static void genclk_mode(struct clk *clk, int enabled) -+{ -+ u32 control; -+ -+ control = pm_readl(GCCTRL(clk->index)); -+ if (enabled) -+ control |= PM_BIT(CEN); -+ else -+ control &= ~PM_BIT(CEN); -+ pm_writel(GCCTRL(clk->index), control); +} + -+static unsigned long genclk_get_rate(struct clk *clk) -+{ -+ u32 control; -+ unsigned long div = 1; -+ -+ control = pm_readl(GCCTRL(clk->index)); -+ if (control & PM_BIT(DIVEN)) -+ div = 2 * (PM_BFEXT(DIV, control) + 1); -+ -+ return clk->parent->get_rate(clk->parent) / div; -+} -+ -+static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply) + static unsigned long pll1_get_rate(struct clk *clk) + { + u32 control; +@@ -138,6 +234,49 @@ + return pll_get_rate(clk, control); + } + ++static long pll1_set_rate(struct clk *clk, unsigned long rate, int apply) +{ -+ u32 control; -+ unsigned long parent_rate, actual_rate, div; ++ u32 ctrl = 0; ++ unsigned long actual_rate; + -+ parent_rate = clk->parent->get_rate(clk->parent); -+ control = pm_readl(GCCTRL(clk->index)); ++ actual_rate = pll_set_rate(clk, rate, &ctrl); + -+ if (rate > 3 * parent_rate / 4) { -+ actual_rate = parent_rate; -+ control &= ~PM_BIT(DIVEN); -+ } else { -+ div = (parent_rate + rate) / (2 * rate) - 1; -+ control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN); -+ actual_rate = parent_rate / (2 * (div + 1)); ++ if (apply) { ++ if (actual_rate != rate) ++ return -EINVAL; ++ if (clk->users > 0) ++ return -EBUSY; ++ pr_debug(KERN_INFO "clk %s: new rate %lu (actual rate %lu)\n", ++ clk->name, rate, actual_rate); ++ pm_writel(PLL1, ctrl); + } + -+ dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n", -+ clk->name, rate, actual_rate); -+ -+ if (apply) -+ pm_writel(GCCTRL(clk->index), control); -+ + return actual_rate; +} + -+int genclk_set_parent(struct clk *clk, struct clk *parent) ++static int pll1_set_parent(struct clk *clk, struct clk *parent) +{ -+ u32 control; ++ u32 ctrl; + -+ dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n", -+ clk->name, parent->name, clk->parent->name); ++ if (clk->users > 0) ++ return -EBUSY; + -+ control = pm_readl(GCCTRL(clk->index)); ++ ctrl = pm_readl(PLL1); ++ WARN_ON(ctrl & PM_BIT(PLLEN)); + -+ if (parent == &osc1 || parent == &pll1) -+ control |= PM_BIT(OSCSEL); -+ else if (parent == &osc0 || parent == &pll0) -+ control &= ~PM_BIT(OSCSEL); ++ if (parent == &osc0) ++ ctrl &= ~PM_BIT(PLLOSC); ++ else if (parent == &osc1) ++ ctrl |= PM_BIT(PLLOSC); + else + return -EINVAL; + -+ if (parent == &pll0 || parent == &pll1) -+ control |= PM_BIT(PLLSEL); -+ else -+ control &= ~PM_BIT(PLLSEL); -+ -+ pm_writel(GCCTRL(clk->index), control); ++ pm_writel(PLL1, ctrl); + clk->parent = parent; + + return 0; +} + -+static void __init genclk_init_parent(struct clk *clk) -+{ -+ u32 control; -+ struct clk *parent; -+ -+ BUG_ON(clk->index > 7); -+ -+ control = pm_readl(GCCTRL(clk->index)); -+ if (control & PM_BIT(OSCSEL)) -+ parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1; -+ else -+ parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0; -+ -+ clk->parent = parent; -+} -+ -+/* -------------------------------------------------------------------- -+ * System peripherals -+ * -------------------------------------------------------------------- */ -+static struct resource at32_pm0_resource[] = { -+ { -+ .start = 0xfff00000, -+ .end = 0xfff0007f, -+ .flags = IORESOURCE_MEM, -+ }, -+ IRQ(20), -+}; -+ -+static struct resource at32ap700x_rtc0_resource[] = { -+ { -+ .start = 0xfff00080, -+ .end = 0xfff000af, -+ .flags = IORESOURCE_MEM, -+ }, -+ IRQ(21), -+}; -+ -+static struct resource at32_wdt0_resource[] = { -+ { -+ .start = 0xfff000b0, -+ .end = 0xfff000cf, -+ .flags = IORESOURCE_MEM, -+ }, -+}; -+ -+static struct resource at32_eic0_resource[] = { -+ { -+ .start = 0xfff00100, -+ .end = 0xfff0013f, -+ .flags = IORESOURCE_MEM, -+ }, -+ IRQ(19), -+}; -+ -+DEFINE_DEV(at32_pm, 0); -+DEFINE_DEV(at32ap700x_rtc, 0); -+DEFINE_DEV(at32_wdt, 0); -+DEFINE_DEV(at32_eic, 0); -+ -+/* -+ * Peripheral clock for PM, RTC, WDT and EIC. PM will ensure that this -+ * is always running. -+ */ -+static struct clk at32_pm_pclk = { -+ .name = "pclk", -+ .dev = &at32_pm0_device.dev, -+ .parent = &pbb_clk, -+ .mode = pbb_clk_mode, -+ .get_rate = pbb_clk_get_rate, -+ .users = 1, -+ .index = 0, -+}; -+ -+static struct resource intc0_resource[] = { -+ PBMEM(0xfff00400), -+}; -+struct platform_device at32_intc0_device = { -+ .name = "intc", -+ .id = 0, -+ .resource = intc0_resource, -+ .num_resources = ARRAY_SIZE(intc0_resource), -+}; -+DEV_CLK(pclk, at32_intc0, pbb, 1); -+ -+static struct clk ebi_clk = { -+ .name = "ebi", -+ .parent = &hsb_clk, -+ .mode = hsb_clk_mode, -+ .get_rate = hsb_clk_get_rate, -+ .users = 1, -+}; -+static struct clk hramc_clk = { -+ .name = "hramc", -+ .parent = &hsb_clk, -+ .mode = hsb_clk_mode, -+ .get_rate = hsb_clk_get_rate, -+ .users = 1, -+ .index = 3, -+}; -+ -+static struct resource smc0_resource[] = { -+ PBMEM(0xfff03400), -+}; -+DEFINE_DEV(smc, 0); -+DEV_CLK(pclk, smc0, pbb, 13); -+DEV_CLK(mck, smc0, hsb, 0); -+ -+static struct platform_device pdc_device = { -+ .name = "pdc", -+ .id = 0, -+}; -+DEV_CLK(hclk, pdc, hsb, 4); -+DEV_CLK(pclk, pdc, pba, 16); -+ -+static struct clk pico_clk = { -+ .name = "pico", -+ .parent = &cpu_clk, -+ .mode = cpu_clk_mode, -+ .get_rate = cpu_clk_get_rate, -+ .users = 1, -+}; -+ -+static struct resource dmaca0_resource[] = { -+ { -+ .start = 0xff200000, -+ .end = 0xff20ffff, -+ .flags = IORESOURCE_MEM, -+ }, -+ IRQ(2), -+}; -+DEFINE_DEV(dmaca, 0); -+DEV_CLK(hclk, dmaca0, hsb, 10); -+ -+/* -------------------------------------------------------------------- -+ * HMATRIX -+ * -------------------------------------------------------------------- */ -+ -+static struct clk hmatrix_clk = { -+ .name = "hmatrix_clk", + /* + * The AT32AP7000 has five primary clock sources: One 32kHz + * oscillator, two crystal oscillators and two PLLs. +@@ -166,7 +305,10 @@ + }; + static struct clk pll1 = { + .name = "pll1", ++ .mode = pll1_mode, + .get_rate = pll1_get_rate, ++ .set_rate = pll1_set_rate, ++ .set_parent = pll1_set_parent, + .parent = &osc0, + }; + +@@ -534,6 +676,14 @@ + .users = 1, + .index = 3, + }; ++static struct clk sdramc_clk = { ++ .name = "sdramc_clk", + .parent = &pbb_clk, + .mode = pbb_clk_mode, + .get_rate = pbb_clk_get_rate, -+ .index = 2, + .users = 1, ++ .index = 14, +}; -+#define HMATRIX_BASE ((void __iomem *)0xfff00800) -+ -+#define hmatrix_readl(reg) \ -+ __raw_readl((HMATRIX_BASE) + HMATRIX_##reg) -+#define hmatrix_writel(reg,value) \ -+ __raw_writel((value), (HMATRIX_BASE) + HMATRIX_##reg) -+ -+/* -+ * Set bits in the HMATRIX Special Function Register (SFR) used by the -+ * External Bus Interface (EBI). This can be used to enable special -+ * features like CompactFlash support, NAND Flash support, etc. on -+ * certain chipselects. -+ */ -+static inline void set_ebi_sfr_bits(u32 mask) -+{ -+ u32 sfr; -+ -+ clk_enable(&hmatrix_clk); -+ sfr = hmatrix_readl(SFR4); -+ sfr |= mask; -+ hmatrix_writel(SFR4, sfr); -+ clk_disable(&hmatrix_clk); -+} -+ -+/* -------------------------------------------------------------------- + + static struct resource smc0_resource[] = { + PBMEM(0xfff03400), +@@ -605,19 +755,32 @@ + } + + /* -------------------------------------------------------------------- +- * System Timer/Counter (TC) + * Timer/Counter (TC) -+ * -------------------------------------------------------------------- */ + * -------------------------------------------------------------------- */ +-static struct resource at32_systc0_resource[] = { + +static struct resource at32_tcb0_resource[] = { -+ PBMEM(0xfff00c00), -+ IRQ(22), -+}; + PBMEM(0xfff00c00), + IRQ(22), + }; +-struct platform_device at32_systc0_device = { +- .name = "systc", +static struct platform_device at32_tcb0_device = { + .name = "atmel_tcb", -+ .id = 0, + .id = 0, +- .resource = at32_systc0_resource, +- .num_resources = ARRAY_SIZE(at32_systc0_resource), + .resource = at32_tcb0_resource, + .num_resources = ARRAY_SIZE(at32_tcb0_resource), -+}; + }; +-DEV_CLK(pclk, at32_systc0, pbb, 3); +DEV_CLK(t0_clk, at32_tcb0, pbb, 3); + +static struct resource at32_tcb1_resource[] = { @@ -8999,68 +5607,23 @@ + .num_resources = ARRAY_SIZE(at32_tcb1_resource), +}; +DEV_CLK(t0_clk, at32_tcb1, pbb, 4); -+ -+/* -------------------------------------------------------------------- -+ * PIO -+ * -------------------------------------------------------------------- */ -+ -+static struct resource pio0_resource[] = { -+ PBMEM(0xffe02800), -+ IRQ(13), -+}; -+DEFINE_DEV(pio, 0); -+DEV_CLK(mck, pio0, pba, 10); -+ -+static struct resource pio1_resource[] = { -+ PBMEM(0xffe02c00), -+ IRQ(14), -+}; -+DEFINE_DEV(pio, 1); -+DEV_CLK(mck, pio1, pba, 11); -+ -+static struct resource pio2_resource[] = { -+ PBMEM(0xffe03000), -+ IRQ(15), -+}; -+DEFINE_DEV(pio, 2); -+DEV_CLK(mck, pio2, pba, 12); -+ -+static struct resource pio3_resource[] = { -+ PBMEM(0xffe03400), -+ IRQ(16), -+}; -+DEFINE_DEV(pio, 3); -+DEV_CLK(mck, pio3, pba, 13); -+ -+static struct resource pio4_resource[] = { -+ PBMEM(0xffe03800), -+ IRQ(17), -+}; -+DEFINE_DEV(pio, 4); -+DEV_CLK(mck, pio4, pba, 14); -+ -+void __init at32_add_system_devices(void) -+{ -+ platform_device_register(&at32_pm0_device); -+ platform_device_register(&at32_intc0_device); -+ platform_device_register(&at32ap700x_rtc0_device); -+ platform_device_register(&at32_wdt0_device); -+ platform_device_register(&at32_eic0_device); -+ platform_device_register(&smc0_device); -+ platform_device_register(&pdc_device); -+ platform_device_register(&dmaca0_device); -+ + + /* -------------------------------------------------------------------- + * PIO +@@ -669,7 +832,8 @@ + platform_device_register(&pdc_device); + platform_device_register(&dmaca0_device); + +- platform_device_register(&at32_systc0_device); + platform_device_register(&at32_tcb0_device); + platform_device_register(&at32_tcb1_device); -+ -+ platform_device_register(&pio0_device); -+ platform_device_register(&pio1_device); -+ platform_device_register(&pio2_device); -+ platform_device_register(&pio3_device); -+ platform_device_register(&pio4_device); -+} -+ -+/* -------------------------------------------------------------------- + + platform_device_register(&pio0_device); + platform_device_register(&pio1_device); +@@ -679,6 +843,81 @@ + } + + /* -------------------------------------------------------------------- + * PSIF + * -------------------------------------------------------------------- */ +static struct resource atmel_psif0_resource[] __initdata = { @@ -9136,391 +5699,62 @@ +} + +/* -------------------------------------------------------------------- -+ * USART -+ * -------------------------------------------------------------------- */ -+ -+static struct atmel_uart_data atmel_usart0_data = { -+ .use_dma_tx = 1, -+ .use_dma_rx = 1, -+}; -+static struct resource atmel_usart0_resource[] = { -+ PBMEM(0xffe00c00), -+ IRQ(6), -+}; -+DEFINE_DEV_DATA(atmel_usart, 0); -+DEV_CLK(usart, atmel_usart0, pba, 3); -+ -+static struct atmel_uart_data atmel_usart1_data = { -+ .use_dma_tx = 1, -+ .use_dma_rx = 1, -+}; -+static struct resource atmel_usart1_resource[] = { -+ PBMEM(0xffe01000), -+ IRQ(7), -+}; -+DEFINE_DEV_DATA(atmel_usart, 1); -+DEV_CLK(usart, atmel_usart1, pba, 4); -+ -+static struct atmel_uart_data atmel_usart2_data = { -+ .use_dma_tx = 1, -+ .use_dma_rx = 1, -+}; -+static struct resource atmel_usart2_resource[] = { -+ PBMEM(0xffe01400), -+ IRQ(8), -+}; -+DEFINE_DEV_DATA(atmel_usart, 2); -+DEV_CLK(usart, atmel_usart2, pba, 5); -+ -+static struct atmel_uart_data atmel_usart3_data = { -+ .use_dma_tx = 1, -+ .use_dma_rx = 1, -+}; -+static struct resource atmel_usart3_resource[] = { -+ PBMEM(0xffe01800), -+ IRQ(9), -+}; -+DEFINE_DEV_DATA(atmel_usart, 3); -+DEV_CLK(usart, atmel_usart3, pba, 6); -+ -+static inline void configure_usart0_pins(void) -+{ -+ select_peripheral(PA(8), PERIPH_B, 0); /* RXD */ -+ select_peripheral(PA(9), PERIPH_B, 0); /* TXD */ -+} -+ -+static inline void configure_usart1_pins(void) -+{ -+ select_peripheral(PA(17), PERIPH_A, 0); /* RXD */ -+ select_peripheral(PA(18), PERIPH_A, 0); /* TXD */ -+} -+ -+static inline void configure_usart2_pins(void) -+{ -+ select_peripheral(PB(26), PERIPH_B, 0); /* RXD */ -+ select_peripheral(PB(27), PERIPH_B, 0); /* TXD */ -+} -+ -+static inline void configure_usart3_pins(void) -+{ -+ select_peripheral(PB(18), PERIPH_B, 0); /* RXD */ -+ select_peripheral(PB(17), PERIPH_B, 0); /* TXD */ -+} -+ -+static struct platform_device *__initdata at32_usarts[4]; -+ -+void __init at32_map_usart(unsigned int hw_id, unsigned int line) -+{ -+ struct platform_device *pdev; -+ -+ switch (hw_id) { -+ case 0: -+ pdev = &atmel_usart0_device; -+ configure_usart0_pins(); -+ break; -+ case 1: -+ pdev = &atmel_usart1_device; -+ configure_usart1_pins(); -+ break; -+ case 2: -+ pdev = &atmel_usart2_device; -+ configure_usart2_pins(); -+ break; -+ case 3: -+ pdev = &atmel_usart3_device; -+ configure_usart3_pins(); -+ break; -+ default: -+ return; -+ } -+ -+ if (PXSEG(pdev->resource[0].start) == P4SEG) { -+ /* Addresses in the P4 segment are permanently mapped 1:1 */ -+ struct atmel_uart_data *data = pdev->dev.platform_data; -+ data->regs = (void __iomem *)pdev->resource[0].start; -+ } -+ -+ pdev->id = line; -+ at32_usarts[line] = pdev; -+} -+ -+struct platform_device *__init at32_add_device_usart(unsigned int id) -+{ -+ platform_device_register(at32_usarts[id]); -+ return at32_usarts[id]; -+} -+ -+struct platform_device *atmel_default_console_device; -+ -+void __init at32_setup_serial_console(unsigned int usart_id) -+{ -+ atmel_default_console_device = at32_usarts[usart_id]; -+} -+ -+/* -------------------------------------------------------------------- -+ * Ethernet -+ * -------------------------------------------------------------------- */ -+ -+#ifdef CONFIG_CPU_AT32AP7000 -+static struct eth_platform_data macb0_data; -+static struct resource macb0_resource[] = { -+ PBMEM(0xfff01800), -+ IRQ(25), -+}; -+DEFINE_DEV_DATA(macb, 0); -+DEV_CLK(hclk, macb0, hsb, 8); -+DEV_CLK(pclk, macb0, pbb, 6); -+ -+static struct eth_platform_data macb1_data; -+static struct resource macb1_resource[] = { -+ PBMEM(0xfff01c00), -+ IRQ(26), -+}; -+DEFINE_DEV_DATA(macb, 1); -+DEV_CLK(hclk, macb1, hsb, 9); -+DEV_CLK(pclk, macb1, pbb, 7); -+ -+struct platform_device *__init -+at32_add_device_eth(unsigned int id, struct eth_platform_data *data) -+{ -+ struct platform_device *pdev; -+ -+ switch (id) { -+ case 0: -+ pdev = &macb0_device; -+ -+ select_peripheral(PC(3), PERIPH_A, 0); /* TXD0 */ -+ select_peripheral(PC(4), PERIPH_A, 0); /* TXD1 */ -+ select_peripheral(PC(7), PERIPH_A, 0); /* TXEN */ -+ select_peripheral(PC(8), PERIPH_A, 0); /* TXCK */ -+ select_peripheral(PC(9), PERIPH_A, 0); /* RXD0 */ -+ select_peripheral(PC(10), PERIPH_A, 0); /* RXD1 */ -+ select_peripheral(PC(13), PERIPH_A, 0); /* RXER */ -+ select_peripheral(PC(15), PERIPH_A, 0); /* RXDV */ -+ select_peripheral(PC(16), PERIPH_A, 0); /* MDC */ -+ select_peripheral(PC(17), PERIPH_A, 0); /* MDIO */ -+ -+ if (!data->is_rmii) { -+ select_peripheral(PC(0), PERIPH_A, 0); /* COL */ -+ select_peripheral(PC(1), PERIPH_A, 0); /* CRS */ -+ select_peripheral(PC(2), PERIPH_A, 0); /* TXER */ -+ select_peripheral(PC(5), PERIPH_A, 0); /* TXD2 */ -+ select_peripheral(PC(6), PERIPH_A, 0); /* TXD3 */ -+ select_peripheral(PC(11), PERIPH_A, 0); /* RXD2 */ -+ select_peripheral(PC(12), PERIPH_A, 0); /* RXD3 */ -+ select_peripheral(PC(14), PERIPH_A, 0); /* RXCK */ -+ select_peripheral(PC(18), PERIPH_A, 0); /* SPD */ -+ } -+ break; -+ -+ case 1: -+ pdev = &macb1_device; -+ -+ select_peripheral(PD(13), PERIPH_B, 0); /* TXD0 */ -+ select_peripheral(PD(14), PERIPH_B, 0); /* TXD1 */ -+ select_peripheral(PD(11), PERIPH_B, 0); /* TXEN */ -+ select_peripheral(PD(12), PERIPH_B, 0); /* TXCK */ -+ select_peripheral(PD(10), PERIPH_B, 0); /* RXD0 */ -+ select_peripheral(PD(6), PERIPH_B, 0); /* RXD1 */ -+ select_peripheral(PD(5), PERIPH_B, 0); /* RXER */ -+ select_peripheral(PD(4), PERIPH_B, 0); /* RXDV */ -+ select_peripheral(PD(3), PERIPH_B, 0); /* MDC */ -+ select_peripheral(PD(2), PERIPH_B, 0); /* MDIO */ -+ -+ if (!data->is_rmii) { -+ select_peripheral(PC(19), PERIPH_B, 0); /* COL */ -+ select_peripheral(PC(23), PERIPH_B, 0); /* CRS */ -+ select_peripheral(PC(26), PERIPH_B, 0); /* TXER */ -+ select_peripheral(PC(27), PERIPH_B, 0); /* TXD2 */ -+ select_peripheral(PC(28), PERIPH_B, 0); /* TXD3 */ -+ select_peripheral(PC(29), PERIPH_B, 0); /* RXD2 */ -+ select_peripheral(PC(30), PERIPH_B, 0); /* RXD3 */ -+ select_peripheral(PC(24), PERIPH_B, 0); /* RXCK */ -+ select_peripheral(PD(15), PERIPH_B, 0); /* SPD */ -+ } -+ break; -+ -+ default: -+ return NULL; -+ } -+ -+ memcpy(pdev->dev.platform_data, data, sizeof(struct eth_platform_data)); -+ platform_device_register(pdev); -+ -+ return pdev; -+} -+#endif -+ -+/* -------------------------------------------------------------------- -+ * SPI -+ * -------------------------------------------------------------------- */ -+static struct resource atmel_spi0_resource[] = { -+ PBMEM(0xffe00000), -+ IRQ(3), -+}; -+DEFINE_DEV(atmel_spi, 0); -+DEV_CLK(spi_clk, atmel_spi0, pba, 0); -+ -+static struct resource atmel_spi1_resource[] = { -+ PBMEM(0xffe00400), -+ IRQ(4), -+}; -+DEFINE_DEV(atmel_spi, 1); -+DEV_CLK(spi_clk, atmel_spi1, pba, 1); -+ -+static void __init -+at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b, -+ unsigned int n, const u8 *pins) -+{ -+ unsigned int pin, mode; -+ -+ for (; n; n--, b++) { -+ b->bus_num = bus_num; -+ if (b->chip_select >= 4) -+ continue; -+ pin = (unsigned)b->controller_data; -+ if (!pin) { -+ pin = pins[b->chip_select]; -+ b->controller_data = (void *)pin; -+ } -+ mode = AT32_GPIOF_OUTPUT; -+ if (!(b->mode & SPI_CS_HIGH)) -+ mode |= AT32_GPIOF_HIGH; -+ at32_select_gpio(pin, mode); -+ } -+} -+ -+struct platform_device *__init -+at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n) -+{ -+ /* -+ * Manage the chipselects as GPIOs, normally using the same pins -+ * the SPI controller expects; but boards can use other pins. -+ */ -+ static u8 __initdata spi0_pins[] = -+ { GPIO_PIN_PA(3), GPIO_PIN_PA(4), -+ GPIO_PIN_PA(5), GPIO_PIN_PA(20), }; -+ static u8 __initdata spi1_pins[] = -+ { GPIO_PIN_PB(2), GPIO_PIN_PB(3), -+ GPIO_PIN_PB(4), GPIO_PIN_PA(27), }; -+ struct platform_device *pdev; -+ -+ switch (id) { -+ case 0: -+ pdev = &atmel_spi0_device; -+ select_peripheral(PA(0), PERIPH_A, 0); /* MISO */ -+ select_peripheral(PA(1), PERIPH_A, 0); /* MOSI */ -+ select_peripheral(PA(2), PERIPH_A, 0); /* SCK */ -+ at32_spi_setup_slaves(0, b, n, spi0_pins); -+ break; -+ -+ case 1: -+ pdev = &atmel_spi1_device; -+ select_peripheral(PB(0), PERIPH_B, 0); /* MISO */ -+ select_peripheral(PB(1), PERIPH_B, 0); /* MOSI */ -+ select_peripheral(PB(5), PERIPH_B, 0); /* SCK */ -+ at32_spi_setup_slaves(1, b, n, spi1_pins); -+ break; -+ -+ default: -+ return NULL; -+ } -+ -+ spi_register_board_info(b, n); -+ platform_device_register(pdev); -+ return pdev; -+} -+ -+/* -------------------------------------------------------------------- -+ * TWI -+ * -------------------------------------------------------------------- */ -+static struct resource atmel_twi0_resource[] __initdata = { -+ PBMEM(0xffe00800), -+ IRQ(5), -+}; -+static struct clk atmel_twi0_pclk = { -+ .name = "twi_pclk", -+ .parent = &pba_clk, -+ .mode = pba_clk_mode, -+ .get_rate = pba_clk_get_rate, -+ .index = 2, -+}; -+ + * USART + * -------------------------------------------------------------------- */ + +@@ -989,7 +1228,9 @@ + .index = 2, + }; + +-struct platform_device *__init at32_add_device_twi(unsigned int id) +struct platform_device *__init at32_add_device_twi(unsigned int id, + struct i2c_board_info *b, + unsigned int n) -+{ -+ struct platform_device *pdev; -+ -+ if (id != 0) -+ return NULL; -+ -+ pdev = platform_device_alloc("atmel_twi", id); -+ if (!pdev) -+ return NULL; -+ -+ if (platform_device_add_resources(pdev, atmel_twi0_resource, -+ ARRAY_SIZE(atmel_twi0_resource))) -+ goto err_add_resources; -+ -+ select_peripheral(PA(6), PERIPH_A, 0); /* SDA */ -+ select_peripheral(PA(7), PERIPH_A, 0); /* SDL */ -+ -+ atmel_twi0_pclk.dev = &pdev->dev; -+ + { + struct platform_device *pdev; + +@@ -1009,6 +1250,9 @@ + + atmel_twi0_pclk.dev = &pdev->dev; + + if (b) + i2c_register_board_info(id, b, n); + -+ platform_device_add(pdev); -+ return pdev; -+ -+err_add_resources: -+ platform_device_put(pdev); -+ return NULL; -+} -+ -+/* -------------------------------------------------------------------- -+ * MMC -+ * -------------------------------------------------------------------- */ -+static struct resource atmel_mci0_resource[] __initdata = { -+ PBMEM(0xfff02400), -+ IRQ(28), -+}; -+static struct clk atmel_mci0_pclk = { -+ .name = "mci_clk", -+ .parent = &pbb_clk, -+ .mode = pbb_clk_mode, -+ .get_rate = pbb_clk_get_rate, -+ .index = 9, -+}; -+ + platform_device_add(pdev); + return pdev; + +@@ -1032,7 +1276,8 @@ + .index = 9, + }; + +-struct platform_device *__init at32_add_device_mci(unsigned int id) +struct platform_device *__init +at32_add_device_mci(unsigned int id, struct mci_platform_data *data) -+{ -+ struct platform_device *pdev; -+ -+ if (id != 0) -+ return NULL; -+ -+ pdev = platform_device_alloc("atmel_mci", id); -+ if (!pdev) + { + struct platform_device *pdev; + +@@ -1041,11 +1286,15 @@ + + pdev = platform_device_alloc("atmel_mci", id); + if (!pdev) +- return NULL; + goto fail; -+ -+ if (platform_device_add_resources(pdev, atmel_mci0_resource, -+ ARRAY_SIZE(atmel_mci0_resource))) + + if (platform_device_add_resources(pdev, atmel_mci0_resource, + ARRAY_SIZE(atmel_mci0_resource))) +- goto err_add_resources; + goto fail; + + if (data && platform_device_add_data(pdev, data, + sizeof(struct mci_platform_data))) + goto fail; -+ -+ select_peripheral(PA(10), PERIPH_A, 0); /* CLK */ -+ select_peripheral(PA(11), PERIPH_A, 0); /* CMD */ -+ select_peripheral(PA(12), PERIPH_A, 0); /* DATA0 */ -+ select_peripheral(PA(13), PERIPH_A, 0); /* DATA1 */ -+ select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */ -+ select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */ -+ + + select_peripheral(PA(10), PERIPH_A, 0); /* CLK */ + select_peripheral(PA(11), PERIPH_A, 0); /* CMD */ +@@ -1054,12 +1303,19 @@ + select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */ + select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */ + + if (data) { + if (data->detect_pin != GPIO_PIN_NONE) + at32_select_gpio(data->detect_pin, 0); @@ -9528,303 +5762,139 @@ + at32_select_gpio(data->wp_pin, 0); + } + -+ atmel_mci0_pclk.dev = &pdev->dev; -+ -+ platform_device_add(pdev); -+ return pdev; -+ + atmel_mci0_pclk.dev = &pdev->dev; + + platform_device_add(pdev); + return pdev; + +-err_add_resources: +fail: -+ platform_device_put(pdev); -+ return NULL; -+} -+ -+/* -------------------------------------------------------------------- -+ * LCDC -+ * -------------------------------------------------------------------- */ -+#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002) -+static struct atmel_lcdfb_info atmel_lcdfb0_data; -+static struct resource atmel_lcdfb0_resource[] = { -+ { -+ .start = 0xff000000, -+ .end = 0xff000fff, -+ .flags = IORESOURCE_MEM, -+ }, -+ IRQ(1), -+ { -+ /* Placeholder for pre-allocated fb memory */ -+ .start = 0x00000000, -+ .end = 0x00000000, -+ .flags = 0, -+ }, -+}; -+DEFINE_DEV_DATA(atmel_lcdfb, 0); -+DEV_CLK(hck1, atmel_lcdfb0, hsb, 7); -+static struct clk atmel_lcdfb0_pixclk = { -+ .name = "lcdc_clk", -+ .dev = &atmel_lcdfb0_device.dev, -+ .mode = genclk_mode, -+ .get_rate = genclk_get_rate, -+ .set_rate = genclk_set_rate, -+ .set_parent = genclk_set_parent, -+ .index = 7, -+}; -+ -+struct platform_device *__init -+at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data, -+ unsigned long fbmem_start, unsigned long fbmem_len) -+{ -+ struct platform_device *pdev; -+ struct atmel_lcdfb_info *info; -+ struct fb_monspecs *monspecs; -+ struct fb_videomode *modedb; -+ unsigned int modedb_size; -+ -+ /* -+ * Do a deep copy of the fb data, monspecs and modedb. Make -+ * sure all allocations are done before setting up the -+ * portmux. -+ */ -+ monspecs = kmemdup(data->default_monspecs, -+ sizeof(struct fb_monspecs), GFP_KERNEL); -+ if (!monspecs) -+ return NULL; -+ -+ modedb_size = sizeof(struct fb_videomode) * monspecs->modedb_len; -+ modedb = kmemdup(monspecs->modedb, modedb_size, GFP_KERNEL); -+ if (!modedb) -+ goto err_dup_modedb; -+ monspecs->modedb = modedb; -+ -+ switch (id) { -+ case 0: -+ pdev = &atmel_lcdfb0_device; -+ select_peripheral(PC(19), PERIPH_A, 0); /* CC */ -+ select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC */ -+ select_peripheral(PC(21), PERIPH_A, 0); /* PCLK */ -+ select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC */ -+ select_peripheral(PC(23), PERIPH_A, 0); /* DVAL */ -+ select_peripheral(PC(24), PERIPH_A, 0); /* MODE */ -+ select_peripheral(PC(25), PERIPH_A, 0); /* PWR */ -+ select_peripheral(PC(26), PERIPH_A, 0); /* DATA0 */ -+ select_peripheral(PC(27), PERIPH_A, 0); /* DATA1 */ -+ select_peripheral(PC(28), PERIPH_A, 0); /* DATA2 */ -+ select_peripheral(PC(29), PERIPH_A, 0); /* DATA3 */ -+ select_peripheral(PC(30), PERIPH_A, 0); /* DATA4 */ -+ select_peripheral(PC(31), PERIPH_A, 0); /* DATA5 */ -+ select_peripheral(PD(0), PERIPH_A, 0); /* DATA6 */ -+ select_peripheral(PD(1), PERIPH_A, 0); /* DATA7 */ -+ select_peripheral(PD(2), PERIPH_A, 0); /* DATA8 */ -+ select_peripheral(PD(3), PERIPH_A, 0); /* DATA9 */ -+ select_peripheral(PD(4), PERIPH_A, 0); /* DATA10 */ -+ select_peripheral(PD(5), PERIPH_A, 0); /* DATA11 */ -+ select_peripheral(PD(6), PERIPH_A, 0); /* DATA12 */ -+ select_peripheral(PD(7), PERIPH_A, 0); /* DATA13 */ -+ select_peripheral(PD(8), PERIPH_A, 0); /* DATA14 */ -+ select_peripheral(PD(9), PERIPH_A, 0); /* DATA15 */ -+ select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */ -+ select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */ -+ select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */ -+ select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */ -+ select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */ -+ select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */ -+ select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */ -+ select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */ -+ -+ clk_set_parent(&atmel_lcdfb0_pixclk, &pll0); -+ clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0)); -+ break; -+ -+ default: -+ goto err_invalid_id; -+ } -+ -+ if (fbmem_len) { -+ pdev->resource[2].start = fbmem_start; -+ pdev->resource[2].end = fbmem_start + fbmem_len - 1; -+ pdev->resource[2].flags = IORESOURCE_MEM; -+ } -+ -+ info = pdev->dev.platform_data; -+ memcpy(info, data, sizeof(struct atmel_lcdfb_info)); -+ info->default_monspecs = monspecs; -+ -+ platform_device_register(pdev); -+ return pdev; -+ -+err_invalid_id: -+ kfree(modedb); -+err_dup_modedb: -+ kfree(monspecs); -+ return NULL; -+} -+#endif -+ -+/* -------------------------------------------------------------------- -+ * PWM -+ * -------------------------------------------------------------------- */ -+static struct resource atmel_pwm0_resource[] __initdata = { -+ PBMEM(0xfff01400), -+ IRQ(24), -+}; -+static struct clk atmel_pwm0_mck = { -+ .name = "mck", -+ .parent = &pbb_clk, -+ .mode = pbb_clk_mode, -+ .get_rate = pbb_clk_get_rate, -+ .index = 5, -+}; -+ -+struct platform_device *__init at32_add_device_pwm(u32 mask) -+{ -+ struct platform_device *pdev; -+ -+ if (!mask) -+ return NULL; -+ -+ pdev = platform_device_alloc("atmel_pwm", 0); -+ if (!pdev) -+ return NULL; -+ -+ if (platform_device_add_resources(pdev, atmel_pwm0_resource, -+ ARRAY_SIZE(atmel_pwm0_resource))) -+ goto out_free_pdev; -+ -+ if (platform_device_add_data(pdev, &mask, sizeof(mask))) -+ goto out_free_pdev; -+ -+ if (mask & (1 << 0)) -+ select_peripheral(PA(28), PERIPH_A, 0); -+ if (mask & (1 << 1)) -+ select_peripheral(PA(29), PERIPH_A, 0); -+ if (mask & (1 << 2)) -+ select_peripheral(PA(21), PERIPH_B, 0); -+ if (mask & (1 << 3)) -+ select_peripheral(PA(22), PERIPH_B, 0); -+ -+ atmel_pwm0_mck.dev = &pdev->dev; -+ -+ platform_device_add(pdev); -+ -+ return pdev; -+ -+out_free_pdev: -+ platform_device_put(pdev); -+ return NULL; -+} -+ -+/* -------------------------------------------------------------------- -+ * SSC -+ * -------------------------------------------------------------------- */ -+static struct resource ssc0_resource[] = { -+ PBMEM(0xffe01c00), -+ IRQ(10), -+}; -+DEFINE_DEV(ssc, 0); -+DEV_CLK(pclk, ssc0, pba, 7); -+ -+static struct resource ssc1_resource[] = { -+ PBMEM(0xffe02000), -+ IRQ(11), -+}; -+DEFINE_DEV(ssc, 1); -+DEV_CLK(pclk, ssc1, pba, 8); -+ -+static struct resource ssc2_resource[] = { -+ PBMEM(0xffe02400), -+ IRQ(12), -+}; -+DEFINE_DEV(ssc, 2); -+DEV_CLK(pclk, ssc2, pba, 9); -+ -+struct platform_device *__init -+at32_add_device_ssc(unsigned int id, unsigned int flags) -+{ -+ struct platform_device *pdev; -+ -+ switch (id) { -+ case 0: -+ pdev = &ssc0_device; -+ if (flags & ATMEL_SSC_RF) -+ select_peripheral(PA(21), PERIPH_A, 0); /* RF */ -+ if (flags & ATMEL_SSC_RK) -+ select_peripheral(PA(22), PERIPH_A, 0); /* RK */ -+ if (flags & ATMEL_SSC_TK) -+ select_peripheral(PA(23), PERIPH_A, 0); /* TK */ -+ if (flags & ATMEL_SSC_TF) -+ select_peripheral(PA(24), PERIPH_A, 0); /* TF */ -+ if (flags & ATMEL_SSC_TD) -+ select_peripheral(PA(25), PERIPH_A, 0); /* TD */ -+ if (flags & ATMEL_SSC_RD) -+ select_peripheral(PA(26), PERIPH_A, 0); /* RD */ -+ break; -+ case 1: -+ pdev = &ssc1_device; -+ if (flags & ATMEL_SSC_RF) -+ select_peripheral(PA(0), PERIPH_B, 0); /* RF */ -+ if (flags & ATMEL_SSC_RK) -+ select_peripheral(PA(1), PERIPH_B, 0); /* RK */ -+ if (flags & ATMEL_SSC_TK) -+ select_peripheral(PA(2), PERIPH_B, 0); /* TK */ -+ if (flags & ATMEL_SSC_TF) -+ select_peripheral(PA(3), PERIPH_B, 0); /* TF */ -+ if (flags & ATMEL_SSC_TD) -+ select_peripheral(PA(4), PERIPH_B, 0); /* TD */ -+ if (flags & ATMEL_SSC_RD) -+ select_peripheral(PA(5), PERIPH_B, 0); /* RD */ -+ break; -+ case 2: -+ pdev = &ssc2_device; -+ if (flags & ATMEL_SSC_TD) -+ select_peripheral(PB(13), PERIPH_A, 0); /* TD */ -+ if (flags & ATMEL_SSC_RD) -+ select_peripheral(PB(14), PERIPH_A, 0); /* RD */ -+ if (flags & ATMEL_SSC_TK) -+ select_peripheral(PB(15), PERIPH_A, 0); /* TK */ -+ if (flags & ATMEL_SSC_TF) -+ select_peripheral(PB(16), PERIPH_A, 0); /* TF */ -+ if (flags & ATMEL_SSC_RF) -+ select_peripheral(PB(17), PERIPH_A, 0); /* RF */ -+ if (flags & ATMEL_SSC_RK) -+ select_peripheral(PB(18), PERIPH_A, 0); /* RK */ -+ break; -+ default: -+ return NULL; -+ } -+ -+ platform_device_register(pdev); -+ return pdev; -+} -+ -+/* -------------------------------------------------------------------- -+ * USB Device Controller -+ * -------------------------------------------------------------------- */ -+static struct resource usba0_resource[] __initdata = { -+ { -+ .start = 0xff300000, -+ .end = 0xff3fffff, -+ .flags = IORESOURCE_MEM, -+ }, { -+ .start = 0xfff03000, -+ .end = 0xfff033ff, -+ .flags = IORESOURCE_MEM, -+ }, -+ IRQ(31), -+}; -+static struct clk usba0_pclk = { -+ .name = "pclk", -+ .parent = &pbb_clk, -+ .mode = pbb_clk_mode, -+ .get_rate = pbb_clk_get_rate, -+ .index = 12, -+}; -+static struct clk usba0_hclk = { -+ .name = "hclk", -+ .parent = &hsb_clk, -+ .mode = hsb_clk_mode, -+ .get_rate = hsb_clk_get_rate, -+ .index = 6, -+}; + platform_device_put(pdev); + return NULL; + } +@@ -1097,7 +1353,8 @@ + + struct platform_device *__init + at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data, +- unsigned long fbmem_start, unsigned long fbmem_len) ++ unsigned long fbmem_start, unsigned long fbmem_len, ++ unsigned int pin_config) + { + struct platform_device *pdev; + struct atmel_lcdfb_info *info; +@@ -1124,37 +1381,77 @@ + switch (id) { + case 0: + pdev = &atmel_lcdfb0_device; +- select_peripheral(PC(19), PERIPH_A, 0); /* CC */ +- select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC */ +- select_peripheral(PC(21), PERIPH_A, 0); /* PCLK */ +- select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC */ +- select_peripheral(PC(23), PERIPH_A, 0); /* DVAL */ +- select_peripheral(PC(24), PERIPH_A, 0); /* MODE */ +- select_peripheral(PC(25), PERIPH_A, 0); /* PWR */ +- select_peripheral(PC(26), PERIPH_A, 0); /* DATA0 */ +- select_peripheral(PC(27), PERIPH_A, 0); /* DATA1 */ +- select_peripheral(PC(28), PERIPH_A, 0); /* DATA2 */ +- select_peripheral(PC(29), PERIPH_A, 0); /* DATA3 */ +- select_peripheral(PC(30), PERIPH_A, 0); /* DATA4 */ +- select_peripheral(PC(31), PERIPH_A, 0); /* DATA5 */ +- select_peripheral(PD(0), PERIPH_A, 0); /* DATA6 */ +- select_peripheral(PD(1), PERIPH_A, 0); /* DATA7 */ +- select_peripheral(PD(2), PERIPH_A, 0); /* DATA8 */ +- select_peripheral(PD(3), PERIPH_A, 0); /* DATA9 */ +- select_peripheral(PD(4), PERIPH_A, 0); /* DATA10 */ +- select_peripheral(PD(5), PERIPH_A, 0); /* DATA11 */ +- select_peripheral(PD(6), PERIPH_A, 0); /* DATA12 */ +- select_peripheral(PD(7), PERIPH_A, 0); /* DATA13 */ +- select_peripheral(PD(8), PERIPH_A, 0); /* DATA14 */ +- select_peripheral(PD(9), PERIPH_A, 0); /* DATA15 */ +- select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */ +- select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */ +- select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */ +- select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */ +- select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */ +- select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */ +- select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */ +- select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */ + ++ switch (pin_config) { ++ case 0: ++ select_peripheral(PC(19), PERIPH_A, 0); /* CC */ ++ select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC */ ++ select_peripheral(PC(21), PERIPH_A, 0); /* PCLK */ ++ select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC */ ++ select_peripheral(PC(23), PERIPH_A, 0); /* DVAL */ ++ select_peripheral(PC(24), PERIPH_A, 0); /* MODE */ ++ select_peripheral(PC(25), PERIPH_A, 0); /* PWR */ ++ select_peripheral(PC(26), PERIPH_A, 0); /* DATA0 */ ++ select_peripheral(PC(27), PERIPH_A, 0); /* DATA1 */ ++ select_peripheral(PC(28), PERIPH_A, 0); /* DATA2 */ ++ select_peripheral(PC(29), PERIPH_A, 0); /* DATA3 */ ++ select_peripheral(PC(30), PERIPH_A, 0); /* DATA4 */ ++ select_peripheral(PC(31), PERIPH_A, 0); /* DATA5 */ ++ select_peripheral(PD(0), PERIPH_A, 0); /* DATA6 */ ++ select_peripheral(PD(1), PERIPH_A, 0); /* DATA7 */ ++ select_peripheral(PD(2), PERIPH_A, 0); /* DATA8 */ ++ select_peripheral(PD(3), PERIPH_A, 0); /* DATA9 */ ++ select_peripheral(PD(4), PERIPH_A, 0); /* DATA10 */ ++ select_peripheral(PD(5), PERIPH_A, 0); /* DATA11 */ ++ select_peripheral(PD(6), PERIPH_A, 0); /* DATA12 */ ++ select_peripheral(PD(7), PERIPH_A, 0); /* DATA13 */ ++ select_peripheral(PD(8), PERIPH_A, 0); /* DATA14 */ ++ select_peripheral(PD(9), PERIPH_A, 0); /* DATA15 */ ++ select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */ ++ select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */ ++ select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */ ++ select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */ ++ select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */ ++ select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */ ++ select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */ ++ select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */ ++ break; ++ case 1: ++ select_peripheral(PE(0), PERIPH_B, 0); /* CC */ ++ select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC */ ++ select_peripheral(PC(21), PERIPH_A, 0); /* PCLK */ ++ select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC */ ++ select_peripheral(PE(1), PERIPH_B, 0); /* DVAL */ ++ select_peripheral(PE(2), PERIPH_B, 0); /* MODE */ ++ select_peripheral(PC(25), PERIPH_A, 0); /* PWR */ ++ select_peripheral(PE(3), PERIPH_B, 0); /* DATA0 */ ++ select_peripheral(PE(4), PERIPH_B, 0); /* DATA1 */ ++ select_peripheral(PE(5), PERIPH_B, 0); /* DATA2 */ ++ select_peripheral(PE(6), PERIPH_B, 0); /* DATA3 */ ++ select_peripheral(PE(7), PERIPH_B, 0); /* DATA4 */ ++ select_peripheral(PC(31), PERIPH_A, 0); /* DATA5 */ ++ select_peripheral(PD(0), PERIPH_A, 0); /* DATA6 */ ++ select_peripheral(PD(1), PERIPH_A, 0); /* DATA7 */ ++ select_peripheral(PE(8), PERIPH_B, 0); /* DATA8 */ ++ select_peripheral(PE(9), PERIPH_B, 0); /* DATA9 */ ++ select_peripheral(PE(10), PERIPH_B, 0); /* DATA10 */ ++ select_peripheral(PE(11), PERIPH_B, 0); /* DATA11 */ ++ select_peripheral(PE(12), PERIPH_B, 0); /* DATA12 */ ++ select_peripheral(PD(7), PERIPH_A, 0); /* DATA13 */ ++ select_peripheral(PD(8), PERIPH_A, 0); /* DATA14 */ ++ select_peripheral(PD(9), PERIPH_A, 0); /* DATA15 */ ++ select_peripheral(PE(13), PERIPH_B, 0); /* DATA16 */ ++ select_peripheral(PE(14), PERIPH_B, 0); /* DATA17 */ ++ select_peripheral(PE(15), PERIPH_B, 0); /* DATA18 */ ++ select_peripheral(PE(16), PERIPH_B, 0); /* DATA19 */ ++ select_peripheral(PE(17), PERIPH_B, 0); /* DATA20 */ ++ select_peripheral(PE(18), PERIPH_B, 0); /* DATA21 */ ++ select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */ ++ select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */ ++ break; ++ default: ++ goto err_invalid_id; ++ } + + clk_set_parent(&atmel_lcdfb0_pixclk, &pll0); + clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0)); +@@ -1351,9 +1648,39 @@ + .index = 6, + }; + +#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \ + [idx] = { \ + .name = nam, \ @@ -9847,9 +5917,9 @@ + +#undef EP + -+struct platform_device *__init -+at32_add_device_usba(unsigned int id, struct usba_platform_data *data) -+{ + struct platform_device *__init + at32_add_device_usba(unsigned int id, struct usba_platform_data *data) + { + /* + * pdata doesn't have room for any endpoints, so we need to + * append room for the ones we need right after it. @@ -9858,24 +5928,24 @@ + struct usba_platform_data pdata; + struct usba_ep_data ep[7]; + } usba_data; -+ struct platform_device *pdev; -+ -+ if (id != 0) -+ return NULL; -+ -+ pdev = platform_device_alloc("atmel_usba_udc", 0); -+ if (!pdev) -+ return NULL; -+ -+ if (platform_device_add_resources(pdev, usba0_resource, -+ ARRAY_SIZE(usba0_resource))) -+ goto out_free_pdev; -+ + struct platform_device *pdev; + + if (id != 0) +@@ -1367,13 +1694,20 @@ + ARRAY_SIZE(usba0_resource))) + goto out_free_pdev; + +- if (data) { +- if (platform_device_add_data(pdev, data, sizeof(*data))) +- goto out_free_pdev; + if (data) + usba_data.pdata.vbus_pin = data->vbus_pin; + else + usba_data.pdata.vbus_pin = -EINVAL; -+ + +- if (data->vbus_pin != GPIO_PIN_NONE) +- at32_select_gpio(data->vbus_pin, 0); +- } + data = &usba_data.pdata; + data->num_ep = ARRAY_SIZE(at32_usba_ep); + memcpy(data->ep, at32_usba_ep, sizeof(at32_usba_ep)); @@ -9885,147 +5955,55 @@ + + if (data->vbus_pin >= 0) + at32_select_gpio(data->vbus_pin, 0); -+ -+ usba0_pclk.dev = &pdev->dev; -+ usba0_hclk.dev = &pdev->dev; -+ -+ platform_device_add(pdev); -+ -+ return pdev; -+ -+out_free_pdev: -+ platform_device_put(pdev); -+ return NULL; -+} -+ -+/* -------------------------------------------------------------------- -+ * IDE / CompactFlash + + usba0_pclk.dev = &pdev->dev; + usba0_hclk.dev = &pdev->dev; +@@ -1526,6 +1860,58 @@ + #endif + + /* -------------------------------------------------------------------- ++ * NAND Flash / SmartMedia + * -------------------------------------------------------------------- */ -+#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7001) -+static struct resource at32_smc_cs4_resource[] __initdata = { ++static struct resource smc_cs3_resource[] __initdata = { + { -+ .start = 0x04000000, -+ .end = 0x07ffffff, ++ .start = 0x0c000000, ++ .end = 0x0fffffff, + .flags = IORESOURCE_MEM, -+ }, -+ IRQ(~0UL), /* Magic IRQ will be overridden */ -+}; -+static struct resource at32_smc_cs5_resource[] __initdata = { -+ { -+ .start = 0x20000000, -+ .end = 0x23ffffff, ++ }, { ++ .start = 0xfff03c00, ++ .end = 0xfff03fff, + .flags = IORESOURCE_MEM, + }, -+ IRQ(~0UL), /* Magic IRQ will be overridden */ +}; + -+static int __init at32_init_ide_or_cf(struct platform_device *pdev, -+ unsigned int cs, unsigned int extint) -+{ -+ static unsigned int extint_pin_map[4] __initdata = { -+ GPIO_PIN_PB(25), -+ GPIO_PIN_PB(26), -+ GPIO_PIN_PB(27), -+ GPIO_PIN_PB(28), -+ }; -+ static bool common_pins_initialized __initdata = false; -+ unsigned int extint_pin; -+ int ret; -+ -+ if (extint >= ARRAY_SIZE(extint_pin_map)) -+ return -EINVAL; -+ extint_pin = extint_pin_map[extint]; -+ -+ switch (cs) { -+ case 4: -+ ret = platform_device_add_resources(pdev, -+ at32_smc_cs4_resource, -+ ARRAY_SIZE(at32_smc_cs4_resource)); -+ if (ret) -+ return ret; -+ -+ select_peripheral(PE(21), PERIPH_A, 0); /* NCS4 -> OE_N */ -+ set_ebi_sfr_bits(HMATRIX_BIT(CS4A)); -+ break; -+ case 5: -+ ret = platform_device_add_resources(pdev, -+ at32_smc_cs5_resource, -+ ARRAY_SIZE(at32_smc_cs5_resource)); -+ if (ret) -+ return ret; -+ -+ select_peripheral(PE(22), PERIPH_A, 0); /* NCS5 -> OE_N */ -+ set_ebi_sfr_bits(HMATRIX_BIT(CS5A)); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ if (!common_pins_initialized) { -+ select_peripheral(PE(19), PERIPH_A, 0); /* CFCE1 -> CS0_N */ -+ select_peripheral(PE(20), PERIPH_A, 0); /* CFCE2 -> CS1_N */ -+ select_peripheral(PE(23), PERIPH_A, 0); /* CFRNW -> DIR */ -+ select_peripheral(PE(24), PERIPH_A, 0); /* NWAIT <- IORDY */ -+ common_pins_initialized = true; -+ } -+ -+ at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH); -+ -+ pdev->resource[1].start = EIM_IRQ_BASE + extint; -+ pdev->resource[1].end = pdev->resource[1].start; -+ -+ return 0; -+} -+ +struct platform_device *__init -+at32_add_device_ide(unsigned int id, unsigned int extint, -+ struct ide_platform_data *data) ++at32_add_device_nand(unsigned int id, struct atmel_nand_data *data) +{ + struct platform_device *pdev; + -+ pdev = platform_device_alloc("at32_ide", id); -+ if (!pdev) -+ goto fail; -+ -+ if (platform_device_add_data(pdev, data, -+ sizeof(struct ide_platform_data))) -+ goto fail; -+ -+ if (at32_init_ide_or_cf(pdev, data->cs, extint)) -+ goto fail; -+ -+ platform_device_add(pdev); -+ return pdev; -+ -+fail: -+ platform_device_put(pdev); -+ return NULL; -+} -+ -+struct platform_device *__init -+at32_add_device_cf(unsigned int id, unsigned int extint, -+ struct cf_platform_data *data) -+{ -+ struct platform_device *pdev; ++ if (id != 0 || !data) ++ return NULL; + -+ pdev = platform_device_alloc("at32_cf", id); ++ pdev = platform_device_alloc("atmel_nand", id); + if (!pdev) + goto fail; + -+ if (platform_device_add_data(pdev, data, -+ sizeof(struct cf_platform_data))) ++ if (platform_device_add_resources(pdev, smc_cs3_resource, ++ ARRAY_SIZE(smc_cs3_resource))) + goto fail; + -+ if (at32_init_ide_or_cf(pdev, data->cs, extint)) ++ if (platform_device_add_data(pdev, data, ++ sizeof(struct atmel_nand_data))) + goto fail; + -+ if (data->detect_pin != GPIO_PIN_NONE) -+ at32_select_gpio(data->detect_pin, AT32_GPIOF_DEGLITCH); -+ if (data->reset_pin != GPIO_PIN_NONE) -+ at32_select_gpio(data->reset_pin, 0); -+ if (data->vcc_pin != GPIO_PIN_NONE) -+ at32_select_gpio(data->vcc_pin, 0); -+ /* READY is used as extint, so we can't select it as gpio */ ++ set_ebi_sfr_bits(HMATRIX_BIT(CS3A)); ++ if (data->enable_pin) ++ at32_select_gpio(data->enable_pin, ++ AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); ++ if (data->rdy_pin) ++ at32_select_gpio(data->rdy_pin, 0); ++ if (data->det_pin) ++ at32_select_gpio(data->det_pin, 0); + + platform_device_add(pdev); + return pdev; @@ -10034,218 +6012,55 @@ + platform_device_put(pdev); + return NULL; +} -+#endif + +/* -------------------------------------------------------------------- -+ * AC97C -+ * -------------------------------------------------------------------- */ -+static struct resource atmel_ac97c0_resource[] __initdata = { -+ PBMEM(0xfff02800), -+ IRQ(29), -+}; -+static struct clk atmel_ac97c0_pclk = { -+ .name = "pclk", -+ .parent = &pbb_clk, -+ .mode = pbb_clk_mode, -+ .get_rate = pbb_clk_get_rate, -+ .index = 10, -+}; -+ -+struct platform_device *__init at32_add_device_ac97c(unsigned int id) -+{ -+ struct platform_device *pdev; -+ -+ if (id != 0) -+ return NULL; -+ -+ pdev = platform_device_alloc("atmel_ac97c", id); -+ if (!pdev) -+ return NULL; -+ -+ if (platform_device_add_resources(pdev, atmel_ac97c0_resource, -+ ARRAY_SIZE(atmel_ac97c0_resource))) -+ goto err_add_resources; -+ -+ select_peripheral(PB(20), PERIPH_B, 0); /* SYNC */ -+ select_peripheral(PB(21), PERIPH_B, 0); /* SDO */ -+ select_peripheral(PB(22), PERIPH_B, 0); /* SDI */ -+ select_peripheral(PB(23), PERIPH_B, 0); /* SCLK */ -+ -+ atmel_ac97c0_pclk.dev = &pdev->dev; -+ -+ platform_device_add(pdev); -+ return pdev; -+ -+err_add_resources: -+ platform_device_put(pdev); -+ return NULL; -+} -+ -+/* -------------------------------------------------------------------- -+ * ABDAC -+ * -------------------------------------------------------------------- */ -+static struct resource abdac0_resource[] __initdata = { -+ PBMEM(0xfff02000), -+ IRQ(27), -+}; -+static struct clk abdac0_pclk = { -+ .name = "pclk", -+ .parent = &pbb_clk, -+ .mode = pbb_clk_mode, -+ .get_rate = pbb_clk_get_rate, -+ .index = 8, -+}; -+static struct clk abdac0_sample_clk = { -+ .name = "sample_clk", -+ .mode = genclk_mode, -+ .get_rate = genclk_get_rate, -+ .set_rate = genclk_set_rate, -+ .set_parent = genclk_set_parent, -+ .index = 6, -+}; -+ -+struct platform_device *__init at32_add_device_abdac(unsigned int id) -+{ -+ struct platform_device *pdev; -+ -+ if (id != 0) -+ return NULL; -+ -+ pdev = platform_device_alloc("abdac", id); -+ if (!pdev) -+ return NULL; -+ -+ if (platform_device_add_resources(pdev, abdac0_resource, -+ ARRAY_SIZE(abdac0_resource))) -+ goto err_add_resources; -+ -+ select_peripheral(PB(20), PERIPH_A, 0); /* DATA1 */ -+ select_peripheral(PB(21), PERIPH_A, 0); /* DATA0 */ -+ select_peripheral(PB(22), PERIPH_A, 0); /* DATAN1 */ -+ select_peripheral(PB(23), PERIPH_A, 0); /* DATAN0 */ -+ -+ abdac0_pclk.dev = &pdev->dev; -+ abdac0_sample_clk.dev = &pdev->dev; -+ -+ platform_device_add(pdev); -+ return pdev; -+ -+err_add_resources: -+ platform_device_put(pdev); -+ return NULL; -+} -+ -+/* -------------------------------------------------------------------- -+ * GCLK -+ * -------------------------------------------------------------------- */ -+static struct clk gclk0 = { -+ .name = "gclk0", -+ .mode = genclk_mode, -+ .get_rate = genclk_get_rate, -+ .set_rate = genclk_set_rate, -+ .set_parent = genclk_set_parent, -+ .index = 0, -+}; -+static struct clk gclk1 = { -+ .name = "gclk1", -+ .mode = genclk_mode, -+ .get_rate = genclk_get_rate, -+ .set_rate = genclk_set_rate, -+ .set_parent = genclk_set_parent, -+ .index = 1, -+}; -+static struct clk gclk2 = { -+ .name = "gclk2", -+ .mode = genclk_mode, -+ .get_rate = genclk_get_rate, -+ .set_rate = genclk_set_rate, -+ .set_parent = genclk_set_parent, -+ .index = 2, -+}; -+static struct clk gclk3 = { -+ .name = "gclk3", -+ .mode = genclk_mode, -+ .get_rate = genclk_get_rate, -+ .set_rate = genclk_set_rate, -+ .set_parent = genclk_set_parent, -+ .index = 3, -+}; -+static struct clk gclk4 = { -+ .name = "gclk4", -+ .mode = genclk_mode, -+ .get_rate = genclk_get_rate, -+ .set_rate = genclk_set_rate, -+ .set_parent = genclk_set_parent, -+ .index = 4, -+}; -+ -+struct clk *at32_clock_list[] = { -+ &osc32k, -+ &osc0, -+ &osc1, -+ &pll0, -+ &pll1, -+ &cpu_clk, -+ &hsb_clk, -+ &pba_clk, -+ &pbb_clk, -+ &at32_pm_pclk, -+ &at32_intc0_pclk, -+ &hmatrix_clk, -+ &ebi_clk, -+ &hramc_clk, -+ &smc0_pclk, -+ &smc0_mck, -+ &pdc_hclk, -+ &pdc_pclk, -+ &dmaca0_hclk, -+ &pico_clk, -+ &pio0_mck, -+ &pio1_mck, -+ &pio2_mck, -+ &pio3_mck, -+ &pio4_mck, + * AC97C + * -------------------------------------------------------------------- */ + static struct resource atmel_ac97c0_resource[] __initdata = { +@@ -1683,6 +2069,7 @@ + &hmatrix_clk, + &ebi_clk, + &hramc_clk, ++ &sdramc_clk, + &smc0_pclk, + &smc0_mck, + &pdc_hclk, +@@ -1694,7 +2081,10 @@ + &pio2_mck, + &pio3_mck, + &pio4_mck, +- &at32_systc0_pclk, + &at32_tcb0_t0_clk, + &at32_tcb1_t0_clk, + &atmel_psif0_pclk, + &atmel_psif1_pclk, -+ &atmel_usart0_usart, -+ &atmel_usart1_usart, -+ &atmel_usart2_usart, -+ &atmel_usart3_usart, -+ &atmel_pwm0_mck, -+#if defined(CONFIG_CPU_AT32AP7000) -+ &macb0_hclk, -+ &macb0_pclk, -+ &macb1_hclk, -+ &macb1_pclk, -+#endif -+ &atmel_spi0_spi_clk, -+ &atmel_spi1_spi_clk, -+ &atmel_twi0_pclk, -+ &atmel_mci0_pclk, -+#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002) -+ &atmel_lcdfb0_hck1, -+ &atmel_lcdfb0_pixclk, -+#endif -+ &ssc0_pclk, -+ &ssc1_pclk, -+ &ssc2_pclk, -+ &usba0_hclk, -+ &usba0_pclk, -+ &atmel_ac97c0_pclk, -+ &abdac0_pclk, -+ &abdac0_sample_clk, -+ &gclk0, -+ &gclk1, -+ &gclk2, -+ &gclk3, -+ &gclk4, -+}; -+unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list); + &atmel_usart0_usart, + &atmel_usart1_usart, + &atmel_usart2_usart, +@@ -1730,16 +2120,7 @@ + }; + unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list); + +-void __init at32_portmux_init(void) +-{ +- at32_init_pio(&pio0_device); +- at32_init_pio(&pio1_device); +- at32_init_pio(&pio2_device); +- at32_init_pio(&pio3_device); +- at32_init_pio(&pio4_device); +-} +- +-void __init at32_clock_init(void) ++void __init setup_platform(void) + { + u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0; + int i; +@@ -1794,4 +2175,36 @@ + pm_writel(HSB_MASK, hsb_mask); + pm_writel(PBA_MASK, pba_mask); + pm_writel(PBB_MASK, pbb_mask); + -+void __init at32_portmux_init(void) -+{ ++ /* Initialize the port muxes */ + at32_init_pio(&pio0_device); + at32_init_pio(&pio1_device); + at32_init_pio(&pio2_device); @@ -10253,187 +6068,103 @@ + at32_init_pio(&pio4_device); +} + -+void __init at32_clock_init(void) ++struct gen_pool *sram_pool; ++ ++static int __init sram_init(void) +{ -+ u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0; -+ int i; ++ struct gen_pool *pool; + -+ if (pm_readl(MCCTRL) & PM_BIT(PLLSEL)) { -+ main_clock = &pll0; -+ cpu_clk.parent = &pll0; -+ } else { -+ main_clock = &osc0; -+ cpu_clk.parent = &osc0; -+ } -+ -+ if (pm_readl(PLL0) & PM_BIT(PLLOSC)) -+ pll0.parent = &osc1; -+ if (pm_readl(PLL1) & PM_BIT(PLLOSC)) -+ pll1.parent = &osc1; -+ -+ genclk_init_parent(&gclk0); -+ genclk_init_parent(&gclk1); -+ genclk_init_parent(&gclk2); -+ genclk_init_parent(&gclk3); -+ genclk_init_parent(&gclk4); -+#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002) -+ genclk_init_parent(&atmel_lcdfb0_pixclk); -+#endif -+ genclk_init_parent(&abdac0_sample_clk); ++ /* 1KiB granularity */ ++ pool = gen_pool_create(10, -1); ++ if (!pool) ++ goto fail; + -+ /* -+ * Turn on all clocks that have at least one user already, and -+ * turn off everything else. We only do this for module -+ * clocks, and even though it isn't particularly pretty to -+ * check the address of the mode function, it should do the -+ * trick... -+ */ -+ for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) { -+ struct clk *clk = at32_clock_list[i]; ++ if (gen_pool_add(pool, 0x24000000, 0x8000, -1)) ++ goto err_pool_add; + -+ if (clk->users == 0) -+ continue; ++ sram_pool = pool; ++ return 0; + -+ if (clk->mode == &cpu_clk_mode) -+ cpu_mask |= 1 << clk->index; -+ else if (clk->mode == &hsb_clk_mode) -+ hsb_mask |= 1 << clk->index; -+ else if (clk->mode == &pba_clk_mode) -+ pba_mask |= 1 << clk->index; -+ else if (clk->mode == &pbb_clk_mode) -+ pbb_mask |= 1 << clk->index; -+ } -+ -+ pm_writel(CPU_MASK, cpu_mask); -+ pm_writel(HSB_MASK, hsb_mask); -+ pm_writel(PBA_MASK, pba_mask); -+ pm_writel(PBB_MASK, pbb_mask); -+} ---- a/arch/avr32/mach-at32ap/extint.c -+++ b/arch/avr32/mach-at32ap/extint.c -@@ -26,16 +26,10 @@ - #define EIC_MODE 0x0014 - #define EIC_EDGE 0x0018 - #define EIC_LEVEL 0x001c --#define EIC_TEST 0x0020 - #define EIC_NMIC 0x0024 - --/* Bitfields in TEST */ --#define EIC_TESTEN_OFFSET 31 --#define EIC_TESTEN_SIZE 1 ++err_pool_add: ++ gen_pool_destroy(pool); ++fail: ++ pr_err("Failed to create SRAM pool\n"); ++ return -ENOMEM; + } ++core_initcall(sram_init); +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/at32ap.c avr32-2.6/arch/avr32/mach-at32ap/at32ap.c +--- linux-2.6.25.6/arch/avr32/mach-at32ap/at32ap.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/mach-at32ap/at32ap.c 1970-01-01 01:00:00.000000000 +0100 +@@ -1,56 +0,0 @@ +-/* +- * Copyright (C) 2006 Atmel Corporation +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- */ - - /* Bitfields in NMIC */ --#define EIC_EN_OFFSET 0 --#define EIC_EN_SIZE 1 -+#define EIC_NMIC_ENABLE (1 << 0) - - /* Bit manipulation macros */ - #define EIC_BIT(name) \ -@@ -63,6 +57,9 @@ - unsigned int first_irq; - }; - -+static struct eic *nmi_eic; -+static bool nmi_enabled; -+ - static void eic_ack_irq(unsigned int irq) - { - struct eic *eic = get_irq_chip_data(irq); -@@ -133,8 +130,11 @@ - eic_writel(eic, EDGE, edge); - eic_writel(eic, LEVEL, level); - -- if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) -+ if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) { - flow_type |= IRQ_LEVEL; -+ __set_irq_handler_unlocked(irq, handle_level_irq); -+ } else -+ __set_irq_handler_unlocked(irq, handle_edge_irq); - desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); - desc->status |= flow_type; - } -@@ -154,9 +154,8 @@ - static void demux_eic_irq(unsigned int irq, struct irq_desc *desc) +-#include <linux/clk.h> +-#include <linux/err.h> +-#include <linux/init.h> +-#include <linux/platform_device.h> +- +-#include <asm/arch/init.h> +- +-void __init setup_platform(void) +-{ +- at32_clock_init(); +- at32_portmux_init(); +-} +- +-static int __init pdc_probe(struct platform_device *pdev) +-{ +- struct clk *pclk, *hclk; +- +- pclk = clk_get(&pdev->dev, "pclk"); +- if (IS_ERR(pclk)) { +- dev_err(&pdev->dev, "no pclk defined\n"); +- return PTR_ERR(pclk); +- } +- hclk = clk_get(&pdev->dev, "hclk"); +- if (IS_ERR(hclk)) { +- dev_err(&pdev->dev, "no hclk defined\n"); +- clk_put(pclk); +- return PTR_ERR(hclk); +- } +- +- clk_enable(pclk); +- clk_enable(hclk); +- +- dev_info(&pdev->dev, "Atmel Peripheral DMA Controller enabled\n"); +- return 0; +-} +- +-static struct platform_driver pdc_driver = { +- .probe = pdc_probe, +- .driver = { +- .name = "pdc", +- }, +-}; +- +-static int __init pdc_init(void) +-{ +- return platform_driver_register(&pdc_driver); +-} +-arch_initcall(pdc_init); +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/cpufreq.c avr32-2.6/arch/avr32/mach-at32ap/cpufreq.c +--- linux-2.6.25.6/arch/avr32/mach-at32ap/cpufreq.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/mach-at32ap/cpufreq.c 2008-06-12 15:03:55.891816030 +0200 +@@ -108,5 +108,4 @@ { - struct eic *eic = desc->handler_data; -- struct irq_desc *ext_desc; - unsigned long status, pending; -- unsigned int i, ext_irq; -+ unsigned int i; - - status = eic_readl(eic, ISR); - pending = status & eic_readl(eic, IMR); -@@ -165,15 +164,28 @@ - i = fls(pending) - 1; - pending &= ~(1 << i); - -- ext_irq = i + eic->first_irq; -- ext_desc = irq_desc + ext_irq; -- if (ext_desc->status & IRQ_LEVEL) -- handle_level_irq(ext_irq, ext_desc); -- else -- handle_edge_irq(ext_irq, ext_desc); -+ generic_handle_irq(i + eic->first_irq); - } + return cpufreq_register_driver(&at32_driver); } - -+int nmi_enable(void) -+{ -+ nmi_enabled = true; -+ -+ if (nmi_eic) -+ eic_writel(nmi_eic, NMIC, EIC_NMIC_ENABLE); -+ -+ return 0; -+} -+ -+void nmi_disable(void) -+{ -+ if (nmi_eic) -+ eic_writel(nmi_eic, NMIC, 0); -+ -+ nmi_enabled = false; -+} -+ - static int __init eic_probe(struct platform_device *pdev) - { - struct eic *eic; -@@ -214,14 +226,13 @@ - pattern = eic_readl(eic, MODE); - nr_irqs = fls(pattern); - -- /* Trigger on falling edge unless overridden by driver */ -- eic_writel(eic, MODE, 0UL); -+ /* Trigger on low level unless overridden by driver */ - eic_writel(eic, EDGE, 0UL); -+ eic_writel(eic, LEVEL, 0UL); - - eic->chip = &eic_chip; - - for (i = 0; i < nr_irqs; i++) { -- /* NOTE the handler we set here is ignored by the demux */ - set_irq_chip_and_handler(eic->first_irq + i, &eic_chip, - handle_level_irq); - set_irq_chip_data(eic->first_irq + i, eic); -@@ -230,6 +241,16 @@ - set_irq_chained_handler(int_irq, demux_eic_irq); - set_irq_data(int_irq, eic); - -+ if (pdev->id == 0) { -+ nmi_eic = eic; -+ if (nmi_enabled) -+ /* -+ * Someone tried to enable NMI before we were -+ * ready. Do it now. -+ */ -+ nmi_enable(); -+ } -+ - dev_info(&pdev->dev, - "External Interrupt Controller at 0x%p, IRQ %u\n", - eic->regs, int_irq); ---- /dev/null -+++ b/arch/avr32/mach-at32ap/gpio-dev.c +- +-arch_initcall(at32_cpufreq_init); ++late_initcall(at32_cpufreq_init); +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/gpio-dev.c avr32-2.6/arch/avr32/mach-at32ap/gpio-dev.c +--- linux-2.6.25.6/arch/avr32/mach-at32ap/gpio-dev.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/arch/avr32/mach-at32ap/gpio-dev.c 2008-06-12 15:09:38.723815860 +0200 @@ -0,0 +1,573 @@ +/* + * GPIO /dev and configfs interface @@ -11008,46 +6739,128 @@ + return err; +} +late_initcall(gpio_dev_init); ---- a/arch/avr32/mach-at32ap/intc.c -+++ b/arch/avr32/mach-at32ap/intc.c -@@ -13,7 +13,6 @@ +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/hsmc.c avr32-2.6/arch/avr32/mach-at32ap/hsmc.c +--- linux-2.6.25.6/arch/avr32/mach-at32ap/hsmc.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/mach-at32ap/hsmc.c 2008-06-12 15:09:38.723815860 +0200 +@@ -278,4 +278,4 @@ + { + return platform_driver_register(&hsmc_driver); + } +-arch_initcall(hsmc_init); ++core_initcall(hsmc_init); +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/intc.c avr32-2.6/arch/avr32/mach-at32ap/intc.c +--- linux-2.6.25.6/arch/avr32/mach-at32ap/intc.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/mach-at32ap/intc.c 2008-06-12 15:09:38.723815860 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2006 Atmel Corporation ++ * Copyright (C) 2006, 2008 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as +@@ -12,15 +12,20 @@ + #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/platform_device.h> ++#include <linux/sysdev.h> -#include <asm/intc.h> #include <asm/io.h> #include "intc.h" ---- a/arch/avr32/mach-at32ap/Kconfig -+++ b/arch/avr32/mach-at32ap/Kconfig -@@ -3,9 +3,9 @@ - menu "Atmel AVR32 AP options" - - choice -- prompt "AT32AP7000 static memory bus width" -- depends on CPU_AT32AP7000 -- default AP7000_16_BIT_SMC -+ prompt "AT32AP700x static memory bus width" -+ depends on CPU_AT32AP700X -+ default AP700X_16_BIT_SMC - help - Define the width of the AP7000 external static memory interface. - This is used to determine how to mangle the address and/or data -@@ -15,17 +15,24 @@ - width for all chip selects, excluding the flash (which is using - raw access and is thus not affected by any of this.) --config AP7000_32_BIT_SMC -+config AP700X_32_BIT_SMC - bool "32 bit" + struct intc { +- void __iomem *regs; +- struct irq_chip chip; ++ void __iomem *regs; ++ struct irq_chip chip; ++ struct sys_device sysdev; ++#ifdef CONFIG_PM ++ unsigned long suspend_ipr; ++ unsigned long saved_ipr[64]; ++#endif + }; --config AP7000_16_BIT_SMC -+config AP700X_16_BIT_SMC - bool "16 bit" + extern struct platform_device at32_intc0_device; +@@ -137,6 +142,74 @@ + panic("Interrupt controller initialization failed!\n"); + } --config AP7000_8_BIT_SMC -+config AP700X_8_BIT_SMC - bool "8 bit" ++#ifdef CONFIG_PM ++void intc_set_suspend_handler(unsigned long offset) ++{ ++ intc0.suspend_ipr = offset; ++} ++ ++static int intc_suspend(struct sys_device *sdev, pm_message_t state) ++{ ++ struct intc *intc = container_of(sdev, struct intc, sysdev); ++ int i; ++ ++ if (unlikely(!irqs_disabled())) { ++ pr_err("intc_suspend: called with interrupts enabled\n"); ++ return -EINVAL; ++ } ++ ++ if (unlikely(!intc->suspend_ipr)) { ++ pr_err("intc_suspend: suspend_ipr not initialized\n"); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < 64; i++) { ++ intc->saved_ipr[i] = intc_readl(intc, INTPR0 + 4 * i); ++ intc_writel(intc, INTPR0 + 4 * i, intc->suspend_ipr); ++ } ++ ++ return 0; ++} ++ ++static int intc_resume(struct sys_device *sdev) ++{ ++ struct intc *intc = container_of(sdev, struct intc, sysdev); ++ int i; ++ ++ WARN_ON(!irqs_disabled()); ++ ++ for (i = 0; i < 64; i++) ++ intc_writel(intc, INTPR0 + 4 * i, intc->saved_ipr[i]); ++ ++ return 0; ++} ++#else ++#define intc_suspend NULL ++#define intc_resume NULL ++#endif ++ ++static struct sysdev_class intc_class = { ++ .name = "intc", ++ .suspend = intc_suspend, ++ .resume = intc_resume, ++}; ++ ++static int __init intc_init_sysdev(void) ++{ ++ int ret; ++ ++ ret = sysdev_class_register(&intc_class); ++ if (ret) ++ return ret; ++ ++ intc0.sysdev.id = 0; ++ intc0.sysdev.cls = &intc_class; ++ ret = sysdev_register(&intc0.sysdev); ++ ++ return ret; ++} ++device_initcall(intc_init_sysdev); ++ + unsigned long intc_get_pending(unsigned int group) + { + return intc_readl(&intc0, INTREQ0 + 4 * group); +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/Kconfig avr32-2.6/arch/avr32/mach-at32ap/Kconfig +--- linux-2.6.25.6/arch/avr32/mach-at32ap/Kconfig 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/mach-at32ap/Kconfig 2008-06-12 15:09:38.719815350 +0200 +@@ -26,6 +26,13 @@ endchoice @@ -11061,18 +6874,78 @@ endmenu endif # PLATFORM_AT32AP ---- a/arch/avr32/mach-at32ap/Makefile -+++ b/arch/avr32/mach-at32ap/Makefile -@@ -1,4 +1,4 @@ - obj-y += at32ap.o clock.o intc.o extint.o pio.o hsmc.o --obj-$(CONFIG_CPU_AT32AP7000) += at32ap7000.o --obj-$(CONFIG_CPU_AT32AP7000) += time-tc.o +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/Makefile avr32-2.6/arch/avr32/mach-at32ap/Makefile +--- linux-2.6.25.6/arch/avr32/mach-at32ap/Makefile 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/mach-at32ap/Makefile 2008-06-12 15:09:38.719815350 +0200 +@@ -1,4 +1,9 @@ +-obj-y += at32ap.o clock.o intc.o extint.o pio.o hsmc.o +-obj-$(CONFIG_CPU_AT32AP700X) += at32ap700x.o +-obj-$(CONFIG_CPU_AT32AP700X) += time-tc.o ++obj-y += pdc.o clock.o intc.o extint.o pio.o hsmc.o +obj-$(CONFIG_CPU_AT32AP700X) += at32ap700x.o pm-at32ap700x.o obj-$(CONFIG_CPU_FREQ_AT32AP) += cpufreq.o +obj-$(CONFIG_GPIO_DEV) += gpio-dev.o ---- a/arch/avr32/mach-at32ap/pio.c -+++ b/arch/avr32/mach-at32ap/pio.c -@@ -162,6 +162,82 @@ ++obj-$(CONFIG_PM) += pm.o ++ ++ifeq ($(CONFIG_PM_DEBUG),y) ++CFLAGS_pm.o += -DDEBUG ++endif +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/pdc.c avr32-2.6/arch/avr32/mach-at32ap/pdc.c +--- linux-2.6.25.6/arch/avr32/mach-at32ap/pdc.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/arch/avr32/mach-at32ap/pdc.c 2008-06-12 15:09:38.723815860 +0200 +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (C) 2006 Atmel Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/clk.h> ++#include <linux/err.h> ++#include <linux/init.h> ++#include <linux/platform_device.h> ++ ++static int __init pdc_probe(struct platform_device *pdev) ++{ ++ struct clk *pclk, *hclk; ++ ++ pclk = clk_get(&pdev->dev, "pclk"); ++ if (IS_ERR(pclk)) { ++ dev_err(&pdev->dev, "no pclk defined\n"); ++ return PTR_ERR(pclk); ++ } ++ hclk = clk_get(&pdev->dev, "hclk"); ++ if (IS_ERR(hclk)) { ++ dev_err(&pdev->dev, "no hclk defined\n"); ++ clk_put(pclk); ++ return PTR_ERR(hclk); ++ } ++ ++ clk_enable(pclk); ++ clk_enable(hclk); ++ ++ dev_info(&pdev->dev, "Atmel Peripheral DMA Controller enabled\n"); ++ return 0; ++} ++ ++static struct platform_driver pdc_driver = { ++ .probe = pdc_probe, ++ .driver = { ++ .name = "pdc", ++ }, ++}; ++ ++static int __init pdc_init(void) ++{ ++ return platform_driver_register(&pdc_driver); ++} ++arch_initcall(pdc_init); +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/pio.c avr32-2.6/arch/avr32/mach-at32ap/pio.c +--- linux-2.6.25.6/arch/avr32/mach-at32ap/pio.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/mach-at32ap/pio.c 2008-06-12 15:09:38.723815860 +0200 +@@ -157,6 +157,82 @@ dump_stack(); } @@ -11155,9 +7028,19 @@ /*--------------------------------------------------------------------------*/ /* GPIO API */ ---- /dev/null -+++ b/arch/avr32/mach-at32ap/pm-at32ap700x.S -@@ -0,0 +1,66 @@ +@@ -318,6 +394,8 @@ + const char *label; + + label = gpiochip_is_requested(chip, i); ++ if (!label && (imr & mask)) ++ label = "[irq]"; + if (!label) + continue; + +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/pm-at32ap700x.S avr32-2.6/arch/avr32/mach-at32ap/pm-at32ap700x.S +--- linux-2.6.25.6/arch/avr32/mach-at32ap/pm-at32ap700x.S 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/arch/avr32/mach-at32ap/pm-at32ap700x.S 2008-06-12 15:09:38.723815860 +0200 +@@ -0,0 +1,174 @@ +/* + * Low-level Power Management code. + * @@ -11172,6 +7055,12 @@ +#include <asm/thread_info.h> +#include <asm/arch/pm.h> + ++#include "pm.h" ++#include "sdramc.h" ++ ++/* Same as 0xfff00000 but fits in a 21 bit signed immediate */ ++#define PM_BASE -0x100000 ++ + .section .bss, "wa", @nobits + .global disable_idle_sleep + .type disable_idle_sleep, @object @@ -11224,8 +7113,440 @@ + unmask_interrupts + retal r12 + .size cpu_idle_skip_sleep, . - cpu_idle_skip_sleep ---- a/arch/avr32/mach-at32ap/time-tc.c -+++ /dev/null ++ ++#ifdef CONFIG_PM ++ .section .init.text, "ax", @progbits ++ ++ .global pm_exception ++ .type pm_exception, @function ++pm_exception: ++ /* ++ * Exceptions are masked when we switch to this handler, so ++ * we'll only get "unrecoverable" exceptions (offset 0.) ++ */ ++ sub r12, pc, . - .Lpanic_msg ++ lddpc pc, .Lpanic_addr ++ ++ .align 2 ++.Lpanic_addr: ++ .long panic ++.Lpanic_msg: ++ .asciz "Unrecoverable exception during suspend\n" ++ .size pm_exception, . - pm_exception ++ ++ .global pm_irq0 ++ .type pm_irq0, @function ++pm_irq0: ++ /* Disable interrupts and return after the sleep instruction */ ++ mfsr r9, SYSREG_RSR_INT0 ++ mtsr SYSREG_RAR_INT0, r8 ++ sbr r9, SYSREG_GM_OFFSET ++ mtsr SYSREG_RSR_INT0, r9 ++ rete ++ ++ /* ++ * void cpu_enter_standby(unsigned long sdramc_base) ++ * ++ * Enter PM_SUSPEND_STANDBY mode. At this point, all drivers ++ * are suspended and interrupts are disabled. Interrupts ++ * marked as 'wakeup' event sources may still come along and ++ * get us out of here. ++ * ++ * The SDRAM will be put into self-refresh mode (which does ++ * not require a clock from the CPU), and the CPU will be put ++ * into "frozen" mode (HSB bus stopped). The SDRAM controller ++ * will automatically bring the SDRAM into normal mode on the ++ * first access, and the power manager will automatically ++ * start the HSB and CPU clocks upon a wakeup event. ++ * ++ * This code uses the same "skip sleep" technique as above. ++ * It is very important that we jump directly to ++ * cpu_after_sleep after the sleep instruction since that's ++ * where we'll end up if the interrupt handler decides that we ++ * need to skip the sleep instruction. ++ */ ++ .global pm_standby ++ .type pm_standby, @function ++pm_standby: ++ /* ++ * interrupts are already masked at this point, and EVBA ++ * points to pm_exception above. ++ */ ++ ld.w r10, r12[SDRAMC_LPR] ++ sub r8, pc, . - 1f /* return address for irq handler */ ++ mov r11, SDRAMC_LPR_LPCB_SELF_RFR ++ bfins r10, r11, 0, 2 /* LPCB <- self Refresh */ ++ sync 0 /* flush write buffer */ ++ st.w r12[SDRAMC_LPR], r11 /* put SDRAM in self-refresh mode */ ++ ld.w r11, r12[SDRAMC_LPR] ++ unmask_interrupts ++ sleep CPU_SLEEP_FROZEN ++1: mask_interrupts ++ retal r12 ++ .size pm_standby, . - pm_standby ++ ++ .global pm_suspend_to_ram ++ .type pm_suspend_to_ram, @function ++pm_suspend_to_ram: ++ /* ++ * interrupts are already masked at this point, and EVBA ++ * points to pm_exception above. ++ */ ++ mov r11, 0 ++ cache r11[2], 8 /* clean all dcache lines */ ++ sync 0 /* flush write buffer */ ++ ld.w r10, r12[SDRAMC_LPR] ++ sub r8, pc, . - 1f /* return address for irq handler */ ++ mov r11, SDRAMC_LPR_LPCB_SELF_RFR ++ bfins r10, r11, 0, 2 /* LPCB <- self refresh */ ++ st.w r12[SDRAMC_LPR], r10 /* put SDRAM in self-refresh mode */ ++ ld.w r11, r12[SDRAMC_LPR] ++ ++ unmask_interrupts ++ sleep CPU_SLEEP_STOP ++1: mask_interrupts ++ ++ retal r12 ++ .size pm_suspend_to_ram, . - pm_suspend_to_ram ++ ++ .global pm_sram_end ++ .type pm_sram_end, @function ++pm_sram_end: ++ .size pm_sram_end, 0 ++ ++#endif /* CONFIG_PM */ +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/pm.c avr32-2.6/arch/avr32/mach-at32ap/pm.c +--- linux-2.6.25.6/arch/avr32/mach-at32ap/pm.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/arch/avr32/mach-at32ap/pm.c 2008-06-12 15:09:38.723815860 +0200 +@@ -0,0 +1,245 @@ ++/* ++ * AVR32 AP Power Management ++ * ++ * Copyright (C) 2008 Atmel Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ */ ++#include <linux/io.h> ++#include <linux/suspend.h> ++#include <linux/vmalloc.h> ++ ++#include <asm/cacheflush.h> ++#include <asm/sysreg.h> ++ ++#include <asm/arch/pm.h> ++#include <asm/arch/sram.h> ++ ++/* FIXME: This is only valid for AP7000 */ ++#define SDRAMC_BASE 0xfff03800 ++ ++#include "sdramc.h" ++ ++#define SRAM_PAGE_FLAGS (SYSREG_BIT(TLBELO_D) | SYSREG_BF(SZ, 1) \ ++ | SYSREG_BF(AP, 3) | SYSREG_BIT(G)) ++ ++ ++static unsigned long pm_sram_start; ++static size_t pm_sram_size; ++static struct vm_struct *pm_sram_area; ++ ++static void (*avr32_pm_enter_standby)(unsigned long sdramc_base); ++static void (*avr32_pm_enter_str)(unsigned long sdramc_base); ++ ++/* ++ * Must be called with interrupts disabled. Exceptions will be masked ++ * on return (i.e. all exceptions will be "unrecoverable".) ++ */ ++static void *avr32_pm_map_sram(void) ++{ ++ unsigned long vaddr; ++ unsigned long page_addr; ++ u32 tlbehi; ++ u32 mmucr; ++ ++ vaddr = (unsigned long)pm_sram_area->addr; ++ page_addr = pm_sram_start & PAGE_MASK; ++ ++ /* ++ * Mask exceptions and grab the first TLB entry. We won't be ++ * needing it while sleeping. ++ */ ++ asm volatile("ssrf %0" : : "i"(SYSREG_EM_OFFSET) : "memory"); ++ ++ mmucr = sysreg_read(MMUCR); ++ tlbehi = sysreg_read(TLBEHI); ++ sysreg_write(MMUCR, SYSREG_BFINS(DRP, 0, mmucr)); ++ ++ tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi)); ++ tlbehi |= vaddr & PAGE_MASK; ++ tlbehi |= SYSREG_BIT(TLBEHI_V); ++ ++ sysreg_write(TLBELO, page_addr | SRAM_PAGE_FLAGS); ++ sysreg_write(TLBEHI, tlbehi); ++ __builtin_tlbw(); ++ ++ return (void *)(vaddr + pm_sram_start - page_addr); ++} ++ ++/* ++ * Must be called with interrupts disabled. Exceptions will be ++ * unmasked on return. ++ */ ++static void avr32_pm_unmap_sram(void) ++{ ++ u32 mmucr; ++ u32 tlbehi; ++ u32 tlbarlo; ++ ++ /* Going to update TLB entry at index 0 */ ++ mmucr = sysreg_read(MMUCR); ++ tlbehi = sysreg_read(TLBEHI); ++ sysreg_write(MMUCR, SYSREG_BFINS(DRP, 0, mmucr)); ++ ++ /* Clear the "valid" bit */ ++ tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi)); ++ sysreg_write(TLBEHI, tlbehi); ++ ++ /* Mark it as "not accessed" */ ++ tlbarlo = sysreg_read(TLBARLO); ++ sysreg_write(TLBARLO, tlbarlo | 0x80000000U); ++ ++ /* Update the TLB */ ++ __builtin_tlbw(); ++ ++ /* Unmask exceptions */ ++ asm volatile("csrf %0" : : "i"(SYSREG_EM_OFFSET) : "memory"); ++} ++ ++static int avr32_pm_valid_state(suspend_state_t state) ++{ ++ switch (state) { ++ case PM_SUSPEND_ON: ++ case PM_SUSPEND_STANDBY: ++ case PM_SUSPEND_MEM: ++ return 1; ++ ++ default: ++ return 0; ++ } ++} ++ ++static int avr32_pm_enter(suspend_state_t state) ++{ ++ u32 lpr_saved; ++ u32 evba_saved; ++ void *sram; ++ ++ switch (state) { ++ case PM_SUSPEND_STANDBY: ++ sram = avr32_pm_map_sram(); ++ ++ /* Switch to in-sram exception handlers */ ++ evba_saved = sysreg_read(EVBA); ++ sysreg_write(EVBA, (unsigned long)sram); ++ ++ /* ++ * Save the LPR register so that we can re-enable ++ * SDRAM Low Power mode on resume. ++ */ ++ lpr_saved = sdramc_readl(LPR); ++ pr_debug("%s: Entering standby...\n", __func__); ++ avr32_pm_enter_standby(SDRAMC_BASE); ++ sdramc_writel(LPR, lpr_saved); ++ ++ /* Switch back to regular exception handlers */ ++ sysreg_write(EVBA, evba_saved); ++ ++ avr32_pm_unmap_sram(); ++ break; ++ ++ case PM_SUSPEND_MEM: ++ sram = avr32_pm_map_sram(); ++ ++ /* Switch to in-sram exception handlers */ ++ evba_saved = sysreg_read(EVBA); ++ sysreg_write(EVBA, (unsigned long)sram); ++ ++ /* ++ * Save the LPR register so that we can re-enable ++ * SDRAM Low Power mode on resume. ++ */ ++ lpr_saved = sdramc_readl(LPR); ++ pr_debug("%s: Entering suspend-to-ram...\n", __func__); ++ avr32_pm_enter_str(SDRAMC_BASE); ++ sdramc_writel(LPR, lpr_saved); ++ ++ /* Switch back to regular exception handlers */ ++ sysreg_write(EVBA, evba_saved); ++ ++ avr32_pm_unmap_sram(); ++ break; ++ ++ case PM_SUSPEND_ON: ++ pr_debug("%s: Entering idle...\n", __func__); ++ cpu_enter_idle(); ++ break; ++ ++ default: ++ pr_debug("%s: Invalid suspend state %d\n", __func__, state); ++ goto out; ++ } ++ ++ pr_debug("%s: wakeup\n", __func__); ++ ++out: ++ return 0; ++} ++ ++static struct platform_suspend_ops avr32_pm_ops = { ++ .valid = avr32_pm_valid_state, ++ .enter = avr32_pm_enter, ++}; ++ ++static unsigned long avr32_pm_offset(void *symbol) ++{ ++ extern u8 pm_exception[]; ++ ++ return (unsigned long)symbol - (unsigned long)pm_exception; ++} ++ ++static int __init avr32_pm_init(void) ++{ ++ extern u8 pm_exception[]; ++ extern u8 pm_irq0[]; ++ extern u8 pm_standby[]; ++ extern u8 pm_suspend_to_ram[]; ++ extern u8 pm_sram_end[]; ++ void *dst; ++ ++ /* ++ * To keep things simple, we depend on not needing more than a ++ * single page. ++ */ ++ pm_sram_size = avr32_pm_offset(pm_sram_end); ++ if (pm_sram_size > PAGE_SIZE) ++ goto err; ++ ++ pm_sram_start = sram_alloc(pm_sram_size); ++ if (!pm_sram_start) ++ goto err_alloc_sram; ++ ++ /* Grab a virtual area we can use later on. */ ++ pm_sram_area = get_vm_area(pm_sram_size, VM_IOREMAP); ++ if (!pm_sram_area) ++ goto err_vm_area; ++ pm_sram_area->phys_addr = pm_sram_start; ++ ++ local_irq_disable(); ++ dst = avr32_pm_map_sram(); ++ memcpy(dst, pm_exception, pm_sram_size); ++ flush_dcache_region(dst, pm_sram_size); ++ invalidate_icache_region(dst, pm_sram_size); ++ avr32_pm_unmap_sram(); ++ local_irq_enable(); ++ ++ avr32_pm_enter_standby = dst + avr32_pm_offset(pm_standby); ++ avr32_pm_enter_str = dst + avr32_pm_offset(pm_suspend_to_ram); ++ intc_set_suspend_handler(avr32_pm_offset(pm_irq0)); ++ ++ suspend_set_ops(&avr32_pm_ops); ++ ++ printk("AVR32 AP Power Management enabled\n"); ++ ++ return 0; ++ ++err_vm_area: ++ sram_free(pm_sram_start, pm_sram_size); ++err_alloc_sram: ++err: ++ pr_err("AVR32 Power Management initialization failed\n"); ++ return -ENOMEM; ++} ++arch_initcall(avr32_pm_init); +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/sdramc.h avr32-2.6/arch/avr32/mach-at32ap/sdramc.h +--- linux-2.6.25.6/arch/avr32/mach-at32ap/sdramc.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/arch/avr32/mach-at32ap/sdramc.h 2008-06-12 15:09:38.723815860 +0200 +@@ -0,0 +1,76 @@ ++/* ++ * Register definitions for the AT32AP SDRAM Controller ++ * ++ * Copyright (C) 2008 Atmel Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ */ ++ ++/* Register offsets */ ++#define SDRAMC_MR 0x0000 ++#define SDRAMC_TR 0x0004 ++#define SDRAMC_CR 0x0008 ++#define SDRAMC_HSR 0x000c ++#define SDRAMC_LPR 0x0010 ++#define SDRAMC_IER 0x0014 ++#define SDRAMC_IDR 0x0018 ++#define SDRAMC_IMR 0x001c ++#define SDRAMC_ISR 0x0020 ++#define SDRAMC_MDR 0x0024 ++ ++/* MR - Mode Register */ ++#define SDRAMC_MR_MODE_NORMAL ( 0 << 0) ++#define SDRAMC_MR_MODE_NOP ( 1 << 0) ++#define SDRAMC_MR_MODE_BANKS_PRECHARGE ( 2 << 0) ++#define SDRAMC_MR_MODE_LOAD_MODE ( 3 << 0) ++#define SDRAMC_MR_MODE_AUTO_REFRESH ( 4 << 0) ++#define SDRAMC_MR_MODE_EXT_LOAD_MODE ( 5 << 0) ++#define SDRAMC_MR_MODE_POWER_DOWN ( 6 << 0) ++ ++/* CR - Configuration Register */ ++#define SDRAMC_CR_NC_8_BITS ( 0 << 0) ++#define SDRAMC_CR_NC_9_BITS ( 1 << 0) ++#define SDRAMC_CR_NC_10_BITS ( 2 << 0) ++#define SDRAMC_CR_NC_11_BITS ( 3 << 0) ++#define SDRAMC_CR_NR_11_BITS ( 0 << 2) ++#define SDRAMC_CR_NR_12_BITS ( 1 << 2) ++#define SDRAMC_CR_NR_13_BITS ( 2 << 2) ++#define SDRAMC_CR_NB_2_BANKS ( 0 << 4) ++#define SDRAMC_CR_NB_4_BANKS ( 1 << 4) ++#define SDRAMC_CR_CAS(x) ((x) << 5) ++#define SDRAMC_CR_DBW_32_BITS ( 0 << 7) ++#define SDRAMC_CR_DBW_16_BITS ( 1 << 7) ++#define SDRAMC_CR_TWR(x) ((x) << 8) ++#define SDRAMC_CR_TRC(x) ((x) << 12) ++#define SDRAMC_CR_TRP(x) ((x) << 16) ++#define SDRAMC_CR_TRCD(x) ((x) << 20) ++#define SDRAMC_CR_TRAS(x) ((x) << 24) ++#define SDRAMC_CR_TXSR(x) ((x) << 28) ++ ++/* HSR - High Speed Register */ ++#define SDRAMC_HSR_DA ( 1 << 0) ++ ++/* LPR - Low Power Register */ ++#define SDRAMC_LPR_LPCB_INHIBIT ( 0 << 0) ++#define SDRAMC_LPR_LPCB_SELF_RFR ( 1 << 0) ++#define SDRAMC_LPR_LPCB_PDOWN ( 2 << 0) ++#define SDRAMC_LPR_LPCB_DEEP_PDOWN ( 3 << 0) ++#define SDRAMC_LPR_PASR(x) ((x) << 4) ++#define SDRAMC_LPR_TCSR(x) ((x) << 8) ++#define SDRAMC_LPR_DS(x) ((x) << 10) ++#define SDRAMC_LPR_TIMEOUT(x) ((x) << 12) ++ ++/* IER/IDR/IMR/ISR - Interrupt Enable/Disable/Mask/Status Register */ ++#define SDRAMC_ISR_RES ( 1 << 0) ++ ++/* MDR - Memory Device Register */ ++#define SDRAMC_MDR_MD_SDRAM ( 0 << 0) ++#define SDRAMC_MDR_MD_LOW_PWR_SDRAM ( 1 << 0) ++ ++/* Register access macros */ ++#define sdramc_readl(reg) \ ++ __raw_readl((void __iomem __force *)SDRAMC_BASE + SDRAMC_##reg) ++#define sdramc_writel(reg, value) \ ++ __raw_writel(value, (void __iomem __force *)SDRAMC_BASE + SDRAMC_##reg) +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mach-at32ap/time-tc.c avr32-2.6/arch/avr32/mach-at32ap/time-tc.c +--- linux-2.6.25.6/arch/avr32/mach-at32ap/time-tc.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/mach-at32ap/time-tc.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2004-2007 Atmel Corporation @@ -11445,343 +7766,485 @@ - - return IRQ_NONE; -} ---- a/arch/avr32/Makefile -+++ b/arch/avr32/Makefile -@@ -16,7 +16,7 @@ - CFLAGS_MODULE += -mno-relax - LDFLAGS_vmlinux += --relax - --cpuflags-$(CONFIG_CPU_AT32AP7000) += -mcpu=ap7000 -+cpuflags-$(CONFIG_PLATFORM_AT32AP) += -march=ap - - KBUILD_CFLAGS += $(cpuflags-y) - KBUILD_AFLAGS += $(cpuflags-y) -@@ -31,6 +31,8 @@ - core-$(CONFIG_LOADER_U_BOOT) += arch/avr32/boot/u-boot/ +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/Makefile avr32-2.6/arch/avr32/Makefile +--- linux-2.6.25.6/arch/avr32/Makefile 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/Makefile 2008-06-12 15:09:38.711815728 +0200 +@@ -32,6 +32,7 @@ core-y += arch/avr32/kernel/ core-y += arch/avr32/mm/ -+drivers-$(CONFIG_OPROFILE) += arch/avr32/oprofile/ + drivers-$(CONFIG_OPROFILE) += arch/avr32/oprofile/ +drivers-y += arch/avr32/drivers/ libs-y += arch/avr32/lib/ archincdir-$(CONFIG_PLATFORM_AT32AP) := arch-at32ap ---- a/arch/avr32/mm/dma-coherent.c -+++ b/arch/avr32/mm/dma-coherent.c -@@ -41,6 +41,13 @@ - struct page *page, *free, *end; - int order; - -+ /* Following is a work-around (a.k.a. hack) to prevent pages -+ * with __GFP_COMP being passed to split_page() which cannot -+ * handle them. The real problem is that this flag probably -+ * should be 0 on AVR32 as it is not supported on this -+ * platform--see CONFIG_HUGETLB_PAGE. */ -+ gfp &= ~(__GFP_COMP); -+ - size = PAGE_ALIGN(size); - order = get_order(size); - ---- a/arch/avr32/mm/fault.c -+++ b/arch/avr32/mm/fault.c -@@ -189,6 +189,8 @@ - - page = sysreg_read(PTBR); - printk(KERN_ALERT "ptbr = %08lx", page); -+ if (address >= TASK_SIZE) -+ page = (unsigned long)swapper_pg_dir; - if (page) { - page = ((unsigned long *)page)[address >> 22]; - printk(" pgd = %08lx", page); ---- a/arch/avr32/mm/tlb.c -+++ b/arch/avr32/mm/tlb.c -@@ -348,7 +348,7 @@ - return 0; - } +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/mm/init.c avr32-2.6/arch/avr32/mm/init.c +--- linux-2.6.25.6/arch/avr32/mm/init.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/mm/init.c 2008-06-12 15:09:38.727815811 +0200 +@@ -11,6 +11,7 @@ + #include <linux/swap.h> + #include <linux/init.h> + #include <linux/mmzone.h> ++#include <linux/module.h> + #include <linux/bootmem.h> + #include <linux/pagemap.h> + #include <linux/nodemask.h> +@@ -28,15 +29,13 @@ + pgd_t swapper_pg_dir[PTRS_PER_PGD]; --static struct seq_operations tlb_ops = { -+static const struct seq_operations tlb_ops = { - .start = tlb_start, - .next = tlb_next, - .stop = tlb_stop, ---- /dev/null -+++ b/arch/avr32/oprofile/Makefile -@@ -0,0 +1,8 @@ -+obj-$(CONFIG_OPROFILE) += oprofile.o -+ -+oprofile-y := $(addprefix ../../../drivers/oprofile/, \ -+ oprof.o cpu_buffer.o buffer_sync.o \ -+ event_buffer.o oprofile_files.o \ -+ oprofilefs.o oprofile_stats.o \ -+ timer_int.o) -+oprofile-y += op_model_avr32.o ---- /dev/null -+++ b/arch/avr32/oprofile/op_model_avr32.c -@@ -0,0 +1,234 @@ -+/* -+ * AVR32 Performance Counter Driver -+ * -+ * Copyright (C) 2005-2007 Atmel Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Author: Ronny Pedersen -+ */ -+#include <linux/errno.h> -+#include <linux/interrupt.h> -+#include <linux/irq.h> -+#include <linux/oprofile.h> -+#include <linux/sched.h> -+#include <linux/types.h> -+ -+#include <asm/sysreg.h> -+#include <asm/system.h> -+ -+#define AVR32_PERFCTR_IRQ_GROUP 0 -+#define AVR32_PERFCTR_IRQ_LINE 1 -+ -+enum { PCCNT, PCNT0, PCNT1, NR_counter }; -+ -+struct avr32_perf_counter { -+ unsigned long enabled; -+ unsigned long event; -+ unsigned long count; -+ unsigned long unit_mask; -+ unsigned long kernel; -+ unsigned long user; -+ -+ u32 ie_mask; -+ u32 flag_mask; -+}; -+ -+static struct avr32_perf_counter counter[NR_counter] = { -+ { -+ .ie_mask = SYSREG_BIT(IEC), -+ .flag_mask = SYSREG_BIT(FC), -+ }, { -+ .ie_mask = SYSREG_BIT(IE0), -+ .flag_mask = SYSREG_BIT(F0), -+ }, { -+ .ie_mask = SYSREG_BIT(IE1), -+ .flag_mask = SYSREG_BIT(F1), -+ }, -+}; -+ -+static void avr32_perf_counter_reset(void) -+{ -+ /* Reset all counter and disable/clear all interrupts */ -+ sysreg_write(PCCR, (SYSREG_BIT(PCCR_R) -+ | SYSREG_BIT(PCCR_C) -+ | SYSREG_BIT(FC) -+ | SYSREG_BIT(F0) -+ | SYSREG_BIT(F1))); -+} -+ -+static irqreturn_t avr32_perf_counter_interrupt(int irq, void *dev_id) -+{ -+ struct avr32_perf_counter *ctr = dev_id; -+ struct pt_regs *regs; -+ u32 pccr; -+ -+ if (likely(!(intc_get_pending(AVR32_PERFCTR_IRQ_GROUP) -+ & (1 << AVR32_PERFCTR_IRQ_LINE)))) -+ return IRQ_NONE; -+ -+ regs = get_irq_regs(); -+ pccr = sysreg_read(PCCR); -+ -+ /* Clear the interrupt flags we're about to handle */ -+ sysreg_write(PCCR, pccr); -+ -+ /* PCCNT */ -+ if (ctr->enabled && (pccr & ctr->flag_mask)) { -+ sysreg_write(PCCNT, -ctr->count); -+ oprofile_add_sample(regs, PCCNT); -+ } -+ ctr++; -+ /* PCNT0 */ -+ if (ctr->enabled && (pccr & ctr->flag_mask)) { -+ sysreg_write(PCNT0, -ctr->count); -+ oprofile_add_sample(regs, PCNT0); -+ } -+ ctr++; -+ /* PCNT1 */ -+ if (ctr->enabled && (pccr & ctr->flag_mask)) { -+ sysreg_write(PCNT1, -ctr->count); -+ oprofile_add_sample(regs, PCNT1); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static int avr32_perf_counter_create_files(struct super_block *sb, -+ struct dentry *root) -+{ -+ struct dentry *dir; -+ unsigned int i; -+ char filename[4]; -+ -+ for (i = 0; i < NR_counter; i++) { -+ snprintf(filename, sizeof(filename), "%u", i); -+ dir = oprofilefs_mkdir(sb, root, filename); -+ -+ oprofilefs_create_ulong(sb, dir, "enabled", -+ &counter[i].enabled); -+ oprofilefs_create_ulong(sb, dir, "event", -+ &counter[i].event); -+ oprofilefs_create_ulong(sb, dir, "count", -+ &counter[i].count); -+ -+ /* Dummy entries */ -+ oprofilefs_create_ulong(sb, dir, "kernel", -+ &counter[i].kernel); -+ oprofilefs_create_ulong(sb, dir, "user", -+ &counter[i].user); -+ oprofilefs_create_ulong(sb, dir, "unit_mask", -+ &counter[i].unit_mask); -+ } -+ -+ return 0; -+} -+ -+static int avr32_perf_counter_setup(void) -+{ -+ struct avr32_perf_counter *ctr; -+ u32 pccr; -+ int ret; -+ int i; -+ -+ pr_debug("avr32_perf_counter_setup\n"); -+ -+ if (sysreg_read(PCCR) & SYSREG_BIT(PCCR_E)) { -+ printk(KERN_ERR -+ "oprofile: setup: perf counter already enabled\n"); -+ return -EBUSY; -+ } -+ -+ ret = request_irq(AVR32_PERFCTR_IRQ_GROUP, -+ avr32_perf_counter_interrupt, IRQF_SHARED, -+ "oprofile", counter); -+ if (ret) -+ return ret; -+ -+ avr32_perf_counter_reset(); -+ -+ pccr = 0; -+ for (i = PCCNT; i < NR_counter; i++) { -+ ctr = &counter[i]; -+ if (!ctr->enabled) -+ continue; -+ -+ pr_debug("enabling counter %d...\n", i); -+ -+ pccr |= ctr->ie_mask; -+ -+ switch (i) { -+ case PCCNT: -+ /* PCCNT always counts cycles, so no events */ -+ sysreg_write(PCCNT, -ctr->count); -+ break; -+ case PCNT0: -+ pccr |= SYSREG_BF(CONF0, ctr->event); -+ sysreg_write(PCNT0, -ctr->count); -+ break; -+ case PCNT1: -+ pccr |= SYSREG_BF(CONF1, ctr->event); -+ sysreg_write(PCNT1, -ctr->count); -+ break; -+ } -+ } -+ -+ pr_debug("oprofile: writing 0x%x to PCCR...\n", pccr); -+ -+ sysreg_write(PCCR, pccr); -+ -+ return 0; -+} -+ -+static void avr32_perf_counter_shutdown(void) -+{ -+ pr_debug("avr32_perf_counter_shutdown\n"); -+ -+ avr32_perf_counter_reset(); -+ free_irq(AVR32_PERFCTR_IRQ_GROUP, counter); -+} -+ -+static int avr32_perf_counter_start(void) -+{ -+ pr_debug("avr32_perf_counter_start\n"); -+ -+ sysreg_write(PCCR, sysreg_read(PCCR) | SYSREG_BIT(PCCR_E)); -+ -+ return 0; -+} -+ -+static void avr32_perf_counter_stop(void) -+{ -+ pr_debug("avr32_perf_counter_stop\n"); -+ -+ sysreg_write(PCCR, sysreg_read(PCCR) & ~SYSREG_BIT(PCCR_E)); -+} -+ -+static struct oprofile_operations avr32_perf_counter_ops __initdata = { -+ .create_files = avr32_perf_counter_create_files, -+ .setup = avr32_perf_counter_setup, -+ .shutdown = avr32_perf_counter_shutdown, -+ .start = avr32_perf_counter_start, -+ .stop = avr32_perf_counter_stop, -+ .cpu_type = "avr32", -+}; -+ -+int __init oprofile_arch_init(struct oprofile_operations *ops) -+{ -+ if (!(current_cpu_data.features & AVR32_FEATURE_PCTR)) -+ return -ENODEV; -+ -+ memcpy(ops, &avr32_perf_counter_ops, -+ sizeof(struct oprofile_operations)); -+ -+ printk(KERN_INFO "oprofile: using AVR32 performance monitoring.\n"); -+ -+ return 0; -+} -+ -+void oprofile_arch_exit(void) -+{ -+ -+} ---- a/Documentation/kernel-parameters.txt -+++ b/Documentation/kernel-parameters.txt -@@ -34,6 +34,7 @@ - ALSA ALSA sound support is enabled. - APIC APIC support is enabled. - APM Advanced Power Management support is enabled. -+ AVR32 AVR32 architecture is enabled. - AX25 Appropriate AX.25 support is enabled. - BLACKFIN Blackfin architecture is enabled. - DRM Direct Rendering Management support is enabled. -@@ -1124,6 +1125,10 @@ - of returning the full 64-bit number. - The default is to return 64-bit inode numbers. + struct page *empty_zero_page; ++EXPORT_SYMBOL(empty_zero_page); -+ nmi_debug= [KNL,AVR32] Specify one or more actions to take -+ when a NMI is triggered. -+ Format: [state][,regs][,debounce][,die] -+ - nmi_watchdog= [KNL,BUGS=X86-32] Debugging features for SMP kernels + /* + * Cache of MMU context last used. + */ + unsigned long mmu_context_cache = NO_CONTEXT; - no387 [BUGS=X86-32] Tells the kernel to use the 387 maths ---- a/drivers/clocksource/Makefile -+++ b/drivers/clocksource/Makefile +-#define START_PFN (NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT) +-#define MAX_LOW_PFN (NODE_DATA(0)->bdata->node_low_pfn) +- + void show_mem(void) + { + int total = 0, reserved = 0, cached = 0; +diff --exclude=.git -urN linux-2.6.25.6/arch/avr32/oprofile/op_model_avr32.c avr32-2.6/arch/avr32/oprofile/op_model_avr32.c +--- linux-2.6.25.6/arch/avr32/oprofile/op_model_avr32.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/arch/avr32/oprofile/op_model_avr32.c 2008-06-12 15:03:55.895816260 +0200 +@@ -16,7 +16,6 @@ + #include <linux/sched.h> + #include <linux/types.h> + +-#include <asm/intc.h> + #include <asm/sysreg.h> + #include <asm/system.h> + +diff --exclude=.git -urN linux-2.6.25.6/Documentation/ABI/stable/sysfs-class-ubi avr32-2.6/Documentation/ABI/stable/sysfs-class-ubi +--- linux-2.6.25.6/Documentation/ABI/stable/sysfs-class-ubi 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/Documentation/ABI/stable/sysfs-class-ubi 2008-06-12 15:03:55.427814470 +0200 +@@ -0,0 +1,212 @@ ++What: /sys/class/ubi/ ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ The ubi/ class sub-directory belongs to the UBI subsystem and ++ provides general UBI information, per-UBI device information ++ and per-UBI volume information. ++ ++What: /sys/class/ubi/version ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ This file contains version of the latest supported UBI on-media ++ format. Currently it is 1, and there is no plan to change this. ++ However, if in the future UBI needs on-flash format changes ++ which cannot be done in a compatible manner, a new format ++ version will be added. So this is a mechanism for possible ++ future backward-compatible (but forward-incompatible) ++ improvements. ++ ++What: /sys/class/ubiX/ ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ The /sys/class/ubi0, /sys/class/ubi1, etc directories describe ++ UBI devices (UBI device 0, 1, etc). They contain general UBI ++ device information and per UBI volume information (each UBI ++ device may have many UBI volumes) ++ ++What: /sys/class/ubi/ubiX/avail_eraseblocks ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ Amount of available logical eraseblock. For example, one may ++ create a new UBI volume which has this amount of logical ++ eraseblocks. ++ ++What: /sys/class/ubi/ubiX/bad_peb_count ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ Count of bad physical eraseblocks on the underlying MTD device. ++ ++What: /sys/class/ubi/ubiX/bgt_enabled ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ Contains ASCII "0\n" if the UBI background thread is disabled, ++ and ASCII "1\n" if it is enabled. ++ ++What: /sys/class/ubi/ubiX/dev ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ Major and minor numbers of the character device corresponding ++ to this UBI device (in <major>:<minor> format). ++ ++What: /sys/class/ubi/ubiX/eraseblock_size ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ Maximum logical eraseblock size this UBI device may provide. UBI ++ volumes may have smaller logical eraseblock size because of their ++ alignment. ++ ++What: /sys/class/ubi/ubiX/max_ec ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ Maximum physical eraseblock erase counter value. ++ ++What: /sys/class/ubi/ubiX/max_vol_count ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ Maximum number of volumes which this UBI device may have. ++ ++What: /sys/class/ubi/ubiX/min_io_size ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ Minimum input/output unit size. All the I/O may only be done ++ in fractions of the contained number. ++ ++What: /sys/class/ubi/ubiX/mtd_num ++Date: January 2008 ++KernelVersion: 2.6.25 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ Number of the underlying MTD device. ++ ++What: /sys/class/ubi/ubiX/reserved_for_bad ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ Number of physical eraseblocks reserved for bad block handling. ++ ++What: /sys/class/ubi/ubiX/total_eraseblocks ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ Total number of good (not marked as bad) physical eraseblocks on ++ the underlying MTD device. ++ ++What: /sys/class/ubi/ubiX/volumes_count ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ Count of volumes on this UBI device. ++ ++What: /sys/class/ubi/ubiX/ubiX_Y/ ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ The /sys/class/ubi/ubiX/ubiX_0/, /sys/class/ubi/ubiX/ubiX_1/, ++ etc directories describe UBI volumes on UBI device X (volumes ++ 0, 1, etc). ++ ++What: /sys/class/ubi/ubiX/ubiX_Y/alignment ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ Volume alignment - the value the logical eraseblock size of ++ this volume has to be aligned on. For example, 2048 means that ++ logical eraseblock size is multiple of 2048. In other words, ++ volume logical eraseblock size is UBI device logical eraseblock ++ size aligned to the alignment value. ++ ++What: /sys/class/ubi/ubiX/ubiX_Y/corrupted ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ Contains ASCII "0\n" if the UBI volume is OK, and ASCII "1\n" ++ if it is corrupted (e.g., due to an interrupted volume update). ++ ++What: /sys/class/ubi/ubiX/ubiX_Y/data_bytes ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ The amount of data this volume contains. This value makes sense ++ only for static volumes, and for dynamic volume it equivalent ++ to the total volume size in bytes. ++ ++What: /sys/class/ubi/ubiX/ubiX_Y/dev ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ Major and minor numbers of the character device corresponding ++ to this UBI volume (in <major>:<minor> format). ++ ++What: /sys/class/ubi/ubiX/ubiX_Y/name ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ Volume name. ++ ++What: /sys/class/ubi/ubiX/ubiX_Y/reserved_ebs ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ Count of physical eraseblock reserved for this volume. ++ Equivalent to the volume size in logical eraseblocks. ++ ++What: /sys/class/ubi/ubiX/ubiX_Y/type ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ Volume type. Contains ASCII "dynamic\n" for dynamic volumes and ++ "static\n" for static volumes. ++ ++What: /sys/class/ubi/ubiX/ubiX_Y/upd_marker ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ Contains ASCII "0\n" if the update marker is not set for this ++ volume, and "1\n" if it is set. The update marker is set when ++ volume update starts, and cleaned when it ends. So the presence ++ of the update marker indicates that the volume is being updated ++ at the moment of the update was interrupted. The later may be ++ checked using the "corrupted" sysfs file. ++ ++What: /sys/class/ubi/ubiX/ubiX_Y/usable_eb_size ++Date: July 2006 ++KernelVersion: 2.6.22 ++Contact: Artem Bityutskiy <dedekind@infradead.org> ++Description: ++ Logical eraseblock size of this volume. Equivalent to logical ++ eraseblock size of the device aligned on the volume alignment ++ value. +diff --exclude=.git -urN linux-2.6.25.6/Documentation/filesystems/ubifs.txt avr32-2.6/Documentation/filesystems/ubifs.txt +--- linux-2.6.25.6/Documentation/filesystems/ubifs.txt 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/Documentation/filesystems/ubifs.txt 2008-06-12 15:09:38.451815572 +0200 +@@ -0,0 +1,163 @@ ++Introduction ++============= ++ ++UBIFS file-system stands for UBI File System. UBI stands for "Unsorted ++Block Images". UBIFS is a flash file system, which means it is designed ++to work with flash devices. It is important to understand, that UBIFS ++is completely different to any traditional file-system in Linux, like ++Ext2, XFS, JFS, etc. UBIFS represents a separate class of file-systems ++which work with MTD devices, not block devices. The other Linux ++file-system of this class is JFFS2. ++ ++To make it more clear, here is a small comparison of MTD devices and ++block devices. ++ ++1 MTD devices represent flash devices and they consist of eraseblocks of ++ rather large size, typically about 128KiB. Block devices consist of ++ small blocks, typically 512 bytes. ++2 MTD devices support 3 main operations - read from some offset within an ++ eraseblock, write to some offset within an eraseblock, and erase a whole ++ eraseblock. Block devices support 2 main operations - read a whole ++ block and write a whole block. ++3 The whole eraseblock has to be erased before it becomes possible to ++ re-write its contents. Blocks may be just re-written. ++4 Eraseblocks become worn out after some number of erase cycles - ++ typically 100K-1G for SLC NAND and NOR flashes, and 1K-10K for MLC ++ NAND flashes. Blocks do not have the wear-out property. ++5 Eraseblocks may become bad (only on NAND flashes) and software should ++ deal with this. Blocks on hard drives typically do not become bad, ++ because hardware has mechanisms to substitute bad blocks, at least in ++ modern LBA disks. ++ ++It should be quite obvious why UBIFS is very different to traditional ++file-systems. ++ ++UBIFS works on top of UBI. UBI is a separate software layer which may be ++found in drivers/mtd/ubi. UBI is basically a volume management and ++wear-leveling layer. It provides so called UBI volumes which is a higher ++level abstraction than a MTD device. The programming model of UBI devices ++is very similar to MTD devices - they still consist of large eraseblocks, ++they have read/write/erase operations, but UBI devices are devoid of ++limitations like wear and bad blocks (items 4 and 5 in the above list). ++ ++In a sense, UBIFS is a next generation of JFFS2 file-system, but it is ++very different and incompatible to JFFS2. The following are the main ++differences. ++ ++* JFFS2 works on top of MTD devices, UBIFS depends on UBI and works on ++ top of UBI volumes. ++* JFFS2 does not have on-media index and has to build it while mounting, ++ which requires full media scan. UBIFS maintains the FS indexing ++ information on the flash media and does not require full media scan, ++ so it mounts many times faster than JFFS2. ++* JFFS2 is a write-through file-system, while UBIFS supports write-back, ++ which makes UBIFS much faster on writes. ++ ++Similarly to JFFS2, UBIFS supports on-the-flight compression which makes ++it possible to fit quite a lot of data to the flash. ++ ++Similarly to JFFS2, UBIFS is tolerant of unclean reboots and power-cuts. ++It does not need stuff like ckfs.ext2. UBIFS automatically replays its ++journal and recovers from crashes, ensuring that the on-flash data ++structures are consistent. ++ ++UBIFS scales logarithmically (most of the data structures it uses are ++trees), so the mount time and memory consumption do not linearly depend ++on the flash size, like in case of JFFS2. This is because UBIFS ++maintains the FS index on the flash media. However, UBIFS depends on ++UBI, which scales linearly. So overall UBI/UBIFS stack scales linearly. ++Nevertheless, UBI/UBIFS scales considerably better than JFFS2. ++ ++The authors of UBIFS believe, that it is possible to develop UBI2 which ++would scale logarithmically as well. UBI2 would support the same API as UBI, ++but it would be binary incompatible to UBI. So UBIFS would not need to be ++changed to use UBI2 ++ ++ ++Mount options ++============= ++ ++(*) == default. ++ ++norm_unmount (*) commit on unmount; the journal is committed ++ when the file-system is unmounted so that the ++ next mount does not have to replay the journal ++ and it becomes very fast; ++fast_unmount do not commit on unmount; this option makes ++ unmount faster, but the next mount slower ++ because of the need to replay the journal. ++ ++ ++Quick usage instructions ++======================== ++ ++The UBI volume to mount is specified using "ubiX_Y" or "ubiX:NAME" syntax, ++where "X" is UBI device number, "Y" is UBI volume number, and "NAME" is ++UBI volume name. ++ ++Mount volume 0 on UBI device 0 to /mnt/ubifs: ++$ mount -t ubifs ubi0_0 /mnt/ubifs ++ ++Mount "rootfs" volume of UBI device 0 to /mnt/ubifs ("rootfs" is volume ++name): ++$ mount -t ubifs ubi0:rootfs /mnt/ubifs ++ ++The following is an example of the kernel boot arguments to attach mtd0 ++to UBI and mount volume "rootfs": ++ubi.mtd=0 root=ubi0:rootfs rootfstype=ubifs ++ ++ ++Module Parameters for Debugging ++=============================== ++ ++When UBIFS has been compiled with debugging enabled, there are 3 module ++parameters that are available to control aspects of testing and debugging. ++The parameters are unsigned integers where each bit controls an option. ++The parameters are: ++ ++debug_msgs Selects which debug messages to display, as follows: ++ ++ Message Type Flag value ++ ++ General messages 1 ++ Journal messages 2 ++ Mount messages 4 ++ Commit messages 8 ++ LEB search messages 16 ++ Budgeting messages 32 ++ Garbage collection messages 64 ++ Tree Node Cache (TNC) messages 128 ++ LEB properties (lprops) messages 256 ++ Input/output messages 512 ++ Log messages 1024 ++ Scan messages 2048 ++ Recovery messages 4096 ++ ++debug_chks Selects extra checks that UBIFS can do while running: ++ ++ Check Flag value ++ ++ General checks 1 ++ Check Tree Node Cache (TNC) 2 ++ Check indexing tree size 4 ++ Check orphan area 8 ++ Check old indexing tree 16 ++ Check LEB properties (lprops) 32 ++ ++debug_tsts Selects a mode of testing, as follows: ++ ++ Test mode Flag value ++ ++ Force in-the-gaps method 2 ++ Failure mode for recovery testing 4 ++ ++For example, set debug_msgs to 5 to display General messages and Mount ++messages. ++ ++ ++References ++========== ++ ++UBIFS documentation and FAQ/HOWTO at the MTD web site: ++http://www.linux-mtd.infradead.org/doc/ubifs.html ++http://www.linux-mtd.infradead.org/faq/ubifs.html +diff --exclude=.git -urN linux-2.6.25.6/drivers/char/Kconfig avr32-2.6/drivers/char/Kconfig +--- linux-2.6.25.6/drivers/char/Kconfig 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/char/Kconfig 2008-06-12 15:09:40.071816052 +0200 +@@ -706,7 +706,7 @@ + + config RTC + tristate "Enhanced Real Time Clock Support" +- depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390 ++ depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390 && !AVR32 + ---help--- + If you say Y here and create a character special file /dev/rtc with + major number 10 and minor number 135 using mknod ("man mknod"), you +@@ -776,7 +776,7 @@ + + config GEN_RTC + tristate "Generic /dev/rtc emulation" +- depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH ++ depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH && !AVR32 + ---help--- + If you say Y here and create a character special file /dev/rtc with + major number 10 and minor number 135 using mknod ("man mknod"), you +diff --exclude=.git -urN linux-2.6.25.6/drivers/char/keyboard.c avr32-2.6/drivers/char/keyboard.c +--- linux-2.6.25.6/drivers/char/keyboard.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/char/keyboard.c 2008-06-12 15:09:40.243816452 +0200 +@@ -1033,7 +1033,8 @@ + #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\ + defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\ + defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\ +- (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) ++ (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) ||\ ++ defined(CONFIG_AVR32) + + #define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\ + ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001)) +diff --exclude=.git -urN linux-2.6.25.6/drivers/clocksource/Makefile avr32-2.6/drivers/clocksource/Makefile +--- linux-2.6.25.6/drivers/clocksource/Makefile 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/clocksource/Makefile 2008-06-12 15:03:58.475816394 +0200 @@ -1,3 +1,4 @@ +obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o ---- /dev/null -+++ b/drivers/clocksource/tcb_clksrc.c -@@ -0,0 +1,305 @@ +diff --exclude=.git -urN linux-2.6.25.6/drivers/clocksource/tcb_clksrc.c avr32-2.6/drivers/clocksource/tcb_clksrc.c +--- linux-2.6.25.6/drivers/clocksource/tcb_clksrc.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/drivers/clocksource/tcb_clksrc.c 2008-06-12 15:03:58.479814669 +0200 +@@ -0,0 +1,302 @@ +#include <linux/init.h> +#include <linux/clocksource.h> +#include <linux/clockchips.h> @@ -11964,10 +8427,8 @@ + .handler = ch2_irq, +}; + -+static void __init setup_clkevents(struct atmel_tc *tc, -+ struct clk *t0_clk, int clk32k_divisor_idx) ++static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) +{ -+ struct platform_device *pdev = tc->pdev; + struct clk *t2_clk = tc->clk[2]; + int irq = tc->irq[2]; + @@ -11989,8 +8450,7 @@ + +#else /* !CONFIG_GENERIC_CLOCKEVENTS */ + -+static void __init setup_clkevents(struct atmel_tc *tc, -+ struct clk *t0_clk, int clk32k_divisor_idx) ++static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) +{ + /* NOTHING */ +} @@ -12004,7 +8464,7 @@ + + struct platform_device *pdev; + struct atmel_tc *tc; -+ struct clk *t0_clk, *t1_clk; ++ struct clk *t0_clk; + u32 rate, divided_rate = 0; + int best_divisor_idx = -1; + int clk32k_divisor_idx = -1; @@ -12082,13 +8542,14 @@ + clocksource_register(&clksrc); + + /* channel 2: periodic and oneshot timer support */ -+ setup_clkevents(tc, t0_clk, clk32k_divisor_idx); ++ setup_clkevents(tc, clk32k_divisor_idx); + + return 0; +} +arch_initcall(tcb_clksrc_init); ---- /dev/null -+++ b/drivers/i2c/busses/i2c-atmeltwi.c +diff --exclude=.git -urN linux-2.6.25.6/drivers/i2c/busses/i2c-atmeltwi.c avr32-2.6/drivers/i2c/busses/i2c-atmeltwi.c +--- linux-2.6.25.6/drivers/i2c/busses/i2c-atmeltwi.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/drivers/i2c/busses/i2c-atmeltwi.c 2008-06-12 15:09:40.391816588 +0200 @@ -0,0 +1,436 @@ +/* + * i2c Support for Atmel's Two-Wire Interface (TWI) @@ -12526,8 +8987,9 @@ +MODULE_AUTHOR("Espen Krangnes"); +MODULE_DESCRIPTION("I2C driver for Atmel TWI"); +MODULE_LICENSE("GPL"); ---- /dev/null -+++ b/drivers/i2c/busses/i2c-atmeltwi.h +diff --exclude=.git -urN linux-2.6.25.6/drivers/i2c/busses/i2c-atmeltwi.h avr32-2.6/drivers/i2c/busses/i2c-atmeltwi.h +--- linux-2.6.25.6/drivers/i2c/busses/i2c-atmeltwi.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/drivers/i2c/busses/i2c-atmeltwi.h 2008-06-12 15:09:40.391816588 +0200 @@ -0,0 +1,117 @@ +/* + * Register definitions for the Atmel Two-Wire Interface @@ -12646,8 +9108,9 @@ + __raw_writel((value), (port)->regs + TWI_##reg) + +#endif /* __ATMELTWI_H__ */ ---- a/drivers/i2c/busses/Kconfig -+++ b/drivers/i2c/busses/Kconfig +diff --exclude=.git -urN linux-2.6.25.6/drivers/i2c/busses/Kconfig avr32-2.6/drivers/i2c/busses/Kconfig +--- linux-2.6.25.6/drivers/i2c/busses/Kconfig 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/i2c/busses/Kconfig 2008-06-12 15:09:40.383816128 +0200 @@ -88,6 +88,14 @@ to support combined I2C messages. Use the i2c-gpio driver unless your system can cope with those limitations. @@ -12663,9 +9126,10 @@ config I2C_AU1550 tristate "Au1550/Au1200 SMBus interface" depends on SOC_AU1550 || SOC_AU1200 ---- a/drivers/i2c/busses/Makefile -+++ b/drivers/i2c/busses/Makefile -@@ -53,6 +53,7 @@ +diff --exclude=.git -urN linux-2.6.25.6/drivers/i2c/busses/Makefile avr32-2.6/drivers/i2c/busses/Makefile +--- linux-2.6.25.6/drivers/i2c/busses/Makefile 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/i2c/busses/Makefile 2008-06-12 15:09:40.383816128 +0200 +@@ -52,6 +52,7 @@ obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o @@ -12673,8 +9137,9 @@ ifeq ($(CONFIG_I2C_DEBUG_BUS),y) EXTRA_CFLAGS += -DDEBUG ---- /dev/null -+++ b/drivers/input/serio/at32psif.c +diff --exclude=.git -urN linux-2.6.25.6/drivers/input/serio/at32psif.c avr32-2.6/drivers/input/serio/at32psif.c +--- linux-2.6.25.6/drivers/input/serio/at32psif.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/drivers/input/serio/at32psif.c 2008-06-12 15:09:40.619816021 +0200 @@ -0,0 +1,351 @@ +/* + * Copyright (C) 2007 Atmel Corporation @@ -13027,8 +9492,9 @@ +MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>"); +MODULE_DESCRIPTION("Atmel AVR32 PSIF PS/2 driver"); +MODULE_LICENSE("GPL"); ---- /dev/null -+++ b/drivers/input/serio/at32psif.h +diff --exclude=.git -urN linux-2.6.25.6/drivers/input/serio/at32psif.h avr32-2.6/drivers/input/serio/at32psif.h +--- linux-2.6.25.6/drivers/input/serio/at32psif.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/drivers/input/serio/at32psif.h 2008-06-12 15:09:40.619816021 +0200 @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2007 Atmel Corporation @@ -13112,8 +9578,9 @@ + __raw_writel((value), (port)->regs + PSIF_##reg) + +#endif /* _AT32PSIF_H */ ---- a/drivers/input/serio/Kconfig -+++ b/drivers/input/serio/Kconfig +diff --exclude=.git -urN linux-2.6.25.6/drivers/input/serio/Kconfig avr32-2.6/drivers/input/serio/Kconfig +--- linux-2.6.25.6/drivers/input/serio/Kconfig 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/input/serio/Kconfig 2008-06-12 15:09:40.615815791 +0200 @@ -88,6 +88,17 @@ To compile this driver as a module, choose M here: the module will be called rpckbd. @@ -13132,8 +9599,9 @@ config SERIO_AMBAKMI tristate "AMBA KMI keyboard controller" depends on ARM_AMBA ---- a/drivers/input/serio/Makefile -+++ b/drivers/input/serio/Makefile +diff --exclude=.git -urN linux-2.6.25.6/drivers/input/serio/Makefile avr32-2.6/drivers/input/serio/Makefile +--- linux-2.6.25.6/drivers/input/serio/Makefile 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/input/serio/Makefile 2008-06-12 15:03:58.919815686 +0200 @@ -12,6 +12,7 @@ obj-$(CONFIG_SERIO_RPCKBD) += rpckbd.o obj-$(CONFIG_SERIO_SA1111) += sa1111ps2.o @@ -13142,604 +9610,9 @@ obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o obj-$(CONFIG_HP_SDC) += hp_sdc.o ---- a/drivers/leds/Kconfig -+++ b/drivers/leds/Kconfig -@@ -18,6 +18,13 @@ - - comment "LED drivers" - -+config LEDS_ATMEL_PWM -+ tristate "LED Support using Atmel PWM outputs" -+ depends on LEDS_CLASS && ATMEL_PWM -+ help -+ This option enables support for LEDs driven using outputs -+ of the dedicated PWM controller found on newer Atmel SOCs. -+ - config LEDS_CORGI - tristate "LED Support for the Sharp SL-C7x0 series" - depends on LEDS_CLASS && PXA_SHARP_C7xx ---- /dev/null -+++ b/drivers/leds/leds-atmel-pwm.c -@@ -0,0 +1,155 @@ -+#include <linux/kernel.h> -+#include <linux/platform_device.h> -+#include <linux/leds.h> -+#include <linux/io.h> -+#include <linux/atmel_pwm.h> -+ -+ -+struct pwmled { -+ struct led_classdev cdev; -+ struct pwm_channel pwmc; -+ struct gpio_led *desc; -+ u32 mult; -+ u8 active_low; -+}; -+ -+ -+/* -+ * For simplicity, we use "brightness" as if it were a linear function -+ * of PWM duty cycle. However, a logarithmic function of duty cycle is -+ * probably a better match for perceived brightness: two is half as bright -+ * as four, four is half as bright as eight, etc -+ */ -+static void pwmled_brightness(struct led_classdev *cdev, enum led_brightness b) -+{ -+ struct pwmled *led; -+ -+ /* update the duty cycle for the *next* period */ -+ led = container_of(cdev, struct pwmled, cdev); -+ pwm_channel_writel(&led->pwmc, PWM_CUPD, led->mult * (unsigned) b); -+} -+ -+/* -+ * NOTE: we reuse the platform_data structure of GPIO leds, -+ * but repurpose its "gpio" number as a PWM channel number. -+ */ -+static int __init pwmled_probe(struct platform_device *pdev) -+{ -+ const struct gpio_led_platform_data *pdata; -+ struct pwmled *leds; -+ unsigned i; -+ int status; -+ -+ pdata = pdev->dev.platform_data; -+ if (!pdata || pdata->num_leds < 1) -+ return -ENODEV; -+ -+ leds = kcalloc(pdata->num_leds, sizeof(*leds), GFP_KERNEL); -+ if (!leds) -+ return -ENOMEM; -+ -+ for (i = 0; i < pdata->num_leds; i++) { -+ struct pwmled *led = leds + i; -+ const struct gpio_led *dat = pdata->leds + i; -+ u32 tmp; -+ -+ led->cdev.name = dat->name; -+ led->cdev.brightness = LED_OFF; -+ led->cdev.brightness_set = pwmled_brightness; -+ led->cdev.default_trigger = dat->default_trigger; -+ -+ led->active_low = dat->active_low; -+ -+ status = pwm_channel_alloc(dat->gpio, &led->pwmc); -+ if (status < 0) -+ goto err; -+ -+ /* -+ * Prescale clock by 2^x, so PWM counts in low MHz. -+ * Start each cycle with the LED active, so increasing -+ * the duty cycle gives us more time on (== brighter). -+ */ -+ tmp = 5; -+ if (!led->active_low) -+ tmp |= PWM_CPR_CPOL; -+ pwm_channel_writel(&led->pwmc, PWM_CMR, tmp); -+ -+ /* -+ * Pick a period so PWM cycles at 100+ Hz; and a multiplier -+ * for scaling duty cycle: brightness * mult. -+ */ -+ tmp = (led->pwmc.mck / (1 << 5)) / 100; -+ tmp /= 255; -+ led->mult = tmp; -+ pwm_channel_writel(&led->pwmc, PWM_CDTY, -+ led->cdev.brightness * 255); -+ pwm_channel_writel(&led->pwmc, PWM_CPRD, -+ LED_FULL * tmp); -+ -+ pwm_channel_enable(&led->pwmc); -+ -+ /* Hand it over to the LED framework */ -+ status = led_classdev_register(&pdev->dev, &led->cdev); -+ if (status < 0) { -+ pwm_channel_free(&led->pwmc); -+ goto err; -+ } -+ } -+ -+ platform_set_drvdata(pdev, leds); -+ return 0; -+ -+err: -+ while (i-- > 0) { -+ led_classdev_unregister(&leds[i].cdev); -+ pwm_channel_free(&leds[i].pwmc); -+ } -+ kfree(leds); -+ -+ return status; -+} -+ -+static int __exit pwmled_remove(struct platform_device *pdev) -+{ -+ const struct gpio_led_platform_data *pdata; -+ struct pwmled *leds; -+ unsigned i; -+ -+ pdata = pdev->dev.platform_data; -+ leds = platform_get_drvdata(pdev); -+ -+ for (i = 0; i < pdata->num_leds; i++) { -+ struct pwmled *led = leds + i; -+ -+ led_classdev_unregister(&led->cdev); -+ pwm_channel_free(&led->pwmc); -+ } -+ -+ kfree(leds); -+ platform_set_drvdata(pdev, NULL); -+ return 0; -+} -+ -+static struct platform_driver pwmled_driver = { -+ .driver = { -+ .name = "leds-atmel-pwm", -+ .owner = THIS_MODULE, -+ }, -+ /* REVISIT add suspend() and resume() methods */ -+ .remove = __exit_p(pwmled_remove), -+}; -+ -+static int __init modinit(void) -+{ -+ return platform_driver_probe(&pwmled_driver, pwmled_probe); -+} -+module_init(modinit); -+ -+static void __exit modexit(void) -+{ -+ platform_driver_unregister(&pwmled_driver); -+} -+module_exit(modexit); -+ -+MODULE_DESCRIPTION("Driver for LEDs with PWM-controlled brightness"); -+MODULE_LICENSE("GPL"); ---- a/drivers/leds/Makefile -+++ b/drivers/leds/Makefile -@@ -5,6 +5,7 @@ - obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o - - # LED Platform Drivers -+obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o - obj-$(CONFIG_LEDS_CORGI) += leds-corgi.o - obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o - obj-$(CONFIG_LEDS_SPITZ) += leds-spitz.o ---- /dev/null -+++ b/drivers/misc/atmel_pwm.c -@@ -0,0 +1,409 @@ -+#include <linux/module.h> -+#include <linux/clk.h> -+#include <linux/err.h> -+#include <linux/io.h> -+#include <linux/interrupt.h> -+#include <linux/platform_device.h> -+#include <linux/atmel_pwm.h> -+ -+ -+/* -+ * This is a simple driver for the PWM controller found in various newer -+ * Atmel SOCs, including the AVR32 series and the AT91sam9263. -+ * -+ * Chips with current Linux ports have only 4 PWM channels, out of max 32. -+ * AT32UC3A and AT32UC3B chips have 7 channels (but currently no Linux). -+ * Docs are inconsistent about the width of the channel counter registers; -+ * it's at least 16 bits, but several places say 20 bits. -+ */ -+#define PWM_NCHAN 4 /* max 32 */ -+ -+struct pwm { -+ spinlock_t lock; -+ struct platform_device *pdev; -+ u32 mask; -+ int irq; -+ void __iomem *base; -+ struct clk *clk; -+ struct pwm_channel *channel[PWM_NCHAN]; -+ void (*handler[PWM_NCHAN])(struct pwm_channel *); -+}; -+ -+ -+/* global PWM controller registers */ -+#define PWM_MR 0x00 -+#define PWM_ENA 0x04 -+#define PWM_DIS 0x08 -+#define PWM_SR 0x0c -+#define PWM_IER 0x10 -+#define PWM_IDR 0x14 -+#define PWM_IMR 0x18 -+#define PWM_ISR 0x1c -+ -+static inline void pwm_writel(const struct pwm *p, unsigned offset, u32 val) -+{ -+ __raw_writel(val, p->base + offset); -+} -+ -+static inline u32 pwm_readl(const struct pwm *p, unsigned offset) -+{ -+ return __raw_readl(p->base + offset); -+} -+ -+static inline void __iomem *pwmc_regs(const struct pwm *p, int index) -+{ -+ return p->base + 0x200 + index * 0x20; -+} -+ -+static struct pwm *pwm; -+ -+static void pwm_dumpregs(struct pwm_channel *ch, char *tag) -+{ -+ struct device *dev = &pwm->pdev->dev; -+ -+ dev_dbg(dev, "%s: mr %08x, sr %08x, imr %08x\n", -+ tag, -+ pwm_readl(pwm, PWM_MR), -+ pwm_readl(pwm, PWM_SR), -+ pwm_readl(pwm, PWM_IMR)); -+ dev_dbg(dev, -+ "pwm ch%d - mr %08x, dty %u, prd %u, cnt %u\n", -+ ch->index, -+ pwm_channel_readl(ch, PWM_CMR), -+ pwm_channel_readl(ch, PWM_CDTY), -+ pwm_channel_readl(ch, PWM_CPRD), -+ pwm_channel_readl(ch, PWM_CCNT)); -+} -+ -+ -+/** -+ * pwm_channel_alloc - allocate an unused PWM channel -+ * @index: identifies the channel -+ * @ch: structure to be initialized -+ * -+ * Drivers allocate PWM channels according to the board's wiring, and -+ * matching board-specific setup code. Returns zero or negative errno. -+ */ -+int pwm_channel_alloc(int index, struct pwm_channel *ch) -+{ -+ unsigned long flags; -+ int status = 0; -+ -+ /* insist on PWM init, with this signal pinned out */ -+ if (!pwm || !(pwm->mask & 1 << index)) -+ return -ENODEV; -+ -+ if (index < 0 || index >= PWM_NCHAN || !ch) -+ return -EINVAL; -+ memset(ch, 0, sizeof *ch); -+ -+ spin_lock_irqsave(&pwm->lock, flags); -+ if (pwm->channel[index]) -+ status = -EBUSY; -+ else { -+ clk_enable(pwm->clk); -+ -+ ch->regs = pwmc_regs(pwm, index); -+ ch->index = index; -+ -+ /* REVISIT: ap7000 seems to go 2x as fast as we expect!! */ -+ ch->mck = clk_get_rate(pwm->clk); -+ -+ pwm->channel[index] = ch; -+ pwm->handler[index] = NULL; -+ -+ /* channel and irq are always disabled when we return */ -+ pwm_writel(pwm, PWM_DIS, 1 << index); -+ pwm_writel(pwm, PWM_IDR, 1 << index); -+ } -+ spin_unlock_irqrestore(&pwm->lock, flags); -+ return status; -+} -+EXPORT_SYMBOL(pwm_channel_alloc); -+ -+static int pwmcheck(struct pwm_channel *ch) -+{ -+ int index; -+ -+ if (!pwm) -+ return -ENODEV; -+ if (!ch) -+ return -EINVAL; -+ index = ch->index; -+ if (index < 0 || index >= PWM_NCHAN || pwm->channel[index] != ch) -+ return -EINVAL; -+ -+ return index; -+} -+ -+/** -+ * pwm_channel_free - release a previously allocated channel -+ * @ch: the channel being released -+ * -+ * The channel is completely shut down (counter and IRQ disabled), -+ * and made available for re-use. Returns zero, or negative errno. -+ */ -+int pwm_channel_free(struct pwm_channel *ch) -+{ -+ unsigned long flags; -+ int t; -+ -+ spin_lock_irqsave(&pwm->lock, flags); -+ t = pwmcheck(ch); -+ if (t >= 0) { -+ pwm->channel[t] = NULL; -+ pwm->handler[t] = NULL; -+ -+ /* channel and irq are always disabled when we return */ -+ pwm_writel(pwm, PWM_DIS, 1 << t); -+ pwm_writel(pwm, PWM_IDR, 1 << t); -+ -+ clk_disable(pwm->clk); -+ t = 0; -+ } -+ spin_unlock_irqrestore(&pwm->lock, flags); -+ return t; -+} -+EXPORT_SYMBOL(pwm_channel_free); -+ -+int __pwm_channel_onoff(struct pwm_channel *ch, int enabled) -+{ -+ unsigned long flags; -+ int t; -+ -+ /* OMITTED FUNCTIONALITY: starting several channels in synch */ -+ -+ spin_lock_irqsave(&pwm->lock, flags); -+ t = pwmcheck(ch); -+ if (t >= 0) { -+ pwm_writel(pwm, enabled ? PWM_ENA : PWM_DIS, 1 << t); -+ t = 0; -+ pwm_dumpregs(ch, enabled ? "enable" : "disable"); -+ } -+ spin_unlock_irqrestore(&pwm->lock, flags); -+ -+ return t; -+} -+EXPORT_SYMBOL(__pwm_channel_onoff); -+ -+/** -+ * pwm_clk_alloc - allocate and configure CLKA or CLKB -+ * @prescale: from 0..10, the power of two used to divide MCK -+ * @div: from 1..255, the linear divisor to use -+ * -+ * Returns PWM_CPR_CLKA, PWM_CPR_CLKB, or negative errno. The allocated -+ * clock will run with a period of (2^prescale * div) / MCK, or twice as -+ * long if center aligned PWM output is used. The clock must later be -+ * deconfigured using pwm_clk_free(). -+ */ -+int pwm_clk_alloc(unsigned prescale, unsigned div) -+{ -+ unsigned long flags; -+ u32 mr; -+ u32 val = (prescale << 8) | div; -+ int ret = -EBUSY; -+ -+ if (prescale >= 10 || div == 0 || div > 255) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&pwm->lock, flags); -+ mr = pwm_readl(pwm, PWM_MR); -+ if ((mr & 0xffff) == 0) { -+ mr |= val; -+ ret = PWM_CPR_CLKA; -+ } -+ if ((mr & (0xffff << 16)) == 0) { -+ mr |= val << 16; -+ ret = PWM_CPR_CLKB; -+ } -+ if (ret > 0) -+ pwm_writel(pwm, PWM_MR, mr); -+ spin_unlock_irqrestore(&pwm->lock, flags); -+ return ret; -+} -+EXPORT_SYMBOL(pwm_clk_alloc); -+ -+/** -+ * pwm_clk_free - deconfigure and release CLKA or CLKB -+ * -+ * Reverses the effect of pwm_clk_alloc(). -+ */ -+void pwm_clk_free(unsigned clk) -+{ -+ unsigned long flags; -+ u32 mr; -+ -+ spin_lock_irqsave(&pwm->lock, flags); -+ mr = pwm_readl(pwm, PWM_MR); -+ if (clk == PWM_CPR_CLKA) -+ pwm_writel(pwm, PWM_MR, mr & ~(0xffff << 0)); -+ if (clk == PWM_CPR_CLKB) -+ pwm_writel(pwm, PWM_MR, mr & ~(0xffff << 16)); -+ spin_unlock_irqrestore(&pwm->lock, flags); -+} -+EXPORT_SYMBOL(pwm_clk_free); -+ -+/** -+ * pwm_channel_handler - manage channel's IRQ handler -+ * @ch: the channel -+ * @handler: the handler to use, possibly NULL -+ * -+ * If the handler is non-null, the handler will be called after every -+ * period of this PWM channel. If the handler is null, this channel -+ * won't generate an IRQ. -+ */ -+int pwm_channel_handler(struct pwm_channel *ch, -+ void (*handler)(struct pwm_channel *ch)) -+{ -+ unsigned long flags; -+ int t; -+ -+ spin_lock_irqsave(&pwm->lock, flags); -+ t = pwmcheck(ch); -+ if (t >= 0) { -+ pwm->handler[t] = handler; -+ pwm_writel(pwm, handler ? PWM_IER : PWM_IDR, 1 << t); -+ t = 0; -+ } -+ spin_unlock_irqrestore(&pwm->lock, flags); -+ -+ return t; -+} -+EXPORT_SYMBOL(pwm_channel_handler); -+ -+static irqreturn_t pwm_irq(int id, void *_pwm) -+{ -+ struct pwm *p = _pwm; -+ irqreturn_t handled = IRQ_NONE; -+ u32 irqstat; -+ int index; -+ -+ spin_lock(&p->lock); -+ -+ /* ack irqs, then handle them */ -+ irqstat = pwm_readl(pwm, PWM_ISR); -+ -+ while (irqstat) { -+ struct pwm_channel *ch; -+ void (*handler)(struct pwm_channel *ch); -+ -+ index = ffs(irqstat) - 1; -+ irqstat &= ~(1 << index); -+ ch = pwm->channel[index]; -+ handler = pwm->handler[index]; -+ if (handler && ch) { -+ spin_unlock(&p->lock); -+ handler(ch); -+ spin_lock(&p->lock); -+ handled = IRQ_HANDLED; -+ } -+ } -+ -+ spin_unlock(&p->lock); -+ return handled; -+} -+ -+static int __init pwm_probe(struct platform_device *pdev) -+{ -+ struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ int irq = platform_get_irq(pdev, 0); -+ u32 *mp = pdev->dev.platform_data; -+ struct pwm *p; -+ int status = -EIO; -+ -+ if (pwm) -+ return -EBUSY; -+ if (!r || irq < 0 || !mp || !*mp) -+ return -ENODEV; -+ if (*mp & ~((1<<PWM_NCHAN)-1)) { -+ dev_warn(&pdev->dev, "mask 0x%x ... more than %d channels\n", -+ *mp, PWM_NCHAN); -+ return -EINVAL; -+ } -+ -+ p = kzalloc(sizeof(*p), GFP_KERNEL); -+ if (!p) -+ return -ENOMEM; -+ -+ spin_lock_init(&p->lock); -+ p->pdev = pdev; -+ p->mask = *mp; -+ p->irq = irq; -+ p->base = ioremap(r->start, r->end - r->start + 1); -+ if (!p->base) -+ goto fail; -+ p->clk = clk_get(&pdev->dev, "mck"); -+ if (IS_ERR(p->clk)) { -+ status = PTR_ERR(p->clk); -+ p->clk = NULL; -+ goto fail; -+ } -+ -+ status = request_irq(irq, pwm_irq, 0, pdev->name, p); -+ if (status < 0) -+ goto fail; -+ -+ pwm = p; -+ platform_set_drvdata(pdev, p); -+ -+ return 0; -+ -+fail: -+ if (p->clk) -+ clk_put(p->clk); -+ if (p->base) -+ iounmap(p->base); -+ -+ kfree(p); -+ return status; -+} -+ -+static int __exit pwm_remove(struct platform_device *pdev) -+{ -+ struct pwm *p = platform_get_drvdata(pdev); -+ -+ if (p != pwm) -+ return -EINVAL; -+ -+ clk_enable(pwm->clk); -+ pwm_writel(pwm, PWM_DIS, (1 << PWM_NCHAN) - 1); -+ pwm_writel(pwm, PWM_IDR, (1 << PWM_NCHAN) - 1); -+ clk_disable(pwm->clk); -+ -+ pwm = NULL; -+ -+ free_irq(p->irq, p); -+ clk_put(p->clk); -+ iounmap(p->base); -+ kfree(p); -+ -+ return 0; -+} -+ -+static struct platform_driver atmel_pwm_driver = { -+ .driver = { -+ .name = "atmel_pwm", -+ .owner = THIS_MODULE, -+ }, -+ .remove = __exit_p(pwm_remove), -+ -+ /* NOTE: PWM can keep running in AVR32 "idle" and "frozen" states; -+ * and all AT91sam9263 states, albeit at reduced clock rate if -+ * MCK becomes the slow clock (i.e. what Linux labels STR). -+ */ -+}; -+ -+static int __init pwm_init(void) -+{ -+ return platform_driver_probe(&atmel_pwm_driver, pwm_probe); -+} -+module_init(pwm_init); -+ -+static void __exit pwm_exit(void) -+{ -+ platform_driver_unregister(&atmel_pwm_driver); -+} -+module_exit(pwm_exit); -+ -+MODULE_DESCRIPTION("Driver for AT32/AT91 PWM module"); -+MODULE_LICENSE("GPL"); ---- /dev/null -+++ b/drivers/misc/atmel_tclib.c +diff --exclude=.git -urN linux-2.6.25.6/drivers/misc/atmel_tclib.c avr32-2.6/drivers/misc/atmel_tclib.c +--- linux-2.6.25.6/drivers/misc/atmel_tclib.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/drivers/misc/atmel_tclib.c 2008-06-12 15:03:59.515815344 +0200 @@ -0,0 +1,161 @@ +#include <linux/atmel_tc.h> +#include <linux/clk.h> @@ -13902,21 +9775,13 @@ + return platform_driver_probe(&tc_driver, tc_probe); +} +arch_initcall(tc_init); ---- a/drivers/misc/Kconfig -+++ b/drivers/misc/Kconfig -@@ -13,6 +13,48 @@ - - if MISC_DEVICES +diff --exclude=.git -urN linux-2.6.25.6/drivers/misc/Kconfig avr32-2.6/drivers/misc/Kconfig +--- linux-2.6.25.6/drivers/misc/Kconfig 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/misc/Kconfig 2008-06-12 15:09:41.067816939 +0200 +@@ -22,6 +22,39 @@ + purposes including software controlled power-efficent backlights + on LCD displays, motor control, and waveform generation. -+config ATMEL_PWM -+ tristate "Atmel AT32/AT91 PWM support" -+ depends on AVR32 || ARCH_AT91 -+ help -+ This option enables device driver support for the PWM channels -+ on certain Atmel prcoessors. Pulse Width Modulation is used for -+ purposes including software controlled power-efficent backlights -+ on LCD displays, motor control, and waveform generation. -+ +config ATMEL_TCLIB + bool "Atmel AT32/AT91 Timer/Counter Library" + depends on (AVR32 || ARCH_AT91) @@ -13953,20 +9818,20 @@ config IBM_ASM tristate "Device driver for IBM RSA service processor" depends on X86 && PCI && INPUT && EXPERIMENTAL ---- a/drivers/misc/Makefile -+++ b/drivers/misc/Makefile -@@ -7,7 +7,9 @@ - obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ - obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o +diff --exclude=.git -urN linux-2.6.25.6/drivers/misc/Makefile avr32-2.6/drivers/misc/Makefile +--- linux-2.6.25.6/drivers/misc/Makefile 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/misc/Makefile 2008-06-12 15:09:41.067816939 +0200 +@@ -10,6 +10,7 @@ obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o -+obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o + obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o +obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o + obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o - obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o ---- /dev/null -+++ b/drivers/mmc/host/atmel-mci.c +diff --exclude=.git -urN linux-2.6.25.6/drivers/mmc/host/atmel-mci.c avr32-2.6/drivers/mmc/host/atmel-mci.c +--- linux-2.6.25.6/drivers/mmc/host/atmel-mci.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/drivers/mmc/host/atmel-mci.c 2008-06-12 15:09:41.083816184 +0200 @@ -0,0 +1,1220 @@ +/* + * Atmel MultiMedia Card Interface driver @@ -15188,8 +11053,9 @@ + +MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver"); +MODULE_LICENSE("GPL"); ---- /dev/null -+++ b/drivers/mmc/host/atmel-mci.h +diff --exclude=.git -urN linux-2.6.25.6/drivers/mmc/host/atmel-mci.h avr32-2.6/drivers/mmc/host/atmel-mci.h +--- linux-2.6.25.6/drivers/mmc/host/atmel-mci.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/drivers/mmc/host/atmel-mci.h 2008-06-12 15:09:41.083816184 +0200 @@ -0,0 +1,192 @@ +/* + * Atmel MultiMedia Card Interface driver @@ -15383,8 +11249,9 @@ + __raw_writel((value), (port)->regs + MCI_##reg) + +#endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */ ---- a/drivers/mmc/host/Kconfig -+++ b/drivers/mmc/host/Kconfig +diff --exclude=.git -urN linux-2.6.25.6/drivers/mmc/host/Kconfig avr32-2.6/drivers/mmc/host/Kconfig +--- linux-2.6.25.6/drivers/mmc/host/Kconfig 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mmc/host/Kconfig 2008-06-12 15:09:41.083816184 +0200 @@ -91,6 +91,16 @@ If unsure, say N. @@ -15402,8 +11269,9 @@ config MMC_IMX tristate "Motorola i.MX Multimedia Card Interface support" depends on ARCH_IMX ---- a/drivers/mmc/host/Makefile -+++ b/drivers/mmc/host/Makefile +diff --exclude=.git -urN linux-2.6.25.6/drivers/mmc/host/Makefile avr32-2.6/drivers/mmc/host/Makefile +--- linux-2.6.25.6/drivers/mmc/host/Makefile 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mmc/host/Makefile 2008-06-12 15:09:41.083816184 +0200 @@ -15,6 +15,7 @@ obj-$(CONFIG_MMC_AU1X) += au1xmmc.o obj-$(CONFIG_MMC_OMAP) += omap.o @@ -15412,103 +11280,2352 @@ obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o obj-$(CONFIG_MMC_SPI) += mmc_spi.o ---- a/drivers/mtd/chips/cfi_cmdset_0001.c -+++ b/drivers/mtd/chips/cfi_cmdset_0001.c -@@ -50,6 +50,7 @@ - #define I82802AC 0x00ac - #define MANUFACTURER_ST 0x0020 - #define M50LPW080 0x002F -+#define AT49BV640D 0x02de - - static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); - static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); -@@ -157,6 +158,47 @@ +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/nand/at91_nand.c avr32-2.6/drivers/mtd/nand/at91_nand.c +--- linux-2.6.25.6/drivers/mtd/nand/at91_nand.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/nand/at91_nand.c 1970-01-01 01:00:00.000000000 +0100 +@@ -1,236 +0,0 @@ +-/* +- * drivers/mtd/nand/at91_nand.c +- * +- * Copyright (C) 2003 Rick Bronson +- * +- * Derived from drivers/mtd/nand/autcpu12.c +- * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) +- * +- * Derived from drivers/mtd/spia.c +- * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- * +- */ +- +-#include <linux/slab.h> +-#include <linux/module.h> +-#include <linux/platform_device.h> +-#include <linux/mtd/mtd.h> +-#include <linux/mtd/nand.h> +-#include <linux/mtd/partitions.h> +- +-#include <asm/io.h> +-#include <asm/sizes.h> +- +-#include <asm/hardware.h> +-#include <asm/arch/board.h> +-#include <asm/arch/gpio.h> +- +-struct at91_nand_host { +- struct nand_chip nand_chip; +- struct mtd_info mtd; +- void __iomem *io_base; +- struct at91_nand_data *board; +-}; +- +-/* +- * Hardware specific access to control-lines +- */ +-static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +-{ +- struct nand_chip *nand_chip = mtd->priv; +- struct at91_nand_host *host = nand_chip->priv; +- +- if (cmd == NAND_CMD_NONE) +- return; +- +- if (ctrl & NAND_CLE) +- writeb(cmd, host->io_base + (1 << host->board->cle)); +- else +- writeb(cmd, host->io_base + (1 << host->board->ale)); +-} +- +-/* +- * Read the Device Ready pin. +- */ +-static int at91_nand_device_ready(struct mtd_info *mtd) +-{ +- struct nand_chip *nand_chip = mtd->priv; +- struct at91_nand_host *host = nand_chip->priv; +- +- return at91_get_gpio_value(host->board->rdy_pin); +-} +- +-/* +- * Enable NAND. +- */ +-static void at91_nand_enable(struct at91_nand_host *host) +-{ +- if (host->board->enable_pin) +- at91_set_gpio_value(host->board->enable_pin, 0); +-} +- +-/* +- * Disable NAND. +- */ +-static void at91_nand_disable(struct at91_nand_host *host) +-{ +- if (host->board->enable_pin) +- at91_set_gpio_value(host->board->enable_pin, 1); +-} +- +-#ifdef CONFIG_MTD_PARTITIONS +-const char *part_probes[] = { "cmdlinepart", NULL }; +-#endif +- +-/* +- * Probe for the NAND device. +- */ +-static int __init at91_nand_probe(struct platform_device *pdev) +-{ +- struct at91_nand_host *host; +- struct mtd_info *mtd; +- struct nand_chip *nand_chip; +- int res; +- +-#ifdef CONFIG_MTD_PARTITIONS +- struct mtd_partition *partitions = NULL; +- int num_partitions = 0; +-#endif +- +- /* Allocate memory for the device structure (and zero it) */ +- host = kzalloc(sizeof(struct at91_nand_host), GFP_KERNEL); +- if (!host) { +- printk(KERN_ERR "at91_nand: failed to allocate device structure.\n"); +- return -ENOMEM; +- } +- +- host->io_base = ioremap(pdev->resource[0].start, +- pdev->resource[0].end - pdev->resource[0].start + 1); +- if (host->io_base == NULL) { +- printk(KERN_ERR "at91_nand: ioremap failed\n"); +- kfree(host); +- return -EIO; +- } +- +- mtd = &host->mtd; +- nand_chip = &host->nand_chip; +- host->board = pdev->dev.platform_data; +- +- nand_chip->priv = host; /* link the private data structures */ +- mtd->priv = nand_chip; +- mtd->owner = THIS_MODULE; +- +- /* Set address of NAND IO lines */ +- nand_chip->IO_ADDR_R = host->io_base; +- nand_chip->IO_ADDR_W = host->io_base; +- nand_chip->cmd_ctrl = at91_nand_cmd_ctrl; +- +- if (host->board->rdy_pin) +- nand_chip->dev_ready = at91_nand_device_ready; +- +- nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ +- nand_chip->chip_delay = 20; /* 20us command delay time */ +- +- if (host->board->bus_width_16) /* 16-bit bus width */ +- nand_chip->options |= NAND_BUSWIDTH_16; +- +- platform_set_drvdata(pdev, host); +- at91_nand_enable(host); +- +- if (host->board->det_pin) { +- if (at91_get_gpio_value(host->board->det_pin)) { +- printk ("No SmartMedia card inserted.\n"); +- res = ENXIO; +- goto out; +- } +- } +- +- /* Scan to find existance of the device */ +- if (nand_scan(mtd, 1)) { +- res = -ENXIO; +- goto out; +- } +- +-#ifdef CONFIG_MTD_PARTITIONS +-#ifdef CONFIG_MTD_CMDLINE_PARTS +- mtd->name = "at91_nand"; +- num_partitions = parse_mtd_partitions(mtd, part_probes, +- &partitions, 0); +-#endif +- if (num_partitions <= 0 && host->board->partition_info) +- partitions = host->board->partition_info(mtd->size, +- &num_partitions); +- +- if ((!partitions) || (num_partitions == 0)) { +- printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n"); +- res = ENXIO; +- goto release; +- } +- +- res = add_mtd_partitions(mtd, partitions, num_partitions); +-#else +- res = add_mtd_device(mtd); +-#endif +- +- if (!res) +- return res; +- +-release: +- nand_release(mtd); +-out: +- at91_nand_disable(host); +- platform_set_drvdata(pdev, NULL); +- iounmap(host->io_base); +- kfree(host); +- return res; +-} +- +-/* +- * Remove a NAND device. +- */ +-static int __devexit at91_nand_remove(struct platform_device *pdev) +-{ +- struct at91_nand_host *host = platform_get_drvdata(pdev); +- struct mtd_info *mtd = &host->mtd; +- +- nand_release(mtd); +- +- at91_nand_disable(host); +- +- iounmap(host->io_base); +- kfree(host); +- +- return 0; +-} +- +-static struct platform_driver at91_nand_driver = { +- .probe = at91_nand_probe, +- .remove = at91_nand_remove, +- .driver = { +- .name = "at91_nand", +- .owner = THIS_MODULE, +- }, +-}; +- +-static int __init at91_nand_init(void) +-{ +- return platform_driver_register(&at91_nand_driver); +-} +- +- +-static void __exit at91_nand_exit(void) +-{ +- platform_driver_unregister(&at91_nand_driver); +-} +- +- +-module_init(at91_nand_init); +-module_exit(at91_nand_exit); +- +-MODULE_LICENSE("GPL"); +-MODULE_AUTHOR("Rick Bronson"); +-MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200"); +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/nand/atmel_nand.c avr32-2.6/drivers/mtd/nand/atmel_nand.c +--- linux-2.6.25.6/drivers/mtd/nand/atmel_nand.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/drivers/mtd/nand/atmel_nand.c 2008-06-12 15:09:41.107815889 +0200 +@@ -0,0 +1,650 @@ ++/* ++ * Copyright (C) 2003 Rick Bronson ++ * ++ * Derived from drivers/mtd/nand/autcpu12.c ++ * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) ++ * ++ * Derived from drivers/mtd/spia.c ++ * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) ++ * ++ * ++ * Add Hardware ECC support for AT91SAM9260 / AT91SAM9263 ++ * Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright (C) 2007 ++ * ++ * Derived from Das U-Boot source code ++ * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c) ++ * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas ++ * ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include <linux/slab.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/nand.h> ++#include <linux/mtd/partitions.h> ++ ++#include <linux/gpio.h> ++#include <linux/io.h> ++ ++#include <asm/arch/board.h> ++#include <asm/arch/cpu.h> ++ ++#ifdef CONFIG_MTD_NAND_ATMEL_ECC_HW ++#define hard_ecc 1 ++#else ++#define hard_ecc 0 ++#endif ++ ++#ifdef CONFIG_MTD_NAND_ATMEL_ECC_NONE ++#define no_ecc 1 ++#else ++#define no_ecc 0 ++#endif ++ ++/* Register access macros */ ++#define ecc_readl(add, reg) \ ++ __raw_readl(add + ATMEL_ECC_##reg) ++#define ecc_writel(add, reg, value) \ ++ __raw_writel((value), add + ATMEL_ECC_##reg) ++ ++#include "atmel_nand_ecc.h" /* Hardware ECC registers */ ++ ++/* oob layout for large page size ++ * bad block info is on bytes 0 and 1 ++ * the bytes have to be consecutives to avoid ++ * several NAND_CMD_RNDOUT during read ++ */ ++static struct nand_ecclayout atmel_oobinfo_large = { ++ .eccbytes = 4, ++ .eccpos = {60, 61, 62, 63}, ++ .oobfree = { ++ {2, 58} ++ }, ++}; ++ ++/* oob layout for small page size ++ * bad block info is on bytes 4 and 5 ++ * the bytes have to be consecutives to avoid ++ * several NAND_CMD_RNDOUT during read ++ */ ++static struct nand_ecclayout atmel_oobinfo_small = { ++ .eccbytes = 4, ++ .eccpos = {0, 1, 2, 3}, ++ .oobfree = { ++ {6, 10} ++ }, ++}; ++ ++struct atmel_nand_host { ++ struct nand_chip nand_chip; ++ struct mtd_info mtd; ++ void __iomem *io_base; ++ struct atmel_nand_data *board; ++ struct device *dev; ++ void __iomem *ecc; ++}; ++ ++/* ++ * Enable NAND. ++ */ ++static void atmel_nand_enable(struct atmel_nand_host *host) ++{ ++ if (host->board->enable_pin) ++ gpio_set_value(host->board->enable_pin, 0); ++} ++ ++/* ++ * Disable NAND. ++ */ ++static void atmel_nand_disable(struct atmel_nand_host *host) ++{ ++ if (host->board->enable_pin) ++ gpio_set_value(host->board->enable_pin, 1); ++} ++ ++/* ++ * Hardware specific access to control-lines ++ */ ++static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ struct atmel_nand_host *host = nand_chip->priv; ++ ++ if (ctrl & NAND_CTRL_CHANGE) { ++ if (ctrl & NAND_NCE) ++ atmel_nand_enable(host); ++ else ++ atmel_nand_disable(host); ++ } ++ if (cmd == NAND_CMD_NONE) ++ return; ++ ++ if (ctrl & NAND_CLE) ++ writeb(cmd, host->io_base + (1 << host->board->cle)); ++ else ++ writeb(cmd, host->io_base + (1 << host->board->ale)); ++} ++ ++/* ++ * Read the Device Ready pin. ++ */ ++static int atmel_nand_device_ready(struct mtd_info *mtd) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ struct atmel_nand_host *host = nand_chip->priv; ++ ++ return gpio_get_value(host->board->rdy_pin); ++} ++ ++/* ++ * Minimal-overhead PIO for data access. ++ */ ++static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ ++ __raw_readsb(nand_chip->IO_ADDR_R, buf, len); ++} ++ ++static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ ++ __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2); ++} ++ ++static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ ++ __raw_writesb(nand_chip->IO_ADDR_W, buf, len); ++} ++ ++static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ ++ __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2); ++} ++ ++/* ++ * write oob for small pages ++ */ ++static int atmel_nand_write_oob_512(struct mtd_info *mtd, ++ struct nand_chip *chip, int page) ++{ ++ int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; ++ int eccsize = chip->ecc.size, length = mtd->oobsize; ++ int len, pos, status = 0; ++ const uint8_t *bufpoi = chip->oob_poi; ++ ++ pos = eccsize + chunk; ++ ++ chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); ++ len = min_t(int, length, chunk); ++ chip->write_buf(mtd, bufpoi, len); ++ bufpoi += len; ++ length -= len; ++ if (length > 0) ++ chip->write_buf(mtd, bufpoi, length); ++ ++ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); ++ status = chip->waitfunc(mtd, chip); ++ ++ return status & NAND_STATUS_FAIL ? -EIO : 0; ++ ++} ++ ++/* ++ * read oob for small pages ++ */ ++static int atmel_nand_read_oob_512(struct mtd_info *mtd, ++ struct nand_chip *chip, int page, int sndcmd) ++{ ++ if (sndcmd) { ++ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); ++ sndcmd = 0; ++ } ++ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); ++ return sndcmd; ++} ++ ++/* ++ * Calculate HW ECC ++ * ++ * function called after a write ++ * ++ * mtd: MTD block structure ++ * dat: raw data (unused) ++ * ecc_code: buffer for ECC ++ */ ++static int atmel_nand_calculate(struct mtd_info *mtd, ++ const u_char *dat, unsigned char *ecc_code) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ struct atmel_nand_host *host = nand_chip->priv; ++ uint32_t *eccpos = nand_chip->ecc.layout->eccpos; ++ unsigned int ecc_value; ++ ++ /* get the first 2 ECC bytes */ ++ ecc_value = ecc_readl(host->ecc, PR); ++ ++ ecc_code[eccpos[0]] = ecc_value & 0xFF; ++ ecc_code[eccpos[1]] = (ecc_value >> 8) & 0xFF; ++ ++ /* get the last 2 ECC bytes */ ++ ecc_value = ecc_readl(host->ecc, NPR) & ATMEL_ECC_NPARITY; ++ ++ ecc_code[eccpos[2]] = ecc_value & 0xFF; ++ ecc_code[eccpos[3]] = (ecc_value >> 8) & 0xFF; ++ ++ return 0; ++} ++ ++/* ++ * HW ECC read page function ++ * ++ * mtd: mtd info structure ++ * chip: nand chip info structure ++ * buf: buffer to store read data ++ */ ++static int atmel_nand_read_page(struct mtd_info *mtd, ++ struct nand_chip *chip, uint8_t *buf) ++{ ++ int eccsize = chip->ecc.size; ++ int eccbytes = chip->ecc.bytes; ++ uint32_t *eccpos = chip->ecc.layout->eccpos; ++ uint8_t *p = buf; ++ uint8_t *oob = chip->oob_poi; ++ uint8_t *ecc_pos; ++ int stat; ++ ++ /* ++ * Errata: ALE is incorrectly wired up to the ECC controller ++ * on the AP7000, so it will include the address cycles in the ++ * ECC calculation. ++ * ++ * Workaround: Reset the parity registers before reading the ++ * actual data. ++ */ ++ if (cpu_is_at32ap7000()) { ++ struct atmel_nand_host *host = chip->priv; ++ ecc_writel(host->ecc, CR, ATMEL_ECC_RST); ++ } ++ ++ /* read the page */ ++ chip->read_buf(mtd, p, eccsize); ++ ++ /* move to ECC position if needed */ ++ if (eccpos[0] != 0) { ++ /* This only works on large pages ++ * because the ECC controller waits for ++ * NAND_CMD_RNDOUTSTART after the ++ * NAND_CMD_RNDOUT. ++ * anyway, for small pages, the eccpos[0] == 0 ++ */ ++ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, ++ mtd->writesize + eccpos[0], -1); ++ } ++ ++ /* the ECC controller needs to read the ECC just after the data */ ++ ecc_pos = oob + eccpos[0]; ++ chip->read_buf(mtd, ecc_pos, eccbytes); ++ ++ /* check if there's an error */ ++ stat = chip->ecc.correct(mtd, p, oob, NULL); ++ ++ if (stat < 0) ++ mtd->ecc_stats.failed++; ++ else ++ mtd->ecc_stats.corrected += stat; ++ ++ /* get back to oob start (end of page) */ ++ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); ++ ++ /* read the oob */ ++ chip->read_buf(mtd, oob, mtd->oobsize); ++ ++ return 0; ++} ++ ++/* ++ * HW ECC Correction ++ * ++ * function called after a read ++ * ++ * mtd: MTD block structure ++ * dat: raw data read from the chip ++ * read_ecc: ECC from the chip (unused) ++ * isnull: unused ++ * ++ * Detect and correct a 1 bit error for a page ++ */ ++static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, ++ u_char *read_ecc, u_char *isnull) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ struct atmel_nand_host *host = nand_chip->priv; ++ unsigned int ecc_status; ++ unsigned int ecc_word, ecc_bit; ++ ++ /* get the status from the Status Register */ ++ ecc_status = ecc_readl(host->ecc, SR); ++ ++ /* if there's no error */ ++ if (likely(!(ecc_status & ATMEL_ECC_RECERR))) ++ return 0; ++ ++ /* get error bit offset (4 bits) */ ++ ecc_bit = ecc_readl(host->ecc, PR) & ATMEL_ECC_BITADDR; ++ /* get word address (12 bits) */ ++ ecc_word = ecc_readl(host->ecc, PR) & ATMEL_ECC_WORDADDR; ++ ecc_word >>= 4; ++ ++ /* if there are multiple errors */ ++ if (ecc_status & ATMEL_ECC_MULERR) { ++ /* check if it is a freshly erased block ++ * (filled with 0xff) */ ++ if ((ecc_bit == ATMEL_ECC_BITADDR) ++ && (ecc_word == (ATMEL_ECC_WORDADDR >> 4))) { ++ /* the block has just been erased, return OK */ ++ return 0; ++ } ++ /* it doesn't seems to be a freshly ++ * erased block. ++ * We can't correct so many errors */ ++ dev_dbg(host->dev, "atmel_nand : multiple errors detected." ++ " Unable to correct.\n"); ++ return -EIO; ++ } ++ ++ /* if there's a single bit error : we can correct it */ ++ if (ecc_status & ATMEL_ECC_ECCERR) { ++ /* there's nothing much to do here. ++ * the bit error is on the ECC itself. ++ */ ++ dev_dbg(host->dev, "atmel_nand : one bit error on ECC code." ++ " Nothing to correct\n"); ++ return 0; ++ } ++ ++ dev_dbg(host->dev, "atmel_nand : one bit error on data." ++ " (word offset in the page :" ++ " 0x%x bit offset : 0x%x)\n", ++ ecc_word, ecc_bit); ++ /* correct the error */ ++ if (nand_chip->options & NAND_BUSWIDTH_16) { ++ /* 16 bits words */ ++ ((unsigned short *) dat)[ecc_word] ^= (1 << ecc_bit); ++ } else { ++ /* 8 bits words */ ++ dat[ecc_word] ^= (1 << ecc_bit); ++ } ++ dev_dbg(host->dev, "atmel_nand : error corrected\n"); ++ return 1; ++} ++ ++/* ++ * Enable HW ECC : unused on most chips ++ */ ++static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) ++{ ++ if (cpu_is_at32ap7000()) { ++ struct nand_chip *nand_chip = mtd->priv; ++ struct atmel_nand_host *host = nand_chip->priv; ++ ecc_writel(host->ecc, CR, ATMEL_ECC_RST); ++ } ++} ++ ++#ifdef CONFIG_MTD_PARTITIONS ++static const char *part_probes[] = { "cmdlinepart", NULL }; ++#endif ++ ++/* ++ * Probe for the NAND device. ++ */ ++static int __init atmel_nand_probe(struct platform_device *pdev) ++{ ++ struct atmel_nand_host *host; ++ struct mtd_info *mtd; ++ struct nand_chip *nand_chip; ++ struct resource *regs; ++ struct resource *mem; ++ int res; ++ ++#ifdef CONFIG_MTD_PARTITIONS ++ struct mtd_partition *partitions = NULL; ++ int num_partitions = 0; ++#endif ++ ++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!mem) { ++ printk(KERN_ERR "atmel_nand: can't get I/O resource mem\n"); ++ return -ENXIO; ++ } ++ ++ /* Allocate memory for the device structure (and zero it) */ ++ host = kzalloc(sizeof(struct atmel_nand_host), GFP_KERNEL); ++ if (!host) { ++ printk(KERN_ERR "atmel_nand: failed to allocate device structure.\n"); ++ return -ENOMEM; ++ } ++ ++ host->io_base = ioremap(mem->start, mem->end - mem->start + 1); ++ if (host->io_base == NULL) { ++ printk(KERN_ERR "atmel_nand: ioremap failed\n"); ++ res = -EIO; ++ goto err_nand_ioremap; ++ } ++ ++ mtd = &host->mtd; ++ nand_chip = &host->nand_chip; ++ host->board = pdev->dev.platform_data; ++ host->dev = &pdev->dev; ++ ++ nand_chip->priv = host; /* link the private data structures */ ++ mtd->priv = nand_chip; ++ mtd->owner = THIS_MODULE; ++ ++ /* Set address of NAND IO lines */ ++ nand_chip->IO_ADDR_R = host->io_base; ++ nand_chip->IO_ADDR_W = host->io_base; ++ nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl; ++ ++ if (host->board->rdy_pin) ++ nand_chip->dev_ready = atmel_nand_device_ready; ++ ++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ if (!regs && hard_ecc) { ++ printk(KERN_ERR "atmel_nand: can't get I/O resource " ++ "regs\nFalling back on software ECC\n"); ++ } ++ ++ nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ ++ if (no_ecc) ++ nand_chip->ecc.mode = NAND_ECC_NONE; ++ if (hard_ecc && regs) { ++ host->ecc = ioremap(regs->start, regs->end - regs->start + 1); ++ if (host->ecc == NULL) { ++ printk(KERN_ERR "atmel_nand: ioremap failed\n"); ++ res = -EIO; ++ goto err_ecc_ioremap; ++ } ++ nand_chip->ecc.mode = NAND_ECC_HW_SYNDROME; ++ nand_chip->ecc.calculate = atmel_nand_calculate; ++ nand_chip->ecc.correct = atmel_nand_correct; ++ nand_chip->ecc.hwctl = atmel_nand_hwctl; ++ nand_chip->ecc.read_page = atmel_nand_read_page; ++ nand_chip->ecc.bytes = 4; ++ nand_chip->ecc.prepad = 0; ++ nand_chip->ecc.postpad = 0; ++ } ++ ++ nand_chip->chip_delay = 20; /* 20us command delay time */ ++ ++ if (host->board->bus_width_16) { /* 16-bit bus width */ ++ nand_chip->options |= NAND_BUSWIDTH_16; ++ nand_chip->read_buf = atmel_read_buf16; ++ nand_chip->write_buf = atmel_write_buf16; ++ } else { ++ nand_chip->read_buf = atmel_read_buf; ++ nand_chip->write_buf = atmel_write_buf; ++ } ++ ++ platform_set_drvdata(pdev, host); ++ atmel_nand_enable(host); ++ ++ if (host->board->det_pin) { ++ if (gpio_get_value(host->board->det_pin)) { ++ printk("No SmartMedia card inserted.\n"); ++ res = ENXIO; ++ goto err_no_card; ++ } ++ } ++ ++ /* first scan to find the device and get the page size */ ++ if (nand_scan_ident(mtd, 1)) { ++ res = -ENXIO; ++ goto err_scan_ident; ++ } ++ ++ if (nand_chip->ecc.mode == NAND_ECC_HW_SYNDROME) { ++ /* ECC is calculated for the whole page (1 step) */ ++ nand_chip->ecc.size = mtd->writesize; ++ ++ /* set ECC page size and oob layout */ ++ switch (mtd->writesize) { ++ case 512: ++ nand_chip->ecc.layout = &atmel_oobinfo_small; ++ nand_chip->ecc.read_oob = atmel_nand_read_oob_512; ++ nand_chip->ecc.write_oob = atmel_nand_write_oob_512; ++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); ++ break; ++ case 1024: ++ nand_chip->ecc.layout = &atmel_oobinfo_large; ++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056); ++ break; ++ case 2048: ++ nand_chip->ecc.layout = &atmel_oobinfo_large; ++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112); ++ break; ++ case 4096: ++ nand_chip->ecc.layout = &atmel_oobinfo_large; ++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224); ++ break; ++ default: ++ /* page size not handled by HW ECC */ ++ /* switching back to soft ECC */ ++ nand_chip->ecc.mode = NAND_ECC_SOFT; ++ nand_chip->ecc.calculate = NULL; ++ nand_chip->ecc.correct = NULL; ++ nand_chip->ecc.hwctl = NULL; ++ nand_chip->ecc.read_page = NULL; ++ nand_chip->ecc.postpad = 0; ++ nand_chip->ecc.prepad = 0; ++ nand_chip->ecc.bytes = 0; ++ break; ++ } ++ } ++ ++ /* second phase scan */ ++ if (nand_scan_tail(mtd)) { ++ res = -ENXIO; ++ goto err_scan_tail; ++ } ++ ++#ifdef CONFIG_MTD_PARTITIONS ++#ifdef CONFIG_MTD_CMDLINE_PARTS ++ mtd->name = "atmel_nand"; ++ num_partitions = parse_mtd_partitions(mtd, part_probes, ++ &partitions, 0); ++#endif ++ if (num_partitions <= 0 && host->board->partition_info) ++ partitions = host->board->partition_info(mtd->size, ++ &num_partitions); ++ ++ if ((!partitions) || (num_partitions == 0)) { ++ printk(KERN_ERR "atmel_nand: No parititions defined, or unsupported device.\n"); ++ res = ENXIO; ++ goto err_no_partitions; ++ } ++ ++ res = add_mtd_partitions(mtd, partitions, num_partitions); ++#else ++ res = add_mtd_device(mtd); ++#endif ++ ++ if (!res) ++ return res; ++ ++#ifdef CONFIG_MTD_PARTITIONS ++err_no_partitions: ++#endif ++ nand_release(mtd); ++err_scan_tail: ++err_scan_ident: ++err_no_card: ++ atmel_nand_disable(host); ++ platform_set_drvdata(pdev, NULL); ++ if (host->ecc) ++ iounmap(host->ecc); ++err_ecc_ioremap: ++ iounmap(host->io_base); ++err_nand_ioremap: ++ kfree(host); ++ return res; ++} ++ ++/* ++ * Remove a NAND device. ++ */ ++static int __exit atmel_nand_remove(struct platform_device *pdev) ++{ ++ struct atmel_nand_host *host = platform_get_drvdata(pdev); ++ struct mtd_info *mtd = &host->mtd; ++ ++ nand_release(mtd); ++ ++ atmel_nand_disable(host); ++ ++ if (host->ecc) ++ iounmap(host->ecc); ++ iounmap(host->io_base); ++ kfree(host); ++ ++ return 0; ++} ++ ++static struct platform_driver atmel_nand_driver = { ++ .remove = __exit_p(atmel_nand_remove), ++ .driver = { ++ .name = "atmel_nand", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init atmel_nand_init(void) ++{ ++ return platform_driver_probe(&atmel_nand_driver, atmel_nand_probe); ++} ++ ++ ++static void __exit atmel_nand_exit(void) ++{ ++ platform_driver_unregister(&atmel_nand_driver); ++} ++ ++ ++module_init(atmel_nand_init); ++module_exit(atmel_nand_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Rick Bronson"); ++MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91 / AVR32"); ++MODULE_ALIAS("platform:atmel_nand"); +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/nand/atmel_nand_ecc.h avr32-2.6/drivers/mtd/nand/atmel_nand_ecc.h +--- linux-2.6.25.6/drivers/mtd/nand/atmel_nand_ecc.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/drivers/mtd/nand/atmel_nand_ecc.h 2008-06-12 15:09:41.111815840 +0200 +@@ -0,0 +1,36 @@ ++/* ++ * Error Corrected Code Controller (ECC) - System peripherals regsters. ++ * Based on AT91SAM9260 datasheet revision B. ++ * ++ * 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. ++ */ ++ ++#ifndef ATMEL_NAND_ECC_H ++#define ATMEL_NAND_ECC_H ++ ++#define ATMEL_ECC_CR 0x00 /* Control register */ ++#define ATMEL_ECC_RST (1 << 0) /* Reset parity */ ++ ++#define ATMEL_ECC_MR 0x04 /* Mode register */ ++#define ATMEL_ECC_PAGESIZE (3 << 0) /* Page Size */ ++#define ATMEL_ECC_PAGESIZE_528 (0) ++#define ATMEL_ECC_PAGESIZE_1056 (1) ++#define ATMEL_ECC_PAGESIZE_2112 (2) ++#define ATMEL_ECC_PAGESIZE_4224 (3) ++ ++#define ATMEL_ECC_SR 0x08 /* Status register */ ++#define ATMEL_ECC_RECERR (1 << 0) /* Recoverable Error */ ++#define ATMEL_ECC_ECCERR (1 << 1) /* ECC Single Bit Error */ ++#define ATMEL_ECC_MULERR (1 << 2) /* Multiple Errors */ ++ ++#define ATMEL_ECC_PR 0x0c /* Parity register */ ++#define ATMEL_ECC_BITADDR (0xf << 0) /* Bit Error Address */ ++#define ATMEL_ECC_WORDADDR (0xfff << 4) /* Word Error Address */ ++ ++#define ATMEL_ECC_NPR 0x10 /* NParity register */ ++#define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */ ++ ++#endif +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/nand/bf5xx_nand.c avr32-2.6/drivers/mtd/nand/bf5xx_nand.c +--- linux-2.6.25.6/drivers/mtd/nand/bf5xx_nand.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/nand/bf5xx_nand.c 2008-06-12 15:09:41.111815840 +0200 +@@ -803,3 +803,4 @@ + MODULE_LICENSE("GPL"); + MODULE_AUTHOR(DRV_AUTHOR); + MODULE_DESCRIPTION(DRV_DESC); ++MODULE_ALIAS("platform:" DRV_NAME); +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/nand/Kconfig avr32-2.6/drivers/mtd/nand/Kconfig +--- linux-2.6.25.6/drivers/mtd/nand/Kconfig 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/nand/Kconfig 2008-06-12 15:09:41.107815889 +0200 +@@ -272,12 +272,54 @@ + + If you say "m", the module will be called "cs553x_nand.ko". + +-config MTD_NAND_AT91 +- bool "Support for NAND Flash / SmartMedia on AT91" +- depends on ARCH_AT91 ++config MTD_NAND_ATMEL ++ bool "Support for NAND Flash / SmartMedia on AT91 and AVR32" ++ depends on ARCH_AT91 || AVR32 + help + Enables support for NAND Flash / Smart Media Card interface +- on Atmel AT91 processors. ++ on Atmel AT91 and AVR32 processors. ++choice ++ prompt "ECC management for NAND Flash / SmartMedia on AT91 / AVR32" ++ depends on MTD_NAND_ATMEL ++ ++config MTD_NAND_ATMEL_ECC_HW ++ bool "Hardware ECC" ++ depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 || AVR32 ++ help ++ Use hardware ECC instead of software ECC when the chip ++ supports it. ++ ++ The hardware ECC controller is capable of single bit error ++ correction and 2-bit random detection per page. ++ ++ NB : hardware and software ECC schemes are incompatible. ++ If you switch from one to another, you'll have to erase your ++ mtd partition. ++ ++ If unsure, say Y ++ ++config MTD_NAND_ATMEL_ECC_SOFT ++ bool "Software ECC" ++ help ++ Use software ECC. ++ ++ NB : hardware and software ECC schemes are incompatible. ++ If you switch from one to another, you'll have to erase your ++ mtd partition. ++ ++config MTD_NAND_ATMEL_ECC_NONE ++ bool "No ECC (testing only, DANGEROUS)" ++ depends on DEBUG_KERNEL ++ help ++ No ECC will be used. ++ It's not a good idea and it should be reserved for testing ++ purpose only. ++ ++ If unsure, say N ++ ++ endchoice ++ ++endchoice + + config MTD_NAND_CM_X270 + tristate "Support for NAND Flash on CM-X270 modules" +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/nand/Makefile avr32-2.6/drivers/mtd/nand/Makefile +--- linux-2.6.25.6/drivers/mtd/nand/Makefile 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/nand/Makefile 2008-06-12 15:09:41.107815889 +0200 +@@ -24,7 +24,7 @@ + obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o + obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o + obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o +-obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o ++obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o + obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o + obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o + obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/nand/ndfc.c avr32-2.6/drivers/mtd/nand/ndfc.c +--- linux-2.6.25.6/drivers/mtd/nand/ndfc.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/nand/ndfc.c 2008-06-12 15:03:59.579815954 +0200 +@@ -317,3 +317,5 @@ + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); + MODULE_DESCRIPTION("Platform driver for NDFC"); ++MODULE_ALIAS("platform:ndfc-chip"); ++MODULE_ALIAS("platform:ndfc-nand"); +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/nand/orion_nand.c avr32-2.6/drivers/mtd/nand/orion_nand.c +--- linux-2.6.25.6/drivers/mtd/nand/orion_nand.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/nand/orion_nand.c 2008-06-12 15:09:41.115816070 +0200 +@@ -169,3 +169,4 @@ + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Tzachi Perelstein"); + MODULE_DESCRIPTION("NAND glue for Orion platforms"); ++MODULE_ALIAS("platform:orion_nand"); +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/nand/plat_nand.c avr32-2.6/drivers/mtd/nand/plat_nand.c +--- linux-2.6.25.6/drivers/mtd/nand/plat_nand.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/nand/plat_nand.c 2008-06-12 15:09:41.115816070 +0200 +@@ -150,3 +150,4 @@ + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Vitaly Wool"); + MODULE_DESCRIPTION("Simple generic NAND driver"); ++MODULE_ALIAS("platform:gen_nand"); +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/nand/s3c2410.c avr32-2.6/drivers/mtd/nand/s3c2410.c +--- linux-2.6.25.6/drivers/mtd/nand/s3c2410.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/nand/s3c2410.c 2008-06-12 15:09:41.115816070 +0200 +@@ -927,3 +927,6 @@ + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); + MODULE_DESCRIPTION("S3C24XX MTD NAND driver"); ++MODULE_ALIAS("platform:s3c2410-nand"); ++MODULE_ALIAS("platform:s3c2412-nand"); ++MODULE_ALIAS("platform:s3c2440-nand"); +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/build.c avr32-2.6/drivers/mtd/ubi/build.c +--- linux-2.6.25.6/drivers/mtd/ubi/build.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/ubi/build.c 2008-06-12 15:09:41.119815462 +0200 +@@ -355,15 +355,34 @@ } - #endif -+/* Atmel chips don't use the same PRI format as Intel chips */ -+static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param) -+{ -+ struct map_info *map = mtd->priv; -+ struct cfi_private *cfi = map->fldrv_priv; -+ struct cfi_pri_intelext *extp = cfi->cmdset_priv; -+ struct cfi_pri_atmel atmel_pri; -+ uint32_t features = 0; -+ -+ /* Reverse byteswapping */ -+ extp->FeatureSupport = cpu_to_le32(extp->FeatureSupport); -+ extp->BlkStatusRegMask = cpu_to_le16(extp->BlkStatusRegMask); -+ extp->ProtRegAddr = cpu_to_le16(extp->ProtRegAddr); -+ -+ memcpy(&atmel_pri, extp, sizeof(atmel_pri)); -+ memset((char *)extp + 5, 0, sizeof(*extp) - 5); -+ -+ printk(KERN_ERR "atmel Features: %02x\n", atmel_pri.Features); -+ -+ if (atmel_pri.Features & 0x01) /* chip erase supported */ -+ features |= (1<<0); -+ if (atmel_pri.Features & 0x02) /* erase suspend supported */ -+ features |= (1<<1); -+ if (atmel_pri.Features & 0x04) /* program suspend supported */ -+ features |= (1<<2); -+ if (atmel_pri.Features & 0x08) /* simultaneous operations supported */ -+ features |= (1<<9); -+ if (atmel_pri.Features & 0x20) /* page mode read supported */ -+ features |= (1<<7); -+ if (atmel_pri.Features & 0x40) /* queued erase supported */ -+ features |= (1<<4); -+ if (atmel_pri.Features & 0x80) /* Protection bits supported */ -+ features |= (1<<6); -+ -+ extp->FeatureSupport = features; -+ -+ /* burst write mode not supported */ -+ cfi->cfiq->BufWriteTimeoutTyp = 0; -+ cfi->cfiq->BufWriteTimeoutMax = 0; -+} -+ - #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE - /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ - static void fixup_intel_strataflash(struct mtd_info *mtd, void* param) -@@ -234,6 +276,7 @@ + /** ++ * free_user_volumes - free all user volumes. ++ * @ubi: UBI device description object ++ * ++ * Normally the volumes are freed at the release function of the volume device ++ * objects. However, on error paths the volumes have to be freed before the ++ * device objects have been initialized. ++ */ ++static void free_user_volumes(struct ubi_device *ubi) ++{ ++ int i; ++ ++ for (i = 0; i < ubi->vtbl_slots; i++) ++ if (ubi->volumes[i]) { ++ kfree(ubi->volumes[i]->eba_tbl); ++ kfree(ubi->volumes[i]); ++ } ++} ++ ++/** + * uif_init - initialize user interfaces for an UBI device. + * @ubi: UBI device description object + * + * This function returns zero in case of success and a negative error code in +- * case of failure. ++ * case of failure. Note, this function destroys all volumes if it failes. + */ + static int uif_init(struct ubi_device *ubi) + { +- int i, err; ++ int i, err, do_free = 0; + dev_t dev; + + sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); +@@ -410,10 +429,13 @@ + + out_volumes: + kill_volumes(ubi); ++ do_free = 0; + out_sysfs: + ubi_sysfs_close(ubi); + cdev_del(&ubi->cdev); + out_unreg: ++ if (do_free) ++ free_user_volumes(ubi); + unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); + ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err); + return err; +@@ -422,6 +444,10 @@ + /** + * uif_close - close user interfaces for an UBI device. + * @ubi: UBI device description object ++ * ++ * Note, since this function un-registers UBI volume device objects (@vol->dev), ++ * the memory allocated voe the volumes is freed as well (in the release ++ * function). + */ + static void uif_close(struct ubi_device *ubi) + { +@@ -432,6 +458,21 @@ } - static struct cfi_fixup cfi_fixup_table[] = { -+ { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL }, - #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE - { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, + /** ++ * free_internal_volumes - free internal volumes. ++ * @ubi: UBI device description object ++ */ ++static void free_internal_volumes(struct ubi_device *ubi) ++{ ++ int i; ++ ++ for (i = ubi->vtbl_slots; ++ i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) { ++ kfree(ubi->volumes[i]->eba_tbl); ++ kfree(ubi->volumes[i]); ++ } ++} ++ ++/** + * attach_by_scanning - attach an MTD device using scanning method. + * @ubi: UBI device descriptor + * +@@ -475,6 +516,7 @@ + out_wl: + ubi_wl_close(ubi); + out_vtbl: ++ free_internal_volumes(ubi); + vfree(ubi->vtbl); + out_si: + ubi_scan_destroy_si(si); +@@ -530,7 +572,11 @@ + ubi->min_io_size = ubi->mtd->writesize; + ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft; + +- /* Make sure minimal I/O unit is power of 2 */ ++ /* ++ * Make sure minimal I/O unit is power of 2. Note, there is no ++ * fundamental reason for this assumption. It is just an optimization ++ * which allows us to avoid costly division operations. ++ */ + if (!is_power_of_2(ubi->min_io_size)) { + ubi_err("min. I/O unit (%d) is not power of 2", + ubi->min_io_size); +@@ -581,7 +627,7 @@ + if (ubi->vid_hdr_offset < UBI_EC_HDR_SIZE || + ubi->leb_start < ubi->vid_hdr_offset + UBI_VID_HDR_SIZE || + ubi->leb_start > ubi->peb_size - UBI_VID_HDR_SIZE || +- ubi->leb_start % ubi->min_io_size) { ++ ubi->leb_start & (ubi->min_io_size - 1)) { + ubi_err("bad VID header (%d) or data offsets (%d)", + ubi->vid_hdr_offset, ubi->leb_start); + return -EINVAL; +@@ -606,8 +652,16 @@ + ubi->ro_mode = 1; + } + +- dbg_msg("leb_size %d", ubi->leb_size); +- dbg_msg("ro_mode %d", ubi->ro_mode); ++ ubi_msg("physical eraseblock size: %d bytes (%d KiB)", ++ ubi->peb_size, ubi->peb_size >> 10); ++ ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size); ++ ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size); ++ if (ubi->hdrs_min_io_size != ubi->min_io_size) ++ ubi_msg("sub-page size: %d", ++ ubi->hdrs_min_io_size); ++ ubi_msg("VID header offset: %d (aligned %d)", ++ ubi->vid_hdr_offset, ubi->vid_hdr_aloffset); ++ ubi_msg("data offset: %d", ubi->leb_start); + + /* + * Note, ideally, we have to initialize ubi->bad_peb_count here. But +@@ -638,7 +692,7 @@ + + /* + * Clear the auto-resize flag in the volume in-memory copy of the +- * volume table, and 'ubi_resize_volume()' will propogate this change ++ * volume table, and 'ubi_resize_volume()' will propagate this change + * to the flash. + */ + ubi->vtbl[vol_id].flags &= ~UBI_VTBL_AUTORESIZE_FLG; +@@ -647,7 +701,7 @@ + struct ubi_vtbl_record vtbl_rec; + + /* +- * No avalilable PEBs to re-size the volume, clear the flag on ++ * No available PEBs to re-size the volume, clear the flag on + * flash and exit. + */ + memcpy(&vtbl_rec, &ubi->vtbl[vol_id], +@@ -680,7 +734,7 @@ + * + * This function attaches MTD device @mtd_dev to UBI and assign @ubi_num number + * to the newly created UBI device, unless @ubi_num is %UBI_DEV_NUM_AUTO, in +- * which case this function finds a vacant device nubert and assings it ++ * which case this function finds a vacant device number and assigns it + * automatically. Returns the new UBI device number in case of success and a + * negative error code in case of failure. + * +@@ -690,7 +744,7 @@ + int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) + { + struct ubi_device *ubi; +- int i, err; ++ int i, err, do_free = 1; + + /* + * Check if we already have the same MTD device attached. +@@ -755,8 +809,7 @@ + mutex_init(&ubi->volumes_mutex); + spin_lock_init(&ubi->volumes_lock); + +- dbg_msg("attaching mtd%d to ubi%d: VID header offset %d", +- mtd->index, ubi_num, vid_hdr_offset); ++ ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num); + + err = io_init(ubi); + if (err) +@@ -791,7 +844,7 @@ + + err = uif_init(ubi); + if (err) +- goto out_detach; ++ goto out_nofree; + + ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name); + if (IS_ERR(ubi->bgt_thread)) { +@@ -804,15 +857,8 @@ + ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num); + ubi_msg("MTD device name: \"%s\"", mtd->name); + ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); +- ubi_msg("physical eraseblock size: %d bytes (%d KiB)", +- ubi->peb_size, ubi->peb_size >> 10); +- ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size); + ubi_msg("number of good PEBs: %d", ubi->good_peb_count); + ubi_msg("number of bad PEBs: %d", ubi->bad_peb_count); +- ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size); +- ubi_msg("VID header offset: %d (aligned %d)", +- ubi->vid_hdr_offset, ubi->vid_hdr_aloffset); +- ubi_msg("data offset: %d", ubi->leb_start); + ubi_msg("max. allowed volumes: %d", ubi->vtbl_slots); + ubi_msg("wear-leveling threshold: %d", CONFIG_MTD_UBI_WL_THRESHOLD); + ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT); +@@ -835,9 +881,13 @@ + + out_uif: + uif_close(ubi); ++out_nofree: ++ do_free = 0; + out_detach: +- ubi_eba_close(ubi); + ubi_wl_close(ubi); ++ if (do_free) ++ free_user_volumes(ubi); ++ free_internal_volumes(ubi); + vfree(ubi->vtbl); + out_free: + vfree(ubi->peb_buf1); +@@ -899,8 +949,8 @@ + kthread_stop(ubi->bgt_thread); + + uif_close(ubi); +- ubi_eba_close(ubi); + ubi_wl_close(ubi); ++ free_internal_volumes(ubi); + vfree(ubi->vtbl); + put_mtd_device(ubi->mtd); + vfree(ubi->peb_buf1); +@@ -950,8 +1000,7 @@ + BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64); + + if (mtd_devs > UBI_MAX_DEVICES) { +- printk(KERN_ERR "UBI error: too many MTD devices, " +- "maximum is %d\n", UBI_MAX_DEVICES); ++ ubi_err("too many MTD devices, maximum is %d", UBI_MAX_DEVICES); + return -EINVAL; + } + +@@ -959,25 +1008,25 @@ + ubi_class = class_create(THIS_MODULE, UBI_NAME_STR); + if (IS_ERR(ubi_class)) { + err = PTR_ERR(ubi_class); +- printk(KERN_ERR "UBI error: cannot create UBI class\n"); ++ ubi_err("cannot create UBI class"); + goto out; + } + + err = class_create_file(ubi_class, &ubi_version); + if (err) { +- printk(KERN_ERR "UBI error: cannot create sysfs file\n"); ++ ubi_err("cannot create sysfs file"); + goto out_class; + } + + err = misc_register(&ubi_ctrl_cdev); + if (err) { +- printk(KERN_ERR "UBI error: cannot register device\n"); ++ ubi_err("cannot register device"); + goto out_version; + } + + ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab", +- sizeof(struct ubi_wl_entry), +- 0, 0, NULL); ++ sizeof(struct ubi_wl_entry), ++ 0, 0, NULL); + if (!ubi_wl_entry_slab) + goto out_dev_unreg; + +@@ -1000,8 +1049,7 @@ + mutex_unlock(&ubi_devices_mutex); + if (err < 0) { + put_mtd_device(mtd); +- printk(KERN_ERR "UBI error: cannot attach mtd%d\n", +- mtd->index); ++ ubi_err("cannot attach mtd%d", mtd->index); + goto out_detach; + } + } +@@ -1023,7 +1071,7 @@ + out_class: + class_destroy(ubi_class); + out: +- printk(KERN_ERR "UBI error: cannot initialize UBI, error %d\n", err); ++ ubi_err("UBI error: cannot initialize UBI, error %d", err); + return err; + } + module_init(ubi_init); +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/cdev.c avr32-2.6/drivers/mtd/ubi/cdev.c +--- linux-2.6.25.6/drivers/mtd/ubi/cdev.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/ubi/cdev.c 2008-06-12 15:09:41.119815462 +0200 +@@ -290,7 +290,7 @@ + off = do_div(tmp, vol->usable_leb_size); + lnum = tmp; + +- if (off % ubi->min_io_size) { ++ if (off & (ubi->min_io_size - 1)) { + dbg_err("unaligned position"); + return -EINVAL; + } +@@ -299,7 +299,7 @@ + count_save = count = vol->used_bytes - *offp; + + /* We can write only in fractions of the minimum I/O unit */ +- if (count % ubi->min_io_size) { ++ if (count & (ubi->min_io_size - 1)) { + dbg_err("unaligned write length"); + return -EINVAL; + } +@@ -559,7 +559,7 @@ + if (req->alignment > ubi->leb_size) + goto bad; + +- n = req->alignment % ubi->min_io_size; ++ n = req->alignment & (ubi->min_io_size - 1); + if (req->alignment != 1 && n) + goto bad; + +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/debug.h avr32-2.6/drivers/mtd/ubi/debug.h +--- linux-2.6.25.6/drivers/mtd/ubi/debug.h 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/ubi/debug.h 2008-06-12 15:09:41.123815692 +0200 +@@ -99,8 +99,10 @@ + #ifdef CONFIG_MTD_UBI_DEBUG_MSG_BLD + /* Initialization and build messages */ + #define dbg_bld(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) ++#define UBI_IO_DEBUG 1 + #else + #define dbg_bld(fmt, ...) ({}) ++#define UBI_IO_DEBUG 0 #endif ---- a/drivers/mtd/chips/cfi_cmdset_0002.c -+++ b/drivers/mtd/chips/cfi_cmdset_0002.c -@@ -186,6 +186,10 @@ - extp->TopBottom = 2; + + #ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_BITFLIPS +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/eba.c avr32-2.6/drivers/mtd/ubi/eba.c +--- linux-2.6.25.6/drivers/mtd/ubi/eba.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/ubi/eba.c 2008-06-12 15:09:41.123815692 +0200 +@@ -752,7 +752,7 @@ + /* If this is the last LEB @len may be unaligned */ + len = ALIGN(data_size, ubi->min_io_size); else - extp->TopBottom = 3; -+ -+ /* burst write mode not supported */ -+ cfi->cfiq->BufWriteTimeoutTyp = 0; -+ cfi->cfiq->BufWriteTimeoutMax = 0; +- ubi_assert(len % ubi->min_io_size == 0); ++ ubi_assert(!(len & (ubi->min_io_size - 1))); + + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); + if (!vid_hdr) +@@ -1233,20 +1233,3 @@ + } + return err; } +- +-/** +- * ubi_eba_close - close EBA unit. +- * @ubi: UBI device description object +- */ +-void ubi_eba_close(const struct ubi_device *ubi) +-{ +- int i, num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT; +- +- dbg_eba("close EBA unit"); +- +- for (i = 0; i < num_volumes; i++) { +- if (!ubi->volumes[i]) +- continue; +- kfree(ubi->volumes[i]->eba_tbl); +- } +-} +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/gluebi.c avr32-2.6/drivers/mtd/ubi/gluebi.c +--- linux-2.6.25.6/drivers/mtd/ubi/gluebi.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/ubi/gluebi.c 2008-06-12 15:03:59.587815297 +0200 +@@ -291,11 +291,12 @@ + /* + * In case of dynamic volume, MTD device size is just volume size. In + * case of a static volume the size is equivalent to the amount of data +- * bytes, which is zero at this moment and will be changed after volume +- * update. ++ * bytes. + */ + if (vol->vol_type == UBI_DYNAMIC_VOLUME) + mtd->size = vol->usable_leb_size * vol->reserved_pebs; ++ else ++ mtd->size = vol->used_bytes; + + if (add_mtd_device(mtd)) { + ubi_err("cannot not add MTD device\n"); +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/io.c avr32-2.6/drivers/mtd/ubi/io.c +--- linux-2.6.25.6/drivers/mtd/ubi/io.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/ubi/io.c 2008-06-12 15:03:59.587815297 +0200 +@@ -631,6 +631,8 @@ + + dbg_io("read EC header from PEB %d", pnum); + ubi_assert(pnum >= 0 && pnum < ubi->peb_count); ++ if (UBI_IO_DEBUG) ++ verbose = 1; + + err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE); + if (err) { +@@ -904,6 +906,8 @@ + + dbg_io("read VID header from PEB %d", pnum); + ubi_assert(pnum >= 0 && pnum < ubi->peb_count); ++ if (UBI_IO_DEBUG) ++ verbose = 1; + + p = (char *)vid_hdr - ubi->vid_hdr_shift; + err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset, +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/kapi.c avr32-2.6/drivers/mtd/ubi/kapi.c +--- linux-2.6.25.6/drivers/mtd/ubi/kapi.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/ubi/kapi.c 2008-06-12 15:09:41.123815692 +0200 +@@ -397,8 +397,8 @@ + return -EROFS; + + if (lnum < 0 || lnum >= vol->reserved_pebs || offset < 0 || len < 0 || +- offset + len > vol->usable_leb_size || offset % ubi->min_io_size || +- len % ubi->min_io_size) ++ offset + len > vol->usable_leb_size || ++ offset & (ubi->min_io_size - 1) || len & (ubi->min_io_size - 1)) + return -EINVAL; + + if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM && +@@ -447,7 +447,7 @@ + return -EROFS; + + if (lnum < 0 || lnum >= vol->reserved_pebs || len < 0 || +- len > vol->usable_leb_size || len % ubi->min_io_size) ++ len > vol->usable_leb_size || len & (ubi->min_io_size - 1)) + return -EINVAL; + + if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM && +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/Kconfig avr32-2.6/drivers/mtd/ubi/Kconfig +--- linux-2.6.25.6/drivers/mtd/ubi/Kconfig 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/ubi/Kconfig 2008-06-12 15:03:59.583815905 +0200 +@@ -24,8 +24,13 @@ + erase counter value and the lowest erase counter value of eraseblocks + of UBI devices. When this threshold is exceeded, UBI starts performing + wear leveling by means of moving data from eraseblock with low erase +- counter to eraseblocks with high erase counter. Leave the default +- value if unsure. ++ counter to eraseblocks with high erase counter. ++ ++ The default value should be OK for SLC NAND flashes, NOR flashes and ++ other flashes which have eraseblock life-cycle 100000 or more. ++ However, in case of MLC NAND flashes which typically have eraseblock ++ life-cycle less then 10000, the threshold should be lessened (e.g., ++ to 128 or 256, although it does not have to be power of 2). + + config MTD_UBI_BEB_RESERVE + int "Percentage of reserved eraseblocks for bad eraseblocks handling" +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/misc.c avr32-2.6/drivers/mtd/ubi/misc.c +--- linux-2.6.25.6/drivers/mtd/ubi/misc.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/ubi/misc.c 2008-06-12 15:09:41.123815692 +0200 +@@ -37,7 +37,7 @@ + { + int i; + +- ubi_assert(length % ubi->min_io_size == 0); ++ ubi_assert(!(length & (ubi->min_io_size - 1))); + + for (i = length - 1; i >= 0; i--) + if (((const uint8_t *)buf)[i] != 0xFF) +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/scan.c avr32-2.6/drivers/mtd/ubi/scan.c +--- linux-2.6.25.6/drivers/mtd/ubi/scan.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/ubi/scan.c 2008-06-12 15:03:59.587815297 +0200 +@@ -42,6 +42,7 @@ + + #include <linux/err.h> + #include <linux/crc32.h> ++#include <asm/div64.h> + #include "ubi.h" - static void fixup_use_secsi(struct mtd_info *mtd, void *param) -@@ -218,6 +222,7 @@ + #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID +@@ -92,27 +93,6 @@ } - static struct cfi_fixup cfi_fixup_table[] = { -+ { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL }, - #ifdef AMD_BOOTLOC_BUG - { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL }, - #endif -@@ -230,7 +235,6 @@ - #if !FORCE_WORD_WRITE - { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, }, - #endif -- { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL }, - { 0, 0, NULL, NULL } + /** +- * commit_to_mean_value - commit intermediate results to the final mean erase +- * counter value. +- * @si: scanning information +- * +- * This is a helper function which calculates partial mean erase counter mean +- * value and adds it to the resulting mean value. As we can work only in +- * integer arithmetic and we want to calculate the mean value of erase counter +- * accurately, we first sum erase counter values in @si->ec_sum variable and +- * count these components in @si->ec_count. If this temporary @si->ec_sum is +- * going to overflow, we calculate the partial mean value +- * (@si->ec_sum/@si->ec_count) and add it to @si->mean_ec. +- */ +-static void commit_to_mean_value(struct ubi_scan_info *si) +-{ +- si->ec_sum /= si->ec_count; +- if (si->ec_sum % si->ec_count >= si->ec_count / 2) +- si->mean_ec += 1; +- si->mean_ec += si->ec_sum; +-} +- +-/** + * validate_vid_hdr - check that volume identifier header is correct and + * consistent. + * @vid_hdr: the volume identifier header to check +@@ -901,15 +881,8 @@ + + adjust_mean_ec: + if (!ec_corr) { +- if (si->ec_sum + ec < ec) { +- commit_to_mean_value(si); +- si->ec_sum = 0; +- si->ec_count = 0; +- } else { +- si->ec_sum += ec; +- si->ec_count += 1; +- } +- ++ si->ec_sum += ec; ++ si->ec_count += 1; + if (ec > si->max_ec) + si->max_ec = ec; + if (ec < si->min_ec) +@@ -965,9 +938,11 @@ + + dbg_msg("scanning is finished"); + +- /* Finish mean erase counter calculations */ +- if (si->ec_count) +- commit_to_mean_value(si); ++ /* Calculate mean erase counter */ ++ if (si->ec_count) { ++ do_div(si->ec_sum, si->ec_count); ++ si->mean_ec = si->ec_sum; ++ } + + if (si->is_empty) + ubi_msg("empty MTD device detected"); +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/scan.h avr32-2.6/drivers/mtd/ubi/scan.h +--- linux-2.6.25.6/drivers/mtd/ubi/scan.h 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/ubi/scan.h 2008-06-12 15:03:59.587815297 +0200 +@@ -124,7 +124,7 @@ + int max_ec; + unsigned long long max_sqnum; + int mean_ec; +- int ec_sum; ++ uint64_t ec_sum; + int ec_count; }; - static struct cfi_fixup jedec_fixup_table[] = { ---- /dev/null -+++ b/drivers/pcmcia/at32_cf.c + +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/ubi.h avr32-2.6/drivers/mtd/ubi/ubi.h +--- linux-2.6.25.6/drivers/mtd/ubi/ubi.h 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/ubi/ubi.h 2008-06-12 15:09:41.123815692 +0200 +@@ -37,10 +37,9 @@ + #include <linux/string.h> + #include <linux/vmalloc.h> + #include <linux/mtd/mtd.h> +- +-#include <mtd/ubi-header.h> + #include <linux/mtd/ubi.h> + ++#include "ubi-media.h" + #include "scan.h" + #include "debug.h" + +@@ -478,7 +477,6 @@ + int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, + struct ubi_vid_hdr *vid_hdr); + int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si); +-void ubi_eba_close(const struct ubi_device *ubi); + + /* wl.c */ + int ubi_wl_get_peb(struct ubi_device *ubi, int dtype); +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/ubi-media.h avr32-2.6/drivers/mtd/ubi/ubi-media.h +--- linux-2.6.25.6/drivers/mtd/ubi/ubi-media.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/drivers/mtd/ubi/ubi-media.h 2008-06-12 15:03:59.587815297 +0200 +@@ -0,0 +1,372 @@ ++/* ++ * Copyright (c) International Business Machines Corp., 2006 ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * Authors: Artem Bityutskiy (Битюцкий Артём) ++ * Thomas Gleixner ++ * Frank Haverkamp ++ * Oliver Lohmann ++ * Andreas Arnez ++ */ ++ ++/* ++ * This file defines the layout of UBI headers and all the other UBI on-flash ++ * data structures. ++ */ ++ ++#ifndef __UBI_MEDIA_H__ ++#define __UBI_MEDIA_H__ ++ ++#include <asm/byteorder.h> ++ ++/* The version of UBI images supported by this implementation */ ++#define UBI_VERSION 1 ++ ++/* The highest erase counter value supported by this implementation */ ++#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF ++ ++/* The initial CRC32 value used when calculating CRC checksums */ ++#define UBI_CRC32_INIT 0xFFFFFFFFU ++ ++/* Erase counter header magic number (ASCII "UBI#") */ ++#define UBI_EC_HDR_MAGIC 0x55424923 ++/* Volume identifier header magic number (ASCII "UBI!") */ ++#define UBI_VID_HDR_MAGIC 0x55424921 ++ ++/* ++ * Volume type constants used in the volume identifier header. ++ * ++ * @UBI_VID_DYNAMIC: dynamic volume ++ * @UBI_VID_STATIC: static volume ++ */ ++enum { ++ UBI_VID_DYNAMIC = 1, ++ UBI_VID_STATIC = 2 ++}; ++ ++/* ++ * Volume flags used in the volume table record. ++ * ++ * @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume ++ * ++ * %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume ++ * table. UBI automatically re-sizes the volume which has this flag and makes ++ * the volume to be of largest possible size. This means that if after the ++ * initialization UBI finds out that there are available physical eraseblocks ++ * present on the device, it automatically appends all of them to the volume ++ * (the physical eraseblocks reserved for bad eraseblocks handling and other ++ * reserved physical eraseblocks are not taken). So, if there is a volume with ++ * the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical ++ * eraseblocks will be zero after UBI is loaded, because all of them will be ++ * reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared ++ * after the volume had been initialized. ++ * ++ * The auto-resize feature is useful for device production purposes. For ++ * example, different NAND flash chips may have different amount of initial bad ++ * eraseblocks, depending of particular chip instance. Manufacturers of NAND ++ * chips usually guarantee that the amount of initial bad eraseblocks does not ++ * exceed certain percent, e.g. 2%. When one creates an UBI image which will be ++ * flashed to the end devices in production, he does not know the exact amount ++ * of good physical eraseblocks the NAND chip on the device will have, but this ++ * number is required to calculate the volume sized and put them to the volume ++ * table of the UBI image. In this case, one of the volumes (e.g., the one ++ * which will store the root file system) is marked as "auto-resizable", and ++ * UBI will adjust its size on the first boot if needed. ++ * ++ * Note, first UBI reserves some amount of physical eraseblocks for bad ++ * eraseblock handling, and then re-sizes the volume, not vice-versa. This ++ * means that the pool of reserved physical eraseblocks will always be present. ++ */ ++enum { ++ UBI_VTBL_AUTORESIZE_FLG = 0x01, ++}; ++ ++/* ++ * Compatibility constants used by internal volumes. ++ * ++ * @UBI_COMPAT_DELETE: delete this internal volume before anything is written ++ * to the flash ++ * @UBI_COMPAT_RO: attach this device in read-only mode ++ * @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its ++ * physical eraseblocks, don't allow the wear-leveling unit to move them ++ * @UBI_COMPAT_REJECT: reject this UBI image ++ */ ++enum { ++ UBI_COMPAT_DELETE = 1, ++ UBI_COMPAT_RO = 2, ++ UBI_COMPAT_PRESERVE = 4, ++ UBI_COMPAT_REJECT = 5 ++}; ++ ++/* Sizes of UBI headers */ ++#define UBI_EC_HDR_SIZE sizeof(struct ubi_ec_hdr) ++#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr) ++ ++/* Sizes of UBI headers without the ending CRC */ ++#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(__be32)) ++#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(__be32)) ++ ++/** ++ * struct ubi_ec_hdr - UBI erase counter header. ++ * @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC) ++ * @version: version of UBI implementation which is supposed to accept this ++ * UBI image ++ * @padding1: reserved for future, zeroes ++ * @ec: the erase counter ++ * @vid_hdr_offset: where the VID header starts ++ * @data_offset: where the user data start ++ * @padding2: reserved for future, zeroes ++ * @hdr_crc: erase counter header CRC checksum ++ * ++ * The erase counter header takes 64 bytes and has a plenty of unused space for ++ * future usage. The unused fields are zeroed. The @version field is used to ++ * indicate the version of UBI implementation which is supposed to be able to ++ * work with this UBI image. If @version is greater then the current UBI ++ * version, the image is rejected. This may be useful in future if something ++ * is changed radically. This field is duplicated in the volume identifier ++ * header. ++ * ++ * The @vid_hdr_offset and @data_offset fields contain the offset of the the ++ * volume identifier header and user data, relative to the beginning of the ++ * physical eraseblock. These values have to be the same for all physical ++ * eraseblocks. ++ */ ++struct ubi_ec_hdr { ++ __be32 magic; ++ __u8 version; ++ __u8 padding1[3]; ++ __be64 ec; /* Warning: the current limit is 31-bit anyway! */ ++ __be32 vid_hdr_offset; ++ __be32 data_offset; ++ __u8 padding2[36]; ++ __be32 hdr_crc; ++} __attribute__ ((packed)); ++ ++/** ++ * struct ubi_vid_hdr - on-flash UBI volume identifier header. ++ * @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC) ++ * @version: UBI implementation version which is supposed to accept this UBI ++ * image (%UBI_VERSION) ++ * @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC) ++ * @copy_flag: if this logical eraseblock was copied from another physical ++ * eraseblock (for wear-leveling reasons) ++ * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE, ++ * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT) ++ * @vol_id: ID of this volume ++ * @lnum: logical eraseblock number ++ * @leb_ver: version of this logical eraseblock (IMPORTANT: obsolete, to be ++ * removed, kept only for not breaking older UBI users) ++ * @data_size: how many bytes of data this logical eraseblock contains ++ * @used_ebs: total number of used logical eraseblocks in this volume ++ * @data_pad: how many bytes at the end of this physical eraseblock are not ++ * used ++ * @data_crc: CRC checksum of the data stored in this logical eraseblock ++ * @padding1: reserved for future, zeroes ++ * @sqnum: sequence number ++ * @padding2: reserved for future, zeroes ++ * @hdr_crc: volume identifier header CRC checksum ++ * ++ * The @sqnum is the value of the global sequence counter at the time when this ++ * VID header was created. The global sequence counter is incremented each time ++ * UBI writes a new VID header to the flash, i.e. when it maps a logical ++ * eraseblock to a new physical eraseblock. The global sequence counter is an ++ * unsigned 64-bit integer and we assume it never overflows. The @sqnum ++ * (sequence number) is used to distinguish between older and newer versions of ++ * logical eraseblocks. ++ * ++ * There are 2 situations when there may be more then one physical eraseblock ++ * corresponding to the same logical eraseblock, i.e., having the same @vol_id ++ * and @lnum values in the volume identifier header. Suppose we have a logical ++ * eraseblock L and it is mapped to the physical eraseblock P. ++ * ++ * 1. Because UBI may erase physical eraseblocks asynchronously, the following ++ * situation is possible: L is asynchronously erased, so P is scheduled for ++ * erasure, then L is written to,i.e. mapped to another physical eraseblock P1, ++ * so P1 is written to, then an unclean reboot happens. Result - there are 2 ++ * physical eraseblocks P and P1 corresponding to the same logical eraseblock ++ * L. But P1 has greater sequence number, so UBI picks P1 when it attaches the ++ * flash. ++ * ++ * 2. From time to time UBI moves logical eraseblocks to other physical ++ * eraseblocks for wear-leveling reasons. If, for example, UBI moves L from P ++ * to P1, and an unclean reboot happens before P is physically erased, there ++ * are two physical eraseblocks P and P1 corresponding to L and UBI has to ++ * select one of them when the flash is attached. The @sqnum field says which ++ * PEB is the original (obviously P will have lower @sqnum) and the copy. But ++ * it is not enough to select the physical eraseblock with the higher sequence ++ * number, because the unclean reboot could have happen in the middle of the ++ * copying process, so the data in P is corrupted. It is also not enough to ++ * just select the physical eraseblock with lower sequence number, because the ++ * data there may be old (consider a case if more data was added to P1 after ++ * the copying). Moreover, the unclean reboot may happen when the erasure of P ++ * was just started, so it result in unstable P, which is "mostly" OK, but ++ * still has unstable bits. ++ * ++ * UBI uses the @copy_flag field to indicate that this logical eraseblock is a ++ * copy. UBI also calculates data CRC when the data is moved and stores it at ++ * the @data_crc field of the copy (P1). So when UBI needs to pick one physical ++ * eraseblock of two (P or P1), the @copy_flag of the newer one (P1) is ++ * examined. If it is cleared, the situation* is simple and the newer one is ++ * picked. If it is set, the data CRC of the copy (P1) is examined. If the CRC ++ * checksum is correct, this physical eraseblock is selected (P1). Otherwise ++ * the older one (P) is selected. ++ * ++ * Note, there is an obsolete @leb_ver field which was used instead of @sqnum ++ * in the past. But it is not used anymore and we keep it in order to be able ++ * to deal with old UBI images. It will be removed at some point. ++ * ++ * There are 2 sorts of volumes in UBI: user volumes and internal volumes. ++ * Internal volumes are not seen from outside and are used for various internal ++ * UBI purposes. In this implementation there is only one internal volume - the ++ * layout volume. Internal volumes are the main mechanism of UBI extensions. ++ * For example, in future one may introduce a journal internal volume. Internal ++ * volumes have their own reserved range of IDs. ++ * ++ * The @compat field is only used for internal volumes and contains the "degree ++ * of their compatibility". It is always zero for user volumes. This field ++ * provides a mechanism to introduce UBI extensions and to be still compatible ++ * with older UBI binaries. For example, if someone introduced a journal in ++ * future, he would probably use %UBI_COMPAT_DELETE compatibility for the ++ * journal volume. And in this case, older UBI binaries, which know nothing ++ * about the journal volume, would just delete this volume and work perfectly ++ * fine. This is similar to what Ext2fs does when it is fed by an Ext3fs image ++ * - it just ignores the Ext3fs journal. ++ * ++ * The @data_crc field contains the CRC checksum of the contents of the logical ++ * eraseblock if this is a static volume. In case of dynamic volumes, it does ++ * not contain the CRC checksum as a rule. The only exception is when the ++ * data of the physical eraseblock was moved by the wear-leveling unit, then ++ * the wear-leveling unit calculates the data CRC and stores it in the ++ * @data_crc field. And of course, the @copy_flag is %in this case. ++ * ++ * The @data_size field is used only for static volumes because UBI has to know ++ * how many bytes of data are stored in this eraseblock. For dynamic volumes, ++ * this field usually contains zero. The only exception is when the data of the ++ * physical eraseblock was moved to another physical eraseblock for ++ * wear-leveling reasons. In this case, UBI calculates CRC checksum of the ++ * contents and uses both @data_crc and @data_size fields. In this case, the ++ * @data_size field contains data size. ++ * ++ * The @used_ebs field is used only for static volumes and indicates how many ++ * eraseblocks the data of the volume takes. For dynamic volumes this field is ++ * not used and always contains zero. ++ * ++ * The @data_pad is calculated when volumes are created using the alignment ++ * parameter. So, effectively, the @data_pad field reduces the size of logical ++ * eraseblocks of this volume. This is very handy when one uses block-oriented ++ * software (say, cramfs) on top of the UBI volume. ++ */ ++struct ubi_vid_hdr { ++ __be32 magic; ++ __u8 version; ++ __u8 vol_type; ++ __u8 copy_flag; ++ __u8 compat; ++ __be32 vol_id; ++ __be32 lnum; ++ __be32 leb_ver; /* obsolete, to be removed, don't use */ ++ __be32 data_size; ++ __be32 used_ebs; ++ __be32 data_pad; ++ __be32 data_crc; ++ __u8 padding1[4]; ++ __be64 sqnum; ++ __u8 padding2[12]; ++ __be32 hdr_crc; ++} __attribute__ ((packed)); ++ ++/* Internal UBI volumes count */ ++#define UBI_INT_VOL_COUNT 1 ++ ++/* ++ * Starting ID of internal volumes. There is reserved room for 4096 internal ++ * volumes. ++ */ ++#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096) ++ ++/* The layout volume contains the volume table */ ++ ++#define UBI_LAYOUT_VOLUME_ID UBI_INTERNAL_VOL_START ++#define UBI_LAYOUT_VOLUME_TYPE UBI_VID_DYNAMIC ++#define UBI_LAYOUT_VOLUME_ALIGN 1 ++#define UBI_LAYOUT_VOLUME_EBS 2 ++#define UBI_LAYOUT_VOLUME_NAME "layout volume" ++#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT ++ ++/* The maximum number of volumes per one UBI device */ ++#define UBI_MAX_VOLUMES 128 ++ ++/* The maximum volume name length */ ++#define UBI_VOL_NAME_MAX 127 ++ ++/* Size of the volume table record */ ++#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record) ++ ++/* Size of the volume table record without the ending CRC */ ++#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(__be32)) ++ ++/** ++ * struct ubi_vtbl_record - a record in the volume table. ++ * @reserved_pebs: how many physical eraseblocks are reserved for this volume ++ * @alignment: volume alignment ++ * @data_pad: how many bytes are unused at the end of the each physical ++ * eraseblock to satisfy the requested alignment ++ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) ++ * @upd_marker: if volume update was started but not finished ++ * @name_len: volume name length ++ * @name: the volume name ++ * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG) ++ * @padding: reserved, zeroes ++ * @crc: a CRC32 checksum of the record ++ * ++ * The volume table records are stored in the volume table, which is stored in ++ * the layout volume. The layout volume consists of 2 logical eraseblock, each ++ * of which contains a copy of the volume table (i.e., the volume table is ++ * duplicated). The volume table is an array of &struct ubi_vtbl_record ++ * objects indexed by the volume ID. ++ * ++ * If the size of the logical eraseblock is large enough to fit ++ * %UBI_MAX_VOLUMES records, the volume table contains %UBI_MAX_VOLUMES ++ * records. Otherwise, it contains as many records as it can fit (i.e., size of ++ * logical eraseblock divided by sizeof(struct ubi_vtbl_record)). ++ * ++ * The @upd_marker flag is used to implement volume update. It is set to %1 ++ * before update and set to %0 after the update. So if the update operation was ++ * interrupted, UBI knows that the volume is corrupted. ++ * ++ * The @alignment field is specified when the volume is created and cannot be ++ * later changed. It may be useful, for example, when a block-oriented file ++ * system works on top of UBI. The @data_pad field is calculated using the ++ * logical eraseblock size and @alignment. The alignment must be multiple to the ++ * minimal flash I/O unit. If @alignment is 1, all the available space of ++ * the physical eraseblocks is used. ++ * ++ * Empty records contain all zeroes and the CRC checksum of those zeroes. ++ */ ++struct ubi_vtbl_record { ++ __be32 reserved_pebs; ++ __be32 alignment; ++ __be32 data_pad; ++ __u8 vol_type; ++ __u8 upd_marker; ++ __be16 name_len; ++ __u8 name[UBI_VOL_NAME_MAX+1]; ++ __u8 flags; ++ __u8 padding[23]; ++ __be32 crc; ++} __attribute__ ((packed)); ++ ++#endif /* !__UBI_MEDIA_H__ */ +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/upd.c avr32-2.6/drivers/mtd/ubi/upd.c +--- linux-2.6.25.6/drivers/mtd/ubi/upd.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/ubi/upd.c 2008-06-12 15:09:41.123815692 +0200 +@@ -237,10 +237,10 @@ + int err; + + if (vol->vol_type == UBI_DYNAMIC_VOLUME) { +- len = ALIGN(len, ubi->min_io_size); +- memset(buf + len, 0xFF, len - len); ++ int l = ALIGN(len, ubi->min_io_size); + +- len = ubi_calc_data_len(ubi, buf, len); ++ memset(buf + len, 0xFF, l - len); ++ len = ubi_calc_data_len(ubi, buf, l); + if (len == 0) { + dbg_msg("all %d bytes contain 0xFF - skip", len); + return 0; +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/vmt.c avr32-2.6/drivers/mtd/ubi/vmt.c +--- linux-2.6.25.6/drivers/mtd/ubi/vmt.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/ubi/vmt.c 2008-06-12 15:09:41.123815692 +0200 +@@ -127,6 +127,7 @@ + { + struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); + ++ kfree(vol->eba_tbl); + kfree(vol); + } + +@@ -201,7 +202,7 @@ + */ + int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) + { +- int i, err, vol_id = req->vol_id, dont_free = 0; ++ int i, err, vol_id = req->vol_id, do_free = 1; + struct ubi_volume *vol; + struct ubi_vtbl_record vtbl_rec; + uint64_t bytes; +@@ -365,14 +366,14 @@ + + out_sysfs: + /* +- * We have registered our device, we should not free the volume* ++ * We have registered our device, we should not free the volume + * description object in this function in case of an error - it is + * freed by the release function. + * + * Get device reference to prevent the release function from being + * called just after sysfs has been closed. + */ +- dont_free = 1; ++ do_free = 0; + get_device(&vol->dev); + volume_sysfs_close(vol); + out_gluebi: +@@ -382,17 +383,18 @@ + out_cdev: + cdev_del(&vol->cdev); + out_mapping: +- kfree(vol->eba_tbl); ++ if (do_free) ++ kfree(vol->eba_tbl); + out_acc: + spin_lock(&ubi->volumes_lock); + ubi->rsvd_pebs -= vol->reserved_pebs; + ubi->avail_pebs += vol->reserved_pebs; + out_unlock: + spin_unlock(&ubi->volumes_lock); +- if (dont_free) +- put_device(&vol->dev); +- else ++ if (do_free) + kfree(vol); ++ else ++ put_device(&vol->dev); + ubi_err("cannot create volume %d, error %d", vol_id, err); + return err; + } +@@ -445,8 +447,6 @@ + goto out_err; + } + +- kfree(vol->eba_tbl); +- vol->eba_tbl = NULL; + cdev_del(&vol->cdev); + volume_sysfs_close(vol); + +@@ -727,7 +727,7 @@ + goto fail; + } + +- n = vol->alignment % ubi->min_io_size; ++ n = vol->alignment & (ubi->min_io_size - 1); + if (vol->alignment != 1 && n) { + ubi_err("alignment is not multiple of min I/O unit"); + goto fail; +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/vtbl.c avr32-2.6/drivers/mtd/ubi/vtbl.c +--- linux-2.6.25.6/drivers/mtd/ubi/vtbl.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/ubi/vtbl.c 2008-06-12 15:09:41.127815922 +0200 +@@ -127,7 +127,7 @@ + const struct ubi_vtbl_record *vtbl) + { + int i, n, reserved_pebs, alignment, data_pad, vol_type, name_len; +- int upd_marker; ++ int upd_marker, err; + uint32_t crc; + const char *name; + +@@ -153,7 +153,7 @@ + if (reserved_pebs == 0) { + if (memcmp(&vtbl[i], &empty_vtbl_record, + UBI_VTBL_RECORD_SIZE)) { +- dbg_err("bad empty record"); ++ err = 2; + goto bad; + } + continue; +@@ -161,56 +161,57 @@ + + if (reserved_pebs < 0 || alignment < 0 || data_pad < 0 || + name_len < 0) { +- dbg_err("negative values"); ++ err = 3; + goto bad; + } + + if (alignment > ubi->leb_size || alignment == 0) { +- dbg_err("bad alignment"); ++ err = 4; + goto bad; + } + +- n = alignment % ubi->min_io_size; ++ n = alignment & (ubi->min_io_size - 1); + if (alignment != 1 && n) { +- dbg_err("alignment is not multiple of min I/O unit"); ++ err = 5; + goto bad; + } + + n = ubi->leb_size % alignment; + if (data_pad != n) { + dbg_err("bad data_pad, has to be %d", n); ++ err = 6; + goto bad; + } + + if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) { +- dbg_err("bad vol_type"); ++ err = 7; + goto bad; + } + + if (upd_marker != 0 && upd_marker != 1) { +- dbg_err("bad upd_marker"); ++ err = 8; + goto bad; + } + + if (reserved_pebs > ubi->good_peb_count) { + dbg_err("too large reserved_pebs, good PEBs %d", + ubi->good_peb_count); ++ err = 9; + goto bad; + } + + if (name_len > UBI_VOL_NAME_MAX) { +- dbg_err("too long volume name, max %d", +- UBI_VOL_NAME_MAX); ++ err = 10; + goto bad; + } + + if (name[0] == '\0') { +- dbg_err("NULL volume name"); ++ err = 11; + goto bad; + } + + if (name_len != strnlen(name, name_len + 1)) { +- dbg_err("bad name_len"); ++ err = 12; + goto bad; + } + } +@@ -235,7 +236,7 @@ + return 0; + + bad: +- ubi_err("volume table check failed, record %d", i); ++ ubi_err("volume table check failed: record %d, error %d", i, err); + ubi_dbg_dump_vtbl_record(&vtbl[i], i); + return -EINVAL; + } +@@ -384,7 +385,16 @@ + err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0, + ubi->vtbl_size); + if (err == UBI_IO_BITFLIPS || err == -EBADMSG) +- /* Scrub the PEB later */ ++ /* ++ * Scrub the PEB later. Note, -EBADMSG indicates an ++ * uncorrectable ECC error, but we have our own CRC and ++ * the data will be checked later. If the data is OK, ++ * the PEB will be scrubbed (because we set ++ * seb->scrub). If the data is not OK, the contents of ++ * the PEB will be recovered from the second copy, and ++ * seb->scrub will be cleared in ++ * 'ubi_scan_add_used()'. ++ */ + seb->scrub = 1; + else if (err) + goto out_free; +@@ -620,30 +630,32 @@ + static int check_sv(const struct ubi_volume *vol, + const struct ubi_scan_volume *sv) + { ++ int err; ++ + if (sv->highest_lnum >= vol->reserved_pebs) { +- dbg_err("bad highest_lnum"); ++ err = 1; + goto bad; + } + if (sv->leb_count > vol->reserved_pebs) { +- dbg_err("bad leb_count"); ++ err = 2; + goto bad; + } + if (sv->vol_type != vol->vol_type) { +- dbg_err("bad vol_type"); ++ err = 3; + goto bad; + } + if (sv->used_ebs > vol->reserved_pebs) { +- dbg_err("bad used_ebs"); ++ err = 4; + goto bad; + } + if (sv->data_pad != vol->data_pad) { +- dbg_err("bad data_pad"); ++ err = 5; + goto bad; + } + return 0; + + bad: +- ubi_err("bad scanning information"); ++ ubi_err("bad scanning information, error %d", err); + ubi_dbg_dump_sv(sv); + ubi_dbg_dump_vol_info(vol); + return -EINVAL; +@@ -672,14 +684,13 @@ + return -EINVAL; + } + +- if (si->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT&& ++ if (si->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT && + si->highest_vol_id < UBI_INTERNAL_VOL_START) { + ubi_err("too large volume ID %d found by scanning", + si->highest_vol_id); + return -EINVAL; + } + +- + for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) { + cond_resched(); + +diff --exclude=.git -urN linux-2.6.25.6/drivers/mtd/ubi/wl.c avr32-2.6/drivers/mtd/ubi/wl.c +--- linux-2.6.25.6/drivers/mtd/ubi/wl.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/mtd/ubi/wl.c 2008-06-12 15:09:41.127815922 +0200 +@@ -1368,7 +1368,7 @@ + int err; + + if (kthread_should_stop()) +- goto out; ++ break; + + if (try_to_freeze()) + continue; +@@ -1403,7 +1403,6 @@ + cond_resched(); + } + +-out: + dbg_wl("background thread \"%s\" is killed", ubi->bgt_name); + return 0; + } +diff --exclude=.git -urN linux-2.6.25.6/drivers/net/macb.c avr32-2.6/drivers/net/macb.c +--- linux-2.6.25.6/drivers/net/macb.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/net/macb.c 2008-06-12 15:09:41.343816061 +0200 +@@ -1277,8 +1277,45 @@ + return 0; + } + ++#ifdef CONFIG_PM ++static int macb_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct net_device *netdev = platform_get_drvdata(pdev); ++ struct macb *bp = netdev_priv(netdev); ++ ++ netif_device_detach(netdev); ++ ++#ifndef CONFIG_ARCH_AT91 ++ clk_disable(bp->hclk); ++#endif ++ clk_disable(bp->pclk); ++ ++ return 0; ++} ++ ++static int macb_resume(struct platform_device *pdev) ++{ ++ struct net_device *netdev = platform_get_drvdata(pdev); ++ struct macb *bp = netdev_priv(netdev); ++ ++ clk_enable(bp->pclk); ++#ifndef CONFIG_ARCH_AT91 ++ clk_enable(bp->hclk); ++#endif ++ ++ netif_device_attach(netdev); ++ ++ return 0; ++} ++#else ++#define macb_suspend NULL ++#define macb_resume NULL ++#endif ++ + static struct platform_driver macb_driver = { + .remove = __exit_p(macb_remove), ++ .suspend = macb_suspend, ++ .resume = macb_resume, + .driver = { + .name = "macb", + }, +diff --exclude=.git -urN linux-2.6.25.6/drivers/parport/Kconfig avr32-2.6/drivers/parport/Kconfig +--- linux-2.6.25.6/drivers/parport/Kconfig 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/parport/Kconfig 2008-06-12 15:04:01.310815768 +0200 +@@ -36,7 +36,7 @@ + config PARPORT_PC + tristate "PC-style hardware" + depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && \ +- (!M68K || ISA) && !MN10300 ++ (!M68K || ISA) && !MN10300 && !AVR32 + ---help--- + You should say Y here if you have a PC-style parallel port. All + IBM PC compatible computers and some Alphas have PC-style +diff --exclude=.git -urN linux-2.6.25.6/drivers/pcmcia/at32_cf.c avr32-2.6/drivers/pcmcia/at32_cf.c +--- linux-2.6.25.6/drivers/pcmcia/at32_cf.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/drivers/pcmcia/at32_cf.c 2008-06-12 15:09:42.047816626 +0200 @@ -0,0 +1,533 @@ +/* + * Driver for AVR32 Static Memory Controller: CompactFlash support @@ -16043,9 +14160,10 @@ +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Driver for SMC PCMCIA interface"); +MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>"); ---- a/drivers/pcmcia/Kconfig -+++ b/drivers/pcmcia/Kconfig -@@ -276,6 +276,13 @@ +diff --exclude=.git -urN linux-2.6.25.6/drivers/pcmcia/Kconfig avr32-2.6/drivers/pcmcia/Kconfig +--- linux-2.6.25.6/drivers/pcmcia/Kconfig 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/pcmcia/Kconfig 2008-06-12 15:09:42.047816626 +0200 +@@ -277,6 +277,13 @@ Say Y here to support the CompactFlash controller on the PA Semi Electra eval board. @@ -16059,8 +14177,9 @@ config PCCARD_NONSTATIC tristate ---- a/drivers/pcmcia/Makefile -+++ b/drivers/pcmcia/Makefile +diff --exclude=.git -urN linux-2.6.25.6/drivers/pcmcia/Makefile avr32-2.6/drivers/pcmcia/Makefile +--- linux-2.6.25.6/drivers/pcmcia/Makefile 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/pcmcia/Makefile 2008-06-12 15:09:42.047816626 +0200 @@ -38,6 +38,7 @@ obj-$(CONFIG_OMAP_CF) += omap_cf.o obj-$(CONFIG_AT91_CF) += at91_cf.o @@ -16069,1525 +14188,192 @@ sa11xx_core-y += soc_common.o sa11xx_base.o pxa2xx_core-y += soc_common.o pxa2xx_base.o ---- a/drivers/serial/atmel_serial.c -+++ b/drivers/serial/atmel_serial.c -@@ -7,6 +7,8 @@ - * Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd. - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * -+ * DMA support added by Chip Coldwell. -+ * - * 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 -@@ -33,7 +35,9 @@ - #include <linux/sysrq.h> - #include <linux/tty_flip.h> - #include <linux/platform_device.h> -+#include <linux/dma-mapping.h> - #include <linux/atmel_pdc.h> -+#include <linux/atmel_serial.h> - - #include <asm/io.h> - -@@ -45,7 +49,9 @@ - #include <asm/arch/gpio.h> - #endif - --#include "atmel_serial.h" -+#define PDC_BUFFER_SIZE 512 -+/* Revisit: We should calculate this based on the actual port settings */ -+#define PDC_RX_TIMEOUT (3 * 10) /* 3 bytes */ - - #if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) - #define SUPPORT_SYSRQ -@@ -74,6 +80,7 @@ - - #define ATMEL_ISR_PASS_LIMIT 256 - -+/* UART registers. CR is write-only, hence no GET macro */ - #define UART_PUT_CR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_CR) - #define UART_GET_MR(port) __raw_readl((port)->membase + ATMEL_US_MR) - #define UART_PUT_MR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_MR) -@@ -87,8 +94,6 @@ - #define UART_PUT_BRGR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_BRGR) - #define UART_PUT_RTOR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_RTOR) - --// #define UART_GET_CR(port) __raw_readl((port)->membase + ATMEL_US_CR) // is write-only -- - /* PDC registers */ - #define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR) - #define UART_GET_PTSR(port) __raw_readl((port)->membase + ATMEL_PDC_PTSR) -@@ -101,12 +106,24 @@ - - #define UART_PUT_TPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TPR) - #define UART_PUT_TCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TCR) --//#define UART_PUT_TNPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TNPR) --//#define UART_PUT_TNCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TNCR) - - static int (*atmel_open_hook)(struct uart_port *); - static void (*atmel_close_hook)(struct uart_port *); - -+struct atmel_dma_buffer { -+ unsigned char *buf; -+ dma_addr_t dma_addr; -+ unsigned int dma_size; -+ unsigned int ofs; -+}; -+ -+struct atmel_uart_char { -+ u16 status; -+ u16 ch; -+}; -+ -+#define ATMEL_SERIAL_RINGSIZE 1024 -+ - /* - * We wrap our port structure around the generic uart_port. - */ -@@ -115,6 +132,19 @@ - struct clk *clk; /* uart clock */ - unsigned short suspended; /* is port suspended? */ - int break_active; /* break being received */ -+ -+ short use_dma_rx; /* enable PDC receiver */ -+ short pdc_rx_idx; /* current PDC RX buffer */ -+ struct atmel_dma_buffer pdc_rx[2]; /* PDC receier */ -+ -+ short use_dma_tx; /* enable PDC transmitter */ -+ struct atmel_dma_buffer pdc_tx; /* PDC transmitter */ -+ -+ struct tasklet_struct tasklet; -+ unsigned int irq_status; -+ unsigned int irq_status_prev; -+ -+ struct circ_buf rx_ring; +diff --exclude=.git -urN linux-2.6.25.6/drivers/serial/atmel_serial.c avr32-2.6/drivers/serial/atmel_serial.c +--- linux-2.6.25.6/drivers/serial/atmel_serial.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/serial/atmel_serial.c 2008-06-12 15:09:42.514816054 +0200 +@@ -1440,6 +1440,15 @@ }; - static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART]; -@@ -123,6 +153,38 @@ - static struct console atmel_console; - #endif - -+static inline struct atmel_uart_port * -+to_atmel_uart_port(struct uart_port *uart) -+{ -+ return container_of(uart, struct atmel_uart_port, uart); -+} -+ -+#ifdef CONFIG_SERIAL_ATMEL_PDC -+static bool atmel_use_dma_rx(struct uart_port *port) -+{ -+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); -+ -+ return atmel_port->use_dma_rx; -+} -+ -+static bool atmel_use_dma_tx(struct uart_port *port) + #ifdef CONFIG_PM ++static bool atmel_serial_clk_will_stop(void) +{ -+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); -+ -+ return atmel_port->use_dma_tx; -+} ++#ifdef CONFIG_ARCH_AT91 ++ return at91_suspend_entering_slow_clock(); +#else -+static bool atmel_use_dma_rx(struct uart_port *port) -+{ + return false; -+} -+ -+static bool atmel_use_dma_tx(struct uart_port *port) -+{ -+ return false; -+} +#endif ++} + - /* - * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty. - */ -@@ -142,8 +204,8 @@ - #ifdef CONFIG_ARCH_AT91RM9200 - if (cpu_is_at91rm9200()) { - /* -- * AT91RM9200 Errata #39: RTS0 is not internally connected to PA21. -- * We need to drive the pin manually. -+ * AT91RM9200 Errata #39: RTS0 is not internally connected -+ * to PA21. We need to drive the pin manually. - */ - if (port->mapbase == AT91RM9200_BASE_US0) { - if (mctrl & TIOCM_RTS) -@@ -204,7 +266,12 @@ - */ - static void atmel_stop_tx(struct uart_port *port) - { -- UART_PUT_IDR(port, ATMEL_US_TXRDY); -+ if (atmel_use_dma_tx(port)) { -+ /* disable PDC transmit */ -+ UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); -+ UART_PUT_IDR(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE); -+ } else -+ UART_PUT_IDR(port, ATMEL_US_TXRDY); - } - - /* -@@ -212,7 +279,17 @@ - */ - static void atmel_start_tx(struct uart_port *port) - { -- UART_PUT_IER(port, ATMEL_US_TXRDY); -+ if (atmel_use_dma_tx(port)) { -+ if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN) -+ /* The transmitter is already running. Yes, we -+ really need this.*/ -+ return; -+ -+ UART_PUT_IER(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE); -+ /* re-enable PDC transmit */ -+ UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); -+ } else -+ UART_PUT_IER(port, ATMEL_US_TXRDY); - } - - /* -@@ -220,7 +297,12 @@ - */ - static void atmel_stop_rx(struct uart_port *port) + static int atmel_serial_suspend(struct platform_device *pdev, + pm_message_t state) { -- UART_PUT_IDR(port, ATMEL_US_RXRDY); -+ if (atmel_use_dma_rx(port)) { -+ /* disable PDC receive */ -+ UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS); -+ UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); -+ } else -+ UART_PUT_IDR(port, ATMEL_US_RXRDY); - } +@@ -1447,7 +1456,7 @@ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - /* -@@ -228,7 +310,8 @@ - */ - static void atmel_enable_ms(struct uart_port *port) - { -- UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC); -+ UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC -+ | ATMEL_US_DCDIC | ATMEL_US_CTSIC); - } + if (device_may_wakeup(&pdev->dev) +- && !at91_suspend_entering_slow_clock()) ++ && !atmel_serial_clk_will_stop()) + enable_irq_wake(port->irq); + else { + uart_suspend_port(&atmel_uart, port); +diff --exclude=.git -urN linux-2.6.25.6/drivers/spi/atmel_spi.c avr32-2.6/drivers/spi/atmel_spi.c +--- linux-2.6.25.6/drivers/spi/atmel_spi.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/spi/atmel_spi.c 2008-06-12 15:09:42.542815989 +0200 +@@ -51,9 +51,7 @@ + u8 stopping; + struct list_head queue; + struct spi_transfer *current_transfer; +- unsigned long current_remaining_bytes; +- struct spi_transfer *next_transfer; +- unsigned long next_remaining_bytes; ++ unsigned long remaining_bytes; - /* -@@ -243,22 +326,63 @@ + void *buffer; + dma_addr_t buffer_dma; +@@ -133,48 +131,6 @@ + gpio_set_value(gpio, !active); } - /* -+ * Stores the incoming character in the ring buffer -+ */ -+static void -+atmel_buffer_rx_char(struct uart_port *port, unsigned int status, -+ unsigned int ch) -+{ -+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); -+ struct circ_buf *ring = &atmel_port->rx_ring; -+ struct atmel_uart_char *c; -+ -+ if (!CIRC_SPACE(ring->head, ring->tail, ATMEL_SERIAL_RINGSIZE)) -+ /* Buffer overflow, ignore char */ -+ return; -+ -+ c = &((struct atmel_uart_char *)ring->buf)[ring->head]; -+ c->status = status; -+ c->ch = ch; -+ -+ /* Make sure the character is stored before we update head. */ -+ smp_wmb(); -+ -+ ring->head = (ring->head + 1) & (ATMEL_SERIAL_RINGSIZE - 1); -+} -+ -+/* -+ * Deal with parity, framing and overrun errors. -+ */ -+static void atmel_pdc_rxerr(struct uart_port *port, unsigned int status) -+{ -+ /* clear error */ -+ UART_PUT_CR(port, ATMEL_US_RSTSTA); -+ -+ if (status & ATMEL_US_RXBRK) { -+ /* ignore side-effect */ -+ status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); -+ port->icount.brk++; -+ } -+ if (status & ATMEL_US_PARE) -+ port->icount.parity++; -+ if (status & ATMEL_US_FRAME) -+ port->icount.frame++; -+ if (status & ATMEL_US_OVRE) -+ port->icount.overrun++; -+} -+ -+/* - * Characters received (called from interrupt handler) - */ - static void atmel_rx_chars(struct uart_port *port) - { -- struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; -- struct tty_struct *tty = port->info->tty; -- unsigned int status, ch, flg; -+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); -+ unsigned int status, ch; - - status = UART_GET_CSR(port); - while (status & ATMEL_US_RXRDY) { - ch = UART_GET_CHAR(port); - -- port->icount.rx++; -- -- flg = TTY_NORMAL; -- - /* - * note that the error handling code is - * out of the main execution path -@@ -266,15 +390,14 @@ - if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME - | ATMEL_US_OVRE | ATMEL_US_RXBRK) - || atmel_port->break_active)) { -- UART_PUT_CR(port, ATMEL_US_RSTSTA); /* clear error */ -+ -+ /* clear error */ -+ UART_PUT_CR(port, ATMEL_US_RSTSTA); -+ - if (status & ATMEL_US_RXBRK - && !atmel_port->break_active) { -- status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); /* ignore side-effect */ -- port->icount.brk++; - atmel_port->break_active = 1; - UART_PUT_IER(port, ATMEL_US_RXBRK); -- if (uart_handle_break(port)) -- goto ignore_char; - } else { - /* - * This is either the end-of-break -@@ -287,52 +410,30 @@ - status &= ~ATMEL_US_RXBRK; - atmel_port->break_active = 0; - } -- if (status & ATMEL_US_PARE) -- port->icount.parity++; -- if (status & ATMEL_US_FRAME) -- port->icount.frame++; -- if (status & ATMEL_US_OVRE) -- port->icount.overrun++; -- -- status &= port->read_status_mask; +-static inline int atmel_spi_xfer_is_last(struct spi_message *msg, +- struct spi_transfer *xfer) +-{ +- return msg->transfers.prev == &xfer->transfer_list; +-} - -- if (status & ATMEL_US_RXBRK) -- flg = TTY_BREAK; -- else if (status & ATMEL_US_PARE) -- flg = TTY_PARITY; -- else if (status & ATMEL_US_FRAME) -- flg = TTY_FRAME; - } - -- if (uart_handle_sysrq_char(port, ch)) -- goto ignore_char; +-static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer) +-{ +- return xfer->delay_usecs == 0 && !xfer->cs_change; +-} - -- uart_insert_char(port, status, ATMEL_US_OVRE, ch, flg); +-static void atmel_spi_next_xfer_data(struct spi_master *master, +- struct spi_transfer *xfer, +- dma_addr_t *tx_dma, +- dma_addr_t *rx_dma, +- u32 *plen) +-{ +- struct atmel_spi *as = spi_master_get_devdata(master); +- u32 len = *plen; - -- ignore_char: -+ atmel_buffer_rx_char(port, status, ch); - status = UART_GET_CSR(port); - } - -- tty_flip_buffer_push(tty); -+ tasklet_schedule(&atmel_port->tasklet); - } - - /* -- * Transmit characters (called from interrupt handler) -+ * Transmit characters (called from tasklet with TXRDY interrupt -+ * disabled) - */ - static void atmel_tx_chars(struct uart_port *port) - { - struct circ_buf *xmit = &port->info->xmit; - -- if (port->x_char) { -+ if (port->x_char && UART_GET_CSR(port) & ATMEL_US_TXRDY) { - UART_PUT_CHAR(port, port->x_char); - port->icount.tx++; - port->x_char = 0; -- return; - } -- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { -- atmel_stop_tx(port); -+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) - return; +- /* use scratch buffer only when rx or tx data is unspecified */ +- if (xfer->rx_buf) +- *rx_dma = xfer->rx_dma + xfer->len - len; +- else { +- *rx_dma = as->buffer_dma; +- if (len > BUFFER_SIZE) +- len = BUFFER_SIZE; - } - - while (UART_GET_CSR(port) & ATMEL_US_TXRDY) { - UART_PUT_CHAR(port, xmit->buf[xmit->tail]); -@@ -345,8 +446,88 @@ - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - -- if (uart_circ_empty(xmit)) -- atmel_stop_tx(port); -+ if (!uart_circ_empty(xmit)) -+ UART_PUT_IER(port, ATMEL_US_TXRDY); -+} -+ -+/* -+ * receive interrupt handler. -+ */ -+static void -+atmel_handle_receive(struct uart_port *port, unsigned int pending) -+{ -+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); -+ -+ if (atmel_use_dma_rx(port)) { -+ /* -+ * PDC receive. Just schedule the tasklet and let it -+ * figure out the details. -+ * -+ * TODO: We're not handling error flags correctly at -+ * the moment. -+ */ -+ if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) { -+ UART_PUT_IDR(port, (ATMEL_US_ENDRX -+ | ATMEL_US_TIMEOUT)); -+ tasklet_schedule(&atmel_port->tasklet); -+ } -+ -+ if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE | -+ ATMEL_US_FRAME | ATMEL_US_PARE)) -+ atmel_pdc_rxerr(port, pending); -+ } -+ -+ /* Interrupt receive */ -+ if (pending & ATMEL_US_RXRDY) -+ atmel_rx_chars(port); -+ else if (pending & ATMEL_US_RXBRK) { -+ /* -+ * End of break detected. If it came along with a -+ * character, atmel_rx_chars will handle it. -+ */ -+ UART_PUT_CR(port, ATMEL_US_RSTSTA); -+ UART_PUT_IDR(port, ATMEL_US_RXBRK); -+ atmel_port->break_active = 0; -+ } -+} -+ -+/* -+ * transmit interrupt handler. (Transmit is IRQF_NODELAY safe) -+ */ -+static void -+atmel_handle_transmit(struct uart_port *port, unsigned int pending) -+{ -+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); -+ -+ if (atmel_use_dma_tx(port)) { -+ /* PDC transmit */ -+ if (pending & (ATMEL_US_ENDTX | ATMEL_US_TXBUFE)) { -+ UART_PUT_IDR(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE); -+ tasklet_schedule(&atmel_port->tasklet); -+ } -+ } else { -+ /* Interrupt transmit */ -+ if (pending & ATMEL_US_TXRDY) { -+ UART_PUT_IDR(port, ATMEL_US_TXRDY); -+ tasklet_schedule(&atmel_port->tasklet); -+ } -+ } -+} -+ -+/* -+ * status flags interrupt handler. -+ */ -+static void -+atmel_handle_status(struct uart_port *port, unsigned int pending, -+ unsigned int status) -+{ -+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); -+ -+ if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC -+ | ATMEL_US_CTSIC)) { -+ atmel_port->irq_status = status; -+ tasklet_schedule(&atmel_port->tasklet); -+ } - } - - /* -@@ -355,47 +536,255 @@ - static irqreturn_t atmel_interrupt(int irq, void *dev_id) - { - struct uart_port *port = dev_id; -- struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; - unsigned int status, pending, pass_counter = 0; - -- status = UART_GET_CSR(port); -- pending = status & UART_GET_IMR(port); -- while (pending) { -- /* Interrupt receive */ -- if (pending & ATMEL_US_RXRDY) -- atmel_rx_chars(port); -- else if (pending & ATMEL_US_RXBRK) { -+ do { -+ status = UART_GET_CSR(port); -+ pending = status & UART_GET_IMR(port); -+ if (!pending) -+ break; -+ -+ atmel_handle_receive(port, pending); -+ atmel_handle_status(port, pending, status); -+ atmel_handle_transmit(port, pending); -+ } while (pass_counter++ < ATMEL_ISR_PASS_LIMIT); -+ -+ return IRQ_HANDLED; -+} -+ -+/* -+ * Called from tasklet with ENDTX and TXBUFE interrupts disabled. -+ */ -+static void atmel_tx_dma(struct uart_port *port) -+{ -+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); -+ struct circ_buf *xmit = &port->info->xmit; -+ struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; -+ int count; -+ -+ xmit->tail += pdc->ofs; -+ xmit->tail &= UART_XMIT_SIZE - 1; -+ -+ port->icount.tx += pdc->ofs; -+ pdc->ofs = 0; -+ -+ if (!uart_circ_empty(xmit)) { -+ /* more to transmit - setup next transfer */ -+ -+ /* disable PDC transmit */ -+ UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); -+ dma_sync_single_for_device(port->dev, -+ pdc->dma_addr, -+ pdc->dma_size, -+ DMA_TO_DEVICE); -+ -+ count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); -+ pdc->ofs = count; -+ -+ UART_PUT_TPR(port, pdc->dma_addr + xmit->tail); -+ UART_PUT_TCR(port, count); -+ /* re-enable PDC transmit and interrupts */ -+ UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); -+ UART_PUT_IER(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE); -+ } else { -+ /* nothing left to transmit - disable the transmitter */ -+ -+ /* disable PDC transmit */ -+ UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); -+ } -+ -+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) -+ uart_write_wakeup(port); -+} -+ -+static void atmel_rx_from_ring(struct uart_port *port) -+{ -+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); -+ struct circ_buf *ring = &atmel_port->rx_ring; -+ unsigned int flg; -+ unsigned int status; -+ -+ while (ring->head != ring->tail) { -+ struct atmel_uart_char c; -+ -+ /* Make sure c is loaded after head. */ -+ smp_rmb(); -+ -+ c = ((struct atmel_uart_char *)ring->buf)[ring->tail]; -+ -+ ring->tail = (ring->tail + 1) & (ATMEL_SERIAL_RINGSIZE - 1); -+ -+ port->icount.rx++; -+ status = c.status; -+ flg = TTY_NORMAL; -+ -+ /* -+ * note that the error handling code is -+ * out of the main execution path -+ */ -+ if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME -+ | ATMEL_US_OVRE | ATMEL_US_RXBRK))) { -+ if (status & ATMEL_US_RXBRK) { -+ /* ignore side-effect */ -+ status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); -+ -+ port->icount.brk++; -+ if (uart_handle_break(port)) -+ continue; -+ } -+ if (status & ATMEL_US_PARE) -+ port->icount.parity++; -+ if (status & ATMEL_US_FRAME) -+ port->icount.frame++; -+ if (status & ATMEL_US_OVRE) -+ port->icount.overrun++; -+ -+ status &= port->read_status_mask; -+ -+ if (status & ATMEL_US_RXBRK) -+ flg = TTY_BREAK; -+ else if (status & ATMEL_US_PARE) -+ flg = TTY_PARITY; -+ else if (status & ATMEL_US_FRAME) -+ flg = TTY_FRAME; -+ } -+ -+ -+ if (uart_handle_sysrq_char(port, c.ch)) -+ continue; -+ -+ uart_insert_char(port, status, ATMEL_US_OVRE, c.ch, flg); -+ } -+ -+ /* -+ * Drop the lock here since it might end up calling -+ * uart_start(), which takes the lock. -+ */ -+ spin_unlock(&port->lock); -+ tty_flip_buffer_push(port->info->tty); -+ spin_lock(&port->lock); -+} -+ -+static void atmel_rx_from_dma(struct uart_port *port) -+{ -+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); -+ struct tty_struct *tty = port->info->tty; -+ struct atmel_dma_buffer *pdc; -+ int rx_idx = atmel_port->pdc_rx_idx; -+ unsigned int head; -+ unsigned int tail; -+ unsigned int count; -+ -+ do { -+ /* Reset the UART timeout early so that we don't miss one */ -+ UART_PUT_CR(port, ATMEL_US_STTTO); -+ -+ pdc = &atmel_port->pdc_rx[rx_idx]; -+ head = UART_GET_RPR(port) - pdc->dma_addr; -+ tail = pdc->ofs; -+ -+ /* If the PDC has switched buffers, RPR won't contain -+ * any address within the current buffer. Since head -+ * is unsigned, we just need a one-way comparison to -+ * find out. -+ * -+ * In this case, we just need to consume the entire -+ * buffer and resubmit it for DMA. This will clear the -+ * ENDRX bit as well, so that we can safely re-enable -+ * all interrupts below. -+ */ -+ head = min(head, pdc->dma_size); -+ -+ if (likely(head != tail)) { -+ dma_sync_single_for_cpu(port->dev, pdc->dma_addr, -+ pdc->dma_size, DMA_FROM_DEVICE); -+ - /* -- * End of break detected. If it came along -- * with a character, atmel_rx_chars will -- * handle it. -+ * head will only wrap around when we recycle -+ * the DMA buffer, and when that happens, we -+ * explicitly set tail to 0. So head will -+ * always be greater than tail. - */ -- UART_PUT_CR(port, ATMEL_US_RSTSTA); -- UART_PUT_IDR(port, ATMEL_US_RXBRK); -- atmel_port->break_active = 0; -+ count = head - tail; -+ -+ tty_insert_flip_string(tty, pdc->buf + pdc->ofs, count); -+ -+ dma_sync_single_for_device(port->dev, pdc->dma_addr, -+ pdc->dma_size, DMA_FROM_DEVICE); -+ -+ port->icount.rx += count; -+ pdc->ofs = head; -+ } -+ -+ /* -+ * If the current buffer is full, we need to check if -+ * the next one contains any additional data. -+ */ -+ if (head >= pdc->dma_size) { -+ pdc->ofs = 0; -+ UART_PUT_RNPR(port, pdc->dma_addr); -+ UART_PUT_RNCR(port, pdc->dma_size); -+ -+ rx_idx = !rx_idx; -+ atmel_port->pdc_rx_idx = rx_idx; - } -+ } while (head >= pdc->dma_size); -+ -+ /* -+ * Drop the lock here since it might end up calling -+ * uart_start(), which takes the lock. -+ */ -+ spin_unlock(&port->lock); -+ tty_flip_buffer_push(tty); -+ spin_lock(&port->lock); -+ -+ UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); -+} - -- // TODO: All reads to CSR will clear these interrupts! -- if (pending & ATMEL_US_RIIC) port->icount.rng++; -- if (pending & ATMEL_US_DSRIC) port->icount.dsr++; -- if (pending & ATMEL_US_DCDIC) -+/* -+ * tasklet handling tty stuff outside the interrupt handler. -+ */ -+static void atmel_tasklet_func(unsigned long data) -+{ -+ struct uart_port *port = (struct uart_port *)data; -+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); -+ unsigned int status; -+ unsigned int status_change; -+ -+ /* The interrupt handler does not take the lock */ -+ spin_lock(&port->lock); -+ -+ if (atmel_use_dma_tx(port)) -+ atmel_tx_dma(port); -+ else -+ atmel_tx_chars(port); -+ -+ status = atmel_port->irq_status; -+ status_change = status ^ atmel_port->irq_status_prev; -+ -+ if (status_change & (ATMEL_US_RI | ATMEL_US_DSR -+ | ATMEL_US_DCD | ATMEL_US_CTS)) { -+ /* TODO: All reads to CSR will clear these interrupts! */ -+ if (status_change & ATMEL_US_RI) -+ port->icount.rng++; -+ if (status_change & ATMEL_US_DSR) -+ port->icount.dsr++; -+ if (status_change & ATMEL_US_DCD) - uart_handle_dcd_change(port, !(status & ATMEL_US_DCD)); -- if (pending & ATMEL_US_CTSIC) -+ if (status_change & ATMEL_US_CTS) - uart_handle_cts_change(port, !(status & ATMEL_US_CTS)); -- if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC)) -- wake_up_interruptible(&port->info->delta_msr_wait); -- -- /* Interrupt transmit */ -- if (pending & ATMEL_US_TXRDY) -- atmel_tx_chars(port); - -- if (pass_counter++ > ATMEL_ISR_PASS_LIMIT) -- break; -+ wake_up_interruptible(&port->info->delta_msr_wait); - -- status = UART_GET_CSR(port); -- pending = status & UART_GET_IMR(port); -+ atmel_port->irq_status_prev = status; - } -- return IRQ_HANDLED; -+ -+ if (atmel_use_dma_rx(port)) -+ atmel_rx_from_dma(port); -+ else -+ atmel_rx_from_ring(port); -+ -+ spin_unlock(&port->lock); - } - - /* -@@ -403,6 +792,8 @@ - */ - static int atmel_startup(struct uart_port *port) - { -+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); -+ struct tty_struct *tty = port->info->tty; - int retval; - - /* -@@ -415,13 +806,64 @@ - /* - * Allocate the IRQ - */ -- retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED, "atmel_serial", port); -+ retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED, -+ tty ? tty->name : "atmel_serial", port); - if (retval) { - printk("atmel_serial: atmel_startup - Can't get irq\n"); - return retval; - } - - /* -+ * Initialize DMA (if necessary) -+ */ -+ if (atmel_use_dma_rx(port)) { -+ int i; -+ -+ for (i = 0; i < 2; i++) { -+ struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i]; -+ -+ pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL); -+ if (pdc->buf == NULL) { -+ if (i != 0) { -+ dma_unmap_single(port->dev, -+ atmel_port->pdc_rx[0].dma_addr, -+ PDC_BUFFER_SIZE, -+ DMA_FROM_DEVICE); -+ kfree(atmel_port->pdc_rx[0].buf); -+ } -+ free_irq(port->irq, port); -+ return -ENOMEM; -+ } -+ pdc->dma_addr = dma_map_single(port->dev, -+ pdc->buf, -+ PDC_BUFFER_SIZE, -+ DMA_FROM_DEVICE); -+ pdc->dma_size = PDC_BUFFER_SIZE; -+ pdc->ofs = 0; -+ } -+ -+ atmel_port->pdc_rx_idx = 0; -+ -+ UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr); -+ UART_PUT_RCR(port, PDC_BUFFER_SIZE); -+ -+ UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr); -+ UART_PUT_RNCR(port, PDC_BUFFER_SIZE); -+ } -+ if (atmel_use_dma_tx(port)) { -+ struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; -+ struct circ_buf *xmit = &port->info->xmit; -+ -+ pdc->buf = xmit->buf; -+ pdc->dma_addr = dma_map_single(port->dev, -+ pdc->buf, -+ UART_XMIT_SIZE, -+ DMA_TO_DEVICE); -+ pdc->dma_size = UART_XMIT_SIZE; -+ pdc->ofs = 0; -+ } -+ -+ /* - * If there is a specific "open" function (to register - * control line interrupts) - */ -@@ -437,9 +879,21 @@ - * Finally, enable the serial port - */ - UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); -- UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); /* enable xmit & rcvr */ -+ /* enable xmit & rcvr */ -+ UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); - -- UART_PUT_IER(port, ATMEL_US_RXRDY); /* enable receive only */ -+ if (atmel_use_dma_rx(port)) { -+ /* set UART timeout */ -+ UART_PUT_RTOR(port, PDC_RX_TIMEOUT); -+ UART_PUT_CR(port, ATMEL_US_STTTO); -+ -+ UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); -+ /* enable PDC controller */ -+ UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); -+ } else { -+ /* enable receive only */ -+ UART_PUT_IER(port, ATMEL_US_RXRDY); -+ } - - return 0; - } -@@ -449,6 +903,38 @@ - */ - static void atmel_shutdown(struct uart_port *port) - { -+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); -+ /* -+ * Ensure everything is stopped. -+ */ -+ atmel_stop_rx(port); -+ atmel_stop_tx(port); -+ -+ /* -+ * Shut-down the DMA. -+ */ -+ if (atmel_use_dma_rx(port)) { -+ int i; -+ -+ for (i = 0; i < 2; i++) { -+ struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i]; -+ -+ dma_unmap_single(port->dev, -+ pdc->dma_addr, -+ pdc->dma_size, -+ DMA_FROM_DEVICE); -+ kfree(pdc->buf); -+ } -+ } -+ if (atmel_use_dma_tx(port)) { -+ struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; -+ -+ dma_unmap_single(port->dev, -+ pdc->dma_addr, -+ pdc->dma_size, -+ DMA_TO_DEVICE); -+ } -+ - /* - * Disable all interrupts, port and break condition. - */ -@@ -471,45 +957,48 @@ - /* - * Power / Clock management. - */ --static void atmel_serial_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) -+static void atmel_serial_pm(struct uart_port *port, unsigned int state, -+ unsigned int oldstate) - { -- struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; -+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - - switch (state) { -- case 0: -- /* -- * Enable the peripheral clock for this serial port. -- * This is called on uart_open() or a resume event. -- */ -- clk_enable(atmel_port->clk); -- break; -- case 3: -- /* -- * Disable the peripheral clock for this serial port. -- * This is called on uart_close() or a suspend event. -- */ -- clk_disable(atmel_port->clk); -- break; -- default: -- printk(KERN_ERR "atmel_serial: unknown pm %d\n", state); -+ case 0: -+ /* -+ * Enable the peripheral clock for this serial port. -+ * This is called on uart_open() or a resume event. -+ */ -+ clk_enable(atmel_port->clk); -+ break; -+ case 3: -+ /* -+ * Disable the peripheral clock for this serial port. -+ * This is called on uart_close() or a suspend event. -+ */ -+ clk_disable(atmel_port->clk); -+ break; -+ default: -+ printk(KERN_ERR "atmel_serial: unknown pm %d\n", state); - } - } - - /* - * Change the port parameters - */ --static void atmel_set_termios(struct uart_port *port, struct ktermios * termios, struct ktermios * old) -+static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, -+ struct ktermios *old) - { - unsigned long flags; - unsigned int mode, imr, quot, baud; - - /* Get current mode register */ -- mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP | ATMEL_US_PAR); -+ mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL -+ | ATMEL_US_NBSTOP | ATMEL_US_PAR); - -- baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); -+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); - quot = uart_get_divisor(port, baud); - -- if (quot > 65535) { /* BRGR is 16-bit, so switch to slower clock */ -+ if (quot > 65535) { /* BRGR is 16-bit, so switch to slower clock */ - quot /= 8; - mode |= ATMEL_US_USCLKS_MCK_DIV8; - } -@@ -536,18 +1025,17 @@ - - /* parity */ - if (termios->c_cflag & PARENB) { -- if (termios->c_cflag & CMSPAR) { /* Mark or Space parity */ -+ /* Mark or Space parity */ -+ if (termios->c_cflag & CMSPAR) { - if (termios->c_cflag & PARODD) - mode |= ATMEL_US_PAR_MARK; - else - mode |= ATMEL_US_PAR_SPACE; -- } -- else if (termios->c_cflag & PARODD) -+ } else if (termios->c_cflag & PARODD) - mode |= ATMEL_US_PAR_ODD; - else - mode |= ATMEL_US_PAR_EVEN; +- if (xfer->tx_buf) +- *tx_dma = xfer->tx_dma + xfer->len - len; +- else { +- *tx_dma = as->buffer_dma; +- if (len > BUFFER_SIZE) +- len = BUFFER_SIZE; +- memset(as->buffer, 0, len); +- dma_sync_single_for_device(&as->pdev->dev, +- as->buffer_dma, len, DMA_TO_DEVICE); - } -- else -+ } else - mode |= ATMEL_US_PAR_NONE; - - spin_lock_irqsave(&port->lock, flags); -@@ -558,6 +1046,10 @@ - if (termios->c_iflag & (BRKINT | PARMRK)) - port->read_status_mask |= ATMEL_US_RXBRK; - -+ if (atmel_use_dma_rx(port)) -+ /* need to enable error interrupts */ -+ UART_PUT_IER(port, port->read_status_mask); -+ - /* - * Characters to ignore - */ -@@ -573,16 +1065,16 @@ - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= ATMEL_US_OVRE; - } - -- // TODO: Ignore all characters if CREAD is set. -+ /* TODO: Ignore all characters if CREAD is set.*/ - - /* update the per-port timeout */ - uart_update_timeout(port, termios->c_cflag, baud); - -- /* disable interrupts and drain transmitter */ -- imr = UART_GET_IMR(port); /* get interrupt mask */ -- UART_PUT_IDR(port, -1); /* disable all interrupts */ -- while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY)) { barrier(); } -+ /* save/disable interrupts and drain transmitter */ -+ imr = UART_GET_IMR(port); -+ UART_PUT_IDR(port, -1); -+ while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY)) -+ cpu_relax(); - - /* disable receiver and transmitter */ - UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS); -@@ -708,7 +1200,8 @@ - /* - * Configure the port from the platform device resource info. - */ --static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct platform_device *pdev) -+static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, -+ struct platform_device *pdev) - { - struct uart_port *port = &atmel_port->uart; - struct atmel_uart_data *data = pdev->dev.platform_data; -@@ -723,6 +1216,11 @@ - port->mapbase = pdev->resource[0].start; - port->irq = pdev->resource[1].start; - -+ tasklet_init(&atmel_port->tasklet, atmel_tasklet_func, -+ (unsigned long)port); -+ -+ memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); -+ - if (data->regs) - /* Already mapped by setup code */ - port->membase = data->regs; -@@ -731,11 +1229,17 @@ - port->membase = NULL; - } - -- if (!atmel_port->clk) { /* for console, the clock could already be configured */ -+ /* for console, the clock could already be configured */ -+ if (!atmel_port->clk) { - atmel_port->clk = clk_get(&pdev->dev, "usart"); - clk_enable(atmel_port->clk); - port->uartclk = clk_get_rate(atmel_port->clk); - } -+ -+ atmel_port->use_dma_rx = data->use_dma_rx; -+ atmel_port->use_dma_tx = data->use_dma_tx; -+ if (atmel_use_dma_tx(port)) -+ port->fifosize = PDC_BUFFER_SIZE; - } - - /* -@@ -755,12 +1259,11 @@ - atmel_pops.set_wake = fns->set_wake; - } - +- *plen = len; +-} - - #ifdef CONFIG_SERIAL_ATMEL_CONSOLE - static void atmel_console_putchar(struct uart_port *port, int ch) - { - while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY)) -- barrier(); -+ cpu_relax(); - UART_PUT_CHAR(port, ch); - } - -@@ -773,38 +1276,40 @@ - unsigned int status, imr; - - /* -- * First, save IMR and then disable interrupts -+ * First, save IMR and then disable interrupts - */ -- imr = UART_GET_IMR(port); /* get interrupt mask */ -+ imr = UART_GET_IMR(port); - UART_PUT_IDR(port, ATMEL_US_RXRDY | ATMEL_US_TXRDY); - - uart_console_write(port, s, count, atmel_console_putchar); - - /* -- * Finally, wait for transmitter to become empty -- * and restore IMR -+ * Finally, wait for transmitter to become empty -+ * and restore IMR - */ - do { - status = UART_GET_CSR(port); - } while (!(status & ATMEL_US_TXRDY)); -- UART_PUT_IER(port, imr); /* set interrupts back the way they were */ -+ /* set interrupts back the way they were */ -+ UART_PUT_IER(port, imr); - } - - /* -- * If the port was already initialised (eg, by a boot loader), try to determine -- * the current setup. -+ * If the port was already initialised (eg, by a boot loader), -+ * try to determine the current setup. - */ --static void __init atmel_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits) -+static void __init atmel_console_get_options(struct uart_port *port, int *baud, -+ int *parity, int *bits) - { - unsigned int mr, quot; - --// TODO: CR is a write-only register --// unsigned int cr; --// --// cr = UART_GET_CR(port) & (ATMEL_US_RXEN | ATMEL_US_TXEN); --// if (cr == (ATMEL_US_RXEN | ATMEL_US_TXEN)) { --// /* ok, the port was enabled */ --// } -+ /* -+ * If the baud rate generator isn't running, the port wasn't -+ * initialized by the boot loader. -+ */ -+ quot = UART_GET_BRGR(port); -+ if (!quot) -+ return; - - mr = UART_GET_MR(port) & ATMEL_US_CHRL; - if (mr == ATMEL_US_CHRL_8) -@@ -824,7 +1329,6 @@ - * lower than one of those, as it would make us fall through - * to a much lower baud rate than we really want. - */ -- quot = UART_GET_BRGR(port); - *baud = port->uartclk / (16 * (quot - 1)); - } - -@@ -836,10 +1340,12 @@ - int parity = 'n'; - int flow = 'n'; - -- if (port->membase == 0) /* Port not initialized yet - delay setup */ -+ if (port->membase == NULL) { -+ /* Port not initialized yet - delay setup */ - return -ENODEV; -+ } - -- UART_PUT_IDR(port, -1); /* disable interrupts */ -+ UART_PUT_IDR(port, -1); - UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); - UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); - -@@ -871,13 +1377,16 @@ - static int __init atmel_console_init(void) - { - if (atmel_default_console_device) { -- add_preferred_console(ATMEL_DEVICENAME, atmel_default_console_device->id, NULL); -- atmel_init_port(&(atmel_ports[atmel_default_console_device->id]), atmel_default_console_device); -+ add_preferred_console(ATMEL_DEVICENAME, -+ atmel_default_console_device->id, NULL); -+ atmel_init_port(&atmel_ports[atmel_default_console_device->id], -+ atmel_default_console_device); - register_console(&atmel_console); - } - - return 0; - } -+ - console_initcall(atmel_console_init); - /* -@@ -885,34 +1394,48 @@ - */ - static int __init atmel_late_console_init(void) - { -- if (atmel_default_console_device && !(atmel_console.flags & CON_ENABLED)) -+ if (atmel_default_console_device -+ && !(atmel_console.flags & CON_ENABLED)) - register_console(&atmel_console); - - return 0; - } -+ - core_initcall(atmel_late_console_init); - -+static inline bool atmel_is_console_port(struct uart_port *port) -+{ -+ return port->cons && port->cons->index == port->line; -+} -+ - #else - #define ATMEL_CONSOLE_DEVICE NULL -+ -+static inline bool atmel_is_console_port(struct uart_port *port) -+{ -+ return false; -+} - #endif - - static struct uart_driver atmel_uart = { -- .owner = THIS_MODULE, -- .driver_name = "atmel_serial", -- .dev_name = ATMEL_DEVICENAME, -- .major = SERIAL_ATMEL_MAJOR, -- .minor = MINOR_START, -- .nr = ATMEL_MAX_UART, -- .cons = ATMEL_CONSOLE_DEVICE, -+ .owner = THIS_MODULE, -+ .driver_name = "atmel_serial", -+ .dev_name = ATMEL_DEVICENAME, -+ .major = SERIAL_ATMEL_MAJOR, -+ .minor = MINOR_START, -+ .nr = ATMEL_MAX_UART, -+ .cons = ATMEL_CONSOLE_DEVICE, - }; - - #ifdef CONFIG_PM --static int atmel_serial_suspend(struct platform_device *pdev, pm_message_t state) -+static int atmel_serial_suspend(struct platform_device *pdev, -+ pm_message_t state) - { - struct uart_port *port = platform_get_drvdata(pdev); -- struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; -+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - -- if (device_may_wakeup(&pdev->dev) && !at91_suspend_entering_slow_clock()) -+ if (device_may_wakeup(&pdev->dev) -+ && !at91_suspend_entering_slow_clock()) - enable_irq_wake(port->irq); - else { - uart_suspend_port(&atmel_uart, port); -@@ -925,13 +1448,12 @@ - static int atmel_serial_resume(struct platform_device *pdev) + * Submit next transfer for DMA. + * lock is held, spi irq is blocked +@@ -184,78 +140,53 @@ { - struct uart_port *port = platform_get_drvdata(pdev); -- struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; -+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct atmel_spi *as = spi_master_get_devdata(master); + struct spi_transfer *xfer; +- u32 len, remaining, total; ++ u32 len; + dma_addr_t tx_dma, rx_dma; - if (atmel_port->suspended) { - uart_resume_port(&atmel_uart, port); - atmel_port->suspended = 0; -- } +- if (!as->current_transfer) +- xfer = list_entry(msg->transfers.next, +- struct spi_transfer, transfer_list); +- else if (!as->next_transfer) +- xfer = list_entry(as->current_transfer->transfer_list.next, +- struct spi_transfer, transfer_list); - else -+ } else - disable_irq_wake(port->irq); - - return 0; -@@ -944,15 +1466,40 @@ - static int __devinit atmel_serial_probe(struct platform_device *pdev) - { - struct atmel_uart_port *port; -+ void *data; - int ret; - -+ BUILD_BUG_ON(!is_power_of_2(ATMEL_SERIAL_RINGSIZE)); -+ - port = &atmel_ports[pdev->id]; - atmel_init_port(port, pdev); - -+ if (!atmel_use_dma_rx(&port->uart)) { -+ ret = -ENOMEM; -+ data = kmalloc(sizeof(struct atmel_uart_char) -+ * ATMEL_SERIAL_RINGSIZE, GFP_KERNEL); -+ if (!data) -+ goto err_alloc_ring; -+ port->rx_ring.buf = data; -+ } -+ - ret = uart_add_one_port(&atmel_uart, &port->uart); -- if (!ret) { -- device_init_wakeup(&pdev->dev, 1); -- platform_set_drvdata(pdev, port); -+ if (ret) -+ goto err_add_port; -+ -+ device_init_wakeup(&pdev->dev, 1); -+ platform_set_drvdata(pdev, port); -+ -+ return 0; -+ -+err_add_port: -+ kfree(port->rx_ring.buf); -+ port->rx_ring.buf = NULL; -+err_alloc_ring: -+ if (!atmel_is_console_port(&port->uart)) { -+ clk_disable(port->clk); -+ clk_put(port->clk); -+ port->clk = NULL; - } - - return ret; -@@ -961,19 +1508,21 @@ - static int __devexit atmel_serial_remove(struct platform_device *pdev) - { - struct uart_port *port = platform_get_drvdata(pdev); -- struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; -+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - int ret = 0; - -- clk_disable(atmel_port->clk); -- clk_put(atmel_port->clk); +- xfer = NULL; - - device_init_wakeup(&pdev->dev, 0); - platform_set_drvdata(pdev, NULL); - -- if (port) { -- ret = uart_remove_one_port(&atmel_uart, port); -- kfree(port); -- } -+ ret = uart_remove_one_port(&atmel_uart, port); -+ -+ tasklet_kill(&atmel_port->tasklet); -+ kfree(atmel_port->rx_ring.buf); -+ -+ /* "port" is allocated statically, so we shouldn't free it */ -+ -+ clk_disable(atmel_port->clk); -+ clk_put(atmel_port->clk); - - return ret; - } ---- a/drivers/serial/atmel_serial.h -+++ /dev/null -@@ -1,127 +0,0 @@ --/* -- * drivers/serial/atmel_serial.h -- * -- * Copyright (C) 2005 Ivan Kokshaysky -- * Copyright (C) SAN People -- * -- * USART registers. -- * Based on AT91RM9200 datasheet revision E. -- * -- * 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. -- */ -- --#ifndef ATMEL_SERIAL_H --#define ATMEL_SERIAL_H -- --#define ATMEL_US_CR 0x00 /* Control Register */ --#define ATMEL_US_RSTRX (1 << 2) /* Reset Receiver */ --#define ATMEL_US_RSTTX (1 << 3) /* Reset Transmitter */ --#define ATMEL_US_RXEN (1 << 4) /* Receiver Enable */ --#define ATMEL_US_RXDIS (1 << 5) /* Receiver Disable */ --#define ATMEL_US_TXEN (1 << 6) /* Transmitter Enable */ --#define ATMEL_US_TXDIS (1 << 7) /* Transmitter Disable */ --#define ATMEL_US_RSTSTA (1 << 8) /* Reset Status Bits */ --#define ATMEL_US_STTBRK (1 << 9) /* Start Break */ --#define ATMEL_US_STPBRK (1 << 10) /* Stop Break */ --#define ATMEL_US_STTTO (1 << 11) /* Start Time-out */ --#define ATMEL_US_SENDA (1 << 12) /* Send Address */ --#define ATMEL_US_RSTIT (1 << 13) /* Reset Iterations */ --#define ATMEL_US_RSTNACK (1 << 14) /* Reset Non Acknowledge */ --#define ATMEL_US_RETTO (1 << 15) /* Rearm Time-out */ --#define ATMEL_US_DTREN (1 << 16) /* Data Terminal Ready Enable [AT91RM9200 only] */ --#define ATMEL_US_DTRDIS (1 << 17) /* Data Terminal Ready Disable [AT91RM9200 only] */ --#define ATMEL_US_RTSEN (1 << 18) /* Request To Send Enable */ --#define ATMEL_US_RTSDIS (1 << 19) /* Request To Send Disable */ -- --#define ATMEL_US_MR 0x04 /* Mode Register */ --#define ATMEL_US_USMODE (0xf << 0) /* Mode of the USART */ --#define ATMEL_US_USMODE_NORMAL 0 --#define ATMEL_US_USMODE_RS485 1 --#define ATMEL_US_USMODE_HWHS 2 --#define ATMEL_US_USMODE_MODEM 3 --#define ATMEL_US_USMODE_ISO7816_T0 4 --#define ATMEL_US_USMODE_ISO7816_T1 6 --#define ATMEL_US_USMODE_IRDA 8 --#define ATMEL_US_USCLKS (3 << 4) /* Clock Selection */ --#define ATMEL_US_USCLKS_MCK (0 << 4) --#define ATMEL_US_USCLKS_MCK_DIV8 (1 << 4) --#define ATMEL_US_USCLKS_SCK (3 << 4) --#define ATMEL_US_CHRL (3 << 6) /* Character Length */ --#define ATMEL_US_CHRL_5 (0 << 6) --#define ATMEL_US_CHRL_6 (1 << 6) --#define ATMEL_US_CHRL_7 (2 << 6) --#define ATMEL_US_CHRL_8 (3 << 6) --#define ATMEL_US_SYNC (1 << 8) /* Synchronous Mode Select */ --#define ATMEL_US_PAR (7 << 9) /* Parity Type */ --#define ATMEL_US_PAR_EVEN (0 << 9) --#define ATMEL_US_PAR_ODD (1 << 9) --#define ATMEL_US_PAR_SPACE (2 << 9) --#define ATMEL_US_PAR_MARK (3 << 9) --#define ATMEL_US_PAR_NONE (4 << 9) --#define ATMEL_US_PAR_MULTI_DROP (6 << 9) --#define ATMEL_US_NBSTOP (3 << 12) /* Number of Stop Bits */ --#define ATMEL_US_NBSTOP_1 (0 << 12) --#define ATMEL_US_NBSTOP_1_5 (1 << 12) --#define ATMEL_US_NBSTOP_2 (2 << 12) --#define ATMEL_US_CHMODE (3 << 14) /* Channel Mode */ --#define ATMEL_US_CHMODE_NORMAL (0 << 14) --#define ATMEL_US_CHMODE_ECHO (1 << 14) --#define ATMEL_US_CHMODE_LOC_LOOP (2 << 14) --#define ATMEL_US_CHMODE_REM_LOOP (3 << 14) --#define ATMEL_US_MSBF (1 << 16) /* Bit Order */ --#define ATMEL_US_MODE9 (1 << 17) /* 9-bit Character Length */ --#define ATMEL_US_CLKO (1 << 18) /* Clock Output Select */ --#define ATMEL_US_OVER (1 << 19) /* Oversampling Mode */ --#define ATMEL_US_INACK (1 << 20) /* Inhibit Non Acknowledge */ --#define ATMEL_US_DSNACK (1 << 21) /* Disable Successive NACK */ --#define ATMEL_US_MAX_ITER (7 << 24) /* Max Iterations */ --#define ATMEL_US_FILTER (1 << 28) /* Infrared Receive Line Filter */ -- --#define ATMEL_US_IER 0x08 /* Interrupt Enable Register */ --#define ATMEL_US_RXRDY (1 << 0) /* Receiver Ready */ --#define ATMEL_US_TXRDY (1 << 1) /* Transmitter Ready */ --#define ATMEL_US_RXBRK (1 << 2) /* Break Received / End of Break */ --#define ATMEL_US_ENDRX (1 << 3) /* End of Receiver Transfer */ --#define ATMEL_US_ENDTX (1 << 4) /* End of Transmitter Transfer */ --#define ATMEL_US_OVRE (1 << 5) /* Overrun Error */ --#define ATMEL_US_FRAME (1 << 6) /* Framing Error */ --#define ATMEL_US_PARE (1 << 7) /* Parity Error */ --#define ATMEL_US_TIMEOUT (1 << 8) /* Receiver Time-out */ --#define ATMEL_US_TXEMPTY (1 << 9) /* Transmitter Empty */ --#define ATMEL_US_ITERATION (1 << 10) /* Max number of Repetitions Reached */ --#define ATMEL_US_TXBUFE (1 << 11) /* Transmission Buffer Empty */ --#define ATMEL_US_RXBUFF (1 << 12) /* Reception Buffer Full */ --#define ATMEL_US_NACK (1 << 13) /* Non Acknowledge */ --#define ATMEL_US_RIIC (1 << 16) /* Ring Indicator Input Change [AT91RM9200 only] */ --#define ATMEL_US_DSRIC (1 << 17) /* Data Set Ready Input Change [AT91RM9200 only] */ --#define ATMEL_US_DCDIC (1 << 18) /* Data Carrier Detect Input Change [AT91RM9200 only] */ --#define ATMEL_US_CTSIC (1 << 19) /* Clear to Send Input Change */ --#define ATMEL_US_RI (1 << 20) /* RI */ --#define ATMEL_US_DSR (1 << 21) /* DSR */ --#define ATMEL_US_DCD (1 << 22) /* DCD */ --#define ATMEL_US_CTS (1 << 23) /* CTS */ -- --#define ATMEL_US_IDR 0x0c /* Interrupt Disable Register */ --#define ATMEL_US_IMR 0x10 /* Interrupt Mask Register */ --#define ATMEL_US_CSR 0x14 /* Channel Status Register */ --#define ATMEL_US_RHR 0x18 /* Receiver Holding Register */ --#define ATMEL_US_THR 0x1c /* Transmitter Holding Register */ --#define ATMEL_US_SYNH (1 << 15) /* Transmit/Receive Sync [AT91SAM9261 only] */ +- if (xfer) { +- len = xfer->len; +- atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len); +- remaining = xfer->len - len; - --#define ATMEL_US_BRGR 0x20 /* Baud Rate Generator Register */ --#define ATMEL_US_CD (0xffff << 0) /* Clock Divider */ +- spi_writel(as, RPR, rx_dma); +- spi_writel(as, TPR, tx_dma); - --#define ATMEL_US_RTOR 0x24 /* Receiver Time-out Register */ --#define ATMEL_US_TO (0xffff << 0) /* Time-out Value */ +- if (msg->spi->bits_per_word > 8) +- len >>= 1; +- spi_writel(as, RCR, len); +- spi_writel(as, TCR, len); - --#define ATMEL_US_TTGR 0x28 /* Transmitter Timeguard Register */ --#define ATMEL_US_TG (0xff << 0) /* Timeguard Value */ -- --#define ATMEL_US_FIDI 0x40 /* FI DI Ratio Register */ --#define ATMEL_US_NER 0x44 /* Number of Errors Register */ --#define ATMEL_US_IF 0x4c /* IrDA Filter Register */ -- --#endif ---- a/drivers/serial/Kconfig -+++ b/drivers/serial/Kconfig -@@ -380,6 +380,21 @@ - console is the device which receives all kernel messages and - warnings and which allows logins in single user mode). - -+config SERIAL_ATMEL_PDC -+ bool "Support DMA transfers on AT91 / AT32 serial port" -+ depends on SERIAL_ATMEL -+ default y -+ help -+ Say Y here if you wish to use the PDC to do DMA transfers to -+ and from the Atmel AT91 / AT32 serial port. In order to -+ actually use DMA transfers, make sure that the use_dma_tx -+ and use_dma_rx members in the atmel_uart_data struct is set -+ appropriately for each port. -+ -+ Note that break and error handling currently doesn't work -+ properly when DMA is enabled. Make sure that ports where -+ this matters don't use DMA. -+ - config SERIAL_ATMEL_TTYAT - bool "Install as device ttyATn instead of ttySn" - depends on SERIAL_ATMEL=y ---- a/drivers/spi/atmel_spi.c -+++ b/drivers/spi/atmel_spi.c -@@ -51,7 +51,9 @@ - u8 stopping; - struct list_head queue; - struct spi_transfer *current_transfer; -- unsigned long remaining_bytes; -+ unsigned long current_remaining_bytes; -+ struct spi_transfer *next_transfer; -+ unsigned long next_remaining_bytes; - - void *buffer; - dma_addr_t buffer_dma; -@@ -113,6 +115,16 @@ - unsigned gpio = (unsigned) spi->controller_data; - unsigned active = spi->mode & SPI_CS_HIGH; - u32 mr; -+ int i; -+ u32 csr; -+ u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0; -+ -+ /* Make sure clock polarity is correct */ -+ for (i = 0; i < spi->master->num_chipselect; i++) { -+ csr = spi_readl(as, CSR0 + 4 * i); -+ if ((csr ^ cpol) & SPI_BIT(CPOL)) -+ spi_writel(as, CSR0 + 4 * i, csr ^ SPI_BIT(CPOL)); -+ } - - /* only deactivate *this* device; sometimes transfers to - * another device may be active when this routine is called. -@@ -131,6 +143,48 @@ - gpio_set_value(gpio, !active); - } +- dev_dbg(&msg->spi->dev, +- " start xfer %p: len %u tx %p/%08x rx %p/%08x\n", +- xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, +- xfer->rx_buf, xfer->rx_dma); +- } else { +- xfer = as->next_transfer; +- remaining = as->next_remaining_bytes; ++ xfer = as->current_transfer; ++ if (!xfer || as->remaining_bytes == 0) { ++ if (xfer) ++ xfer = list_entry(xfer->transfer_list.next, ++ struct spi_transfer, transfer_list); ++ else ++ xfer = list_entry(msg->transfers.next, ++ struct spi_transfer, transfer_list); ++ as->remaining_bytes = xfer->len; ++ as->current_transfer = xfer; + } -+static inline int atmel_spi_xfer_is_last(struct spi_message *msg, -+ struct spi_transfer *xfer) -+{ -+ return msg->transfers.prev == &xfer->transfer_list; -+} -+ -+static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer) -+{ -+ return xfer->delay_usecs == 0 && !xfer->cs_change; -+} -+ -+static void atmel_spi_next_xfer_data(struct spi_master *master, -+ struct spi_transfer *xfer, -+ dma_addr_t *tx_dma, -+ dma_addr_t *rx_dma, -+ u32 *plen) -+{ -+ struct atmel_spi *as = spi_master_get_devdata(master); -+ u32 len = *plen; -+ +- as->current_transfer = xfer; +- as->current_remaining_bytes = remaining; +- +- if (remaining > 0) +- len = remaining; +- else if (!atmel_spi_xfer_is_last(msg, xfer) +- && atmel_spi_xfer_can_be_chained(xfer)) { +- xfer = list_entry(xfer->transfer_list.next, +- struct spi_transfer, transfer_list); +- len = xfer->len; +- } else +- xfer = NULL; ++ len = as->remaining_bytes; + +- as->next_transfer = xfer; ++ tx_dma = xfer->tx_dma + xfer->len - len; ++ rx_dma = xfer->rx_dma + xfer->len - len; + +- if (xfer) { +- total = len; +- atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len); +- as->next_remaining_bytes = total - len; +- +- spi_writel(as, RNPR, rx_dma); +- spi_writel(as, TNPR, tx_dma); +- +- if (msg->spi->bits_per_word > 8) +- len >>= 1; +- spi_writel(as, RNCR, len); +- spi_writel(as, TNCR, len); +- +- dev_dbg(&msg->spi->dev, +- " next xfer %p: len %u tx %p/%08x rx %p/%08x\n", +- xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, +- xfer->rx_buf, xfer->rx_dma); +- } else { +- spi_writel(as, RNCR, 0); +- spi_writel(as, TNCR, 0); + /* use scratch buffer only when rx or tx data is unspecified */ -+ if (xfer->rx_buf) -+ *rx_dma = xfer->rx_dma + xfer->len - len; -+ else { -+ *rx_dma = as->buffer_dma; ++ if (!xfer->rx_buf) { ++ rx_dma = as->buffer_dma; + if (len > BUFFER_SIZE) + len = BUFFER_SIZE; -+ } -+ if (xfer->tx_buf) -+ *tx_dma = xfer->tx_dma + xfer->len - len; -+ else { -+ *tx_dma = as->buffer_dma; + } ++ if (!xfer->tx_buf) { ++ tx_dma = as->buffer_dma; + if (len > BUFFER_SIZE) + len = BUFFER_SIZE; + memset(as->buffer, 0, len); @@ -17595,194 +14381,69 @@ + as->buffer_dma, len, DMA_TO_DEVICE); + } + -+ *plen = len; -+} -+ - /* - * Submit next transfer for DMA. - * lock is held, spi irq is blocked -@@ -140,53 +194,78 @@ - { - struct atmel_spi *as = spi_master_get_devdata(master); - struct spi_transfer *xfer; -- u32 len; -+ u32 len, remaining, total; - dma_addr_t tx_dma, rx_dma; ++ spi_writel(as, RPR, rx_dma); ++ spi_writel(as, TPR, tx_dma); -- xfer = as->current_transfer; -- if (!xfer || as->remaining_bytes == 0) { -- if (xfer) -- xfer = list_entry(xfer->transfer_list.next, -- struct spi_transfer, transfer_list); -- else -- xfer = list_entry(msg->transfers.next, -- struct spi_transfer, transfer_list); -- as->remaining_bytes = xfer->len; -- as->current_transfer = xfer; -+ if (!as->current_transfer) -+ xfer = list_entry(msg->transfers.next, -+ struct spi_transfer, transfer_list); -+ else if (!as->next_transfer) -+ xfer = list_entry(as->current_transfer->transfer_list.next, -+ struct spi_transfer, transfer_list); -+ else -+ xfer = NULL; -+ -+ if (xfer) { -+ len = xfer->len; -+ atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len); -+ remaining = xfer->len - len; +- /* REVISIT: We're waiting for ENDRX before we start the next ++ as->remaining_bytes -= len; ++ if (msg->spi->bits_per_word > 8) ++ len >>= 1; + -+ spi_writel(as, RPR, rx_dma); -+ spi_writel(as, TPR, tx_dma); -+ -+ if (msg->spi->bits_per_word > 8) -+ len >>= 1; -+ spi_writel(as, RCR, len); -+ spi_writel(as, TCR, len); -+ -+ dev_dbg(&msg->spi->dev, -+ " start xfer %p: len %u tx %p/%08x rx %p/%08x\n", -+ xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, -+ xfer->rx_buf, xfer->rx_dma); -+ } else { -+ xfer = as->next_transfer; -+ remaining = as->next_remaining_bytes; - } - -- len = as->remaining_bytes; -+ as->current_transfer = xfer; -+ as->current_remaining_bytes = remaining; - -- tx_dma = xfer->tx_dma + xfer->len - len; -- rx_dma = xfer->rx_dma + xfer->len - len; -+ if (remaining > 0) -+ len = remaining; -+ else if (!atmel_spi_xfer_is_last(msg, xfer) -+ && atmel_spi_xfer_can_be_chained(xfer)) { -+ xfer = list_entry(xfer->transfer_list.next, -+ struct spi_transfer, transfer_list); -+ len = xfer->len; -+ } else -+ xfer = NULL; - -- /* use scratch buffer only when rx or tx data is unspecified */ -- if (!xfer->rx_buf) { -- rx_dma = as->buffer_dma; -- if (len > BUFFER_SIZE) -- len = BUFFER_SIZE; -- } -- if (!xfer->tx_buf) { -- tx_dma = as->buffer_dma; -- if (len > BUFFER_SIZE) -- len = BUFFER_SIZE; -- memset(as->buffer, 0, len); -- dma_sync_single_for_device(&as->pdev->dev, -- as->buffer_dma, len, DMA_TO_DEVICE); -- } -+ as->next_transfer = xfer; - -- spi_writel(as, RPR, rx_dma); -- spi_writel(as, TPR, tx_dma); -+ if (xfer) { -+ total = len; -+ atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len); -+ as->next_remaining_bytes = total - len; -+ -+ spi_writel(as, RNPR, rx_dma); -+ spi_writel(as, TNPR, tx_dma); -+ -+ if (msg->spi->bits_per_word > 8) -+ len >>= 1; -+ spi_writel(as, RNCR, len); -+ spi_writel(as, TNCR, len); -+ -+ dev_dbg(&msg->spi->dev, -+ " next xfer %p: len %u tx %p/%08x rx %p/%08x\n", -+ xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, -+ xfer->rx_buf, xfer->rx_dma); -+ } else { -+ spi_writel(as, RNCR, 0); -+ spi_writel(as, TNCR, 0); -+ } - -- as->remaining_bytes -= len; -- if (msg->spi->bits_per_word > 8) -- len >>= 1; -- -- /* REVISIT: when xfer->delay_usecs == 0, the PDC "next transfer" -- * mechanism might help avoid the IRQ latency between transfers -- * (and improve the nCS0 errata handling on at91rm9200 chips) -- * -- * We're also waiting for ENDRX before we start the next -+ /* REVISIT: We're waiting for ENDRX before we start the next ++ /* REVISIT: when xfer->delay_usecs == 0, the PDC "next transfer" ++ * mechanism might help avoid the IRQ latency between transfers ++ * (and improve the nCS0 errata handling on at91rm9200 chips) ++ * ++ * We're also waiting for ENDRX before we start the next * transfer because we need to handle some difficult timing * issues otherwise. If we wait for ENDTX in one transfer and * then starts waiting for ENDRX in the next, it's difficult -@@ -196,17 +275,7 @@ +@@ -265,7 +196,17 @@ * * It should be doable, though. Just not now... */ -- spi_writel(as, TNCR, 0); -- spi_writel(as, RNCR, 0); ++ spi_writel(as, TNCR, 0); ++ spi_writel(as, RNCR, 0); spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES)); -- -- dev_dbg(&msg->spi->dev, -- " start xfer %p: len %u tx %p/%08x rx %p/%08x imr %03x\n", -- xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, -- xfer->rx_buf, xfer->rx_dma, spi_readl(as, IMR)); -- -- spi_writel(as, RCR, len); -- spi_writel(as, TCR, len); ++ ++ dev_dbg(&msg->spi->dev, ++ " start xfer %p: len %u tx %p/%08x rx %p/%08x imr %03x\n", ++ xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, ++ xfer->rx_buf, xfer->rx_dma, spi_readl(as, IMR)); ++ ++ spi_writel(as, RCR, len); ++ spi_writel(as, TCR, len); spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN)); } -@@ -304,6 +373,7 @@ +@@ -363,7 +304,6 @@ spin_lock(&as->lock); as->current_transfer = NULL; -+ as->next_transfer = NULL; +- as->next_transfer = NULL; /* continue if needed */ if (list_empty(&as->queue) || as->stopping) -@@ -387,7 +457,7 @@ +@@ -447,7 +387,7 @@ spi_writel(as, IDR, pending); -- if (as->remaining_bytes == 0) { -+ if (as->current_remaining_bytes == 0) { +- if (as->current_remaining_bytes == 0) { ++ if (as->remaining_bytes == 0) { msg->actual_length += xfer->len; if (!msg->is_dma_mapped) -@@ -397,7 +467,7 @@ +@@ -457,7 +397,7 @@ if (xfer->delay_usecs) udelay(xfer->delay_usecs); -- if (msg->transfers.prev == &xfer->transfer_list) { -+ if (atmel_spi_xfer_is_last(msg, xfer)) { +- if (atmel_spi_xfer_is_last(msg, xfer)) { ++ if (msg->transfers.prev == &xfer->transfer_list) { /* report completed message */ atmel_spi_msg_done(master, as, msg, 0, xfer->cs_change); -@@ -500,9 +570,14 @@ - if (!(spi->mode & SPI_CPHA)) - csr |= SPI_BIT(NCPHA); - -- /* TODO: DLYBS and DLYBCT */ -- csr |= SPI_BF(DLYBS, 10); -- csr |= SPI_BF(DLYBCT, 10); -+ /* DLYBS is mostly irrelevant since we manage chipselect using GPIOs. -+ * -+ * DLYBCT would add delays between words, slowing down transfers. -+ * It could potentially be useful to cope with DMA bottlenecks, but -+ * in those cases it's probably best to just use a lower bitrate. -+ */ -+ csr |= SPI_BF(DLYBS, 0); -+ csr |= SPI_BF(DLYBCT, 0); - - /* chipselect must have been muxed as GPIO (e.g. in board setup) */ - npcs_pin = (unsigned int)spi->controller_data; ---- a/drivers/usb/gadget/atmel_usba_udc.c -+++ b/drivers/usb/gadget/atmel_usba_udc.c +diff --exclude=.git -urN linux-2.6.25.6/drivers/usb/gadget/atmel_usba_udc.c avr32-2.6/drivers/usb/gadget/atmel_usba_udc.c +--- linux-2.6.25.6/drivers/usb/gadget/atmel_usba_udc.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/usb/gadget/atmel_usba_udc.c 2008-06-12 15:09:42.586816287 +0200 @@ -18,6 +18,7 @@ #include <linux/platform_device.h> #include <linux/usb/ch9.h> @@ -17799,14 +14460,15 @@ #ifdef CONFIG_USB_GADGET_DEBUG_FS #include <linux/debugfs.h> -@@ -324,53 +326,6 @@ +@@ -324,53 +326,28 @@ return 1; } -static void copy_to_fifo(void __iomem *fifo, const void *buf, int len) -{ - unsigned long tmp; -- ++#if defined(CONFIG_AVR32) + - DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len); - for (; len > 0; len -= 4, buf += 4, fifo += 4) { - tmp = *(unsigned long *)buf; @@ -17823,10 +14485,17 @@ - break; - } - } --} -- ++static void toggle_bias(int is_on) ++{ + } + -static void copy_from_fifo(void *buf, void __iomem *fifo, int len) --{ ++#elif defined(CONFIG_ARCH_AT91) ++ ++#include <asm/arch/at91_pmc.h> ++ ++static void toggle_bias(int is_on) + { - union { - unsigned long *w; - unsigned char *b; @@ -17848,12 +14517,20 @@ - } while (--len); - } - } --} -- ++ unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR); ++ ++ if (is_on) ++ at91_sys_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN); ++ else ++ at91_sys_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN)); + } + ++#endif /* CONFIG_ARCH_AT91 */ ++ static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req) { unsigned int transaction_len; -@@ -387,7 +342,7 @@ +@@ -387,7 +364,7 @@ ep->ep.name, req, transaction_len, req->last_transaction ? ", done" : ""); @@ -17862,7 +14539,7 @@ usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); req->req.actual += transaction_len; } -@@ -476,7 +431,7 @@ +@@ -476,7 +453,7 @@ bytecount = req->req.length - req->req.actual; } @@ -17871,7 +14548,7 @@ ep->fifo, bytecount); req->req.actual += bytecount; -@@ -1029,33 +984,6 @@ +@@ -1029,33 +1006,6 @@ .set_selfpowered = usba_udc_set_selfpowered, }; @@ -17905,7 +14582,7 @@ static struct usb_endpoint_descriptor usba_ep0_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, -@@ -1074,7 +1002,6 @@ +@@ -1074,7 +1024,6 @@ static struct usba_udc the_udc = { .gadget = { .ops = &usba_udc_ops, @@ -17913,7 +14590,7 @@ .ep_list = LIST_HEAD_INIT(the_udc.gadget.ep_list), .is_dualspeed = 1, .name = "atmel_usba_udc", -@@ -1231,7 +1158,7 @@ +@@ -1231,7 +1180,7 @@ } else { usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); usba_writel(udc, TST, USBA_TST_PKT_MODE); @@ -17922,7 +14599,14 @@ sizeof(test_packet_buffer)); usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); dev_info(dev, "Entering Test_Packet mode...\n"); -@@ -1539,7 +1466,7 @@ +@@ -1530,13 +1479,13 @@ + DBG(DBG_HW, "Packet length: %u\n", pkt_len); + if (pkt_len != sizeof(crq)) { + pr_warning("udc: Invalid packet length %u " +- "(expected %lu)\n", pkt_len, sizeof(crq)); ++ "(expected %zu)\n", pkt_len, sizeof(crq)); + set_protocol_stall(udc, ep); + return; } DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo); @@ -17931,7 +14615,60 @@ /* Free up one bank in the FIFO so that we can * generate or receive a reply right away. */ -@@ -1911,7 +1838,7 @@ +@@ -1688,6 +1637,7 @@ + DBG(DBG_INT, "irq, status=%#08x\n", status); + + if (status & USBA_DET_SUSPEND) { ++ toggle_bias(0); + usba_writel(udc, INT_CLR, USBA_DET_SUSPEND); + DBG(DBG_BUS, "Suspend detected\n"); + if (udc->gadget.speed != USB_SPEED_UNKNOWN +@@ -1699,6 +1649,7 @@ + } + + if (status & USBA_WAKE_UP) { ++ toggle_bias(1); + usba_writel(udc, INT_CLR, USBA_WAKE_UP); + DBG(DBG_BUS, "Wake Up CPU detected\n"); + } +@@ -1792,12 +1743,14 @@ + vbus = gpio_get_value(udc->vbus_pin); + if (vbus != udc->vbus_prev) { + if (vbus) { +- usba_writel(udc, CTRL, USBA_EN_USBA); ++ toggle_bias(1); ++ usba_writel(udc, CTRL, USBA_ENABLE_MASK); + usba_writel(udc, INT_ENB, USBA_END_OF_RESET); + } else { + udc->gadget.speed = USB_SPEED_UNKNOWN; + reset_all_endpoints(udc); +- usba_writel(udc, CTRL, 0); ++ toggle_bias(0); ++ usba_writel(udc, CTRL, USBA_DISABLE_MASK); + spin_unlock(&udc->lock); + udc->driver->disconnect(&udc->gadget); + spin_lock(&udc->lock); +@@ -1850,7 +1803,8 @@ + /* If Vbus is present, enable the controller and wait for reset */ + spin_lock_irqsave(&udc->lock, flags); + if (vbus_is_present(udc) && udc->vbus_prev == 0) { +- usba_writel(udc, CTRL, USBA_EN_USBA); ++ toggle_bias(1); ++ usba_writel(udc, CTRL, USBA_ENABLE_MASK); + usba_writel(udc, INT_ENB, USBA_END_OF_RESET); + } + spin_unlock_irqrestore(&udc->lock, flags); +@@ -1883,7 +1837,8 @@ + spin_unlock_irqrestore(&udc->lock, flags); + + /* This will also disable the DP pullup */ +- usba_writel(udc, CTRL, 0); ++ toggle_bias(0); ++ usba_writel(udc, CTRL, USBA_DISABLE_MASK); + + driver->unbind(&udc->gadget); + udc->gadget.dev.driver = NULL; +@@ -1908,7 +1863,7 @@ regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID); fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID); @@ -17940,8 +14677,13 @@ return -ENXIO; irq = platform_get_irq(pdev, 0); -@@ -1959,16 +1886,44 @@ - usba_writel(udc, CTRL, 0); +@@ -1953,19 +1908,48 @@ + + /* Make sure we start from a clean slate */ + clk_enable(pclk); +- usba_writel(udc, CTRL, 0); ++ toggle_bias(0); ++ usba_writel(udc, CTRL, USBA_DISABLE_MASK); clk_disable(pclk); + usba_ep = kmalloc(sizeof(struct usba_ep) * pdata->num_ep, @@ -17986,7 +14728,7 @@ list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); } -@@ -1987,7 +1942,7 @@ +@@ -1984,7 +1968,7 @@ goto err_device_add; } @@ -17995,7 +14737,7 @@ if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) { udc->vbus_pin = pdata->vbus_pin; -@@ -2007,7 +1962,7 @@ +@@ -2004,7 +1988,7 @@ } usba_init_debugfs(udc); @@ -18004,7 +14746,7 @@ usba_ep_init_debugfs(udc, &usba_ep[i]); return 0; -@@ -2015,6 +1970,8 @@ +@@ -2012,6 +1996,8 @@ err_device_add: free_irq(irq, udc); err_request_irq: @@ -18013,7 +14755,7 @@ iounmap(udc->fifo); err_map_fifo: iounmap(udc->regs); -@@ -2032,10 +1989,11 @@ +@@ -2029,10 +2015,11 @@ { struct usba_udc *udc; int i; @@ -18026,17 +14768,53 @@ usba_ep_cleanup_debugfs(&usba_ep[i]); usba_cleanup_debugfs(udc); ---- a/drivers/video/atmel_lcdfb.c -+++ b/drivers/video/atmel_lcdfb.c -@@ -16,6 +16,7 @@ - #include <linux/fb.h> - #include <linux/init.h> - #include <linux/delay.h> -+#include <linux/backlight.h> +@@ -2040,6 +2027,7 @@ + gpio_free(udc->vbus_pin); - #include <asm/arch/board.h> - #include <asm/arch/cpu.h> -@@ -37,7 +38,9 @@ + free_irq(udc->irq, udc); ++ kfree(usba_ep); + iounmap(udc->fifo); + iounmap(udc->regs); + clk_put(udc->hclk); +diff --exclude=.git -urN linux-2.6.25.6/drivers/usb/gadget/atmel_usba_udc.h avr32-2.6/drivers/usb/gadget/atmel_usba_udc.h +--- linux-2.6.25.6/drivers/usb/gadget/atmel_usba_udc.h 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/usb/gadget/atmel_usba_udc.h 2008-06-12 15:04:02.443815949 +0200 +@@ -41,6 +41,15 @@ + #define USBA_EN_USBA (1 << 8) + #define USBA_DETACH (1 << 9) + #define USBA_REMOTE_WAKE_UP (1 << 10) ++#define USBA_PULLD_DIS (1 << 11) ++ ++#if defined(CONFIG_AVR32) ++#define USBA_ENABLE_MASK USBA_EN_USBA ++#define USBA_DISABLE_MASK 0 ++#elif defined(CONFIG_ARCH_AT91) ++#define USBA_ENABLE_MASK (USBA_EN_USBA | USBA_PULLD_DIS) ++#define USBA_DISABLE_MASK USBA_DETACH ++#endif /* CONFIG_ARCH_AT91 */ + + /* Bitfields in FNUM */ + #define USBA_MICRO_FRAME_NUM_OFFSET 0 +diff --exclude=.git -urN linux-2.6.25.6/drivers/usb/gadget/Kconfig avr32-2.6/drivers/usb/gadget/Kconfig +--- linux-2.6.25.6/drivers/usb/gadget/Kconfig 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/usb/gadget/Kconfig 2008-06-12 15:09:42.582816057 +0200 +@@ -118,10 +118,10 @@ + config USB_GADGET_ATMEL_USBA + boolean "Atmel USBA" + select USB_GADGET_DUALSPEED +- depends on AVR32 ++ depends on AVR32 || ARCH_AT91CAP9 + help + USBA is the integrated high-speed USB Device controller on +- the AT32AP700x processors from Atmel. ++ the AT32AP700x and AT91CAP9 processors from Atmel. + + config USB_ATMEL_USBA + tristate +diff --exclude=.git -urN linux-2.6.25.6/drivers/video/atmel_lcdfb.c avr32-2.6/drivers/video/atmel_lcdfb.c +--- linux-2.6.25.6/drivers/video/atmel_lcdfb.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/drivers/video/atmel_lcdfb.c 2008-06-12 15:09:43.343816340 +0200 +@@ -38,7 +38,9 @@ #endif #if defined(CONFIG_ARCH_AT91) @@ -18047,357 +14825,32539 @@ static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, struct fb_var_screeninfo *var) -@@ -69,12 +72,113 @@ +@@ -176,7 +178,7 @@ + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .xpanstep = 0, +- .ypanstep = 0, ++ .ypanstep = 1, + .ywrapstep = 0, + .accel = FB_ACCEL_NONE, + }; +@@ -250,6 +252,8 @@ + return -ENOMEM; + } + ++ memset(info->screen_base, 0, info->fix.smem_len); ++ + return 0; } - #endif -+static const u32 contrast_ctr = ATMEL_LCDC_PS_DIV8 -+ | ATMEL_LCDC_POL_POSITIVE -+ | ATMEL_LCDC_ENA_PWMENABLE; +@@ -634,7 +638,6 @@ + struct fb_info *info = sinfo->info; + int ret = 0; + +- memset_io(info->screen_base, 0, info->fix.smem_len); + info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW; + + dev_info(info->device, +@@ -764,6 +767,11 @@ + info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); + if (!info->screen_base) + goto release_intmem; + -+#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC ++ /* ++ * Don't clear the framebuffer -- someone may have set ++ * up a splash image. ++ */ + } else { + /* alocate memory buffer */ + ret = atmel_lcdfb_alloc_video_memory(sinfo); +diff --exclude=.git -urN linux-2.6.25.6/fs/fs-writeback.c avr32-2.6/fs/fs-writeback.c +--- linux-2.6.25.6/fs/fs-writeback.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/fs/fs-writeback.c 2008-06-12 15:09:44.531816544 +0200 +@@ -385,8 +385,6 @@ + * WB_SYNC_HOLD is a hack for sys_sync(): reattach the inode to sb->s_dirty so + * that it can be located for waiting on in __writeback_single_inode(). + * +- * Called under inode_lock. +- * + * If `bdi' is non-zero then we're being asked to writeback a specific queue. + * This function assumes that the blockdev superblock's inodes are backed by + * a variety of queues, so all inodes are searched. For other superblocks, +@@ -402,11 +400,12 @@ + * on the writer throttling path, and we get decent balancing between many + * throttled threads: we don't want them all piling up on inode_sync_wait. + */ +-static void +-sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc) ++void generic_sync_sb_inodes(struct super_block *sb, ++ struct writeback_control *wbc) + { + const unsigned long start = jiffies; /* livelock avoidance */ + ++ spin_lock(&inode_lock); + if (!wbc->for_kupdate || list_empty(&sb->s_io)) + queue_io(sb, wbc->older_than_this); + +@@ -485,8 +484,16 @@ + if (!list_empty(&sb->s_more_io)) + wbc->more_io = 1; + } ++ spin_unlock(&inode_lock); + return; /* Leave any unwritten inodes on s_io */ + } ++EXPORT_SYMBOL_GPL(generic_sync_sb_inodes); + -+/* some bl->props field just changed */ -+static int atmel_bl_update_status(struct backlight_device *bl) ++static void sync_sb_inodes(struct super_block *sb, ++ struct writeback_control *wbc) +{ -+ struct atmel_lcdfb_info *sinfo = bl_get_data(bl); -+ int power = sinfo->bl_power; -+ int brightness = bl->props.brightness; ++ generic_sync_sb_inodes(sb, wbc); ++} + + /* + * Start writeback of dirty pagecache data against all unlocked inodes. +@@ -526,11 +533,8 @@ + * be unmounted by the time it is released. + */ + if (down_read_trylock(&sb->s_umount)) { +- if (sb->s_root) { +- spin_lock(&inode_lock); ++ if (sb->s_root) + sync_sb_inodes(sb, wbc); +- spin_unlock(&inode_lock); +- } + up_read(&sb->s_umount); + } + spin_lock(&sb_lock); +@@ -568,9 +572,7 @@ + (inodes_stat.nr_inodes - inodes_stat.nr_unused) + + nr_dirty + nr_unstable; + wbc.nr_to_write += wbc.nr_to_write / 2; /* Bit more for luck */ +- spin_lock(&inode_lock); + sync_sb_inodes(sb, &wbc); +- spin_unlock(&inode_lock); + } + + /* +diff --exclude=.git -urN linux-2.6.25.6/fs/Kconfig avr32-2.6/fs/Kconfig +--- linux-2.6.25.6/fs/Kconfig 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/fs/Kconfig 2008-06-12 15:09:43.915816293 +0200 +@@ -1347,6 +1347,9 @@ + + endchoice + ++# UBIFS File system configuration ++source "fs/ubifs/Kconfig" ++ + config CRAMFS + tristate "Compressed ROM file system support (cramfs)" + depends on BLOCK +diff --exclude=.git -urN linux-2.6.25.6/fs/Makefile avr32-2.6/fs/Makefile +--- linux-2.6.25.6/fs/Makefile 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/fs/Makefile 2008-06-12 15:09:43.915816293 +0200 +@@ -100,6 +100,7 @@ + obj-$(CONFIG_UFS_FS) += ufs/ + obj-$(CONFIG_EFS_FS) += efs/ + obj-$(CONFIG_JFFS2_FS) += jffs2/ ++obj-$(CONFIG_UBIFS_FS) += ubifs/ + obj-$(CONFIG_AFFS_FS) += affs/ + obj-$(CONFIG_ROMFS_FS) += romfs/ + obj-$(CONFIG_QNX4FS_FS) += qnx4/ +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/budget.c avr32-2.6/fs/ubifs/budget.c +--- linux-2.6.25.6/fs/ubifs/budget.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/budget.c 2008-06-12 15:09:45.311815896 +0200 +@@ -0,0 +1,863 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Adrian Hunter ++ * Artem Bityutskiy (Битюцкий Артём) ++ */ ++ ++/* ++ * This file implements the budgeting unit which is responsible for UBIFS space ++ * management. ++ * ++ * Factors such as compression, wasted space at the ends of LEBs, space in other ++ * journal heads, the effect of updates on the index, and so on, make it ++ * impossible to accurately predict the amount of space needed. Consequently ++ * approximations are used. ++ */ ++ ++#include "ubifs.h" ++#include <linux/writeback.h> ++#include <asm/div64.h> + -+ /* REVISIT there may be a meaningful difference between -+ * fb_blank and power ... there seem to be some cases -+ * this doesn't handle correctly. ++/* ++ * When pessimistic budget calculations say that there is no enough space, ++ * UBIFS starts writing back dirty inodes and pages, doing garbage collection, ++ * or committing. The below constants define maximum number of times UBIFS ++ * repeats the operations. ++ */ ++#define MAX_SHRINK_RETRIES 8 ++#define MAX_GC_RETRIES 4 ++#define MAX_CMT_RETRIES 2 ++#define MAX_NOSPC_RETRIES 1 ++ ++/* ++ * The below constant defines amount of dirty pages which should be written ++ * back at when trying to shrink the liability. ++ */ ++#define NR_TO_WRITE 16 ++ ++/** ++ * struct retries_info - information about re-tries while making free space. ++ * @prev_liability: previous liability ++ * @shrink_cnt: how many times the liability was shrinked ++ * @shrink_retries: count of liability shrink re-tries (increased when ++ * liability does not shrink) ++ * @try_gc: GC should be tried first ++ * @gc_retries: how many times GC was run ++ * @cmt_retries: how many times commit has been done ++ * @nospc_retries: how many times GC returned %-ENOSPC ++ * ++ * Since we consider budgeting to be the fast-path, and this structure has to ++ * be allocated on stack and zeroed out, we make it smaller using bit-fields. ++ */ ++struct retries_info { ++ long long prev_liability; ++ unsigned int shrink_cnt; ++ unsigned int shrink_retries:5; ++ unsigned int try_gc:1; ++ unsigned int gc_retries:4; ++ unsigned int cmt_retries:3; ++ unsigned int nospc_retries:1; ++}; ++ ++/** ++ * shrink_liability - write-back some dirty pages/inodes. ++ * @c: UBIFS file-system description object ++ * @nr_to_write: how many dirty pages to write-back ++ * ++ * This function shrinks UBIFS liability by means of writing back some amount ++ * of dirty inodes and their pages. Returns the amount of pages which were ++ * written back. The returned value does not include dirty inodes which were ++ * synchronized. ++ * ++ * Note, this function synchronizes even VFS inodes which are locked ++ * (@i_mutex) by the caller of the budgeting function, because write-back does ++ * not touch @i_mutex. ++ */ ++static int shrink_liability(struct ubifs_info *c, int nr_to_write) ++{ ++ struct writeback_control wbc = { ++ .sync_mode = WB_SYNC_NONE, ++ .range_end = LLONG_MAX, ++ .nr_to_write = nr_to_write, ++ }; ++ ++ generic_sync_sb_inodes(c->vfs_sb, &wbc); ++ dbg_budg("%ld pages were written back", nr_to_write - wbc.nr_to_write); ++ return nr_to_write - wbc.nr_to_write; ++} ++ ++ ++/** ++ * run_gc - run garbage collector. ++ * @c: UBIFS file-system description object ++ * ++ * This function runs garbage collector to make some more free space. Returns ++ * zero if a free LEB has been produced, %-EAGAIN if commit is required, and a ++ * negative error code in case of failure. ++ */ ++static int run_gc(struct ubifs_info *c) ++{ ++ int err, lnum; ++ ++ /* Make some free space by garbage-collecting dirty space */ ++ down_read(&c->commit_sem); ++ lnum = ubifs_garbage_collect(c, 1); ++ up_read(&c->commit_sem); ++ if (lnum < 0) ++ return lnum; ++ ++ /* GC freed one LEB, return it to lprops */ ++ dbg_budg("GC freed LEB %d", lnum); ++ err = ubifs_return_leb(c, lnum); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++/** ++ * make_free_space - make more free space on the file-system. ++ * @c: UBIFS file-system description object ++ * @ri: information about previous invocations of this function ++ * ++ * This function is called when an operation cannot be budgeted because there ++ * is supposedly no free space. But in most cases there is some free space: ++ * o budgeting is pessimistic, so it always budgets more then it is actually ++ * needed, so shrinking the liability is one way to make free space - the ++ * cached data will take less space then it was budgeted for; ++ * o GC may turn some dark space into free space (budgeting treats dark space ++ * as not available); ++ * o commit may free some LEB, i.e., turn freeable LEBs into free LEBs. ++ * ++ * So this function tries to do the above. Returns %-EAGAIN if some free space ++ * was presumably made and the caller has to re-try budgeting the operation. ++ * Returns %-ENOSPC if it couldn't do more free space, and other negative error ++ * codes on failures. ++ */ ++static int make_free_space(struct ubifs_info *c, struct retries_info *ri) ++{ ++ int err; ++ ++ /* ++ * If we have some dirty pages and inodes (liability), try to write ++ * them back unless this was tried too many times without effect ++ * already. + */ -+ if (bl->props.fb_blank != sinfo->bl_power) -+ power = bl->props.fb_blank; -+ else if (bl->props.power != sinfo->bl_power) -+ power = bl->props.power; ++ if (ri->shrink_retries < MAX_SHRINK_RETRIES && !ri->try_gc) { ++ long long liability; ++ ++ spin_lock(&c->space_lock); ++ liability = c->budg_idx_growth + c->budg_data_growth + ++ c->budg_dd_growth; ++ spin_unlock(&c->space_lock); ++ ++ if (ri->prev_liability >= liability) { ++ /* Liability does not shrink, next time try GC then */ ++ ri->shrink_retries += 1; ++ if (ri->gc_retries < MAX_GC_RETRIES) ++ ri->try_gc = 1; ++ dbg_budg("liability did not shrink: retries %d of %d", ++ ri->shrink_retries, MAX_SHRINK_RETRIES); ++ } + -+ if (brightness < 0 && power == FB_BLANK_UNBLANK) -+ brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); -+ else if (power != FB_BLANK_UNBLANK) -+ brightness = 0; ++ dbg_budg("force write-back (count %d)", ri->shrink_cnt); ++ shrink_liability(c, NR_TO_WRITE + ri->shrink_cnt); + -+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness); -+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, -+ brightness ? contrast_ctr : 0); ++ ri->prev_liability = liability; ++ ri->shrink_cnt += 1; ++ return -EAGAIN; ++ } ++ ++ /* ++ * Try to run garbage collector unless it was already tried too many ++ * times. ++ */ ++ if (ri->gc_retries < MAX_GC_RETRIES) { ++ ri->gc_retries += 1; ++ dbg_budg("run GC, retries %d of %d", ++ ri->gc_retries, MAX_GC_RETRIES); ++ ++ ri->try_gc = 0; ++ err = run_gc(c); ++ if (!err) ++ return -EAGAIN; ++ ++ if (err == -EAGAIN) { ++ dbg_budg("GC asked to commit"); ++ err = ubifs_run_commit(c); ++ if (err) ++ return err; ++ return -EAGAIN; ++ } ++ ++ if (err != -ENOSPC) ++ return err; ++ ++ /* ++ * GC could not make any progress. If this is the first time, ++ * then it makes sense to try to commit, because it might make ++ * some dirty space. ++ */ ++ dbg_budg("GC returned -ENOSPC, retries %d", ++ ri->nospc_retries); ++ if (ri->nospc_retries >= MAX_NOSPC_RETRIES) ++ return err; ++ ri->nospc_retries += 1; ++ } ++ ++ /* Neither GC nor write-back helped, try to commit */ ++ if (ri->cmt_retries < MAX_CMT_RETRIES) { ++ ri->cmt_retries += 1; ++ dbg_budg("run commit, retries %d of %d", ++ ri->cmt_retries, MAX_CMT_RETRIES); ++ err = ubifs_run_commit(c); ++ if (err) ++ return err; ++ return -EAGAIN; ++ } ++ ++ return -ENOSPC; ++} ++ ++/** ++ * ubifs_calc_min_idx_lebs - calculate amount of eraseblocks for the index. ++ * @c: UBIFS file-system description object ++ * ++ * This function calculates and returns the number of eraseblocks which should ++ * be kept for index usage. ++ */ ++int ubifs_calc_min_idx_lebs(struct ubifs_info *c) ++{ ++ int ret; ++ uint64_t idx_size; + -+ bl->props.fb_blank = bl->props.power = sinfo->bl_power = power; ++ idx_size = c->old_idx_sz + c->budg_idx_growth + c->budg_uncommitted_idx; ++ ++ /* And make sure we have twice the index size of space reserved */ ++ idx_size <<= 1; ++ ++ /* ++ * We do not maintain 'old_idx_size' as 'old_idx_lebs'/'old_idx_bytes' ++ * pair, nor similarly the two variables for the new index size, so we ++ * have to do this costly 64-bit division on fast-path. ++ */ ++ if (do_div(idx_size, c->leb_size - c->max_idx_node_sz)) ++ ret = idx_size + 1; ++ else ++ ret = idx_size; ++ /* ++ * The index head is not available for the in-the-gaps method, so add an ++ * extra LEB to compensate. ++ */ ++ ret += 1; ++ /* ++ * At present the index needs at least 2 LEBs: one for the index head ++ * and one for in-the-gaps method (which currently does not cater for ++ * the index head and so excludes it from consideration). ++ */ ++ if (ret < 2) ++ ret = 2; ++ return ret; ++} ++ ++/** ++ * ubifs_calc_available - calculate available FS space. ++ * @c: UBIFS file-system description object ++ * ++ * This function calculates and returns amount of FS space available for use. ++ */ ++long long ubifs_calc_available(const struct ubifs_info *c) ++{ ++ long long available, subtract_lebs; ++ ++ /* ++ * Force the amount available to the total size reported if the used ++ * space is zero. ++ */ ++ if (c->lst.total_used <= UBIFS_INO_NODE_SZ && ++ c->budg_data_growth + c->budg_dd_growth == 0) { ++ /* Do the same calculation as for c->block_cnt */ ++ available = c->main_lebs - 2; ++ available *= c->leb_size - c->dark_wm; ++ return available; ++ } ++ ++ available = c->main_bytes - c->lst.total_used; ++ ++ /* ++ * Now 'available' contains theoretically available flash space ++ * assuming there is no index, so we have to subtract the space which ++ * is reserved for the index. ++ */ ++ subtract_lebs = c->min_idx_lebs; ++ ++ /* Take into account that GC reserves one LEB for its own needs */ ++ subtract_lebs += 1; ++ ++ /* ++ * The GC journal head LEB is not really accessible. And since ++ * different write types go to different heads, we may count only on ++ * one head's space. ++ */ ++ subtract_lebs += c->jhead_cnt - 1; ++ ++ /* We also reserve one LEB for deletions, which bypass budgeting */ ++ subtract_lebs += 1; ++ ++ available -= subtract_lebs * c->leb_size; ++ ++ /* Subtract the dead space which is not available for use */ ++ available -= c->lst.total_dead; ++ ++ /* ++ * Subtract dark space, which might or might not be usable - it depends ++ * on the data which we have on the media and which will be written. If ++ * this is a lot of uncompressed or not-compressible data, the dark ++ * space cannot be used. ++ */ ++ available -= c->lst.total_dark; ++ ++ /* ++ * However, there is more dark space. The index may be bigger than ++ * min_idx_lebs. Those extra LEBs are assumed to be available, but ++ * their dark space is not included in total_dark, so it is subtracted ++ * here. ++ */ ++ if (c->lst.idx_lebs > c->min_idx_lebs) { ++ subtract_lebs = c->lst.idx_lebs - c->min_idx_lebs; ++ available -= subtract_lebs * c->dark_wm; ++ } ++ ++ /* The calculations are rough and may end up with a negative number */ ++ return available > 0 ? available : 0; ++} ++ ++/** ++ * rp_can_write - check whether the user is allowed to write. ++ * @c: UBIFS file-system description object ++ * @avail: available space on FS ++ * ++ * UBIFS has so-called "reserved pool" which is flash space reserved ++ * for the superuser and for uses whose UID/GID is recorded in UBIFS superblock. ++ * This function checks whether current user is allowed to write ++ * to the file-system - it returns %1 if there is plenty of space or the user ++ * is eligible to use the reserved pool and %0 otherwise. ++ */ ++static int rp_can_write(struct ubifs_info *c, long long avail) ++{ ++ if (avail > c->rp_size || current->fsuid == c->rp_uid || ++ capable(CAP_SYS_RESOURCE) || ++ (c->rp_gid != 0 && in_group_p(c->rp_gid))) ++ return 1; ++ ++ return 0; ++} ++ ++/** ++ * do_budget_space - reserve flash space for index and data growth. ++ * @c: UBIFS file-system description object ++ * ++ * This function makes sure UBIFS has enough free eraseblocks for index growth ++ * and data. ++ * ++ * When budgeting index space, UBIFS reserves twice as more LEBs as the index ++ * would take if it was consolidated and written to the flash. This guarantees ++ * that the "in-the-gaps" commit method always succeeds and UBIFS will always ++ * be able to commit dirty index. So this function basically adds amount of ++ * budgeted index space to the size of the current index, multiplies this by 2, ++ * and makes sure this does not exceed the amount of free eraseblocks. ++ * ++ * Notes about @c->min_idx_lebs and @c->lst.idx_lebs variables: ++ * o @c->lst.idx_lebs is the number of LEBs the index currently uses. It might ++ * be large, because UBIFS does not do any index consolidation as long as ++ * there is free space. IOW, the index may take a lot of LEBs, but the LEBs ++ * will contain a lot of dirt. ++ * o @c->min_idx_lebs is the the index presumably takes. IOW, the index may be ++ * consolidated to take up to @c->min_idx_lebs LEBs. ++ * ++ * This function returns zero in case of success, and %-ENOSPC in case of ++ * failure. ++ */ ++static int do_budget_space(struct ubifs_info *c) ++{ ++ long long outstanding, available; ++ int lebs, rsvd_idx_lebs, min_idx_lebs; ++ ++ /* First budget index space */ ++ min_idx_lebs = ubifs_calc_min_idx_lebs(c); ++ ++ /* Now 'min_idx_lebs' contains number of LEBs to reserve */ ++ if (min_idx_lebs > c->lst.idx_lebs) ++ rsvd_idx_lebs = min_idx_lebs - c->lst.idx_lebs; ++ else ++ rsvd_idx_lebs = 0; ++ ++ /* ++ * The number of LEBs that are available to be used by the index is: ++ * ++ * @c->lst.empty_lebs + @c->freeable_cnt + @c->idx_gc_cnt - ++ * @c->lst.taken_empty_lebs ++ * ++ * @empty_lebs are available because they are empty. @freeable_cnt are ++ * available because they contain only free and dirty space and the ++ * index allocation always occurs after wbufs are synch'ed. ++ * @idx_gc_cnt are available because they are index LEBs that have been ++ * garbage collected (including trivial GC) and are awaiting the commit ++ * before they can be unmapped - note that the in-the-gaps method will ++ * grab these if it needs them. @taken_empty_lebs are empty_lebs that ++ * have already been allocated for some purpose (also includes those ++ * LEBs on the @idx_gc list). ++ * ++ * Note, @taken_empty_lebs may temporarily be higher by one because of ++ * the way we serialize LEB allocations and budgeting. See a comment in ++ * 'ubifs_find_free_space()'. ++ */ ++ lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt - ++ c->lst.taken_empty_lebs; ++ if (unlikely(rsvd_idx_lebs > lebs)) { ++ dbg_budg("out of indexing space: min_idx_lebs %d (old %d), " ++ "rsvd_idx_lebs %d", min_idx_lebs, c->min_idx_lebs, ++ rsvd_idx_lebs); ++ return -ENOSPC; ++ } ++ ++ available = ubifs_calc_available(c); ++ outstanding = c->budg_data_growth + c->budg_dd_growth; ++ ++ if (unlikely(available < outstanding)) { ++ dbg_budg("out of data space: available %lld, outstanding %lld", ++ available, outstanding); ++ return -ENOSPC; ++ } ++ ++ if (!rp_can_write(c, available - outstanding)) ++ return -ENOSPC; ++ ++ c->min_idx_lebs = min_idx_lebs; ++ return 0; ++} ++ ++/** ++ * calc_idx_growth - calculate approximate index growth from budgeting request. ++ * @c: UBIFS file-system description object ++ * @req: budgeting request ++ * ++ * For now we assume each new node adds one znode. But this is rather poor ++ * approximation, though. ++ */ ++static int calc_idx_growth(const struct ubifs_info *c, ++ const struct ubifs_budget_req *req) ++{ ++ int znodes; ++ ++ znodes = req->new_ino + (req->new_page << UBIFS_BLOCKS_PER_PAGE_SHIFT) + ++ req->new_dent; ++ return znodes * c->max_idx_node_sz; ++} ++ ++/** ++ * calc_data_growth - calculate approximate amount of new data from budgeting ++ * request. ++ * @c: UBIFS file-system description object ++ * @req: budgeting request ++ */ ++static int calc_data_growth(const struct ubifs_info *c, ++ const struct ubifs_budget_req *req) ++{ ++ int data_growth; ++ ++ data_growth = req->new_ino ? c->inode_budget : 0; ++ if (req->new_page) ++ data_growth += c->page_budget; ++ if (req->new_dent) ++ data_growth += c->dent_budget; ++ data_growth += req->new_ino_d; ++ ++ return data_growth; ++} ++ ++/** ++ * calc_dd_growth - calculate approximate amount of data which makes other data ++ * dirty from budgeting request. ++ * @c: UBIFS file-system description object ++ * @req: budgeting request ++ */ ++static int calc_dd_growth(const struct ubifs_info *c, ++ const struct ubifs_budget_req *req) ++{ ++ int dd_growth; ++ ++ dd_growth = req->dirtied_page ? c->page_budget : 0; ++ ++ if (req->dirtied_ino) ++ dd_growth += c->inode_budget << (req->dirtied_ino - 1); ++ if (req->mod_dent) ++ dd_growth += c->dent_budget; ++ dd_growth += req->dirtied_ino_d; ++ ++ return dd_growth; ++} ++ ++/** ++ * ubifs_budget_space - ensure there is enough space to complete an operation. ++ * @c: UBIFS file-system description object ++ * @req: budget request ++ * ++ * This function allocates budget for an operation. It uses pessimistic ++ * approximation of how much flash space the operation needs. The goal of this ++ * function is to make sure UBIFS always has flash space to flush all dirty ++ * pages, dirty inodes, and dirty znodes (liability). This function may force ++ * commit, garbage-collection or write-back. Returns zero in case of success, ++ * %-ENOSPC if there is no free space and other negative error codes in case of ++ * failures. ++ */ ++int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req) ++{ ++ int uninitialized_var(cmt_retries), uninitialized_var(wb_retries); ++ int err, idx_growth, data_growth, dd_growth; ++ struct retries_info ri; ++ ++ data_growth = calc_data_growth(c, req); ++ dd_growth = calc_dd_growth(c, req); ++ if (!data_growth && !dd_growth) ++ return 0; ++ idx_growth = calc_idx_growth(c, req); ++ memset(&ri, 0, sizeof(struct retries_info)); ++ ++again: ++ spin_lock(&c->space_lock); ++ ubifs_assert(c->budg_idx_growth >= 0); ++ ubifs_assert(c->budg_data_growth >= 0); ++ ubifs_assert(c->budg_dd_growth >= 0); ++ ++ c->budg_idx_growth += idx_growth; ++ c->budg_data_growth += data_growth; ++ c->budg_dd_growth += dd_growth; ++ ++ err = do_budget_space(c); ++ if (unlikely(err)) { ++ /* Restore the old values */ ++ c->budg_idx_growth -= idx_growth; ++ c->budg_data_growth -= data_growth; ++ c->budg_dd_growth -= dd_growth; ++ spin_unlock(&c->space_lock); ++ ++ goto make_space; ++ } ++ ++ req->idx_growth = idx_growth; ++ req->data_growth = data_growth; ++ req->dd_growth = dd_growth; ++ spin_unlock(&c->space_lock); + + return 0; ++ ++make_space: ++ err = make_free_space(c, &ri); ++ if (err == -EAGAIN) { ++ dbg_budg("try again"); ++ cond_resched(); ++ goto again; ++ } else if (err == -ENOSPC) ++ dbg_budg("FS is full, -ENOSPC"); ++ else ++ ubifs_err("cannot budget space, error %d", err); ++ ++ return err; +} + -+static int atmel_bl_get_brightness(struct backlight_device *bl) ++/** ++ * ubifs_release_budget - release budgeted free space. ++ * @c: UBIFS file-system description object ++ * @req: budget request ++ * ++ * This function releases the space budgeted by 'ubifs_budget_space()'. Note, ++ * since the index changes (which were budgeted for in @req->idx_growth) will ++ * only be written to the media on commit, this function moves the index budget ++ * from @c->budg_idx_growth to @c->budg_uncommitted_idx. The latter will be ++ * zeroed by the commit operation. ++ */ ++void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req) +{ -+ struct atmel_lcdfb_info *sinfo = bl_get_data(bl); ++ if (!req->data_growth && !req->dd_growth) ++ return; + -+ return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); ++ if (req->idx_growth == -1) ++ req->idx_growth = calc_idx_growth(c, req); ++ ++ spin_lock(&c->space_lock); ++ c->budg_idx_growth -= req->idx_growth; ++ c->budg_uncommitted_idx += req->idx_growth; ++ c->budg_data_growth -= req->data_growth; ++ c->budg_dd_growth -= req->dd_growth; ++ c->min_idx_lebs = ubifs_calc_min_idx_lebs(c); ++ ++ ubifs_assert(c->budg_idx_growth >= 0); ++ ubifs_assert(c->budg_data_growth >= 0); ++ ubifs_assert(c->min_idx_lebs < c->main_lebs); ++ spin_unlock(&c->space_lock); ++} ++ ++/** ++ * ubifs_convert_page_budget - convert budget of a new page. ++ * @c: UBIFS file-system description object ++ * ++ * This function converts budget which was allocated for a new page of data to ++ * the budget of changing an existing page of data. The latter is not larger ++ * then the former, so this function only does simple re-calculation and does ++ * not involve any write-back. ++ */ ++void ubifs_convert_page_budget(struct ubifs_info *c) ++{ ++ spin_lock(&c->space_lock); ++ /* Release the index growth reservation */ ++ c->budg_idx_growth -= c->max_idx_node_sz << UBIFS_BLOCKS_PER_PAGE_SHIFT; ++ /* Release the data growth reservation */ ++ c->budg_data_growth -= c->page_budget; ++ /* Increase the dirty data growth reservation instead */ ++ c->budg_dd_growth += c->page_budget; ++ /* And re-calculate the indexing space reservation */ ++ c->min_idx_lebs = ubifs_calc_min_idx_lebs(c); ++ spin_unlock(&c->space_lock); +} + -+static struct backlight_ops atmel_lcdc_bl_ops = { -+ .update_status = atmel_bl_update_status, -+ .get_brightness = atmel_bl_get_brightness, ++/** ++ * ubifs_budget_inode_op - budget an operation on inode. ++ * @c: UBIFS file-system description object ++ * @inode: VFS inode which will be made dirty by the operation ++ * @req: budget request of the operation ++ * ++ * This function is called to get budget for an operation which changes an ++ * inode. The inode may be in dirty or clean state. The former means there is ++ * no need to allocate the budget as it has already been allocated before. The ++ * latter means that the inode change budget has to be allocated. ++ * ++ * The caller has to pass the inode which is going to be changed. This function ++ * acquires budget the for as described in @req plus the budget for changing ++ * the inode dirty, if needed. Returns zero in case of success, %-ENOSPC if ++ * there is no more flash space, and other negative error codes in case of ++ * failure. ++ * ++ * Note, upon exit, this function leaves the inode locked, and the ++ * 'ubifs_release_ino_dirty()' or 'ubifs_release_ino_clean()' function has to ++ * be called to unlock it. ++ */ ++int ubifs_budget_inode_op(struct ubifs_info *c, struct inode *inode, ++ struct ubifs_budget_req *req) ++{ ++ struct ubifs_inode *ui = ubifs_inode(inode); ++ int err, old = req->dirtied_ino; ++ ++ ubifs_assert(req->dirtied_ino <= 3); ++ ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 3); ++ ++again: ++ /* ++ * If the inode is clean, it will be dirtied by this operation and we ++ * have to budget for this. ++ */ ++ req->dirtied_ino += !ui->dirty; ++ if (req->dirtied_ino > old) ++ req->dirtied_ino_d += ui->data_len; ++ ++ /* ++ * Note, if the budget request does not actually request anything ++ * (i.e., @req contains only zeroes), 'ubifs_budget_space()' will ++ * return almost straight away. ++ */ ++ err = ubifs_budget_space(c, req); ++ if (unlikely(err)) ++ return err; ++ ++ mutex_lock(&ui->budg_mutex); ++ ++ if (req->dirtied_ino != old + !ui->dirty) { ++ /* The inode has probably been written back meanwhile */ ++ ubifs_release_budget(c, req); ++ mutex_unlock(&ui->budg_mutex); ++ req->dirtied_ino = old; ++ req->dirtied_ino_d -= ui->data_len; ++ goto again; ++ } ++ ++ UBIFS_DBG(ui->budgeted = 1); ++ return 0; ++} ++ ++/** ++ * ubifs_release_ino_dirty - release budget of a "dirtying" operation. ++ * @c: UBIFS file-system description object ++ * @inode: VFS inode the operation worked on ++ * @req: budget to release ++ * ++ * This function has to be called at the end of VFS operations which acquired ++ * budget via 'ubifs_budget_inode_op()'. It assumes that the inode has been ++ * marked as dirty and will be synchronized later by write-back, so it does not ++ * release the budget of the inode. ++ * ++ * Note, this function also avoids releasing page budgets which are released ++ * separately. ++ */ ++void ubifs_release_ino_dirty(struct ubifs_info *c, struct inode *inode, ++ struct ubifs_budget_req *req) ++{ ++ ubifs_assert(req->dirtied_ino <= 4); ++ ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 4); ++ ubifs_assert(req->idx_growth >= 0); ++ ubifs_assert(req->data_growth >= 0); ++ ubifs_assert(req->dd_growth >= 0); ++ ++ if (req->dirtied_ino) { ++ req->dd_growth -= c->inode_budget; ++ req->dd_growth -= req->dirtied_ino_d; ++ } ++ ++ if (req->dirtied_page) { ++ req->dd_growth -= c->page_budget; ++ ubifs_assert(req->new_page == 0); ++ } else if (req->new_page) { ++ req->idx_growth -= ++ c->max_idx_node_sz << UBIFS_BLOCKS_PER_PAGE_SHIFT; ++ req->data_growth -= c->page_budget; ++ ubifs_assert(req->dirtied_page == 0); ++ } ++ ++ ubifs_assert(req->dd_growth >= 0); ++ ubifs_release_budget(c, req); ++ mutex_unlock(&ubifs_inode(inode)->budg_mutex); ++} ++ ++/** ++ * ubifs_cancel_ino_op - cancel budget of an operation on inode. ++ * @c: UBIFS file-system description object ++ * @inode: VFS inode the operation worked on ++ * @req: budget to release ++ * ++ * This function has to be called if the operation failed and whole budget has ++ * to be released, including the budget for inode which would had been ++ * dirtied. It is important not to mark the inode dirty before calling this ++ * function. ++ */ ++void ubifs_cancel_ino_op(struct ubifs_info *c, struct inode *inode, ++ struct ubifs_budget_req *req) ++{ ++ ubifs_assert(req->dirtied_ino <= 4); ++ ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 4); ++ ubifs_assert(req->idx_growth >= 0); ++ ubifs_assert(req->data_growth >= 0); ++ ubifs_assert(req->dd_growth >= 0); ++ ++ ubifs_release_budget(c, req); ++ mutex_unlock(&ubifs_inode(inode)->budg_mutex); ++} ++ ++/** ++ * ubifs_release_ino_clean - release budget of a "cleaning" operation. ++ * @c: UBIFS file-system description object ++ * @inode: VFS inode the operation worked on ++ * @req: budget to release ++ * ++ * This function has to be called at the end of VFS operations which acquired ++ * budget via 'ubifs_budget_inode_op()'. It assumed the operation synchronized ++ * the inode, so it marks the inode clean, unlocks it and releases whole budget. ++ * ++ * Note, this function also avoids releasing page budgets which are released ++ * separately. ++ */ ++void ubifs_release_ino_clean(struct ubifs_info *c, struct inode *inode, ++ struct ubifs_budget_req *req) ++{ ++ struct ubifs_inode *ui = ubifs_inode(inode); ++ ++ ubifs_assert(req->dirtied_ino <= 4); ++ ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 4); ++ ubifs_assert(req->idx_growth >= 0); ++ ubifs_assert(req->data_growth >= 0); ++ ubifs_assert(req->dd_growth >= 0); ++ ubifs_assert(!req->dirtied_page); ++ ubifs_assert(!req->new_page); ++ UBIFS_DBG(ui->budgeted = 0); ++ ++ ubifs_release_budget(c, req); ++ if (ui->dirty) { ++ ui->dirty = 0; ++ /* ++ * Note, VFS still treats the inode as dirty and ++ * 'ubifs_write_inode()' will be called, but it'll do nothing ++ * because @ui->dirty is %0. ++ */ ++ atomic_long_dec(&c->dirty_ino_cnt); ++ } ++ mutex_unlock(&ubifs_inode(inode)->budg_mutex); ++} ++ ++/** ++ * ubifs_release_new_page_budget - release budget of a new page. ++ * @c: UBIFS file-system description object ++ * ++ * This is a helper function which releases budget corresponding to the budget ++ * of one new page of data. ++ */ ++void ubifs_release_new_page_budget(struct ubifs_info *c) ++{ ++ struct ubifs_budget_req req = { .new_page = 1, ++ .idx_growth = -1, ++ .data_growth = c->page_budget }; ++ ++ ubifs_release_budget(c, &req); ++} ++ ++/** ++ * ubifs_budg_get_free_space - return amount of free space. ++ * @c: UBIFS file-system description object ++ * ++ * This function returns amount of free space on the file-system. ++ */ ++long long ubifs_budg_get_free_space(struct ubifs_info *c) ++{ ++ int min_idx_lebs, rsvd_idx_lebs; ++ long long available, outstanding, free; ++ ++ /* Do exactly the same calculations as in 'do_budget_space()' */ ++ spin_lock(&c->space_lock); ++ min_idx_lebs = ubifs_calc_min_idx_lebs(c); ++ ++ if (min_idx_lebs > c->lst.idx_lebs) ++ rsvd_idx_lebs = min_idx_lebs - c->lst.idx_lebs; ++ else ++ rsvd_idx_lebs = 0; ++ ++ if (rsvd_idx_lebs > c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt ++ - c->lst.taken_empty_lebs) { ++ spin_unlock(&c->space_lock); ++ return 0; ++ } ++ ++ c->min_idx_lebs = min_idx_lebs; ++ available = ubifs_calc_available(c); ++ outstanding = c->budg_data_growth + c->budg_dd_growth; ++ spin_unlock(&c->space_lock); ++ ++ if (available > outstanding) ++ free = ubifs_reported_space(c, available - outstanding); ++ else ++ free = 0; ++ ++ return free; ++} +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/commit.c avr32-2.6/fs/ubifs/commit.c +--- linux-2.6.25.6/fs/ubifs/commit.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/commit.c 2008-06-12 15:09:45.311815896 +0200 +@@ -0,0 +1,677 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Adrian Hunter ++ * Artem Bityutskiy (Битюцкий Артём) ++ */ ++ ++/* ++ * This file implements functions that manage the running of the commit process. ++ * Each affected module has its own functions to accomplish their part in the ++ * commit and those functions are called here. ++ * ++ * The commit is the process whereby all updates to the index and LEB properties ++ * are written out together and the journal becomes empty. This keeps the ++ * file system consistent - at all times the state can be recreated by reading ++ * the index and LEB properties and then replaying the journal. ++ * ++ * The commit is split into two parts named "commit start" and "commit end". ++ * During commit start, the commit process has exclusive access to the journal ++ * by holding the commit semaphore down for writing. As few I/O operations as ++ * possible are performed during commit start, instead the nodes that are to be ++ * written are merely identified. During commit end, the commit semaphore is no ++ * longer held and the journal is again in operation, allowing users to continue ++ * to use the file system while the bulk of the commit I/O is performed. The ++ * purpose of this two-step approach is to prevent the commit from causing any ++ * latency blips. Note that in any case, the commit does not prevent lookups ++ * (as permitted by the TNC mutex), or access to VFS data structures e.g. page ++ * cache. ++ */ ++ ++#include <linux/freezer.h> ++#include <linux/kthread.h> ++#include "ubifs.h" ++ ++/** ++ * do_commit - commit the journal. ++ * @c: UBIFS file-system description object ++ * ++ * This function implements UBIFS commit. It has to be called with commit lock ++ * locked. Returns zero in case of success and a negative error code in case of ++ * failure. ++ */ ++static int do_commit(struct ubifs_info *c) ++{ ++ int err, new_ltail_lnum, old_ltail_lnum, i; ++ struct ubifs_zbranch zroot; ++ struct ubifs_lp_stats lst; ++ ++ dbg_cmt("start"); ++ if (c->ro_media) { ++ err = -EROFS; ++ goto out_up; ++ } ++ ++ /* Sync all write buffers (necessary for recovery) */ ++ for (i = 0; i < c->jhead_cnt; i++) { ++ err = ubifs_wbuf_sync(&c->jheads[i].wbuf); ++ if (err) ++ goto out_up; ++ } ++ ++ err = ubifs_gc_start_commit(c); ++ if (err) ++ goto out_up; ++ err = dbg_check_lprops(c); ++ if (err) ++ goto out_up; ++ err = ubifs_log_start_commit(c, &new_ltail_lnum); ++ if (err) ++ goto out_up; ++ err = ubifs_tnc_start_commit(c, &zroot); ++ if (err) ++ goto out_up; ++ err = ubifs_lpt_start_commit(c); ++ if (err) ++ goto out_up; ++ err = ubifs_orphan_start_commit(c); ++ if (err) ++ goto out_up; ++ ++ ubifs_get_lp_stats(c, &lst); ++ ++ up_write(&c->commit_sem); ++ ++ err = ubifs_tnc_end_commit(c); ++ if (err) ++ goto out; ++ err = ubifs_lpt_end_commit(c); ++ if (err) ++ goto out; ++ err = ubifs_orphan_end_commit(c); ++ if (err) ++ goto out; ++ old_ltail_lnum = c->ltail_lnum; ++ err = ubifs_log_end_commit(c, new_ltail_lnum); ++ if (err) ++ goto out; ++ err = dbg_check_old_index(c, &zroot); ++ if (err) ++ goto out; ++ ++ mutex_lock(&c->mst_mutex); ++ c->mst_node->cmt_no = cpu_to_le64(++c->cmt_no); ++ c->mst_node->log_lnum = cpu_to_le32(new_ltail_lnum); ++ c->mst_node->root_lnum = cpu_to_le32(zroot.lnum); ++ c->mst_node->root_offs = cpu_to_le32(zroot.offs); ++ c->mst_node->root_len = cpu_to_le32(zroot.len); ++ c->mst_node->ihead_lnum = cpu_to_le32(c->ihead_lnum); ++ c->mst_node->ihead_offs = cpu_to_le32(c->ihead_offs); ++ c->mst_node->index_size = cpu_to_le64(c->old_idx_sz); ++ c->mst_node->lpt_lnum = cpu_to_le32(c->lpt_lnum); ++ c->mst_node->lpt_offs = cpu_to_le32(c->lpt_offs); ++ c->mst_node->nhead_lnum = cpu_to_le32(c->nhead_lnum); ++ c->mst_node->nhead_offs = cpu_to_le32(c->nhead_offs); ++ c->mst_node->ltab_lnum = cpu_to_le32(c->ltab_lnum); ++ c->mst_node->ltab_offs = cpu_to_le32(c->ltab_offs); ++ c->mst_node->lsave_lnum = cpu_to_le32(c->lsave_lnum); ++ c->mst_node->lsave_offs = cpu_to_le32(c->lsave_offs); ++ c->mst_node->lscan_lnum = cpu_to_le32(c->lscan_lnum); ++ c->mst_node->empty_lebs = cpu_to_le32(lst.empty_lebs); ++ c->mst_node->idx_lebs = cpu_to_le32(lst.idx_lebs); ++ c->mst_node->total_free = cpu_to_le64(lst.total_free); ++ c->mst_node->total_dirty = cpu_to_le64(lst.total_dirty); ++ c->mst_node->total_used = cpu_to_le64(lst.total_used); ++ c->mst_node->total_dead = cpu_to_le64(lst.total_dead); ++ c->mst_node->total_dark = cpu_to_le64(lst.total_dark); ++ if (c->no_orphs) ++ c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS); ++ else ++ c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_NO_ORPHS); ++ err = ubifs_write_master(c); ++ mutex_unlock(&c->mst_mutex); ++ if (err) ++ goto out; ++ ++ err = ubifs_log_post_commit(c, old_ltail_lnum); ++ if (err) ++ goto out; ++ err = ubifs_gc_end_commit(c); ++ if (err) ++ goto out; ++ err = ubifs_lpt_post_commit(c); ++ if (err) ++ goto out; ++ ++ spin_lock(&c->cs_lock); ++ c->cmt_state = COMMIT_RESTING; ++ wake_up(&c->cmt_wq); ++ dbg_cmt("commit end"); ++ spin_unlock(&c->cs_lock); ++ ++ return 0; ++ ++out_up: ++ up_write(&c->commit_sem); ++out: ++ ubifs_err("commit failed, error %d", err); ++ spin_lock(&c->cs_lock); ++ c->cmt_state = COMMIT_BROKEN; ++ wake_up(&c->cmt_wq); ++ spin_unlock(&c->cs_lock); ++ ubifs_ro_mode(c, err); ++ return err; ++} ++ ++/** ++ * run_bg_commit - run background commit if it is needed. ++ * @c: UBIFS file-system description object ++ * ++ * This function runs background commit if it is needed. Returns zero in case ++ * of success and a negative error code in case of failure. ++ */ ++static int run_bg_commit(struct ubifs_info *c) ++{ ++ spin_lock(&c->cs_lock); ++ /* ++ * Run background commit only if background commit was requested or if ++ * commit is required. ++ */ ++ if (c->cmt_state != COMMIT_BACKGROUND && ++ c->cmt_state != COMMIT_REQUIRED) ++ goto out; ++ spin_unlock(&c->cs_lock); ++ ++ down_write(&c->commit_sem); ++ spin_lock(&c->cs_lock); ++ if (c->cmt_state == COMMIT_REQUIRED) ++ c->cmt_state = COMMIT_RUNNING_REQUIRED; ++ else if (c->cmt_state == COMMIT_BACKGROUND) ++ c->cmt_state = COMMIT_RUNNING_BACKGROUND; ++ else ++ goto out_cmt_unlock; ++ spin_unlock(&c->cs_lock); ++ ++ return do_commit(c); ++ ++out_cmt_unlock: ++ up_write(&c->commit_sem); ++out: ++ spin_unlock(&c->cs_lock); ++ return 0; ++} ++ ++/** ++ * ubifs_bg_thread - UBIFS background thread function. ++ * @info: points to the file-system description object ++ * ++ * This function implements various file-system background activities: ++ * o when a write-buffer timer expires it synchronizes the appropriate ++ * write-buffer; ++ * o when the journal is about to be full, it starts in-advance commit. ++ * ++ * Note, other stuff like background garbage collection may be added here in ++ * future. ++ */ ++int ubifs_bg_thread(void *info) ++{ ++ int err; ++ struct ubifs_info *c = info; ++ ++ ubifs_msg("background thread \"%s\" started, PID %d", ++ c->bgt_name, current->pid); ++ set_freezable(); ++ ++ while (1) { ++ if (kthread_should_stop()) ++ break; ++ ++ if (try_to_freeze()) ++ continue; ++ ++ set_current_state(TASK_INTERRUPTIBLE); ++ /* Check if there is something to do */ ++ if (!c->need_bgt) { ++ /* ++ * Nothing prevents us from going sleep now and ++ * be never woken up and block the task which ++ * could wait in 'kthread_stop()' forever. ++ */ ++ if (kthread_should_stop()) ++ break; ++ schedule(); ++ continue; ++ } else ++ __set_current_state(TASK_RUNNING); ++ ++ c->need_bgt = 0; ++ err = ubifs_bg_wbufs_sync(c); ++ if (err) ++ ubifs_ro_mode(c, err); ++ ++ run_bg_commit(c); ++ cond_resched(); ++ } ++ ++ dbg_msg("background thread \"%s\" stops", c->bgt_name); ++ return 0; ++} ++ ++/** ++ * ubifs_commit_required - set commit state to "required". ++ * @c: UBIFS file-system description object ++ * ++ * This function is called if a commit is required but cannot be done from the ++ * calling function, so it is just flagged instead. ++ */ ++void ubifs_commit_required(struct ubifs_info *c) ++{ ++ spin_lock(&c->cs_lock); ++ switch (c->cmt_state) { ++ case COMMIT_RESTING: ++ case COMMIT_BACKGROUND: ++ dbg_cmt("old: %s, new: %s", dbg_cstate(c->cmt_state), ++ dbg_cstate(COMMIT_REQUIRED)); ++ c->cmt_state = COMMIT_REQUIRED; ++ break; ++ case COMMIT_RUNNING_BACKGROUND: ++ dbg_cmt("old: %s, new: %s", dbg_cstate(c->cmt_state), ++ dbg_cstate(COMMIT_RUNNING_REQUIRED)); ++ c->cmt_state = COMMIT_RUNNING_REQUIRED; ++ break; ++ case COMMIT_REQUIRED: ++ case COMMIT_RUNNING_REQUIRED: ++ case COMMIT_BROKEN: ++ break; ++ } ++ spin_unlock(&c->cs_lock); ++} ++ ++/** ++ * ubifs_request_bg_commit - notify the background thread to do a commit. ++ * @c: UBIFS file-system description object ++ * ++ * This function is called if the journal is full enough to make a commit ++ * worthwhile, so background thread is kicked to start it. ++ */ ++void ubifs_request_bg_commit(struct ubifs_info *c) ++{ ++ spin_lock(&c->cs_lock); ++ if (c->cmt_state == COMMIT_RESTING) { ++ dbg_cmt("old: %s, new: %s", dbg_cstate(c->cmt_state), ++ dbg_cstate(COMMIT_BACKGROUND)); ++ c->cmt_state = COMMIT_BACKGROUND; ++ spin_unlock(&c->cs_lock); ++ ubifs_wake_up_bgt(c); ++ } else ++ spin_unlock(&c->cs_lock); ++} ++ ++/** ++ * wait_for_commit - wait for commit. ++ * @c: UBIFS file-system description object ++ * ++ * This function sleeps until the commit operation is no longer running. ++ */ ++static int wait_for_commit(struct ubifs_info *c) ++{ ++ dbg_cmt("pid %d goes sleep", current->pid); ++ ++ /* ++ * The following sleeps if the condition is false, and will be woken ++ * when the commit ends. It is possible, although very unlikely, that we ++ * will wake up and see the subsequent commit running, rather than the ++ * one we were waiting for, and go back to sleep. However, we will be ++ * woken again, so there is no danger of sleeping forever. ++ */ ++ wait_event(c->cmt_wq, c->cmt_state != COMMIT_RUNNING_BACKGROUND && ++ c->cmt_state != COMMIT_RUNNING_REQUIRED); ++ dbg_cmt("commit finished, pid %d woke up", current->pid); ++ return 0; ++} ++ ++/** ++ * ubifs_run_commit - run or wait for commit. ++ * @c: UBIFS file-system description object ++ * ++ * This function runs commit and returns zero in case of success and a negative ++ * error code in case of failure. ++ */ ++int ubifs_run_commit(struct ubifs_info *c) ++{ ++ int err = 0; ++ ++ spin_lock(&c->cs_lock); ++ if (c->cmt_state == COMMIT_BROKEN) { ++ err = -EINVAL; ++ goto out; ++ } ++ ++ if (c->cmt_state == COMMIT_RUNNING_BACKGROUND) ++ /* ++ * We set the commit state to 'running required' to indicate ++ * that we want it to complete as quickly as possible. ++ */ ++ c->cmt_state = COMMIT_RUNNING_REQUIRED; ++ ++ if (c->cmt_state == COMMIT_RUNNING_REQUIRED) { ++ spin_unlock(&c->cs_lock); ++ return wait_for_commit(c); ++ } ++ spin_unlock(&c->cs_lock); ++ ++ /* Ok, the commit is indeed needed */ ++ ++ down_write(&c->commit_sem); ++ spin_lock(&c->cs_lock); ++ /* ++ * Since we unlocked 'c->cs_lock', the state may have changed, so ++ * re-check it. ++ */ ++ if (c->cmt_state == COMMIT_BROKEN) { ++ err = -EINVAL; ++ goto out_cmt_unlock; ++ } ++ ++ if (c->cmt_state == COMMIT_RUNNING_BACKGROUND) ++ c->cmt_state = COMMIT_RUNNING_REQUIRED; ++ ++ if (c->cmt_state == COMMIT_RUNNING_REQUIRED) { ++ up_write(&c->commit_sem); ++ spin_unlock(&c->cs_lock); ++ return wait_for_commit(c); ++ } ++ c->cmt_state = COMMIT_RUNNING_REQUIRED; ++ spin_unlock(&c->cs_lock); ++ ++ err = do_commit(c); ++ return err; ++ ++out_cmt_unlock: ++ up_write(&c->commit_sem); ++out: ++ spin_unlock(&c->cs_lock); ++ return err; ++} ++ ++/** ++ * ubifs_gc_should_commit - determine if it is time for GC to run commit. ++ * @c: UBIFS file-system description object ++ * ++ * This function is called by garbage collection to determine if commit should ++ * be run. If commit state is @COMMIT_BACKGROUND, which means that the journal ++ * is full enough to start commit, this function returns true. It is not ++ * absolutely necessary to commit yet, but it feels like this should be better ++ * then to keep doing GC. This function returns %1 if GC has to initiate commit ++ * and %0 if not. ++ */ ++int ubifs_gc_should_commit(struct ubifs_info *c) ++{ ++ int ret = 0; ++ ++ spin_lock(&c->cs_lock); ++ if (c->cmt_state == COMMIT_BACKGROUND) { ++ dbg_cmt("commit required now"); ++ c->cmt_state = COMMIT_REQUIRED; ++ } else ++ dbg_cmt("commit not requested"); ++ if (c->cmt_state == COMMIT_REQUIRED) ++ ret = 1; ++ spin_unlock(&c->cs_lock); ++ return ret; ++} ++ ++#ifdef CONFIG_UBIFS_FS_DEBUG ++ ++/** ++ * struct idx_node - hold index nodes during index tree traversal. ++ * @list: list ++ * @iip: index in parent (slot number of this indexing node in the parent ++ * indexing node) ++ * @upper_key: all keys in this indexing node have to be less or equivalent to ++ * this key ++ * @idx: index node (8-byte aligned because all node structures must be 8-byte ++ * aligned) ++ */ ++struct idx_node { ++ struct list_head list; ++ int iip; ++ union ubifs_key upper_key; ++ struct ubifs_idx_node idx __attribute__((aligned(8))); ++}; ++ ++/** ++ * dbg_old_index_check_init - get information for the next old index check. ++ * @c: UBIFS file-system description object ++ * @zroot: root of the index ++ * ++ * This function records information about the index that will be needed for the ++ * next old index check i.e. 'dbg_check_old_index()'. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++int dbg_old_index_check_init(struct ubifs_info *c, struct ubifs_zbranch *zroot) ++{ ++ struct ubifs_idx_node *idx; ++ int lnum, offs, len, err = 0; ++ ++ c->old_zroot = *zroot; ++ ++ lnum = c->old_zroot.lnum; ++ offs = c->old_zroot.offs; ++ len = c->old_zroot.len; ++ ++ idx = kmalloc(c->max_idx_node_sz, GFP_NOFS); ++ if (!idx) ++ return -ENOMEM; ++ ++ err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs); ++ if (err) ++ goto out; ++ ++ c->old_zroot_level = le16_to_cpu(idx->level); ++ c->old_zroot_sqnum = le64_to_cpu(idx->ch.sqnum); ++out: ++ kfree(idx); ++ return err; ++} ++ ++/** ++ * dbg_check_old_index - check the old copy of the index. ++ * @c: UBIFS file-system description object ++ * @zroot: root of the new index ++ * ++ * In order to be able to recover from an unclean unmount, a complete copy of ++ * the index must exist on flash. This is the "old" index. The commit process ++ * must write the "new" index to flash without overwriting or destroying any ++ * part of the old index. This function is run at commit end in order to check ++ * that the old index does indeed exist completely intact. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot) ++{ ++ int lnum, offs, len, err = 0, uninitialized_var(last_level), child_cnt; ++ int first = 1, iip; ++ union ubifs_key lower_key, upper_key, l_key, u_key; ++ unsigned long long uninitialized_var(last_sqnum); ++ struct ubifs_idx_node *idx; ++ struct list_head list; ++ struct idx_node *i; ++ size_t sz; ++ ++ if (!(ubifs_chk_flags & UBIFS_CHK_OLD_IDX)) ++ goto out; ++ ++ INIT_LIST_HEAD(&list); ++ ++ sz = sizeof(struct idx_node) + ubifs_idx_node_sz(c, c->fanout) - ++ UBIFS_IDX_NODE_SZ; ++ ++ /* Start at the old zroot */ ++ lnum = c->old_zroot.lnum; ++ offs = c->old_zroot.offs; ++ len = c->old_zroot.len; ++ iip = 0; ++ ++ /* ++ * Traverse the index tree preorder depth-first i.e. do a node and then ++ * its subtrees from left to right. ++ */ ++ while (1) { ++ struct ubifs_branch *br; ++ ++ /* Get the next index node */ ++ i = kmalloc(sz, GFP_NOFS); ++ if (!i) { ++ err = -ENOMEM; ++ goto out_free; ++ } ++ i->iip = iip; ++ /* Keep the index nodes on our path in a linked list */ ++ list_add_tail(&i->list, &list); ++ /* Read the index node */ ++ idx = &i->idx; ++ err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs); ++ if (err) ++ goto out_free; ++ /* Validate index node */ ++ child_cnt = le16_to_cpu(idx->child_cnt); ++ if (child_cnt < 1 || child_cnt > c->fanout) { ++ err = 1; ++ goto out_dump; ++ } ++ if (first) { ++ first = 0; ++ /* Check root level and sqnum */ ++ if (le16_to_cpu(idx->level) != c->old_zroot_level) { ++ err = 2; ++ goto out_dump; ++ } ++ if (le64_to_cpu(idx->ch.sqnum) != c->old_zroot_sqnum) { ++ err = 3; ++ goto out_dump; ++ } ++ /* Set last values as though root had a parent */ ++ last_level = le16_to_cpu(idx->level) + 1; ++ last_sqnum = le64_to_cpu(idx->ch.sqnum) + 1; ++ key_read(c, ubifs_idx_key(c, idx), &lower_key); ++ highest_ino_key(c, &upper_key, INUM_WATERMARK); ++ } ++ key_copy(c, &upper_key, &i->upper_key); ++ if (le16_to_cpu(idx->level) != last_level - 1) { ++ err = 3; ++ goto out_dump; ++ } ++ /* ++ * The index is always written bottom up hence a child's sqnum ++ * is always less than the parents. ++ */ ++ if (le64_to_cpu(idx->ch.sqnum) >= last_sqnum) { ++ err = 4; ++ goto out_dump; ++ } ++ /* Check key range */ ++ key_read(c, ubifs_idx_key(c, idx), &l_key); ++ br = ubifs_idx_branch(c, idx, child_cnt - 1); ++ key_read(c, &br->key, &u_key); ++ if (keys_cmp(c, &lower_key, &l_key) > 0) { ++ err = 5; ++ goto out_dump; ++ } ++ if (keys_cmp(c, &upper_key, &u_key) < 0) { ++ err = 6; ++ goto out_dump; ++ } ++ if (keys_cmp(c, &upper_key, &u_key) == 0) ++ if (!is_hash_key(c, &u_key)) { ++ err = 7; ++ goto out_dump; ++ } ++ /* Go to next index node */ ++ if (le16_to_cpu(idx->level) == 0) { ++ /* At the bottom, so go up until can go right */ ++ while (1) { ++ /* Drop the bottom of the list */ ++ list_del(&i->list); ++ kfree(i); ++ /* No more list means we are done */ ++ if (list_empty(&list)) ++ goto out; ++ /* Look at the new bottom */ ++ i = list_entry(list.prev, struct idx_node, ++ list); ++ idx = &i->idx; ++ /* Can we go right */ ++ if (iip + 1 < le16_to_cpu(idx->child_cnt)) { ++ iip = iip + 1; ++ break; ++ } else ++ /* Nope, so go up again */ ++ iip = i->iip; ++ } ++ } else ++ /* Go down left */ ++ iip = 0; ++ /* ++ * We have the parent in 'idx' and now we set up for reading the ++ * child pointed to by slot 'iip'. ++ */ ++ last_level = le16_to_cpu(idx->level); ++ last_sqnum = le64_to_cpu(idx->ch.sqnum); ++ br = ubifs_idx_branch(c, idx, iip); ++ lnum = le32_to_cpu(br->lnum); ++ offs = le32_to_cpu(br->offs); ++ len = le32_to_cpu(br->len); ++ key_read(c, &br->key, &lower_key); ++ if (iip + 1 < le16_to_cpu(idx->child_cnt)) { ++ br = ubifs_idx_branch(c, idx, iip + 1); ++ key_read(c, &br->key, &upper_key); ++ } else ++ key_copy(c, &i->upper_key, &upper_key); ++ } ++out: ++ err = dbg_old_index_check_init(c, zroot); ++ if (err) ++ goto out_free; ++ ++ return 0; ++ ++out_dump: ++ dbg_err("dumping index node (iip=%d)", i->iip); ++ dbg_dump_node(c, idx); ++ list_del(&i->list); ++ kfree(i); ++ if (!list_empty(&list)) { ++ i = list_entry(list.prev, struct idx_node, list); ++ dbg_err("dumping parent index node"); ++ dbg_dump_node(c, &i->idx); ++ } ++out_free: ++ while (!list_empty(&list)) { ++ i = list_entry(list.next, struct idx_node, list); ++ list_del(&i->list); ++ kfree(i); ++ } ++ ubifs_err("failed, error %d", err); ++ if (err > 0) ++ err = -EINVAL; ++ return err; ++} ++ ++#endif /* CONFIG_UBIFS_FS_DEBUG */ +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/compress.c avr32-2.6/fs/ubifs/compress.c +--- linux-2.6.25.6/fs/ubifs/compress.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/compress.c 2008-06-12 15:09:45.315815846 +0200 +@@ -0,0 +1,253 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * Copyright (C) 2006, 2007 University of Szeged, Hungary ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Adrian Hunter ++ * Artem Bityutskiy (Битюцкий Артём) ++ * Zoltan Sogor ++ */ ++ ++/* ++ * This file provides a single place to access to compression and ++ * decompression. ++ */ ++ ++#include <linux/crypto.h> ++#include "ubifs.h" ++ ++/* Fake description object for the "none" compressor */ ++static struct ubifs_compressor none_compr = { ++ .compr_type = UBIFS_COMPR_NONE, ++ .name = "no compression", ++ .capi_name = "", ++}; ++ ++#ifdef CONFIG_UBIFS_FS_LZO ++static DEFINE_MUTEX(lzo_mutex); ++ ++static struct ubifs_compressor lzo_compr = { ++ .compr_type = UBIFS_COMPR_LZO, ++ .comp_mutex = &lzo_mutex, ++ .name = "LZO", ++ .capi_name = "lzo", ++}; ++#else ++static struct ubifs_compressor lzo_compr = { ++ .compr_type = UBIFS_COMPR_LZO, ++ .name = "LZO", ++}; ++#endif ++ ++#ifdef CONFIG_UBIFS_FS_ZLIB ++static DEFINE_MUTEX(deflate_mutex); ++static DEFINE_MUTEX(inflate_mutex); ++ ++static struct ubifs_compressor zlib_compr = { ++ .compr_type = UBIFS_COMPR_ZLIB, ++ .comp_mutex = &deflate_mutex, ++ .decomp_mutex = &inflate_mutex, ++ .name = "zlib", ++ .capi_name = "deflate", +}; ++#else ++static struct ubifs_compressor zlib_compr = { ++ .compr_type = UBIFS_COMPR_ZLIB, ++ .name = "zlib", ++}; ++#endif ++ ++/* All UBIFS compressors */ ++struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT]; ++ ++/** ++ * ubifs_compress - compress data. ++ * @in_buf: data to compress ++ * @in_len: length of the data to compress ++ * @out_buf: output buffer where compressed data should be stored ++ * @out_len: output buffer length is returned here ++ * @compr_type: type of compression to use on enter, actually used compression ++ * type on exit ++ * ++ * This function compresses input buffer @in_buf of length @in_len and stores ++ * the result in the output buffer @out_buf and the resulting length in ++ * @out_len. If the input buffer does not compress, it is just copied to the ++ * @out_buf. The same happens if @compr_type is %UBIFS_COMPR_NONE or if ++ * compression error occurred. ++ * ++ * Note, if the input buffer was not compressed, it is copied to the output ++ * buffer and %UBIFS_COMPR_NONE is returned in @compr_type. ++ * ++ * This functions returns %0 on success or a negative error code on failure. ++ */ ++void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len, ++ int *compr_type) ++{ ++ int err; ++ struct ubifs_compressor *compr = ubifs_compressors[*compr_type]; ++ ++ if (*compr_type == UBIFS_COMPR_NONE) ++ goto no_compr; ++ ++ /* If the input data is small, do not even try to compress it */ ++ if (in_len < UBIFS_MIN_COMPR_LEN) ++ goto no_compr; ++ ++ if (compr->comp_mutex) ++ mutex_lock(compr->comp_mutex); ++ err = crypto_comp_compress(compr->cc, in_buf, in_len, out_buf, ++ out_len); ++ if (compr->comp_mutex) ++ mutex_unlock(compr->comp_mutex); ++ if (unlikely(err)) { ++ ubifs_warn("cannot compress %d bytes, compressor %s, " ++ "error %d, leave data uncompressed", ++ in_len, compr->name, err); ++ goto no_compr; ++ } ++ ++ /* ++ * Presently, we just require that compression results in less data, ++ * rather than any defined minimum compression ratio or amount. ++ */ ++ if (ALIGN(*out_len, 8) >= ALIGN(in_len, 8)) ++ goto no_compr; ++ ++ return; ++ ++no_compr: ++ memcpy(out_buf, in_buf, in_len); ++ *out_len = in_len; ++ *compr_type = UBIFS_COMPR_NONE; ++} ++ ++/** ++ * ubifs_decompress - decompress data. ++ * @in_buf: data to decompress ++ * @in_len: length of the data to decompress ++ * @out_buf: output buffer where decompressed data should ++ * @out_len: output length is returned here ++ * @compr_type: type of compression ++ * ++ * This function decompresses data from buffer @in_buf into buffer @out_buf. ++ * The length of the uncompressed data is returned in @out_len. This functions ++ * returns %0 on success or a negative error code on failure. ++ */ ++int ubifs_decompress(const void *in_buf, int in_len, void *out_buf, ++ int *out_len, int compr_type) ++{ ++ int err; ++ struct ubifs_compressor *compr; ++ ++ if (unlikely(compr_type < 0 || compr_type >= UBIFS_COMPR_TYPES_CNT)) { ++ ubifs_err("invalid compression type %d", compr_type); ++ return -EINVAL; ++ } ++ ++ compr = ubifs_compressors[compr_type]; ++ ++ if (unlikely(!compr->capi_name)) { ++ ubifs_err("%s compression is not compiled in", compr->name); ++ return -EINVAL; ++ } ++ ++ if (compr_type == UBIFS_COMPR_NONE) { ++ memcpy(out_buf, in_buf, in_len); ++ *out_len = in_len; ++ return 0; ++ } ++ ++ if (compr->decomp_mutex) ++ mutex_lock(compr->decomp_mutex); ++ err = crypto_comp_decompress(compr->cc, in_buf, in_len, out_buf, ++ out_len); ++ if (compr->decomp_mutex) ++ mutex_unlock(compr->decomp_mutex); ++ if (err) ++ ubifs_err("cannot decompress %d bytes, compressor %s, " ++ "error %d", in_len, compr->name, err); ++ ++ return err; ++} ++ ++/** ++ * compr_init - initialize a compressor. ++ * @compr: compressor description object ++ * ++ * This function initializes the requested compressor and returns zero in case ++ * of success or a negative error code in case of failure. ++ */ ++static int __init compr_init(struct ubifs_compressor *compr) ++{ ++ if (compr->capi_name) { ++ compr->cc = crypto_alloc_comp(compr->capi_name, 0, 0); ++ if (IS_ERR(compr->cc)) { ++ ubifs_err("cannot initialize compressor %s, error %ld", ++ compr->name, PTR_ERR(compr->cc)); ++ return PTR_ERR(compr->cc); ++ } ++ } ++ ++ ubifs_compressors[compr->compr_type] = compr; ++ return 0; ++} ++ ++/** ++ * compr_exit - de-initialize a compressor. ++ * @compr: compressor description object ++ */ ++static void compr_exit(struct ubifs_compressor *compr) ++{ ++ if (compr->capi_name) ++ crypto_free_comp(compr->cc); ++ return; ++} ++ ++/** ++ * ubifs_compressors_init - initialize UBIFS compressors. ++ * ++ * This function initializes the compressor which were compiled in. Returns ++ * zero in case of success and a negative error code in case of failure. ++ */ ++int __init ubifs_compressors_init(void) ++{ ++ int err; ++ ++ err = compr_init(&lzo_compr); ++ if (err) ++ return err; ++ ++ err = compr_init(&zlib_compr); ++ if (err) ++ goto out_lzo; ++ ++ ubifs_compressors[UBIFS_COMPR_NONE] = &none_compr; ++ return 0; ++ ++out_lzo: ++ compr_exit(&lzo_compr); ++ return err; ++} ++ ++/** ++ * ubifs_compressors_exit - de-initialize UBIFS compressors. ++ */ ++void __exit ubifs_compressors_exit(void) ++{ ++ compr_exit(&lzo_compr); ++ compr_exit(&zlib_compr); ++} +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/debug.c avr32-2.6/fs/ubifs/debug.c +--- linux-2.6.25.6/fs/ubifs/debug.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/debug.c 2008-06-12 15:09:45.315815846 +0200 +@@ -0,0 +1,2210 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Artem Bityutskiy (Битюцкий Артём) ++ * Adrian Hunter ++ */ ++ ++/* ++ * This file implements most of the debugging stuff which is compiled in only ++ * when it is enabled. But some debugging check functions are implemented in ++ * corresponding subsystem, just because they are closely related and utilize ++ * various local functions of those subsystems. ++ */ ++ ++#define UBIFS_DBG_PRESERVE_UBI ++ ++#include "ubifs.h" ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++ ++#ifdef CONFIG_UBIFS_FS_DEBUG ++ ++DEFINE_SPINLOCK(dbg_lock); ++ ++static char dbg_key_buf0[128]; ++static char dbg_key_buf1[128]; + -+static void init_backlight(struct atmel_lcdfb_info *sinfo) ++unsigned int ubifs_msg_flags = UBIFS_MSG_FLAGS_DEFAULT; ++unsigned int ubifs_chk_flags = UBIFS_CHK_FLAGS_DEFAULT; ++unsigned int ubifs_tst_flags; ++ ++module_param_named(debug_msgs, ubifs_msg_flags, uint, S_IRUGO | S_IWUSR); ++module_param_named(debug_chks, ubifs_chk_flags, uint, S_IRUGO | S_IWUSR); ++module_param_named(debug_tsts, ubifs_tst_flags, uint, S_IRUGO | S_IWUSR); ++ ++MODULE_PARM_DESC(debug_msgs, "Debug message type flags"); ++MODULE_PARM_DESC(debug_chks, "Debug check flags"); ++MODULE_PARM_DESC(debug_tsts, "Debug special test flags"); ++ ++static const char *get_key_fmt(int fmt) ++{ ++ switch (fmt) { ++ case UBIFS_SIMPLE_KEY_FMT: ++ return "simple"; ++ default: ++ return "unknown/invalid format"; ++ } ++} ++ ++static const char *get_key_hash(int hash) ++{ ++ switch (hash) { ++ case UBIFS_KEY_HASH_R5: ++ return "R5"; ++ case UBIFS_KEY_HASH_TEST: ++ return "test"; ++ default: ++ return "unknown/invalid name hash"; ++ } ++} ++ ++static const char *get_key_type(int type) ++{ ++ switch (type) { ++ case UBIFS_INO_KEY: ++ return "inode"; ++ case UBIFS_DENT_KEY: ++ return "direntry"; ++ case UBIFS_XENT_KEY: ++ return "xentry"; ++ case UBIFS_DATA_KEY: ++ return "data"; ++ case UBIFS_TRUN_KEY: ++ return "truncate"; ++ default: ++ return "unknown/invalid key"; ++ } ++} ++ ++static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key, ++ char *buffer) ++{ ++ char *p = buffer; ++ int type = key_type(c, key); ++ ++ if (c->key_fmt == UBIFS_SIMPLE_KEY_FMT) { ++ switch (type) { ++ case UBIFS_INO_KEY: ++ sprintf(p, "(%lu, %s)", key_inum(c, key), ++ get_key_type(type)); ++ break; ++ case UBIFS_DENT_KEY: ++ case UBIFS_XENT_KEY: ++ sprintf(p, "(%lu, %s, %#08x)", key_inum(c, key), ++ get_key_type(type), key_hash(c, key)); ++ break; ++ case UBIFS_DATA_KEY: ++ sprintf(p, "(%lu, %s, %u)", key_inum(c, key), ++ get_key_type(type), key_block(c, key)); ++ break; ++ case UBIFS_TRUN_KEY: ++ sprintf(p, "(%lu, %s)", ++ key_inum(c, key), get_key_type(type)); ++ break; ++ default: ++ sprintf(p, "(bad key type: %#08x, %#08x)", ++ key->u32[0], key->u32[1]); ++ } ++ } else ++ sprintf(p, "bad key format %d", c->key_fmt); ++} ++ ++const char *dbg_key_str0(const struct ubifs_info *c, const union ubifs_key *key) ++{ ++ /* dbg_lock must be held */ ++ sprintf_key(c, key, dbg_key_buf0); ++ return dbg_key_buf0; ++} ++ ++const char *dbg_key_str1(const struct ubifs_info *c, const union ubifs_key *key) ++{ ++ /* dbg_lock must be held */ ++ sprintf_key(c, key, dbg_key_buf1); ++ return dbg_key_buf1; ++} ++ ++const char *dbg_ntype(int type) ++{ ++ switch (type) { ++ case UBIFS_PAD_NODE: ++ return "padding node"; ++ case UBIFS_SB_NODE: ++ return "superblock node"; ++ case UBIFS_MST_NODE: ++ return "master node"; ++ case UBIFS_REF_NODE: ++ return "reference node"; ++ case UBIFS_INO_NODE: ++ return "inode node"; ++ case UBIFS_DENT_NODE: ++ return "direntry node"; ++ case UBIFS_XENT_NODE: ++ return "xentry node"; ++ case UBIFS_DATA_NODE: ++ return "data node"; ++ case UBIFS_TRUN_NODE: ++ return "truncate node"; ++ case UBIFS_IDX_NODE: ++ return "indexing node"; ++ case UBIFS_CS_NODE: ++ return "commit start node"; ++ case UBIFS_ORPH_NODE: ++ return "orphan node"; ++ default: ++ return "unknown node"; ++ } ++} ++ ++static const char *dbg_gtype(int type) +{ -+ struct backlight_device *bl; ++ switch (type) { ++ case UBIFS_NO_NODE_GROUP: ++ return "no node group"; ++ case UBIFS_IN_NODE_GROUP: ++ return "in node group"; ++ case UBIFS_LAST_OF_NODE_GROUP: ++ return "last of node group"; ++ default: ++ return "unknown"; ++ } ++} ++ ++const char *dbg_cstate(int cmt_state) ++{ ++ switch (cmt_state) { ++ case COMMIT_RESTING: ++ return "commit resting"; ++ case COMMIT_BACKGROUND: ++ return "background commit requested"; ++ case COMMIT_REQUIRED: ++ return "commit required"; ++ case COMMIT_RUNNING_BACKGROUND: ++ return "BACKGROUND commit running"; ++ case COMMIT_RUNNING_REQUIRED: ++ return "commit running and required"; ++ case COMMIT_BROKEN: ++ return "broken commit"; ++ default: ++ return "unknown commit state"; ++ } ++} + -+ sinfo->bl_power = FB_BLANK_UNBLANK; ++static void dump_ch(const struct ubifs_ch *ch) ++{ ++ printk(KERN_DEBUG "\tmagic %#x\n", le32_to_cpu(ch->magic)); ++ printk(KERN_DEBUG "\tcrc %#x\n", le32_to_cpu(ch->crc)); ++ printk(KERN_DEBUG "\tnode_type %d (%s)\n", ch->node_type, ++ dbg_ntype(ch->node_type)); ++ printk(KERN_DEBUG "\tgroup_type %d (%s)\n", ch->group_type, ++ dbg_gtype(ch->group_type)); ++ printk(KERN_DEBUG "\tsqnum %llu\n", ++ (unsigned long long)le64_to_cpu(ch->sqnum)); ++ printk(KERN_DEBUG "\tlen %u\n", le32_to_cpu(ch->len)); ++} ++ ++void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode) ++{ ++ const struct ubifs_inode *ui = ubifs_inode(inode); ++ ++ printk(KERN_DEBUG "inode %lu\n", inode->i_ino); ++ printk(KERN_DEBUG "size %llu\n", ++ (unsigned long long)i_size_read(inode)); ++ printk(KERN_DEBUG "nlink %u\n", inode->i_nlink); ++ printk(KERN_DEBUG "uid %u\n", (unsigned int)inode->i_uid); ++ printk(KERN_DEBUG "gid %u\n", (unsigned int)inode->i_gid); ++ printk(KERN_DEBUG "atime %u.%u\n", ++ (unsigned int)inode->i_atime.tv_sec, ++ (unsigned int)inode->i_atime.tv_nsec); ++ printk(KERN_DEBUG "mtime %u.%u\n", ++ (unsigned int)inode->i_mtime.tv_sec, ++ (unsigned int)inode->i_mtime.tv_nsec); ++ printk(KERN_DEBUG "ctime %u.%u\n", ++ (unsigned int)inode->i_ctime.tv_sec, ++ (unsigned int)inode->i_ctime.tv_nsec); ++ printk(KERN_DEBUG "creat_sqnum %llu\n", ui->creat_sqnum); ++ printk(KERN_DEBUG "xattr_size %lld\n", ui->xattr_size); ++ printk(KERN_DEBUG "xattr_cnt %d\n", ui->xattr_cnt); ++ printk(KERN_DEBUG "xattr_names %d\n", ui->xattr_names); ++ printk(KERN_DEBUG "dirty %u\n", ui->dirty); ++ printk(KERN_DEBUG "xattr %u\n", ui->xattr); ++ printk(KERN_DEBUG "flags %d\n", ui->flags); ++ printk(KERN_DEBUG "compr_type %d\n", ui->compr_type); ++ printk(KERN_DEBUG "data_len %d\n", ui->data_len); ++} ++ ++void dbg_dump_node(const struct ubifs_info *c, const void *node) ++{ ++ int i, n; ++ union ubifs_key key; ++ const struct ubifs_ch *ch = node; ++ ++ if (dbg_failure_mode) ++ return; + -+ if (sinfo->backlight) ++ /* If the magic is incorrect, just hexdump the first bytes */ ++ if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC) { ++ printk(KERN_DEBUG "Not a node, first %zu bytes:", UBIFS_CH_SZ); ++ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, ++ (void *)node, UBIFS_CH_SZ, 1); + return; ++ } ++ ++ spin_lock(&dbg_lock); ++ dump_ch(node); ++ ++ switch (ch->node_type) { ++ case UBIFS_PAD_NODE: ++ { ++ const struct ubifs_pad_node *pad = node; ++ ++ printk(KERN_DEBUG "\tpad_len %u\n", ++ le32_to_cpu(pad->pad_len)); ++ break; ++ } ++ case UBIFS_SB_NODE: ++ { ++ const struct ubifs_sb_node *sup = node; ++ unsigned int sup_flags = le32_to_cpu(sup->flags); ++ ++ printk(KERN_DEBUG "\tkey_hash %d (%s)\n", ++ (int)sup->key_hash, get_key_hash(sup->key_hash)); ++ printk(KERN_DEBUG "\tkey_fmt %d (%s)\n", ++ (int)sup->key_fmt, get_key_fmt(sup->key_fmt)); ++ printk(KERN_DEBUG "\tflags %#x\n", sup_flags); ++ printk(KERN_DEBUG "\t big_lpt %u\n", ++ !!(sup_flags & UBIFS_FLG_BIGLPT)); ++ printk(KERN_DEBUG "\tmin_io_size %u\n", ++ le32_to_cpu(sup->min_io_size)); ++ printk(KERN_DEBUG "\tleb_size %u\n", ++ le32_to_cpu(sup->leb_size)); ++ printk(KERN_DEBUG "\tleb_cnt %u\n", ++ le32_to_cpu(sup->leb_cnt)); ++ printk(KERN_DEBUG "\tmax_leb_cnt %u\n", ++ le32_to_cpu(sup->max_leb_cnt)); ++ printk(KERN_DEBUG "\tmax_bud_bytes %llu\n", ++ (unsigned long long)le64_to_cpu(sup->max_bud_bytes)); ++ printk(KERN_DEBUG "\tlog_lebs %u\n", ++ le32_to_cpu(sup->log_lebs)); ++ printk(KERN_DEBUG "\tlpt_lebs %u\n", ++ le32_to_cpu(sup->lpt_lebs)); ++ printk(KERN_DEBUG "\torph_lebs %u\n", ++ le32_to_cpu(sup->orph_lebs)); ++ printk(KERN_DEBUG "\tjhead_cnt %u\n", ++ le32_to_cpu(sup->jhead_cnt)); ++ printk(KERN_DEBUG "\tfanout %u\n", ++ le32_to_cpu(sup->fanout)); ++ printk(KERN_DEBUG "\tlsave_cnt %u\n", ++ le32_to_cpu(sup->lsave_cnt)); ++ printk(KERN_DEBUG "\tdefault_compr %u\n", ++ (int)le16_to_cpu(sup->default_compr)); ++ printk(KERN_DEBUG "\trp_size %llu\n", ++ (unsigned long long)le64_to_cpu(sup->rp_size)); ++ printk(KERN_DEBUG "\trp_uid %u\n", ++ le32_to_cpu(sup->rp_uid)); ++ printk(KERN_DEBUG "\trp_gid %u\n", ++ le32_to_cpu(sup->rp_gid)); ++ printk(KERN_DEBUG "\tfmt_version %u\n", ++ le32_to_cpu(sup->fmt_version)); ++ printk(KERN_DEBUG "\ttime_gran %u\n", ++ le32_to_cpu(sup->time_gran)); ++ printk(KERN_DEBUG "\tUUID %02X%02X%02X%02X-%02X%02X" ++ "-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X\n", ++ sup->uuid[0], sup->uuid[1], sup->uuid[2], sup->uuid[3], ++ sup->uuid[4], sup->uuid[5], sup->uuid[6], sup->uuid[7], ++ sup->uuid[8], sup->uuid[9], sup->uuid[10], sup->uuid[11], ++ sup->uuid[12], sup->uuid[13], sup->uuid[14], ++ sup->uuid[15]); ++ break; ++ } ++ case UBIFS_MST_NODE: ++ { ++ const struct ubifs_mst_node *mst = node; ++ ++ printk(KERN_DEBUG "\thighest_inum %llu\n", ++ (unsigned long long)le64_to_cpu(mst->highest_inum)); ++ printk(KERN_DEBUG "\tcommit number %llu\n", ++ (unsigned long long)le64_to_cpu(mst->cmt_no)); ++ printk(KERN_DEBUG "\tflags %#x\n", ++ le32_to_cpu(mst->flags)); ++ printk(KERN_DEBUG "\tlog_lnum %u\n", ++ le32_to_cpu(mst->log_lnum)); ++ printk(KERN_DEBUG "\troot_lnum %u\n", ++ le32_to_cpu(mst->root_lnum)); ++ printk(KERN_DEBUG "\troot_offs %u\n", ++ le32_to_cpu(mst->root_offs)); ++ printk(KERN_DEBUG "\troot_len %u\n", ++ le32_to_cpu(mst->root_len)); ++ printk(KERN_DEBUG "\tgc_lnum %u\n", ++ le32_to_cpu(mst->gc_lnum)); ++ printk(KERN_DEBUG "\tihead_lnum %u\n", ++ le32_to_cpu(mst->ihead_lnum)); ++ printk(KERN_DEBUG "\tihead_offs %u\n", ++ le32_to_cpu(mst->ihead_offs)); ++ printk(KERN_DEBUG "\tindex_size %u\n", ++ le32_to_cpu(mst->index_size)); ++ printk(KERN_DEBUG "\tlpt_lnum %u\n", ++ le32_to_cpu(mst->lpt_lnum)); ++ printk(KERN_DEBUG "\tlpt_offs %u\n", ++ le32_to_cpu(mst->lpt_offs)); ++ printk(KERN_DEBUG "\tnhead_lnum %u\n", ++ le32_to_cpu(mst->nhead_lnum)); ++ printk(KERN_DEBUG "\tnhead_offs %u\n", ++ le32_to_cpu(mst->nhead_offs)); ++ printk(KERN_DEBUG "\tltab_lnum %u\n", ++ le32_to_cpu(mst->ltab_lnum)); ++ printk(KERN_DEBUG "\tltab_offs %u\n", ++ le32_to_cpu(mst->ltab_offs)); ++ printk(KERN_DEBUG "\tlsave_lnum %u\n", ++ le32_to_cpu(mst->lsave_lnum)); ++ printk(KERN_DEBUG "\tlsave_offs %u\n", ++ le32_to_cpu(mst->lsave_offs)); ++ printk(KERN_DEBUG "\tlscan_lnum %u\n", ++ le32_to_cpu(mst->lscan_lnum)); ++ printk(KERN_DEBUG "\tleb_cnt %u\n", ++ le32_to_cpu(mst->leb_cnt)); ++ printk(KERN_DEBUG "\tempty_lebs %u\n", ++ le32_to_cpu(mst->empty_lebs)); ++ printk(KERN_DEBUG "\tidx_lebs %u\n", ++ le32_to_cpu(mst->idx_lebs)); ++ printk(KERN_DEBUG "\ttotal_free %llu\n", ++ (unsigned long long)le64_to_cpu(mst->total_free)); ++ printk(KERN_DEBUG "\ttotal_dirty %llu\n", ++ (unsigned long long)le64_to_cpu(mst->total_dirty)); ++ printk(KERN_DEBUG "\ttotal_used %llu\n", ++ (unsigned long long)le64_to_cpu(mst->total_used)); ++ printk(KERN_DEBUG "\ttotal_dead %llu\n", ++ (unsigned long long)le64_to_cpu(mst->total_dead)); ++ printk(KERN_DEBUG "\ttotal_dark %llu\n", ++ (unsigned long long)le64_to_cpu(mst->total_dark)); ++ break; ++ } ++ case UBIFS_REF_NODE: ++ { ++ const struct ubifs_ref_node *ref = node; ++ ++ printk(KERN_DEBUG "\tlnum %u\n", ++ le32_to_cpu(ref->lnum)); ++ printk(KERN_DEBUG "\toffs %u\n", ++ le32_to_cpu(ref->offs)); ++ printk(KERN_DEBUG "\tjhead %u\n", ++ le32_to_cpu(ref->jhead)); ++ break; ++ } ++ case UBIFS_INO_NODE: ++ { ++ const struct ubifs_ino_node *ino = node; ++ ++ key_read(c, &ino->key, &key); ++ printk(KERN_DEBUG "\tkey %s\n", DBGKEY(&key)); ++ printk(KERN_DEBUG "\tcreat_sqnum %llu\n", ++ (unsigned long long)le64_to_cpu(ino->creat_sqnum)); ++ printk(KERN_DEBUG "\tsize %llu\n", ++ (unsigned long long)le64_to_cpu(ino->size)); ++ printk(KERN_DEBUG "\tnlink %u\n", ++ le32_to_cpu(ino->nlink)); ++ printk(KERN_DEBUG "\tatime %lld.%u\n", ++ (long long)le64_to_cpu(ino->atime_sec), ++ le32_to_cpu(ino->atime_nsec)); ++ printk(KERN_DEBUG "\tmtime %lld.%u\n", ++ (long long)le64_to_cpu(ino->mtime_sec), ++ le32_to_cpu(ino->mtime_nsec)); ++ printk(KERN_DEBUG "\tctime %lld.%u\n", ++ (long long)le64_to_cpu(ino->ctime_sec), ++ le32_to_cpu(ino->ctime_nsec)); ++ printk(KERN_DEBUG "\tuid %u\n", ++ le32_to_cpu(ino->uid)); ++ printk(KERN_DEBUG "\tgid %u\n", ++ le32_to_cpu(ino->gid)); ++ printk(KERN_DEBUG "\tmode %u\n", ++ le32_to_cpu(ino->mode)); ++ printk(KERN_DEBUG "\tflags %#x\n", ++ le32_to_cpu(ino->flags)); ++ printk(KERN_DEBUG "\txattr_cnt %u\n", ++ le32_to_cpu(ino->xattr_cnt)); ++ printk(KERN_DEBUG "\txattr_size %llu\n", ++ (unsigned long long)le64_to_cpu(ino->xattr_size)); ++ printk(KERN_DEBUG "\txattr_names %u\n", ++ le32_to_cpu(ino->xattr_names)); ++ printk(KERN_DEBUG "\tcompr_type %#x\n", ++ (int)le16_to_cpu(ino->compr_type)); ++ printk(KERN_DEBUG "\tdata len %u\n", ++ le32_to_cpu(ino->data_len)); ++ break; ++ } ++ case UBIFS_DENT_NODE: ++ case UBIFS_XENT_NODE: ++ { ++ const struct ubifs_dent_node *dent = node; ++ int nlen = le16_to_cpu(dent->nlen); ++ ++ key_read(c, &dent->key, &key); ++ printk(KERN_DEBUG "\tkey %s\n", DBGKEY(&key)); ++ printk(KERN_DEBUG "\tinum %llu\n", ++ (unsigned long long)le64_to_cpu(dent->inum)); ++ printk(KERN_DEBUG "\ttype %d\n", (int)dent->type); ++ printk(KERN_DEBUG "\tnlen %d\n", nlen); ++ printk(KERN_DEBUG "\tname "); ++ ++ if (nlen > UBIFS_MAX_NLEN) ++ printk(KERN_DEBUG "(bad name length, not printing, " ++ "bad or corrupted node)"); ++ else { ++ for (i = 0; i < nlen && dent->name[i]; i++) ++ printk("%c", dent->name[i]); ++ } ++ printk("\n"); ++ ++ break; ++ } ++ case UBIFS_DATA_NODE: ++ { ++ const struct ubifs_data_node *dn = node; ++ int dlen = le32_to_cpu(ch->len) - UBIFS_DATA_NODE_SZ; ++ ++ key_read(c, &dn->key, &key); ++ printk(KERN_DEBUG "\tkey %s\n", DBGKEY(&key)); ++ printk(KERN_DEBUG "\tsize %u\n", ++ le32_to_cpu(dn->size)); ++ printk(KERN_DEBUG "\tcompr_typ %d\n", ++ (int)le16_to_cpu(dn->compr_type)); ++ printk(KERN_DEBUG "\tdata size %d\n", ++ dlen); ++ printk(KERN_DEBUG "\tdata:\n"); ++ print_hex_dump(KERN_DEBUG, "\t", DUMP_PREFIX_OFFSET, 32, 1, ++ (void *)&dn->data, dlen, 0); ++ break; ++ } ++ case UBIFS_TRUN_NODE: ++ { ++ const struct ubifs_trun_node *trun = node; ++ ++ printk(KERN_DEBUG "\tinum %u\n", ++ le32_to_cpu(trun->inum)); ++ printk(KERN_DEBUG "\told_size %llu\n", ++ (unsigned long long)le64_to_cpu(trun->old_size)); ++ printk(KERN_DEBUG "\tnew_size %llu\n", ++ (unsigned long long)le64_to_cpu(trun->new_size)); ++ break; ++ } ++ case UBIFS_IDX_NODE: ++ { ++ const struct ubifs_idx_node *idx = node; ++ ++ n = le16_to_cpu(idx->child_cnt); ++ printk(KERN_DEBUG "\tchild_cnt %d\n", n); ++ printk(KERN_DEBUG "\tlevel %d\n", ++ (int)le16_to_cpu(idx->level)); ++ printk(KERN_DEBUG "\tBranches:\n"); ++ ++ for (i = 0; i < n && i < c->fanout - 1; i++) { ++ const struct ubifs_branch *br; ++ ++ br = ubifs_idx_branch(c, idx, i); ++ key_read(c, &br->key, &key); ++ printk(KERN_DEBUG "\t%d: LEB %d:%d len %d key %s\n", ++ i, le32_to_cpu(br->lnum), le32_to_cpu(br->offs), ++ le32_to_cpu(br->len), DBGKEY(&key)); ++ } ++ break; ++ } ++ case UBIFS_CS_NODE: ++ break; ++ case UBIFS_ORPH_NODE: ++ { ++ const struct ubifs_orph_node *orph = node; ++ ++ printk(KERN_DEBUG "\tcommit number %llu\n", ++ (unsigned long long) ++ le64_to_cpu(orph->cmt_no) & LLONG_MAX); ++ printk(KERN_DEBUG "\tlast node flag %llu\n", ++ (unsigned long long)(le64_to_cpu(orph->cmt_no)) >> 63); ++ n = (le32_to_cpu(ch->len) - UBIFS_ORPH_NODE_SZ) >> 3; ++ printk(KERN_DEBUG "\t%d orphan inode numbers:\n", n); ++ for (i = 0; i < n; i++) ++ printk(KERN_DEBUG "\t ino %llu\n", ++ le64_to_cpu(orph->inos[i])); ++ break; ++ } ++ default: ++ printk(KERN_DEBUG "node type %d was not recognized\n", ++ (int)ch->node_type); ++ } ++ spin_unlock(&dbg_lock); ++} ++ ++void dbg_dump_budget_req(const struct ubifs_budget_req *req) ++{ ++ spin_lock(&dbg_lock); ++ printk(KERN_DEBUG "Budgeting request: new_ino %d, dirtied_ino %d\n", ++ req->new_ino, req->dirtied_ino); ++ printk(KERN_DEBUG "\tnew_ino_d %d, dirtied_ino_d %d\n", ++ req->new_ino_d, req->dirtied_ino_d); ++ printk(KERN_DEBUG "\tnew_page %d, dirtied_page %d\n", ++ req->new_page, req->dirtied_page); ++ printk(KERN_DEBUG "\tnew_dent %d, mod_dent %d\n", ++ req->new_dent, req->mod_dent); ++ printk(KERN_DEBUG "\tidx_growth %d\n", req->idx_growth); ++ printk(KERN_DEBUG "\tdata_growth %d dd_growth %d\n", ++ req->data_growth, req->dd_growth); ++ spin_unlock(&dbg_lock); ++} ++ ++void dbg_dump_lstats(const struct ubifs_lp_stats *lst) ++{ ++ spin_lock(&dbg_lock); ++ printk(KERN_DEBUG "Lprops statistics: empty_lebs %d, idx_lebs %d\n", ++ lst->empty_lebs, lst->idx_lebs); ++ printk(KERN_DEBUG "\ttaken_empty_lebs %d, total_free %lld, " ++ "total_dirty %lld\n", lst->taken_empty_lebs, lst->total_free, ++ lst->total_dirty); ++ printk(KERN_DEBUG "\ttotal_used %lld, total_dark %lld, " ++ "total_dead %lld\n", lst->total_used, lst->total_dark, ++ lst->total_dead); ++ spin_unlock(&dbg_lock); ++} ++ ++void dbg_dump_budg(struct ubifs_info *c) ++{ ++ int i; ++ struct rb_node *rb; ++ struct ubifs_bud *bud; ++ struct ubifs_gced_idx_leb *idx_gc; ++ ++ spin_lock(&dbg_lock); ++ printk(KERN_DEBUG "Budgeting info: budg_data_growth %lld, " ++ "budg_dd_growth %lld, budg_idx_growth %lld\n", ++ c->budg_data_growth, c->budg_dd_growth, c->budg_idx_growth); ++ printk(KERN_DEBUG "\tdata budget sum %lld, total budget sum %lld, " ++ "freeable_cnt %d\n", c->budg_data_growth + c->budg_dd_growth, ++ c->budg_data_growth + c->budg_dd_growth + c->budg_idx_growth, ++ c->freeable_cnt); ++ printk(KERN_DEBUG "\tmin_idx_lebs %d, old_idx_sz %lld, " ++ "calc_idx_sz %lld, idx_gc_cnt %d\n", c->min_idx_lebs, ++ c->old_idx_sz, c->calc_idx_sz, c->idx_gc_cnt); ++ printk(KERN_DEBUG "\tdirty_pg_cnt %ld, dirty_ino_cnt %ld, " ++ "dirty_zn_cnt %ld, clean_zn_cnt %ld\n", ++ atomic_long_read(&c->dirty_pg_cnt), ++ atomic_long_read(&c->dirty_ino_cnt), ++ atomic_long_read(&c->dirty_zn_cnt), ++ atomic_long_read(&c->clean_zn_cnt)); ++ printk(KERN_DEBUG "\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n", ++ c->dark_wm, c->dead_wm, c->max_idx_node_sz); ++ printk(KERN_DEBUG "\tgc_lnum %d, ihead_lnum %d\n", ++ c->gc_lnum, c->ihead_lnum); ++ for (i = 0; i < c->jhead_cnt; i++) ++ printk(KERN_DEBUG "\tjhead %d\t LEB %d\n", ++ c->jheads[i].wbuf.jhead, c->jheads[i].wbuf.lnum); ++ for (rb = rb_first(&c->buds); rb; rb = rb_next(rb)) { ++ bud = rb_entry(rb, struct ubifs_bud, rb); ++ printk(KERN_DEBUG "\tbud LEB %d\n", bud->lnum); ++ } ++ list_for_each_entry(bud, &c->old_buds, list) ++ printk(KERN_DEBUG "\told bud LEB %d\n", bud->lnum); ++ list_for_each_entry(idx_gc, &c->idx_gc, list) ++ printk(KERN_DEBUG "\tGC'ed idx LEB %d unmap %d\n", ++ idx_gc->lnum, idx_gc->unmap); ++ printk(KERN_DEBUG "\tcommit state %d\n", c->cmt_state); ++ spin_unlock(&dbg_lock); ++} ++ ++void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp) ++{ ++ printk(KERN_DEBUG "LEB %d lprops: free %d, dirty %d (used %d), " ++ "flags %#x\n", lp->lnum, lp->free, lp->dirty, ++ c->leb_size - lp->free - lp->dirty, lp->flags); ++} ++ ++void dbg_dump_lprops(struct ubifs_info *c) ++{ ++ int lnum, err; ++ struct ubifs_lprops lp; ++ struct ubifs_lp_stats lst; ++ ++ printk(KERN_DEBUG "Dumping LEB properties\n"); ++ ubifs_get_lp_stats(c, &lst); ++ dbg_dump_lstats(&lst); ++ ++ for (lnum = c->main_first; lnum < c->leb_cnt; lnum++) { ++ err = ubifs_read_one_lp(c, lnum, &lp); ++ if (err) ++ ubifs_err("cannot read lprops for LEB %d", lnum); ++ ++ dbg_dump_lprop(c, &lp); ++ } ++} ++ ++void dbg_dump_leb(const struct ubifs_info *c, int lnum) ++{ ++ struct ubifs_scan_leb *sleb; ++ struct ubifs_scan_node *snod; ++ ++ if (dbg_failure_mode) ++ return; ++ ++ printk(KERN_DEBUG "Dumping LEB %d\n", lnum); ++ ++ sleb = ubifs_scan(c, lnum, 0, c->dbg_buf); ++ if (IS_ERR(sleb)) { ++ ubifs_err("scan error %d", (int)PTR_ERR(sleb)); ++ return; ++ } ++ ++ printk(KERN_DEBUG "LEB %d has %d nodes ending at %d\n", lnum, ++ sleb->nodes_cnt, sleb->endpt); ++ ++ list_for_each_entry(snod, &sleb->nodes, list) { ++ cond_resched(); ++ printk(KERN_DEBUG "Dumping node at LEB %d:%d len %d\n", lnum, ++ snod->offs, snod->len); ++ dbg_dump_node(c, snod->node); ++ } ++ ++ ubifs_scan_destroy(sleb); ++ return; ++} ++ ++void dbg_dump_znode(const struct ubifs_info *c, ++ const struct ubifs_znode *znode) ++{ ++ int n; ++ const struct ubifs_zbranch *zbr; ++ ++ spin_lock(&dbg_lock); ++ if (znode->parent) ++ zbr = &znode->parent->zbranch[znode->iip]; ++ else ++ zbr = &c->zroot; ++ ++ printk(KERN_DEBUG "znode %p, LEB %d:%d len %d parent %p iip %d level %d" ++ " child_cnt %d flags %lx\n", znode, zbr->lnum, zbr->offs, ++ zbr->len, znode->parent, znode->iip, znode->level, ++ znode->child_cnt, znode->flags); ++ ++ if (znode->child_cnt <= 0 || znode->child_cnt > c->fanout) { ++ spin_unlock(&dbg_lock); ++ return; ++ } ++ ++ printk(KERN_DEBUG "zbranches:\n"); ++ for (n = 0; n < znode->child_cnt; n++) { ++ zbr = &znode->zbranch[n]; ++ if (znode->level > 0) ++ printk(KERN_DEBUG "\t%d: znode %p LEB %d:%d len %d key " ++ "%s\n", n, zbr->znode, zbr->lnum, ++ zbr->offs, zbr->len, ++ DBGKEY(&zbr->key)); ++ else ++ printk(KERN_DEBUG "\t%d: LNC %p LEB %d:%d len %d key " ++ "%s\n", n, zbr->znode, zbr->lnum, ++ zbr->offs, zbr->len, ++ DBGKEY(&zbr->key)); ++ } ++ spin_unlock(&dbg_lock); ++} ++ ++void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat) ++{ ++ int i; ++ ++ printk(KERN_DEBUG "Dumping heap cat %d (%d elements)\n", ++ cat, heap->cnt); ++ for (i = 0; i < heap->cnt; i++) { ++ struct ubifs_lprops *lprops = heap->arr[i]; ++ ++ printk(KERN_DEBUG "\t%d. LEB %d hpos %d free %d dirty %d " ++ "flags %d\n", i, lprops->lnum, lprops->hpos, ++ lprops->free, lprops->dirty, lprops->flags); ++ } ++} ++ ++void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode, ++ struct ubifs_nnode *parent, int iip) ++{ ++ int i; ++ ++ printk(KERN_DEBUG "Dumping pnode:\n"); ++ printk(KERN_DEBUG "\taddress %zx parent %zx cnext %zx\n", ++ (size_t)pnode, (size_t)parent, (size_t)pnode->cnext); ++ printk(KERN_DEBUG "\tflags %lu iip %d level %d num %d\n", ++ pnode->flags, iip, pnode->level, pnode->num); ++ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { ++ struct ubifs_lprops *lp = &pnode->lprops[i]; ++ ++ printk(KERN_DEBUG "\t%d: free %d dirty %d flags %d lnum %d\n", ++ i, lp->free, lp->dirty, lp->flags, lp->lnum); ++ } ++} ++ ++void dbg_dump_tnc(struct ubifs_info *c) ++{ ++ struct ubifs_znode *znode; ++ int level; ++ ++ printk(KERN_DEBUG "\n"); ++ printk(KERN_DEBUG "Dumping the TNC tree\n"); ++ znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL); ++ level = znode->level; ++ printk(KERN_DEBUG "== Level %d ==\n", level); ++ while (znode) { ++ if (level != znode->level) { ++ level = znode->level; ++ printk(KERN_DEBUG "== Level %d ==\n", level); ++ } ++ dbg_dump_znode(c, znode); ++ znode = ubifs_tnc_levelorder_next(c->zroot.znode, znode); ++ } ++ ++ printk(KERN_DEBUG "\n"); ++} ++ ++static int dump_znode(struct ubifs_info *c, struct ubifs_znode *znode, ++ void *priv) ++{ ++ dbg_dump_znode(c, znode); ++ return 0; ++} ++ ++/** ++ * dbg_dump_index - dump the on-flash index. ++ * @c: UBIFS file-system description object ++ * ++ * This function dumps whole UBIFS indexing B-tree, unlike 'dbg_dump_tnc()' ++ * which dumps only in-memory znodes and does not read znodes which from flash. ++ */ ++void dbg_dump_index(struct ubifs_info *c) ++{ ++ dbg_walk_index(c, NULL, dump_znode, NULL); ++} ++ ++/* ++ * dbg_check_dir - check directory inode size and link count. ++ * @c: UBIFS file-system description object ++ * @dir: the directory to calculate size for ++ * @size: the result is returned here ++ * ++ * This function makes sure that directory size and link count are correct. ++ * Returns zero in case of success and a negative error code in case of ++ * failure. ++ * ++ * Note, it is good idea to make sure the @dir->i_mutex is locked before ++ * calling this function. ++ */ ++int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir) ++{ ++ unsigned int nlink = 2; ++ union ubifs_key key; ++ struct ubifs_dent_node *dent, *pdent = NULL; ++ struct qstr nm = { .name = NULL }; ++ loff_t size = UBIFS_INO_NODE_SZ; ++ ++ if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) ++ return 0; ++ ++ if (!S_ISDIR(dir->i_mode)) ++ return 0; ++ ++ lowest_dent_key(c, &key, dir->i_ino); ++ while (1) { ++ int err; ++ ++ dent = ubifs_tnc_next_ent(c, &key, &nm); ++ if (IS_ERR(dent)) { ++ err = PTR_ERR(dent); ++ if (err == -ENOENT) ++ break; ++ return err; ++ } ++ ++ nm.name = dent->name; ++ nm.len = le16_to_cpu(dent->nlen); ++ size += CALC_DENT_SIZE(nm.len); ++ if (dent->type == UBIFS_ITYPE_DIR) ++ nlink += 1; ++ kfree(pdent); ++ pdent = dent; ++ key_read(c, &dent->key, &key); ++ } ++ kfree(pdent); ++ ++ if (i_size_read(dir) != size) { ++ ubifs_err("directory inode %lu has size %llu, " ++ "but calculated size is %llu", dir->i_ino, ++ (unsigned long long)i_size_read(dir), ++ (unsigned long long)size); ++ dump_stack(); ++ return -EINVAL; ++ } ++ if (dir->i_nlink != nlink) { ++ ubifs_err("directory inode %lu has nlink %u, but calculated " ++ "nlink is %u", dir->i_ino, dir->i_nlink, nlink); ++ dump_stack(); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/** ++ * dbg_check_key_order - make sure that colliding keys are properly ordered. ++ * @c: UBIFS file-system description object ++ * @zbr1: first zbranch ++ * @zbr1: following zbranch ++ * ++ * In UBIFS indexing B-tree colliding keys has to be sorted in binary order of ++ * names of the direntries/xentries which are referred by the keys. This ++ * function reads direntries/xentries referred by @zbr1 and @zbr2 and makes ++ * sure the name of direntry/xentry referred by @zbr1 is less than ++ * direntry/xentry referred by @zbr2. Returns zero if this is true, %1 if not, ++ * and a negative error code in case of failure. ++ */ ++static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1, ++ struct ubifs_zbranch *zbr2) ++{ ++ int err, nlen1, nlen2, cmp; ++ struct ubifs_dent_node *dent1, *dent2; ++ union ubifs_key key; ++ ++ ubifs_assert(!keys_cmp(c, &zbr1->key, &zbr2->key)); ++ dent1 = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS); ++ if (!dent1) ++ return -ENOMEM; ++ dent2 = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS); ++ if (!dent2) { ++ err = -ENOMEM; ++ goto out_free; ++ } ++ ++ err = ubifs_tnc_read_node(c, zbr1, dent1); ++ if (err) ++ goto out_free; ++ err = ubifs_validate_entry(c, dent1); ++ if (err) ++ goto out_free; ++ ++ err = ubifs_tnc_read_node(c, zbr2, dent2); ++ if (err) ++ goto out_free; ++ err = ubifs_validate_entry(c, dent2); ++ if (err) ++ goto out_free; ++ ++ /* Make sure node keys are the same as in zbranch */ ++ err = 1; ++ key_read(c, &dent1->key, &key); ++ if (keys_cmp(c, &zbr1->key, &key)) { ++ dbg_err("1st entry at %d:%d has key %s", zbr1->lnum, ++ zbr1->offs, DBGKEY(&key)); ++ dbg_err("but it should have key %s according to tnc", ++ DBGKEY(&zbr1->key)); ++ dbg_dump_node(c, dent1); ++ goto out_free; ++ } ++ ++ key_read(c, &dent2->key, &key); ++ if (keys_cmp(c, &zbr2->key, &key)) { ++ dbg_err("2nd entry at %d:%d has key %s", zbr1->lnum, ++ zbr1->offs, DBGKEY(&key)); ++ dbg_err("but it should have key %s according to tnc", ++ DBGKEY(&zbr2->key)); ++ dbg_dump_node(c, dent2); ++ goto out_free; ++ } ++ ++ nlen1 = le16_to_cpu(dent1->nlen); ++ nlen2 = le16_to_cpu(dent2->nlen); ++ ++ cmp = memcmp(dent1->name, dent2->name, min_t(int, nlen1, nlen2)); ++ if (cmp < 0 || (cmp == 0 && nlen1 < nlen2)) { ++ err = 0; ++ goto out_free; ++ } ++ if (cmp == 0 && nlen1 == nlen2) ++ dbg_err("2 xent/dent nodes with the same name"); ++ else ++ dbg_err("bad order of colliding key %s", ++ DBGKEY(&key)); ++ ++ dbg_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs); ++ dbg_dump_node(c, dent1); ++ dbg_msg("second node at %d:%d\n", zbr2->lnum, zbr2->offs); ++ dbg_dump_node(c, dent2); ++ ++out_free: ++ kfree(dent2); ++ kfree(dent1); ++ return err; ++} ++ ++/** ++ * dbg_check_znode - check if znode is all right. ++ * @c: UBIFS file-system description object ++ * @zbr: zbranch which points to this znode ++ * ++ * This function makes sure that znode referred to by @zbr is all right. ++ * Returns zero if it is, and %-EINVAL if it is not. ++ */ ++static int dbg_check_znode(struct ubifs_info *c, struct ubifs_zbranch *zbr) ++{ ++ struct ubifs_znode *znode = zbr->znode; ++ struct ubifs_znode *zp = znode->parent; ++ int n, err, cmp; ++ ++ if (znode->child_cnt <= 0 || znode->child_cnt > c->fanout) { ++ err = 1; ++ goto out; ++ } ++ if (znode->level < 0) { ++ err = 2; ++ goto out; ++ } ++ if (znode->iip < 0 || znode->iip >= c->fanout) { ++ err = 3; ++ goto out; ++ } ++ ++ if (zbr->len == 0) ++ /* Only dirty zbranch may have no on-flash nodes */ ++ if (!ubifs_zn_dirty(znode)) { ++ err = 4; ++ goto out; ++ } ++ ++ if (ubifs_zn_dirty(znode)) { ++ /* ++ * If znode is dirty, its parent has to be dirty as well. The ++ * order of the operation is important, so we have to have ++ * memory barriers. ++ */ ++ smp_mb(); ++ if (zp && !ubifs_zn_dirty(zp)) { ++ /* ++ * The dirty flag is atomic and is cleared outside the ++ * TNC mutex, so znode's dirty flag may now have ++ * been cleared. The child is always cleared before the ++ * parent, so we just need to check again. ++ */ ++ smp_mb(); ++ if (ubifs_zn_dirty(znode)) { ++ err = 5; ++ goto out; ++ } ++ } ++ } ++ ++ if (zp) { ++ const union ubifs_key *min, *max; ++ ++ if (znode->level != zp->level - 1) { ++ err = 6; ++ goto out; ++ } ++ ++ /* Make sure the 'parent' pointer in our znode is correct */ ++ err = ubifs_search_zbranch(c, zp, &zbr->key, &n); ++ if (!err) { ++ /* This zbranch does not exist in the parent */ ++ err = 7; ++ goto out; ++ } ++ ++ if (znode->iip >= zp->child_cnt) { ++ err = 8; ++ goto out; ++ } ++ ++ if (znode->iip != n) { ++ /* This may happen only in case of collisions */ ++ if (keys_cmp(c, &zp->zbranch[n].key, ++ &zp->zbranch[znode->iip].key)) { ++ err = 9; ++ goto out; ++ } ++ n = znode->iip; ++ } ++ ++ /* ++ * Make sure that the first key in our znode is greater than or ++ * equal to the key in the pointing zbranch. ++ */ ++ min = &zbr->key; ++ cmp = keys_cmp(c, min, &znode->zbranch[0].key); ++ if (cmp == 1) { ++ err = 10; ++ goto out; ++ } ++ ++ if (n + 1 < zp->child_cnt) { ++ max = &zp->zbranch[n + 1].key; ++ ++ /* ++ * Make sure the last key in our znode is less or ++ * equivalent than the the key in zbranch which goes ++ * after our pointing zbranch. ++ */ ++ cmp = keys_cmp(c, max, ++ &znode->zbranch[znode->child_cnt - 1].key); ++ if (cmp == -1) { ++ err = 11; ++ goto out; ++ } ++ } ++ } else { ++ /* This may only be root znode */ ++ if (zbr != &c->zroot) { ++ err = 12; ++ goto out; ++ } ++ } ++ ++ /* ++ * Make sure that next key is greater or equivalent then the previous ++ * one. ++ */ ++ for (n = 1; n < znode->child_cnt; n++) { ++ cmp = keys_cmp(c, &znode->zbranch[n - 1].key, ++ &znode->zbranch[n].key); ++ if (cmp > 0) { ++ err = 13; ++ goto out; ++ } ++ if (cmp == 0) { ++ /* This can only be keys with colliding hash */ ++ if (!is_hash_key(c, &znode->zbranch[n].key)) { ++ err = 14; ++ goto out; ++ } ++ ++ if (znode->level != 0 || c->replaying) ++ continue; ++ ++ /* ++ * Colliding keys should follow binary order of ++ * corresponding xentry/dentry names. ++ */ ++ err = dbg_check_key_order(c, &znode->zbranch[n - 1], ++ &znode->zbranch[n]); ++ if (err < 0) ++ return err; ++ if (err) { ++ err = 15; ++ goto out; ++ } ++ } ++ } ++ ++ for (n = 0; n < znode->child_cnt; n++) { ++ if (!znode->zbranch[n].znode && ++ (znode->zbranch[n].lnum == 0 || ++ znode->zbranch[n].len == 0)) { ++ err = 16; ++ goto out; ++ } ++ ++ if (znode->zbranch[n].lnum != 0 && ++ znode->zbranch[n].len == 0) { ++ err = 17; ++ goto out; ++ } ++ ++ if (znode->zbranch[n].lnum == 0 && ++ znode->zbranch[n].len != 0) { ++ err = 18; ++ goto out; ++ } ++ ++ if (znode->zbranch[n].lnum == 0 && ++ znode->zbranch[n].offs != 0) { ++ err = 19; ++ goto out; ++ } ++ ++ if (znode->level != 0 && znode->zbranch[n].znode) ++ if (znode->zbranch[n].znode->parent != znode) { ++ err = 20; ++ goto out; ++ } ++ } ++ ++ return 0; ++ ++out: ++ ubifs_err("failed, error %d", err); ++ ubifs_msg("dump of the znode"); ++ dbg_dump_znode(c, znode); ++ if (zp) { ++ ubifs_msg("dump of the parent znode"); ++ dbg_dump_znode(c, zp); ++ } ++ dump_stack(); ++ return -EINVAL; ++} ++ ++/** ++ * dbg_check_tnc - check TNC tree. ++ * @c: UBIFS file-system description object ++ * @extra: do extra checks that are possible at start commit ++ * ++ * This function traverses whole TNC tree and checks every znode. Returns zero ++ * if everything is all right and %-EINVAL if something is wrong with TNC. ++ */ ++int dbg_check_tnc(struct ubifs_info *c, int extra) ++{ ++ struct ubifs_znode *znode; ++ long clean_cnt = 0, dirty_cnt = 0; ++ int err, last; ++ ++ if (!(ubifs_chk_flags & UBIFS_CHK_TNC)) ++ return 0; ++ ++ ubifs_assert(mutex_is_locked(&c->tnc_mutex)); ++ if (!c->zroot.znode) ++ return 0; ++ ++ znode = ubifs_tnc_postorder_first(c->zroot.znode); ++ while (1) { ++ struct ubifs_znode *prev; ++ struct ubifs_zbranch *zbr; ++ ++ if (!znode->parent) ++ zbr = &c->zroot; ++ else ++ zbr = &znode->parent->zbranch[znode->iip]; ++ ++ err = dbg_check_znode(c, zbr); ++ if (err) ++ return err; ++ ++ if (extra) { ++ if (ubifs_zn_dirty(znode)) ++ dirty_cnt += 1; ++ else ++ clean_cnt += 1; ++ } ++ ++ prev = znode; ++ znode = ubifs_tnc_postorder_next(znode); ++ if (!znode) ++ break; ++ ++ /* ++ * If the last key of this znode is equivalent to the first key ++ * of the next znode (collision), then check order of the keys. ++ */ ++ last = prev->child_cnt - 1; ++ if (prev->level == 0 && znode->level == 0 && !c->replaying && ++ !keys_cmp(c, &prev->zbranch[last].key, ++ &znode->zbranch[0].key)) { ++ err = dbg_check_key_order(c, &prev->zbranch[last], ++ &znode->zbranch[0]); ++ if (err < 0) ++ return err; ++ if (err) { ++ ubifs_msg("first znode"); ++ dbg_dump_znode(c, prev); ++ ubifs_msg("second znode"); ++ dbg_dump_znode(c, znode); ++ return -EINVAL; ++ } ++ } ++ } ++ ++ if (extra) { ++ if (clean_cnt != atomic_long_read(&c->clean_zn_cnt)) { ++ ubifs_err("incorrect clean_zn_cnt %ld, calculated %ld", ++ atomic_long_read(&c->clean_zn_cnt), ++ clean_cnt); ++ return -EINVAL; ++ } ++ if (dirty_cnt != atomic_long_read(&c->dirty_zn_cnt)) { ++ ubifs_err("incorrect dirty_zn_cnt %ld, calculated %ld", ++ atomic_long_read(&c->dirty_zn_cnt), ++ dirty_cnt); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++/** ++ * dbg_walk_index - walk the on-flash index. ++ * @c: UBIFS file-system description object ++ * @leaf_cb: called for each leaf node ++ * @znode_cb: called for each indexing node ++ * @priv: private date which is passed to callbacks ++ * ++ * This function walks the UBIFS index and calls the @leaf_cb for each leaf ++ * node and @znode_cb for each indexing node. Returns zero in case of success ++ * and a negative error code in case of failure. ++ * ++ * It would be better if this function removed every znode it pulled to into ++ * the TNC, so that the behavior more closely matched the non-debugging ++ * behavior. ++ */ ++int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb, ++ dbg_znode_callback znode_cb, void *priv) ++{ ++ int err; ++ struct ubifs_zbranch *zbr; ++ struct ubifs_znode *znode, *child; ++ ++ mutex_lock(&c->tnc_mutex); ++ /* If the root indexing node is not in TNC - pull it */ ++ if (!c->zroot.znode) { ++ c->zroot.znode = ubifs_load_znode(c, &c->zroot, NULL, 0); ++ if (IS_ERR(c->zroot.znode)) { ++ err = PTR_ERR(c->zroot.znode); ++ c->zroot.znode = NULL; ++ goto out_unlock; ++ } ++ } ++ ++ /* ++ * We are going to traverse the indexing tree in the postorder manner. ++ * Go down and find the leftmost indexing node where we are going to ++ * start from. ++ */ ++ znode = c->zroot.znode; ++ while (znode->level > 0) { ++ zbr = &znode->zbranch[0]; ++ child = zbr->znode; ++ if (!child) { ++ child = ubifs_load_znode(c, zbr, znode, 0); ++ if (IS_ERR(child)) { ++ err = PTR_ERR(child); ++ goto out_unlock; ++ } ++ zbr->znode = child; ++ } ++ ++ znode = child; ++ } ++ ++ /* Iterate over all indexing nodes */ ++ while (1) { ++ int idx; ++ ++ cond_resched(); ++ ++ if (znode_cb) { ++ err = znode_cb(c, znode, priv); ++ if (err) { ++ ubifs_err("znode checking function returned " ++ "error %d", err); ++ dbg_dump_znode(c, znode); ++ goto out_dump; ++ } ++ } ++ if (leaf_cb && znode->level == 0) { ++ for (idx = 0; idx < znode->child_cnt; idx++) { ++ zbr = &znode->zbranch[idx]; ++ err = leaf_cb(c, zbr, priv); ++ if (err) { ++ ubifs_err("leaf checking function " ++ "returned error %d, for leaf " ++ "at LEB %d:%d", ++ err, zbr->lnum, zbr->offs); ++ goto out_dump; ++ } ++ } ++ } ++ ++ if (!znode->parent) ++ break; ++ ++ idx = znode->iip + 1; ++ znode = znode->parent; ++ if (idx < znode->child_cnt) { ++ /* Switch to the next index in the parent */ ++ zbr = &znode->zbranch[idx]; ++ child = zbr->znode; ++ if (!child) { ++ child = ubifs_load_znode(c, zbr, znode, idx); ++ if (IS_ERR(child)) { ++ err = PTR_ERR(child); ++ goto out_unlock; ++ } ++ zbr->znode = child; ++ } ++ znode = child; ++ } else ++ /* ++ * This is the last child, switch to the parent and ++ * continue. ++ */ ++ continue; ++ ++ /* Go to the lowest leftmost znode in the new sub-tree */ ++ while (znode->level > 0) { ++ zbr = &znode->zbranch[0]; ++ child = zbr->znode; ++ if (!child) { ++ child = ubifs_load_znode(c, zbr, znode, 0); ++ if (IS_ERR(child)) { ++ err = PTR_ERR(child); ++ goto out_unlock; ++ } ++ zbr->znode = child; ++ } ++ znode = child; ++ } ++ } ++ ++ mutex_unlock(&c->tnc_mutex); ++ return 0; ++ ++out_dump: ++ if (znode->parent) ++ zbr = &znode->parent->zbranch[znode->iip]; ++ else ++ zbr = &c->zroot; ++ ubifs_msg("dump of znode at LEB %d:%d", zbr->lnum, zbr->offs); ++ dbg_dump_znode(c, znode); ++out_unlock: ++ mutex_unlock(&c->tnc_mutex); ++ return err; ++} ++ ++/** ++ * add_size - add znode size to partially calculated index size. ++ * @c: UBIFS file-system description object ++ * @znode: znode to add size for ++ * @priv: partially calculated index size ++ * ++ * This is a helper function for 'dbg_check_idx_size()' which is called for ++ * every indexing node and adds its size to the 'long long' variable pointed to ++ * by @priv. ++ */ ++static int add_size(struct ubifs_info *c, struct ubifs_znode *znode, void *priv) ++{ ++ long long *idx_size = priv; ++ int add; ++ ++ add = ubifs_idx_node_sz(c, znode->child_cnt); ++ add = ALIGN(add, 8); ++ *idx_size += add; ++ return 0; ++} ++ ++/** ++ * dbg_check_idx_size - check index size. ++ * @c: UBIFS file-system description object ++ * @idx_size: size to check ++ * ++ * This function walks the UBIFS index, calculates its size and checks that the ++ * size is equivalent to @idx_size. Returns zero in case of success and a ++ * negative error code in case of failure. ++ */ ++int dbg_check_idx_size(struct ubifs_info *c, long long idx_size) ++{ ++ int err; ++ long long calc = 0; ++ ++ if (!(ubifs_chk_flags & UBIFS_CHK_IDX_SZ)) ++ return 0; ++ ++ err = dbg_walk_index(c, NULL, add_size, &calc); ++ if (err) { ++ ubifs_err("error %d while walking the index", err); ++ return err; ++ } ++ ++ if (calc != idx_size) { ++ ubifs_err("index size check failed: calculated size is %lld, " ++ "should be %lld", calc, idx_size); ++ dump_stack(); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/** ++ * fsck_inode - information about an inode used when checking the file-system. ++ * @rb: link in the RB-tree of inodes ++ * @inum: inode number ++ * @mode: inode type, permissions, etc ++ * @nlink: inode link count ++ * @xatt_cnt: count of extended attributes ++ * @references: how many directory/xattr entries refer this inode (calculated ++ * while walking the index) ++ * @calc_cnt: for directory inode count of child directories, for regular files ++ * count of extended attributes ++ * @size: inode size (read from on-flash inode) ++ * @xattr_sz: summary size of all extended attributes (read from on-flash ++ * inode) ++ * @calc_sz: for directories calculated directory size, for regular files ++ * calculated summary size of all extended attributes ++ */ ++struct fsck_inode { ++ struct rb_node rb; ++ ino_t inum; ++ umode_t mode; ++ int nlink; ++ int xattr_cnt; ++ int references; ++ int calc_cnt; ++ long long size; ++ long long xattr_sz; ++ long long calc_sz; ++}; ++ ++/** ++ * fsck_data - private FS checking information. ++ * @inodes: RB-tree of all inodes (contains @struct fsck_inode objects) ++ */ ++struct fsck_data { ++ struct rb_root inodes; ++}; ++ ++/** ++ * add_inode - add inode information to RB-tree of inodes. ++ * @c: UBIFS file-system description object ++ * @fsckd: FS checking information ++ * @ino: raw UBIFS inode to add ++ * ++ * This is a helper function for 'check_leaf()' which adds information about ++ * inode @ino to the RB-tree of inodes. Returns inode information pointer in ++ * case of success and a negative error code in case of failure. ++ */ ++static struct fsck_inode *add_inode(struct ubifs_info *c, ++ struct fsck_data *fsckd, ++ struct ubifs_ino_node *ino) ++{ ++ struct rb_node **p, *parent = NULL; ++ struct fsck_inode *fscki; ++ ino_t inum = key_inum_flash(c, &ino->key); ++ ++ p = &fsckd->inodes.rb_node; ++ while (*p) { ++ parent = *p; ++ fscki = rb_entry(parent, struct fsck_inode, rb); ++ if (inum < fscki->inum) ++ p = &(*p)->rb_left; ++ else if (inum > fscki->inum) ++ p = &(*p)->rb_right; ++ else ++ return fscki; ++ } ++ ++ fscki = kzalloc(sizeof(struct fsck_inode), GFP_NOFS); ++ if (!fscki) ++ return ERR_PTR(-ENOMEM); ++ ++ fscki->inum = inum; ++ fscki->nlink = le32_to_cpu(ino->nlink); ++ fscki->size = le64_to_cpu(ino->size); ++ fscki->xattr_cnt = le32_to_cpu(ino->xattr_cnt); ++ fscki->xattr_sz = le64_to_cpu(ino->xattr_size); ++ fscki->mode = le32_to_cpu(ino->mode); ++ if (S_ISDIR(fscki->mode)) { ++ fscki->calc_sz = UBIFS_INO_NODE_SZ; ++ fscki->calc_cnt = 2; ++ } ++ rb_link_node(&fscki->rb, parent, p); ++ rb_insert_color(&fscki->rb, &fsckd->inodes); ++ return fscki; ++} ++ ++/** ++ * search_inode - search inode in the RB-tree of inodes. ++ * @fsckd: FS checking information ++ * @inum: inode number to search ++ * ++ * This is a helper function for 'check_leaf()' which searches inode @inum in ++ * the RB-tree of inodes and returns an inode information pointer or %NULL if ++ * the inode was not found. ++ */ ++static struct fsck_inode *search_inode(struct fsck_data *fsckd, ino_t inum) ++{ ++ struct rb_node *p; ++ struct fsck_inode *fscki; ++ ++ p = fsckd->inodes.rb_node; ++ while (p) { ++ fscki = rb_entry(p, struct fsck_inode, rb); ++ if (inum < fscki->inum) ++ p = p->rb_left; ++ else if (inum > fscki->inum) ++ p = p->rb_right; ++ else ++ return fscki; ++ } ++ return NULL; ++} ++ ++/** ++ * read_add_inode - read inode node and add it to RB-tree of inodes. ++ * @c: UBIFS file-system description object ++ * @fsckd: FS checking information ++ * @inum: inode number to read ++ * ++ * This is a helper function for 'check_leaf()' which finds inode node @inum in ++ * the index, reads it, and adds it to the RB-tree of inodes. Returns inode ++ * information pointer in case of success and a negative error code in case of ++ * failure. ++ */ ++static struct fsck_inode *read_add_inode(struct ubifs_info *c, ++ struct fsck_data *fsckd, ino_t inum) ++{ ++ int n, err; ++ union ubifs_key key; ++ struct ubifs_znode *znode; ++ struct ubifs_zbranch *zbr; ++ struct ubifs_ino_node *ino; ++ struct fsck_inode *fscki; ++ ++ fscki = search_inode(fsckd, inum); ++ if (fscki) ++ return fscki; ++ ++ ino_key_init(c, &key, inum); ++ err = ubifs_lookup_level0(c, &key, &znode, &n); ++ if (!err) { ++ ubifs_err("inode %lu not found in index", inum); ++ return ERR_PTR(-ENOENT); ++ } else if (err < 0) { ++ ubifs_err("error %d while looking up inode %lu", err, inum); ++ return ERR_PTR(err); ++ } ++ ++ zbr = &znode->zbranch[n]; ++ if (zbr->len < UBIFS_INO_NODE_SZ) { ++ ubifs_err("bad node %lu node length %d", inum, zbr->len); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ ino = kmalloc(zbr->len, GFP_NOFS); ++ if (!ino) ++ return ERR_PTR(-ENOMEM); ++ ++ err = ubifs_tnc_read_node(c, zbr, ino); ++ if (err) { ++ ubifs_err("cannot read inode node at LEB %d:%d, error %d", ++ zbr->lnum, zbr->offs, err); ++ kfree(ino); ++ return ERR_PTR(err); ++ } ++ ++ fscki = add_inode(c, fsckd, ino); ++ kfree(ino); ++ if (IS_ERR(fscki)) { ++ ubifs_err("error %ld while adding inode %lu node", ++ PTR_ERR(fscki), inum); ++ return fscki; ++ } ++ ++ return fscki; ++} ++ ++/** ++ * check_leaf - check leaf node. ++ * @c: UBIFS file-system description object ++ * @zbr: zbranch of the leaf node to check ++ * @priv: FS checking information ++ * ++ * This is a helper function for 'dbg_check_filesystem()' which is called for ++ * every single leaf node while walking the indexing tree. It checks that the ++ * leaf node referred from the indexing tree exists, has correct CRC, and does ++ * some other basic validation. This function is also responsible for building ++ * an RB-tree of inodes - it adds all inodes into the RB-tree. It also ++ * calculates reference count, size, etc for each inode in order to later ++ * compare them to the information stored inside the inodes and detect possible ++ * inconsistencies. Returns zero in case of success and a negative error code ++ * in case of failure. ++ */ ++static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr, ++ void *priv) ++{ ++ ino_t inum; ++ void *node; ++ int err, type = key_type(c, &zbr->key); ++ struct fsck_inode *fscki; ++ ++ if (zbr->len < UBIFS_CH_SZ) { ++ ubifs_err("bad leaf length %d (LEB %d:%d)", ++ zbr->len, zbr->lnum, zbr->offs); ++ return -EINVAL; ++ } ++ ++ node = kmalloc(zbr->len, GFP_NOFS); ++ if (!node) ++ return -ENOMEM; ++ ++ err = ubifs_tnc_read_node(c, zbr, node); ++ if (err) { ++ ubifs_err("cannot read leaf node at LEB %d:%d, error %d", ++ zbr->lnum, zbr->offs, err); ++ goto out_free; ++ } ++ ++ /* If this is an inode node, add it to RB-tree of inodes */ ++ if (type == UBIFS_INO_KEY) { ++ fscki = add_inode(c, priv, node); ++ if (IS_ERR(fscki)) { ++ err = PTR_ERR(fscki); ++ ubifs_err("error %d while adding inode node", err); ++ goto out_dump; ++ } ++ goto out; ++ } ++ ++ if (type != UBIFS_DENT_KEY && type != UBIFS_XENT_KEY && ++ type != UBIFS_DATA_KEY) { ++ ubifs_err("unexpected node type %d at LEB %d:%d", ++ type, zbr->lnum, zbr->offs); ++ err = -EINVAL; ++ goto out_free; ++ } ++ ++ if (type == UBIFS_DATA_KEY) { ++ long long blk_offs; ++ struct ubifs_data_node *dn = node; ++ ++ /* ++ * Search the inode node this data node belongs to and insert ++ * it to the RB-tree of inodes. ++ */ ++ inum = key_inum_flash(c, &dn->key); ++ fscki = read_add_inode(c, priv, inum); ++ if (IS_ERR(fscki)) { ++ err = PTR_ERR(fscki); ++ ubifs_err("error %d while processing data node and " ++ "trying to find inode node %lu", err, inum); ++ goto out_dump; ++ } ++ ++ /* Make sure the data node is within inode size */ ++ blk_offs = (key_block_flash(c, &dn->key) << UBIFS_BLOCK_SHIFT); ++ blk_offs += le32_to_cpu(dn->size); ++ if (blk_offs > fscki->size) { ++ ubifs_err("data node at LEB %d:%d is not within inode " ++ "size %lld", zbr->lnum, zbr->offs, fscki->size); ++ err = -EINVAL; ++ goto out_dump; ++ } ++ } else { ++ int nlen; ++ struct ubifs_dent_node *dent = node; ++ struct fsck_inode *fscki1; ++ ++ err = ubifs_validate_entry(c, dent); ++ if (err) ++ goto out_dump; ++ ++ /* ++ * Search the inode node this entry refers to and the parent ++ * inode node and insert them to the RB-tree of inodes. ++ */ ++ inum = le64_to_cpu(dent->inum); ++ fscki = read_add_inode(c, priv, inum); ++ if (IS_ERR(fscki)) { ++ err = PTR_ERR(fscki); ++ ubifs_err("error %d while processing entry node and " ++ "trying to find inode node %lu", err, inum); ++ goto out_dump; ++ } ++ ++ /* Count how many direntries or xentries refers this inode */ ++ fscki->references += 1; ++ ++ inum = key_inum_flash(c, &dent->key); ++ fscki1 = read_add_inode(c, priv, inum); ++ if (IS_ERR(fscki1)) { ++ err = PTR_ERR(fscki); ++ ubifs_err("error %d while processing entry node and " ++ "trying to find parent inode node %lu", ++ err, inum); ++ goto out_dump; ++ } ++ ++ nlen = le16_to_cpu(dent->nlen); ++ if (type == UBIFS_XENT_KEY) { ++ fscki1->calc_cnt += 1; ++ fscki1->calc_sz += CALC_DENT_SIZE(nlen); ++ fscki1->calc_sz += CALC_XATTR_BYTES(fscki->size); ++ } else { ++ fscki1->calc_sz += CALC_DENT_SIZE(nlen); ++ if (dent->type == UBIFS_ITYPE_DIR) ++ fscki1->calc_cnt += 1; ++ } ++ } ++ ++out: ++ kfree(node); ++ return 0; ++ ++out_dump: ++ ubifs_msg("dump of node at LEB %d:%d", zbr->lnum, zbr->offs); ++ dbg_dump_node(c, node); ++out_free: ++ kfree(node); ++ return err; ++} ++ ++/** ++ * free_inodes - free RB-tree of inodes. ++ * @fsckd: FS checking information ++ */ ++static void free_inodes(struct fsck_data *fsckd) ++{ ++ struct rb_node *this = fsckd->inodes.rb_node; ++ struct fsck_inode *fscki; ++ ++ while (this) { ++ if (this->rb_left) ++ this = this->rb_left; ++ else if (this->rb_right) ++ this = this->rb_right; ++ else { ++ fscki = rb_entry(this, struct fsck_inode, rb); ++ this = rb_parent(this); ++ if (this) { ++ if (this->rb_left == &fscki->rb) ++ this->rb_left = NULL; ++ else ++ this->rb_right = NULL; ++ } ++ kfree(fscki); ++ } ++ } ++} ++ ++/** ++ * check_inodes - checks all inodes. ++ * @c: UBIFS file-system description object ++ * @fsckd: FS checking information ++ * ++ * This is a helper function for 'dbg_check_filesystem()' which walks the ++ * RB-tree of inodes after the index scan has been finished, and checks that ++ * inode nlink, size, etc are correct. Returns zero if inodes are fine, ++ * %-EINVAL if not, and a negative error code in case of failure. ++ */ ++static int check_inodes(struct ubifs_info *c, struct fsck_data *fsckd) ++{ ++ int n, err; ++ union ubifs_key key; ++ struct ubifs_znode *znode; ++ struct ubifs_zbranch *zbr; ++ struct ubifs_ino_node *ino; ++ struct fsck_inode *fscki; ++ struct rb_node *this = rb_first(&fsckd->inodes); ++ ++ while (this) { ++ fscki = rb_entry(this, struct fsck_inode, rb); ++ this = rb_next(this); ++ ++ if (S_ISDIR(fscki->mode)) { ++ /* ++ * Directories have to have exactly one reference (they ++ * cannot have hardlinks), although root inode is an ++ * exception. ++ */ ++ if (fscki->inum != UBIFS_ROOT_INO && ++ fscki->references != 1) { ++ ubifs_err("directory inode %lu has %d " ++ "direntries which refer it, but " ++ "should be 1", fscki->inum, ++ fscki->references); ++ goto out_dump; ++ } ++ if (fscki->inum == UBIFS_ROOT_INO && ++ fscki->references != 0) { ++ ubifs_err("root inode %lu has non-zero (%d) " ++ "direntries which refer it", ++ fscki->inum, fscki->references); ++ goto out_dump; ++ } ++ if (fscki->calc_sz != fscki->size) { ++ ubifs_err("directory inode %lu size is %lld, " ++ "but calculated size is %lld", ++ fscki->inum, fscki->size, ++ fscki->calc_sz); ++ goto out_dump; ++ } ++ if (fscki->calc_cnt != fscki->nlink) { ++ ubifs_err("directory inode %lu nlink is %d, " ++ "but calculated nlink is %d", ++ fscki->inum, fscki->nlink, ++ fscki->calc_cnt); ++ goto out_dump; ++ } ++ } else { ++ if (fscki->references != fscki->nlink) { ++ ubifs_err("inode %lu nlink is %d, but " ++ "calculated nlink is %d", fscki->inum, ++ fscki->nlink, fscki->references); ++ goto out_dump; ++ } ++ if (fscki->xattr_sz != fscki->calc_sz) { ++ ubifs_err("inode %lu has xattr size %lld, but " ++ "calculated size is %lld", ++ fscki->inum, fscki->xattr_sz, ++ fscki->calc_sz); ++ goto out_dump; ++ } ++ if (fscki->xattr_cnt != fscki->calc_cnt) { ++ ubifs_err("inode %lu has %d xattrs, but " ++ "calculated count is %d", fscki->inum, ++ fscki->xattr_cnt, fscki->calc_cnt); ++ goto out_dump; ++ } ++ } ++ } ++ ++ return 0; ++ ++out_dump: ++ /* Read the bad inode and dump it */ ++ ino_key_init(c, &key, fscki->inum); ++ err = ubifs_lookup_level0(c, &key, &znode, &n); ++ if (!err) { ++ ubifs_err("inode %lu not found in index", fscki->inum); ++ return -ENOENT; ++ } else if (err < 0) { ++ ubifs_err("error %d while looking up inode %lu", ++ err, fscki->inum); ++ return err; ++ } ++ ++ zbr = &znode->zbranch[n]; ++ ino = kmalloc(zbr->len, GFP_NOFS); ++ if (!ino) ++ return -ENOMEM; ++ ++ err = ubifs_tnc_read_node(c, zbr, ino); ++ if (err) { ++ ubifs_err("cannot read inode node at LEB %d:%d, error %d", ++ zbr->lnum, zbr->offs, err); ++ kfree(ino); ++ return err; ++ } ++ ++ ubifs_msg("dump of the inode %lu sitting in LEB %d:%d", ++ fscki->inum, zbr->lnum, zbr->offs); ++ dbg_dump_node(c, ino); ++ kfree(ino); ++ return -EINVAL; ++} ++ ++/** ++ * dbg_check_filesystem - check the file-system. ++ * @c: UBIFS file-system description object ++ * ++ * This function checks the file system, namely: ++ * o makes sure that all leaf nodes exist and their CRCs are correct; ++ * o makes sure inode nlink, size, xattr size/count are correct (for all ++ * inodes). ++ * ++ * The function reads whole indexing tree and all nodes, so it is pretty ++ * heavy-weight. Returns zero if the file-system is consistent, %-EINVAL if ++ * not, and a negative error code in case of failure. ++ */ ++int dbg_check_filesystem(struct ubifs_info *c) ++{ ++ int err; ++ struct fsck_data fsckd; ++ ++ if (!(ubifs_chk_flags & UBIFS_CHK_FS)) ++ return 0; ++ ++ fsckd.inodes = RB_ROOT; ++ err = dbg_walk_index(c, check_leaf, NULL, &fsckd); ++ if (err) ++ goto out_free; ++ ++ err = check_inodes(c, &fsckd); ++ if (err) ++ goto out_free; ++ ++ free_inodes(&fsckd); ++ return 0; ++ ++out_free: ++ ubifs_err("file-system check failed with error %d", err); ++ dump_stack(); ++ free_inodes(&fsckd); ++ return err; ++} ++ ++static int invocation_cnt; ++ ++int dbg_force_in_the_gaps(void) ++{ ++ if (!dbg_force_in_the_gaps_enabled) ++ return 0; ++ /* Force in-the-gaps every 8th commit */ ++ return !((invocation_cnt++) & 0x7); ++} ++ ++/* Failure mode for recovery testing */ ++ ++#define chance(n, d) (simple_rand() <= (n) * 32768LL / (d)) ++ ++struct failure_mode_info { ++ struct list_head list; ++ struct ubifs_info *c; ++}; ++ ++static LIST_HEAD(fmi_list); ++static DEFINE_SPINLOCK(fmi_lock); ++ ++static unsigned int next; + -+ bl = backlight_device_register("backlight", &sinfo->pdev->dev, -+ sinfo, &atmel_lcdc_bl_ops); -+ if (IS_ERR(sinfo->backlight)) { -+ dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n", -+ PTR_ERR(bl)); ++static int simple_rand(void) ++{ ++ if (next == 0) ++ next = current->pid; ++ next = next * 1103515245 + 12345; ++ return (next >> 16) & 32767; ++} ++ ++void dbg_failure_mode_registration(struct ubifs_info *c) ++{ ++ struct failure_mode_info *fmi; ++ ++ fmi = kmalloc(sizeof(struct failure_mode_info), GFP_NOFS); ++ if (!fmi) { ++ dbg_err("Failed to register failure mode - no memory"); + return; + } -+ sinfo->backlight = bl; ++ fmi->c = c; ++ spin_lock(&fmi_lock); ++ list_add_tail(&fmi->list, &fmi_list); ++ spin_unlock(&fmi_lock); ++} ++ ++void dbg_failure_mode_deregistration(struct ubifs_info *c) ++{ ++ struct failure_mode_info *fmi, *tmp; ++ ++ spin_lock(&fmi_lock); ++ list_for_each_entry_safe(fmi, tmp, &fmi_list, list) ++ if (fmi->c == c) { ++ list_del(&fmi->list); ++ kfree(fmi); ++ } ++ spin_unlock(&fmi_lock); ++} ++ ++static struct ubifs_info *dbg_find_info(struct ubi_volume_desc *desc) ++{ ++ struct failure_mode_info *fmi; ++ ++ spin_lock(&fmi_lock); ++ list_for_each_entry(fmi, &fmi_list, list) ++ if (fmi->c->ubi == desc) { ++ struct ubifs_info *c = fmi->c; ++ ++ spin_unlock(&fmi_lock); ++ return c; ++ } ++ spin_unlock(&fmi_lock); ++ return NULL; ++} ++ ++static int in_failure_mode(struct ubi_volume_desc *desc) ++{ ++ struct ubifs_info *c = dbg_find_info(desc); ++ ++ if (c) ++ return c->failure_mode; ++ return 0; ++} ++ ++static int do_fail(struct ubi_volume_desc *desc, int lnum, int write) ++{ ++ struct ubifs_info *c = dbg_find_info(desc); ++ ++ if (!c || !dbg_failure_mode) ++ return 0; ++ if (c->failure_mode) ++ return 1; ++ if (!c->fail_cnt) { ++ /* First call - decide delay to failure */ ++ if (chance(1, 2)) { ++ unsigned int delay = 1 << (simple_rand() >> 11); ++ ++ if (chance(1, 2)) { ++ c->fail_delay = 1; ++ c->fail_timeout = jiffies + ++ msecs_to_jiffies(delay); ++ dbg_rcvry("failing after %ums", delay); ++ } else { ++ c->fail_delay = 2; ++ c->fail_cnt_max = delay; ++ dbg_rcvry("failing after %u calls", delay); ++ } ++ } ++ c->fail_cnt += 1; ++ } ++ /* Determine if failure delay has expired */ ++ if (c->fail_delay == 1) { ++ if (time_before(jiffies, c->fail_timeout)) ++ return 0; ++ } else if (c->fail_delay == 2) ++ if (c->fail_cnt++ < c->fail_cnt_max) ++ return 0; ++ if (lnum == UBIFS_SB_LNUM) { ++ if (write) { ++ if (chance(1, 2)) ++ return 0; ++ } else if (chance(19, 20)) ++ return 0; ++ dbg_rcvry("failing in super block LEB %d", lnum); ++ } else if (lnum == UBIFS_MST_LNUM || lnum == UBIFS_MST_LNUM + 1) { ++ if (chance(19, 20)) ++ return 0; ++ dbg_rcvry("failing in master LEB %d", lnum); ++ } else if (lnum >= UBIFS_LOG_LNUM && lnum <= c->log_last) { ++ if (write) { ++ if (chance(99, 100)) ++ return 0; ++ } else if (chance(399, 400)) ++ return 0; ++ dbg_rcvry("failing in log LEB %d", lnum); ++ } else if (lnum >= c->lpt_first && lnum <= c->lpt_last) { ++ if (write) { ++ if (chance(7, 8)) ++ return 0; ++ } else if (chance(19, 20)) ++ return 0; ++ dbg_rcvry("failing in LPT LEB %d", lnum); ++ } else if (lnum >= c->orph_first && lnum <= c->orph_last) { ++ if (write) { ++ if (chance(1, 2)) ++ return 0; ++ } else if (chance(9, 10)) ++ return 0; ++ dbg_rcvry("failing in orphan LEB %d", lnum); ++ } else if (lnum == c->ihead_lnum) { ++ if (chance(99, 100)) ++ return 0; ++ dbg_rcvry("failing in index head LEB %d", lnum); ++ } else if (c->jheads && lnum == c->jheads[GCHD].wbuf.lnum) { ++ if (chance(9, 10)) ++ return 0; ++ dbg_rcvry("failing in GC head LEB %d", lnum); ++ } else if (write && !RB_EMPTY_ROOT(&c->buds) && ++ !ubifs_search_bud(c, lnum)) { ++ if (chance(19, 20)) ++ return 0; ++ dbg_rcvry("failing in non-bud LEB %d", lnum); ++ } else if (c->cmt_state == COMMIT_RUNNING_BACKGROUND || ++ c->cmt_state == COMMIT_RUNNING_REQUIRED) { ++ if (chance(999, 1000)) ++ return 0; ++ dbg_rcvry("failing in bud LEB %d commit running", lnum); ++ } else { ++ if (chance(9999, 10000)) ++ return 0; ++ dbg_rcvry("failing in bud LEB %d commit not running", lnum); ++ } ++ ubifs_err("*** SETTING FAILURE MODE ON (LEB %d) ***", lnum); ++ c->failure_mode = 1; ++ dump_stack(); ++ return 1; ++} ++ ++static void cut_data(const void *buf, int len) ++{ ++ int flen, i; ++ unsigned char *p = (void *)buf; ++ ++ flen = (len * (long long)simple_rand()) >> 15; ++ for (i = flen; i < len; i++) ++ p[i] = 0xff; ++} ++ ++int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, ++ int len, int check) ++{ ++ if (in_failure_mode(desc)) ++ return -EIO; ++ return ubi_leb_read(desc, lnum, buf, offset, len, check); ++} ++ ++int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf, ++ int offset, int len, int dtype) ++{ ++ int err; + -+ bl->props.power = FB_BLANK_UNBLANK; -+ bl->props.fb_blank = FB_BLANK_UNBLANK; -+ bl->props.max_brightness = 0xff; -+ bl->props.brightness = atmel_bl_get_brightness(bl); ++ if (in_failure_mode(desc)) ++ return -EIO; ++ if (do_fail(desc, lnum, 1)) ++ cut_data(buf, len); ++ err = ubi_leb_write(desc, lnum, buf, offset, len, dtype); ++ if (err) ++ return err; ++ if (in_failure_mode(desc)) ++ return -EIO; ++ return 0; +} + -+static void exit_backlight(struct atmel_lcdfb_info *sinfo) ++int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf, ++ int len, int dtype) +{ -+ if (sinfo->backlight) -+ backlight_device_unregister(sinfo->backlight); ++ int err; ++ ++ if (do_fail(desc, lnum, 1)) ++ return -EIO; ++ err = ubi_leb_change(desc, lnum, buf, len, dtype); ++ if (err) ++ return err; ++ if (do_fail(desc, lnum, 1)) ++ return -EIO; ++ return 0; +} + ++int dbg_leb_erase(struct ubi_volume_desc *desc, int lnum) ++{ ++ int err; ++ ++ if (do_fail(desc, lnum, 0)) ++ return -EIO; ++ err = ubi_leb_erase(desc, lnum); ++ if (err) ++ return err; ++ if (do_fail(desc, lnum, 0)) ++ return -EIO; ++ return 0; ++} ++ ++int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum) ++{ ++ int err; ++ ++ if (do_fail(desc, lnum, 0)) ++ return -EIO; ++ err = ubi_leb_unmap(desc, lnum); ++ if (err) ++ return err; ++ if (do_fail(desc, lnum, 0)) ++ return -EIO; ++ return 0; ++} ++ ++int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum) ++{ ++ if (in_failure_mode(desc)) ++ return -EIO; ++ return ubi_is_mapped(desc, lnum); ++} ++ ++#endif /* CONFIG_UBIFS_FS_DEBUG */ +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/debug.h avr32-2.6/fs/ubifs/debug.h +--- linux-2.6.25.6/fs/ubifs/debug.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/debug.h 2008-06-12 15:09:45.315815846 +0200 +@@ -0,0 +1,396 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Artem Bityutskiy (Битюцкий Артём) ++ * Adrian Hunter ++ */ ++ ++#ifndef __UBIFS_DEBUG_H__ ++#define __UBIFS_DEBUG_H__ ++ ++#ifdef CONFIG_UBIFS_FS_DEBUG ++ ++#define UBIFS_DBG(op) op ++ ++#define ubifs_assert(expr) do { \ ++ if (unlikely(!(expr))) { \ ++ printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \ ++ __func__, __LINE__, current->pid); \ ++ dbg_dump_stack(); \ ++ } \ ++} while (0) ++ ++#define ubifs_assert_cmt_locked(c) do { \ ++ if (unlikely(down_write_trylock(&(c)->commit_sem))) { \ ++ up_write(&(c)->commit_sem); \ ++ printk(KERN_CRIT "commit lock is not locked!\n"); \ ++ ubifs_assert(0); \ ++ } \ ++} while (0) ++ ++#define dbg_dump_stack() do { \ ++ if (!dbg_failure_mode) \ ++ dump_stack(); \ ++} while (0) ++ ++/* Generic debugging messages */ ++#define dbg_msg(fmt, ...) do { \ ++ spin_lock(&dbg_lock); \ ++ printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", current->pid, \ ++ __func__, ##__VA_ARGS__); \ ++ spin_unlock(&dbg_lock); \ ++} while (0) ++ ++#define dbg_do_msg(typ, fmt, ...) do { \ ++ if (ubifs_msg_flags & typ) \ ++ dbg_msg(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define dbg_err(fmt, ...) do { \ ++ spin_lock(&dbg_lock); \ ++ ubifs_err(fmt, ##__VA_ARGS__); \ ++ spin_unlock(&dbg_lock); \ ++} while (0) ++ ++const char *dbg_key_str0(const struct ubifs_info *c, ++ const union ubifs_key *key); ++const char *dbg_key_str1(const struct ubifs_info *c, ++ const union ubifs_key *key); ++ ++/* ++ * DBGKEY macros require dbg_lock to be held, which it is in the dbg message ++ * macros. ++ */ ++#define DBGKEY(key) dbg_key_str0(c, (key)) ++#define DBGKEY1(key) dbg_key_str1(c, (key)) ++ ++/* General messages */ ++#define dbg_gen(fmt, ...) dbg_do_msg(UBIFS_MSG_GEN, fmt, ##__VA_ARGS__) ++ ++/* Additional journal messages */ ++#define dbg_jnl(fmt, ...) dbg_do_msg(UBIFS_MSG_JNL, fmt, ##__VA_ARGS__) ++ ++/* Additional TNC messages */ ++#define dbg_tnc(fmt, ...) dbg_do_msg(UBIFS_MSG_TNC, fmt, ##__VA_ARGS__) ++ ++/* Additional lprops messages */ ++#define dbg_lp(fmt, ...) dbg_do_msg(UBIFS_MSG_LP, fmt, ##__VA_ARGS__) ++ ++/* Additional LEB find messages */ ++#define dbg_find(fmt, ...) dbg_do_msg(UBIFS_MSG_FIND, fmt, ##__VA_ARGS__) ++ ++/* Additional mount messages */ ++#define dbg_mnt(fmt, ...) dbg_do_msg(UBIFS_MSG_MNT, fmt, ##__VA_ARGS__) ++ ++/* Additional I/O messages */ ++#define dbg_io(fmt, ...) dbg_do_msg(UBIFS_MSG_IO, fmt, ##__VA_ARGS__) ++ ++/* Additional commit messages */ ++#define dbg_cmt(fmt, ...) dbg_do_msg(UBIFS_MSG_CMT, fmt, ##__VA_ARGS__) ++ ++/* Additional budgeting messages */ ++#define dbg_budg(fmt, ...) dbg_do_msg(UBIFS_MSG_BUDG, fmt, ##__VA_ARGS__) ++ ++/* Additional log messages */ ++#define dbg_log(fmt, ...) dbg_do_msg(UBIFS_MSG_LOG, fmt, ##__VA_ARGS__) ++ ++/* Additional gc messages */ ++#define dbg_gc(fmt, ...) dbg_do_msg(UBIFS_MSG_GC, fmt, ##__VA_ARGS__) ++ ++/* Additional scan messages */ ++#define dbg_scan(fmt, ...) dbg_do_msg(UBIFS_MSG_SCAN, fmt, ##__VA_ARGS__) ++ ++/* Additional recovery messages */ ++#define dbg_rcvry(fmt, ...) dbg_do_msg(UBIFS_MSG_RCVRY, fmt, ##__VA_ARGS__) ++ ++/* ++ * Debugging message type flags (must match msg_type_names in debug.c). ++ * ++ * UBIFS_MSG_GEN: general messages ++ * UBIFS_MSG_JNL: journal messages ++ * UBIFS_MSG_MNT: mount messages ++ * UBIFS_MSG_CMT: commit messages ++ * UBIFS_MSG_FIND: LEB find messages ++ * UBIFS_MSG_BUDG: budgeting messages ++ * UBIFS_MSG_GC: garbage collection messages ++ * UBIFS_MSG_TNC: TNC messages ++ * UBIFS_MSG_LP: lprops messages ++ * UBIFS_MSG_IO: I/O messages ++ * UBIFS_MSG_LOG: log messages ++ * UBIFS_MSG_SCAN: scan messages ++ * UBIFS_MSG_RCVRY: recovery messages ++ */ ++enum { ++ UBIFS_MSG_GEN = 0x1, ++ UBIFS_MSG_JNL = 0x2, ++ UBIFS_MSG_MNT = 0x4, ++ UBIFS_MSG_CMT = 0x8, ++ UBIFS_MSG_FIND = 0x10, ++ UBIFS_MSG_BUDG = 0x20, ++ UBIFS_MSG_GC = 0x40, ++ UBIFS_MSG_TNC = 0x80, ++ UBIFS_MSG_LP = 0x100, ++ UBIFS_MSG_IO = 0x200, ++ UBIFS_MSG_LOG = 0x400, ++ UBIFS_MSG_SCAN = 0x800, ++ UBIFS_MSG_RCVRY = 0x1000, ++}; ++ ++/* Debugging message type flags for each default debug message level */ ++#define UBIFS_MSG_LVL_0 0 ++#define UBIFS_MSG_LVL_1 0x1 ++#define UBIFS_MSG_LVL_2 0x7f ++#define UBIFS_MSG_LVL_3 0xffff ++ ++/* ++ * Debugging check flags (must match chk_names in debug.c). ++ * ++ * UBIFS_CHK_GEN: general checks ++ * UBIFS_CHK_TNC: check TNC ++ * UBIFS_CHK_IDX_SZ: check index size ++ * UBIFS_CHK_ORPH: check orphans ++ * UBIFS_CHK_OLD_IDX: check the old index ++ * UBIFS_CHK_LPROPS: check lprops ++ * UBIFS_CHK_FS: check the file-system ++ */ ++enum { ++ UBIFS_CHK_GEN = 0x1, ++ UBIFS_CHK_TNC = 0x2, ++ UBIFS_CHK_IDX_SZ = 0x4, ++ UBIFS_CHK_ORPH = 0x8, ++ UBIFS_CHK_OLD_IDX = 0x10, ++ UBIFS_CHK_LPROPS = 0x20, ++ UBIFS_CHK_FS = 0x40, ++}; ++ ++/* ++ * Special testing flags (must match tst_names in debug.c). ++ * ++ * UBIFS_TST_FORCE_IN_THE_GAPS: force the use of in-the-gaps method ++ * UBIFS_TST_RCVRY: failure mode for recovery testing ++ */ ++enum { ++ UBIFS_TST_FORCE_IN_THE_GAPS = 0x2, ++ UBIFS_TST_RCVRY = 0x4, ++}; ++ ++#if CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 1 ++#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_1 ++#elif CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 2 ++#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_2 ++#elif CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 3 ++#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_3 +#else ++#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_0 ++#endif + -+static void init_backlight(struct atmel_lcdfb_info *sinfo) ++#ifdef CONFIG_UBIFS_FS_DEBUG_CHKS ++#define UBIFS_CHK_FLAGS_DEFAULT 0xffffffff ++#else ++#define UBIFS_CHK_FLAGS_DEFAULT 0 ++#endif ++ ++extern spinlock_t dbg_lock; ++ ++extern unsigned int ubifs_msg_flags; ++extern unsigned int ubifs_chk_flags; ++extern unsigned int ubifs_tst_flags; ++ ++/* Dump functions */ ++ ++const char *dbg_ntype(int type); ++const char *dbg_cstate(int cmt_state); ++const char *dbg_get_key_dump(const struct ubifs_info *c, ++ const union ubifs_key *key); ++void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode); ++void dbg_dump_node(const struct ubifs_info *c, const void *node); ++void dbg_dump_budget_req(const struct ubifs_budget_req *req); ++void dbg_dump_lstats(const struct ubifs_lp_stats *lst); ++void dbg_dump_budg(struct ubifs_info *c); ++void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp); ++void dbg_dump_lprops(struct ubifs_info *c); ++void dbg_dump_leb(const struct ubifs_info *c, int lnum); ++void dbg_dump_znode(const struct ubifs_info *c, ++ const struct ubifs_znode *znode); ++void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat); ++void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode, ++ struct ubifs_nnode *parent, int iip); ++void dbg_dump_tnc(struct ubifs_info *c); ++void dbg_dump_index(struct ubifs_info *c); ++ ++/* Checking helper functions */ ++ ++typedef int (*dbg_leaf_callback)(struct ubifs_info *c, ++ struct ubifs_zbranch *zbr, void *priv); ++typedef int (*dbg_znode_callback)(struct ubifs_info *c, ++ struct ubifs_znode *znode, void *priv); ++ ++int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb, ++ dbg_znode_callback znode_cb, void *priv); ++ ++/* Checking functions */ ++ ++int dbg_check_lprops(struct ubifs_info *c); ++ ++int dbg_old_index_check_init(struct ubifs_info *c, struct ubifs_zbranch *zroot); ++int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot); ++ ++int dbg_check_cats(struct ubifs_info *c); ++ ++int dbg_check_ltab(struct ubifs_info *c); ++ ++int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir); ++ ++int dbg_check_tnc(struct ubifs_info *c, int extra); ++ ++int dbg_check_idx_size(struct ubifs_info *c, long long idx_size); ++ ++int dbg_check_filesystem(struct ubifs_info *c); ++ ++void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat, ++ int add_pos); ++ ++int dbg_check_lprops(struct ubifs_info *c); ++int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode, ++ int row, int col); ++ ++/* Force the use of in-the-gaps method for testing */ ++ ++#define dbg_force_in_the_gaps_enabled \ ++ (ubifs_tst_flags & UBIFS_TST_FORCE_IN_THE_GAPS) ++ ++int dbg_force_in_the_gaps(void); ++ ++/* Failure mode for recovery testing */ ++ ++#define dbg_failure_mode (ubifs_tst_flags & UBIFS_TST_RCVRY) ++ ++void dbg_failure_mode_registration(struct ubifs_info *c); ++void dbg_failure_mode_deregistration(struct ubifs_info *c); ++ ++#ifndef UBIFS_DBG_PRESERVE_UBI ++ ++#define ubi_leb_read dbg_leb_read ++#define ubi_leb_write dbg_leb_write ++#define ubi_leb_change dbg_leb_change ++#define ubi_leb_erase dbg_leb_erase ++#define ubi_leb_unmap dbg_leb_unmap ++#define ubi_is_mapped dbg_is_mapped ++ ++#endif ++ ++int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, ++ int len, int check); ++int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf, ++ int offset, int len, int dtype); ++int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf, ++ int len, int dtype); ++int dbg_leb_erase(struct ubi_volume_desc *desc, int lnum); ++int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum); ++int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum); ++ ++static inline int dbg_read(struct ubi_volume_desc *desc, int lnum, char *buf, ++ int offset, int len) +{ -+ dev_warn(&sinfo->pdev->dev, "backlight control is not available\n"); ++ return dbg_leb_read(desc, lnum, buf, offset, len, 0); +} + -+static void exit_backlight(struct atmel_lcdfb_info *sinfo) ++static inline int dbg_write(struct ubi_volume_desc *desc, int lnum, ++ const void *buf, int offset, int len) +{ ++ return dbg_leb_write(desc, lnum, buf, offset, len, UBI_UNKNOWN); +} + ++static inline int dbg_change(struct ubi_volume_desc *desc, int lnum, ++ const void *buf, int len) ++{ ++ return dbg_leb_change(desc, lnum, buf, len, UBI_UNKNOWN); ++} ++ ++#else /* !CONFIG_UBIFS_FS_DEBUG */ ++ ++#define UBIFS_DBG(op) ++#define ubifs_assert(expr) ({}) ++#define ubifs_assert_cmt_locked(c) ++#define dbg_dump_stack() ++#define dbg_err(fmt, ...) ({}) ++#define dbg_msg(fmt, ...) ({}) ++#define dbg_key(c, key, fmt, ...) ({}) ++ ++#define dbg_gen(fmt, ...) ({}) ++#define dbg_jnl(fmt, ...) ({}) ++#define dbg_tnc(fmt, ...) ({}) ++#define dbg_lp(fmt, ...) ({}) ++#define dbg_find(fmt, ...) ({}) ++#define dbg_mnt(fmt, ...) ({}) ++#define dbg_io(fmt, ...) ({}) ++#define dbg_cmt(fmt, ...) ({}) ++#define dbg_budg(fmt, ...) ({}) ++#define dbg_log(fmt, ...) ({}) ++#define dbg_gc(fmt, ...) ({}) ++#define dbg_scan(fmt, ...) ({}) ++#define dbg_rcvry(fmt, ...) ({}) ++ ++#define dbg_ntype(type) "" ++#define dbg_cstate(cmt_state) "" ++#define dbg_get_key_dump(c, key) ({}) ++#define dbg_dump_inode(c, inode) ({}) ++#define dbg_dump_node(c, node) ({}) ++#define dbg_dump_budget_req(req) ({}) ++#define dbg_dump_lstats(lst) ({}) ++#define dbg_dump_budg(c) ({}) ++#define dbg_dump_lprop(c, lp) ({}) ++#define dbg_dump_lprops(c) ({}) ++#define dbg_dump_leb(c, lnum) ({}) ++#define dbg_dump_znode(c, znode) ({}) ++#define dbg_dump_heap(c, heap, cat) ({}) ++#define dbg_dump_pnode(c, pnode, parent, iip) ({}) ++#define dbg_dump_tnc(c) ({}) ++#define dbg_dump_index(c) ({}) ++ ++#define dbg_walk_index(c, leaf_cb, znode_cb, priv) 0 ++ ++#define dbg_old_index_check_init(c, zroot) 0 ++#define dbg_check_old_index(c, zroot) 0 ++ ++#define dbg_check_cats(c) 0 ++ ++#define dbg_check_ltab(c) 0 ++ ++#define dbg_check_dir_size(c, dir) 0 ++ ++#define dbg_check_tnc(c, x) 0 ++ ++#define dbg_check_idx_size(c, idx_size) 0 ++#define dbg_check_filesystem(c) 0 ++ ++#define dbg_check_heap(c, heap, cat, add_pos) ({}) ++ ++#define dbg_check_lprops(c) 0 ++#define dbg_check_lpt_nodes(c, cnode, row, col) 0 ++ ++#define dbg_force_in_the_gaps_enabled 0 ++#define dbg_force_in_the_gaps() 0 ++ ++#define dbg_failure_mode 0 ++#define dbg_failure_mode_registration(c) ({}) ++#define dbg_failure_mode_deregistration(c) ({}) ++ ++#endif /* !CONFIG_UBIFS_FS_DEBUG */ ++ ++#endif /* !__UBIFS_DEBUG_H__ */ +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/dir.c avr32-2.6/fs/ubifs/dir.c +--- linux-2.6.25.6/fs/ubifs/dir.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/dir.c 2008-06-12 15:09:45.364399968 +0200 +@@ -0,0 +1,1017 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * Copyright (C) 2006, 2007 University of Szeged, Hungary ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Artem Bityutskiy (Битюцкий Артём) ++ * Adrian Hunter ++ * Zoltan Sogor ++ */ ++ ++/* ++ * This file implements directory operations. ++ * ++ * All FS operations in this file allocate budget before writing anything to the ++ * media. If they fail to allocate it, the error is returned. The only ++ * exceptions are 'ubifs_unlink()' and 'ubifs_rmdir()' which keep working even ++ * if they unable to allocate the budget, because deletion %-ENOSPC failure is ++ * not what users are usually ready to get. UBIFS budgeting subsystem has some ++ * space reserved for these purposes. ++ * ++ * All operations in this file change the parent inode, e.g., 'ubifs_link()' ++ * changes ctime and nlink of the parent inode. The parent inode is written to ++ * the media straight away - it is not marked as dirty and there is no ++ * write-back for it. This was done to simplify file-system recovery which ++ * would otherwise be very difficult to do. So instead of marking the parent ++ * inode dirty, the operations mark it clean. ++ */ ++ ++#include "ubifs.h" ++ ++/* ++ * Provide backing_dev_info in order to disable readahead. For UBIFS, I/O is ++ * not deferred, it is done immediately in readpage, which means the user would ++ * have to wait not just for their own I/O but the readahead I/O as well i.e. ++ * completely pointless. ++ */ ++struct backing_dev_info ubifs_backing_dev_info = { ++ .ra_pages = 0, /* Set to zero to disable readahead */ ++ .state = 0, ++ .capabilities = BDI_CAP_MAP_COPY, ++ .unplug_io_fn = default_unplug_io_fn, ++}; ++ ++/** ++ * inherit_flags - inherit flags of the parent inode. ++ * @dir: parent inode ++ * @mode: new inode mode flags ++ * ++ * This is a helper function for 'ubifs_new_inode()' which inherits flag of the ++ * parent directory inode @dir. UBIFS inodes inherit the following flags: ++ * o %UBIFS_COMPR_FL, which is useful to switch compression on/of on ++ * sub-directory basis; ++ * o %UBIFS_SYNC_FL - useful for the same reasons; ++ * o %UBIFS_DIRSYNC_FL - similar, but relevant only to directories. ++ * ++ * This function returns the inherited flags. ++ */ ++static int inherit_flags(const struct inode *dir, int mode) ++{ ++ int flags; ++ const struct ubifs_inode *ui = ubifs_inode(dir); ++ ++ if (!S_ISDIR(dir->i_mode)) ++ /* ++ * The parent is not a directory, which means that an extended ++ * attribute inode is being created. No flags. ++ */ ++ return 0; ++ ++ flags = ui->flags & (UBIFS_COMPR_FL | UBIFS_SYNC_FL | UBIFS_DIRSYNC_FL); ++ if (!S_ISDIR(mode)) ++ /* The "DIRSYNC" flag only applies to directories */ ++ flags &= ~UBIFS_DIRSYNC_FL; ++ ++ return flags; ++} ++ ++/** ++ * ubifs_new_inode - allocate new UBIFS inode object. ++ * @c: UBIFS file-system description object ++ * @dir: parent directory inode ++ * @mode: inode mode flags ++ * ++ * This function finds an unused inode number, allocates new inode and ++ * initializes it. Returns new inode in case of success and an error code in ++ * case of failure. ++ */ ++struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir, ++ int mode) ++{ ++ struct inode *inode; ++ struct ubifs_inode *ui; ++ ++ inode = new_inode(c->vfs_sb); ++ if (!inode) ++ return ERR_PTR(-ENOMEM); ++ ++ /* ++ * Set 'S_NOCMTIME' to prevent VFS form updating [mc]time of inodes and ++ * marking them dirty in file write path (see 'file_update_time()'). ++ * UBIFS has to fully control "clean <-> dirty" transitions of inodes ++ * to make budgeting work. ++ */ ++ inode->i_flags |= (S_NOCMTIME); ++ ++ inode->i_uid = current->fsuid; ++ if (dir->i_mode & S_ISGID) { ++ inode->i_gid = dir->i_gid; ++ if (S_ISDIR(mode)) ++ mode |= S_ISGID; ++ } else ++ inode->i_gid = current->fsgid; ++ inode->i_mode = mode; ++ inode->i_mtime = inode->i_atime = inode->i_ctime = ++ ubifs_current_time(inode); ++ inode->i_mapping->nrpages = 0; ++ /* Disable readahead */ ++ inode->i_mapping->backing_dev_info = &ubifs_backing_dev_info; ++ ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ inode->i_mapping->a_ops = &ubifs_file_address_operations; ++ inode->i_op = &ubifs_file_inode_operations; ++ inode->i_fop = &ubifs_file_operations; ++ break; ++ case S_IFDIR: ++ inode->i_op = &ubifs_dir_inode_operations; ++ inode->i_fop = &ubifs_dir_operations; ++ inode->i_size = UBIFS_INO_NODE_SZ; ++ break; ++ case S_IFLNK: ++ inode->i_op = &ubifs_symlink_inode_operations; ++ break; ++ case S_IFSOCK: ++ case S_IFIFO: ++ case S_IFBLK: ++ case S_IFCHR: ++ inode->i_op = &ubifs_file_inode_operations; ++ break; ++ default: ++ BUG(); ++ } ++ ++ ui = ubifs_inode(inode); ++ ui->flags = inherit_flags(dir, mode); ++ ubifs_set_inode_flags(inode); ++ ++ if (S_ISREG(mode)) ++ ui->compr_type = c->default_compr; ++ else ++ ui->compr_type = UBIFS_COMPR_NONE; ++ ++ spin_lock(&c->cnt_lock); ++ /* Inode number overflow is currently not supported */ ++ if (c->highest_inum >= INUM_WARN_WATERMARK) { ++ if (c->highest_inum >= INUM_WATERMARK) { ++ spin_unlock(&c->cnt_lock); ++ ubifs_err("out of inode numbers"); ++ make_bad_inode(inode); ++ iput(inode); ++ return ERR_PTR(-EINVAL); ++ } ++ ubifs_warn("running out of inode numbers (current %lu, max %d)", ++ c->highest_inum, INUM_WATERMARK); ++ } ++ ++ inode->i_ino = ++c->highest_inum; ++ inode->i_generation = ++c->vfs_gen; ++ /* ++ * The creation sequence number remains with this inode for its ++ * lifetime. All nodes for this inode have a greater sequence number, ++ * and so it is possible to distinguish obsolete nodes belonging to a ++ * previous incarnation of the same inode number - for example, for the ++ * purpose of rebuilding the index. ++ */ ++ ui->creat_sqnum = ++c->max_sqnum; ++ spin_unlock(&c->cnt_lock); ++ ++ return inode; ++} ++ ++#ifdef CONFIG_UBIFS_FS_DEBUG ++ ++static int dbg_check_name(struct ubifs_dent_node *dent, struct qstr *nm) ++{ ++ if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) ++ return 0; ++ if (le16_to_cpu(dent->nlen) != nm->len) ++ return -EINVAL; ++ if (memcmp(dent->name, nm->name, nm->len)) ++ return -EINVAL; ++ return 0; ++} ++ ++#else ++ ++#define dbg_check_name(dent, nm) 0 ++ +#endif + -+static void init_contrast(struct atmel_lcdfb_info *sinfo) ++static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, ++ struct nameidata *nd) +{ -+ /* have some default contrast/backlight settings */ -+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr); -+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); ++ int err; ++ union ubifs_key key; ++ struct inode *inode = NULL; ++ struct ubifs_dent_node *dent; ++ struct ubifs_info *c = dir->i_sb->s_fs_info; ++ ++ dbg_gen("'%.*s' in dir ino %lu", ++ dentry->d_name.len, dentry->d_name.name, dir->i_ino); ++ ++ if (dentry->d_name.len > UBIFS_MAX_NLEN) ++ return ERR_PTR(-ENAMETOOLONG); ++ ++ dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS); ++ if (!dent) ++ return ERR_PTR(-ENOMEM); + -+ if (sinfo->lcdcon_is_backlight) -+ init_backlight(sinfo); ++ dent_key_init(c, &key, dir->i_ino, &dentry->d_name); ++ ++ err = ubifs_tnc_lookup_nm(c, &key, dent, &dentry->d_name); ++ if (err) { ++ if (err == -ENOENT) { ++ dbg_gen("not found"); ++ goto done; ++ } ++ goto out; ++ } ++ ++ if (dbg_check_name(dent, &dentry->d_name)) { ++ err = -EINVAL; ++ goto out; ++ } ++ ++ inode = ubifs_iget(dir->i_sb, le64_to_cpu(dent->inum)); ++ if (IS_ERR(inode)) { ++ /* ++ * This should not happen. Probably the file-system needs ++ * checking. ++ */ ++ err = PTR_ERR(inode); ++ ubifs_err("dead directory entry '%.*s', error %d", ++ dentry->d_name.len, dentry->d_name.name, err); ++ ubifs_ro_mode(c, err); ++ goto out; ++ } ++ ++done: ++ kfree(dent); ++ /* ++ * Note, d_splice_alias() would be required instead if we supported ++ * NFS. ++ */ ++ d_add(dentry, inode); ++ return NULL; ++ ++out: ++ kfree(dent); ++ return ERR_PTR(err); +} + - - static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = { - .type = FB_TYPE_PACKED_PIXELS, - .visual = FB_VISUAL_TRUECOLOR, - .xpanstep = 0, -- .ypanstep = 0, -+ .ypanstep = 1, - .ywrapstep = 0, - .accel = FB_ACCEL_NONE, - }; -@@ -148,6 +252,8 @@ - return -ENOMEM; - } - -+ memset(info->screen_base, 0, info->fix.smem_len); ++static int ubifs_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *nd) ++{ ++ struct inode *inode; ++ struct ubifs_info *c = dir->i_sb->s_fs_info; ++ struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 }; ++ int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); + - return 0; - } - -@@ -203,6 +309,26 @@ - var->transp.offset = var->transp.length = 0; - var->xoffset = var->yoffset = 0; - -+ /* Saturate vertical and horizontal timings at maximum values */ -+ var->vsync_len = min_t(u32, var->vsync_len, -+ (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1); -+ var->upper_margin = min_t(u32, var->upper_margin, -+ ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET); -+ var->lower_margin = min_t(u32, var->lower_margin, -+ ATMEL_LCDC_VFP); -+ var->right_margin = min_t(u32, var->right_margin, -+ (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1); -+ var->hsync_len = min_t(u32, var->hsync_len, -+ (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1); -+ var->left_margin = min_t(u32, var->left_margin, -+ ATMEL_LCDC_HBP + 1); -+ -+ /* Some parameters can't be zero */ -+ var->vsync_len = max_t(u32, var->vsync_len, 1); -+ var->right_margin = max_t(u32, var->right_margin, 1); -+ var->hsync_len = max_t(u32, var->hsync_len, 1); -+ var->left_margin = max_t(u32, var->left_margin, 1); -+ - switch (var->bits_per_pixel) { - case 1: - case 2: -@@ -370,10 +496,6 @@ - /* Disable all interrupts */ - lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); - -- /* Set contrast */ -- value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE; -- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value); -- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); - /* ...wait for DMA engine to become idle... */ - while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) - msleep(10); -@@ -516,7 +638,6 @@ - struct fb_info *info = sinfo->info; - int ret = 0; - -- memset_io(info->screen_base, 0, info->fix.smem_len); - info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW; - - dev_info(info->device, -@@ -577,6 +698,7 @@ - sinfo->default_monspecs = pdata_sinfo->default_monspecs; - sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control; - sinfo->guard_time = pdata_sinfo->guard_time; -+ sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight; - } else { - dev_err(dev, "cannot get default configuration\n"); - goto free_info; -@@ -645,6 +767,11 @@ - info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); - if (!info->screen_base) - goto release_intmem; ++ dbg_gen("dent '%.*s', mode %#x in dir ino %lu", ++ dentry->d_name.len, dentry->d_name.name, mode, dir->i_ino); ++ ++ inode = ubifs_new_inode(c, dir, mode); ++ if (IS_ERR(inode)) ++ return PTR_ERR(inode); ++ ++ err = ubifs_budget_inode_op(c, dir, &req); ++ if (err) ++ goto out; ++ ++ dir->i_size += sz_change; ++ ++ err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, ++ IS_DIRSYNC(dir), 0); ++ if (err) ++ goto out_budg; ++ ++ insert_inode_hash(inode); ++ d_instantiate(dentry, inode); ++ ubifs_release_ino_clean(c, dir, &req); ++ return 0; ++ ++out_budg: ++ dir->i_size -= sz_change; ++ ubifs_cancel_ino_op(c, dir, &req); ++ ubifs_err("cannot create regular file, error %d", err); ++out: ++ make_bad_inode(inode); ++ iput(inode); ++ return err; ++} ++ ++/** ++ * vfs_dent_type - get VFS directory entry type. ++ * @type: UBIFS directory entry type ++ * ++ * This function converts UBIFS directory entry type into VFS directory entry ++ * type. ++ */ ++static unsigned int vfs_dent_type(uint8_t type) ++{ ++ switch (type) { ++ case UBIFS_ITYPE_REG: ++ return DT_REG; ++ case UBIFS_ITYPE_DIR: ++ return DT_DIR; ++ case UBIFS_ITYPE_LNK: ++ return DT_LNK; ++ case UBIFS_ITYPE_BLK: ++ return DT_BLK; ++ case UBIFS_ITYPE_CHR: ++ return DT_CHR; ++ case UBIFS_ITYPE_FIFO: ++ return DT_FIFO; ++ case UBIFS_ITYPE_SOCK: ++ return DT_SOCK; ++ default: ++ BUG(); ++ } ++ return 0; ++} + ++/* ++ * The classical Unix view for directory is that it is a linear array of ++ * (name, inode number) entries. Linux/VFS assumes this model as well. ++ * Particularly, 'readdir()' call wants us to return a directory entry offset ++ * which later may be used to continue 'readdir()'ing the directory or to ++ * 'seek()' to that specific direntry. Obviously UBIFS does not really fit this ++ * model because directory entries are identified by keys, which may collide. ++ * ++ * UBIFS uses directory entry hash value for directory offsets, so ++ * 'seekdir()'/'telldir()' may not always work because of possible key ++ * collisions. But UBIFS guarantees that consecutive 'readdir()' calls work ++ * properly by means of saving full directory entry name in the private field ++ * of the file description object. ++ * ++ * This means that UBIFS cannot support NFS which requires full ++ * 'seekdir()'/'telldir()' support. ++ */ ++static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir) ++{ ++ int err, over = 0; ++ struct qstr nm; ++ union ubifs_key key; ++ struct ubifs_dent_node *dent; ++ struct inode *dir = file->f_path.dentry->d_inode; ++ struct ubifs_info *c = dir->i_sb->s_fs_info; ++ ++ dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos); ++ ++ if (file->f_pos > UBIFS_S_KEY_HASH_MASK || file->f_pos == 2) + /* -+ * Don't clear the framebuffer -- someone may have set -+ * up a splash image. ++ * The directory was seek'ed to a senseless position or there ++ * are no more entries. + */ - } else { - /* alocate memory buffer */ - ret = atmel_lcdfb_alloc_video_memory(sinfo); -@@ -670,6 +797,9 @@ - goto release_mem; - } - -+ /* Initialize PWM for contrast or backlight ("off") */ -+ init_contrast(sinfo); -+ - /* interrupt */ - ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info); - if (ret) { -@@ -721,6 +851,7 @@ - unregister_irqs: - free_irq(sinfo->irq_base, info); - unmap_mmio: -+ exit_backlight(sinfo); - iounmap(sinfo->mmio); - release_mem: - release_mem_region(info->fix.mmio_start, info->fix.mmio_len); -@@ -755,6 +886,7 @@ - if (!sinfo) - return 0; - -+ exit_backlight(sinfo); - if (sinfo->atmel_lcdfb_power_control) - sinfo->atmel_lcdfb_power_control(0); - unregister_framebuffer(info); -@@ -781,6 +913,9 @@ - - static struct platform_driver atmel_lcdfb_driver = { - .remove = __exit_p(atmel_lcdfb_remove), ++ return 0; + -+// FIXME need suspend, resume ++ /* File positions 0 and 1 correspond to "." and ".." */ ++ if (file->f_pos == 0) { ++ ubifs_assert(!file->private_data); ++ over = filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR); ++ if (over) ++ return 0; ++ file->f_pos = 1; ++ } + - .driver = { - .name = "atmel_lcdfb", - .owner = THIS_MODULE, ---- a/drivers/video/backlight/Kconfig -+++ b/drivers/video/backlight/Kconfig -@@ -50,6 +50,19 @@ - To have support for your specific LCD panel you will have to - select the proper drivers which depend on this option. - -+config BACKLIGHT_ATMEL_LCDC -+ bool "Atmel LCDC Contrast-as-Backlight control" -+ depends on BACKLIGHT_CLASS_DEVICE && FB_ATMEL -+ default y if MACH_SAM9261EK || MACH_SAM9263EK ++ if (file->f_pos == 1) { ++ ubifs_assert(!file->private_data); ++ over = filldir(dirent, "..", 2, 1, ++ parent_ino(file->f_path.dentry), DT_DIR); ++ if (over) ++ return 0; ++ ++ /* Find the first entry in TNC and save it */ ++ lowest_dent_key(c, &key, dir->i_ino); ++ nm.name = NULL; ++ dent = ubifs_tnc_next_ent(c, &key, &nm); ++ if (IS_ERR(dent)) { ++ err = PTR_ERR(dent); ++ goto out; ++ } ++ ++ file->f_pos = key_hash_flash(c, &dent->key); ++ file->private_data = dent; ++ } ++ ++ dent = file->private_data; ++ if (!dent) { ++ /* ++ * The directory was seek'ed to and is now readdir'ed. ++ * Find the entry corresponding to @file->f_pos or the ++ * closest one. ++ */ ++ dent_key_init_hash(c, &key, dir->i_ino, file->f_pos); ++ nm.name = NULL; ++ dent = ubifs_tnc_next_ent(c, &key, &nm); ++ if (IS_ERR(dent)) { ++ err = PTR_ERR(dent); ++ goto out; ++ } ++ file->f_pos = key_hash_flash(c, &dent->key); ++ file->private_data = dent; ++ } ++ ++ while (1) { ++ dbg_gen("feed '%s', ino %llu, new f_pos %#x", ++ dent->name, le64_to_cpu(dent->inum), ++ key_hash_flash(c, &dent->key)); ++ ubifs_assert(dent->ch.sqnum > ubifs_inode(dir)->creat_sqnum); ++ ++ nm.len = le16_to_cpu(dent->nlen); ++ over = filldir(dirent, dent->name, nm.len, file->f_pos, ++ le64_to_cpu(dent->inum), ++ vfs_dent_type(dent->type)); ++ if (over) ++ return 0; ++ ++ /* Switch to the next entry */ ++ key_read(c, &dent->key, &key); ++ nm.name = dent->name; ++ dent = ubifs_tnc_next_ent(c, &key, &nm); ++ if (IS_ERR(dent)) { ++ err = PTR_ERR(dent); ++ goto out; ++ } ++ ++ kfree(file->private_data); ++ file->f_pos = key_hash_flash(c, &dent->key); ++ file->private_data = dent; ++ cond_resched(); ++ } ++ ++out: ++ if (err != -ENOENT) { ++ ubifs_err("cannot find next direntry, error %d", err); ++ return err; ++ } ++ ++ kfree(file->private_data); ++ file->private_data = NULL; ++ file->f_pos = 2; ++ return 0; ++} ++ ++/* If a directory is seeked, we have to free saved readdir() state */ ++loff_t ubifs_dir_llseek(struct file *file, loff_t offset, int origin) ++{ ++ kfree(file->private_data); ++ file->private_data = NULL; ++ return generic_file_llseek(file, offset, origin); ++} ++ ++/* Free saved readdir() state when the directory is closed */ ++static int ubifs_dir_release(struct inode *dir, struct file *file) ++{ ++ kfree(file->private_data); ++ file->private_data = NULL; ++ return 0; ++} ++ ++static int ubifs_link(struct dentry *old_dentry, struct inode *dir, ++ struct dentry *dentry) ++{ ++ struct ubifs_info *c = dir->i_sb->s_fs_info; ++ struct inode *inode = old_dentry->d_inode; ++ struct ubifs_inode *ui = ubifs_inode(inode); ++ struct ubifs_budget_req req = { .new_dent = 1, .dirtied_ino = 1, ++ .dirtied_ino_d = ui->data_len }; ++ int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); ++ ++ dbg_gen("dent '%.*s' to ino %lu (nlink %d) in dir ino %lu", ++ dentry->d_name.len, dentry->d_name.name, inode->i_ino, ++ inode->i_nlink, dir->i_ino); ++ ++ err = ubifs_budget_inode_op(c, dir, &req); ++ if (err) ++ return err; ++ ++ inc_nlink(inode); ++ dir->i_size += sz_change; ++ inode->i_ctime = dir->i_mtime = dir->i_ctime = ++ ubifs_current_time(inode); ++ ++ err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, ++ IS_DIRSYNC(dir), 0); ++ if (err) ++ goto out_budg; ++ ++ atomic_inc(&inode->i_count); ++ d_instantiate(dentry, inode); ++ ubifs_release_ino_clean(c, dir, &req); ++ return 0; ++ ++out_budg: ++ dir->i_size -= sz_change; ++ ubifs_cancel_ino_op(c, dir, &req); ++ drop_nlink(inode); ++ iput(inode); ++ return err; ++} ++ ++static int ubifs_unlink(struct inode *dir, struct dentry *dentry) ++{ ++ struct ubifs_info *c = dir->i_sb->s_fs_info; ++ struct inode *inode = dentry->d_inode; ++ struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 1 }; ++ int sz_change = CALC_DENT_SIZE(dentry->d_name.len); ++ int err, budgeted = 1; ++ ++ dbg_gen("dent '%.*s' from ino %lu (nlink %d) in dir ino %lu", ++ dentry->d_name.len, dentry->d_name.name, inode->i_ino, ++ inode->i_nlink, dir->i_ino); ++ ++ err = ubifs_budget_inode_op(c, dir, &req); ++ if (err) { ++ if (err != -ENOSPC) ++ return err; ++ err = 0; ++ budgeted = 0; ++ } ++ ++ dir->i_size -= sz_change; ++ dir->i_mtime = dir->i_ctime = ubifs_current_time(dir); ++ ++ inode->i_ctime = dir->i_ctime; ++ drop_nlink(inode); ++ ++ err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, ++ IS_DIRSYNC(dir), 0); ++ if (err) ++ goto out_budg; ++ ++ if (budgeted) ++ ubifs_release_ino_clean(c, dir, &req); ++ ++ return 0; ++ ++out_budg: ++ dir->i_size += sz_change; ++ inc_nlink(inode); ++ if (budgeted) ++ ubifs_cancel_ino_op(c, dir, &req); ++ return err; ++} ++ ++/** ++ * check_dir_empty - check if a directory is empty or not. ++ * @c: UBIFS file-system description object ++ * @dir: VFS inode object of the directory to check ++ * ++ * This function checks if directory @dir is empty. Returns zero if the ++ * directory is empty, %-ENOTEMPTY if it is not, and other negative error codes ++ * in case of of errors. ++ */ ++static int check_dir_empty(struct ubifs_info *c, struct inode *dir) ++{ ++ struct qstr nm = { .name = NULL }; ++ struct ubifs_dent_node *dent; ++ union ubifs_key key; ++ int err; ++ ++ lowest_dent_key(c, &key, dir->i_ino); ++ dent = ubifs_tnc_next_ent(c, &key, &nm); ++ if (IS_ERR(dent)) { ++ err = PTR_ERR(dent); ++ if (err == -ENOENT) ++ err = 0; ++ } else { ++ kfree(dent); ++ err = -ENOTEMPTY; ++ } ++ ++ return err; ++} ++ ++static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) ++{ ++ struct ubifs_info *c = dir->i_sb->s_fs_info; ++ struct inode *inode = dentry->d_inode; ++ struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 1 }; ++ int sz_change = CALC_DENT_SIZE(dentry->d_name.len); ++ int err, budgeted = 0; ++ ++ dbg_gen("directory '%.*s', ino %lu in dir ino %lu", dentry->d_name.len, ++ dentry->d_name.name, inode->i_ino, dir->i_ino); ++ ++ err = check_dir_empty(c, dentry->d_inode); ++ if (err) ++ return err; ++ ++ budgeted = 1; ++ err = ubifs_budget_inode_op(c, dir, &req); ++ if (err) { ++ if (err != -ENOSPC) ++ return err; ++ budgeted = 0; ++ } ++ ++ dir->i_size -= sz_change; ++ dir->i_mtime = dir->i_ctime = ubifs_current_time(dir); ++ drop_nlink(dir); ++ ++ inode->i_size = 0; ++ inode->i_ctime = dir->i_ctime; ++ clear_nlink(inode); ++ ++ err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, ++ IS_DIRSYNC(dir), 0); ++ if (err) ++ goto out_budg; ++ ++ if (budgeted) ++ ubifs_release_ino_clean(c, dir, &req); ++ ++ return 0; ++ ++out_budg: ++ dir->i_size += sz_change; ++ inc_nlink(dir); ++ inc_nlink(inode); ++ inc_nlink(inode); ++ if (budgeted) ++ ubifs_cancel_ino_op(c, dir, &req); ++ return err; ++} ++ ++static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ++{ ++ struct inode *inode; ++ struct ubifs_info *c = dir->i_sb->s_fs_info; ++ struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 }; ++ int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); ++ ++ dbg_gen("dent '%.*s', mode %#x in dir ino %lu", ++ dentry->d_name.len, dentry->d_name.name, mode, dir->i_ino); ++ ++ err = ubifs_budget_inode_op(c, dir, &req); ++ if (err) ++ return err; ++ ++ inode = ubifs_new_inode(c, dir, S_IFDIR | mode); ++ if (IS_ERR(inode)) { ++ err = PTR_ERR(inode); ++ goto out_budg; ++ } ++ ++ insert_inode_hash(inode); ++ inc_nlink(inode); ++ ++ dir->i_mtime = dir->i_ctime = ubifs_current_time(dir); ++ dir->i_size += sz_change; ++ inc_nlink(dir); ++ ++ err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, ++ IS_DIRSYNC(dir), 0); ++ if (err) { ++ ubifs_err("cannot create directory, error %d", err); ++ goto out_inode; ++ } ++ ++ d_instantiate(dentry, inode); ++ ubifs_release_ino_clean(c, dir, &req); ++ return 0; ++ ++out_inode: ++ dir->i_size -= sz_change; ++ drop_nlink(dir); ++ make_bad_inode(inode); ++ iput(inode); ++out_budg: ++ ubifs_cancel_ino_op(c, dir, &req); ++ return err; ++} ++ ++static int ubifs_mknod(struct inode *dir, struct dentry *dentry, ++ int mode, dev_t rdev) ++{ ++ struct inode *inode; ++ struct ubifs_info *c = dir->i_sb->s_fs_info; ++ struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 }; ++ union ubifs_dev_desc *dev = NULL; ++ int sz_change = CALC_DENT_SIZE(dentry->d_name.len); ++ int err, devlen = 0; ++ ++ dbg_gen("dent '%.*s' in dir ino %lu", ++ dentry->d_name.len, dentry->d_name.name, dir->i_ino); ++ ++ if (!new_valid_dev(rdev)) ++ return -EINVAL; ++ ++ if (S_ISBLK(mode) || S_ISCHR(mode)) { ++ dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); ++ if (!dev) ++ return -ENOMEM; ++ devlen = ubifs_encode_dev(dev, rdev); ++ } ++ ++ err = ubifs_budget_inode_op(c, dir, &req); ++ if (err) { ++ kfree(dev); ++ return err; ++ } ++ ++ inode = ubifs_new_inode(c, dir, mode); ++ if (IS_ERR(inode)) { ++ kfree(dev); ++ err = PTR_ERR(inode); ++ goto out_budg; ++ } ++ ++ init_special_inode(inode, inode->i_mode, rdev); ++ ++ inode->i_size = devlen; ++ ubifs_inode(inode)->data = dev; ++ ubifs_inode(inode)->data_len = devlen; ++ ++ dir->i_size += sz_change; ++ ++ err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, ++ IS_DIRSYNC(dir), 0); ++ if (err) ++ goto out_inode; ++ ++ insert_inode_hash(inode); ++ d_instantiate(dentry, inode); ++ ubifs_release_ino_clean(c, dir, &req); ++ return 0; ++ ++out_inode: ++ dir->i_size -= sz_change; ++ make_bad_inode(inode); ++ iput(inode); ++out_budg: ++ ubifs_cancel_ino_op(c, dir, &req); ++ return err; ++} ++ ++static int ubifs_symlink(struct inode *dir, struct dentry *dentry, ++ const char *symname) ++{ ++ struct inode *inode; ++ struct ubifs_inode *ui; ++ struct ubifs_info *c = dir->i_sb->s_fs_info; ++ int err, len = strlen(symname); ++ int sz_change = CALC_DENT_SIZE(dentry->d_name.len); ++ struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, ++ .new_ino_d = len }; ++ ++ dbg_gen("dent '%.*s', target '%s' in dir ino %lu", dentry->d_name.len, ++ dentry->d_name.name, symname, dir->i_ino); ++ ++ if (len > UBIFS_MAX_INO_DATA) ++ return -ENAMETOOLONG; ++ ++ err = ubifs_budget_inode_op(c, dir, &req); ++ if (err) ++ return err; ++ ++ inode = ubifs_new_inode(c, dir, S_IFLNK | S_IRWXUGO); ++ if (IS_ERR(inode)) { ++ err = PTR_ERR(inode); ++ goto out_budg; ++ } ++ ++ ui = ubifs_inode(inode); ++ ui->data = kmalloc(len + 1, GFP_NOFS); ++ if (!ui->data) { ++ err = -ENOMEM; ++ goto out_inode; ++ } ++ ++ memcpy(ui->data, symname, len); ++ ((char *)ui->data)[len] = '\0'; ++ /* ++ * The terminating zero byte is not written to the flash media and it ++ * is put just to make later in-memory string processing simpler. Thus, ++ * data length is @len, not @len + %1. ++ */ ++ ui->data_len = len; ++ inode->i_size = len; ++ ++ dir->i_size += sz_change; ++ ++ err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, ++ IS_DIRSYNC(dir), 0); ++ if (err) ++ goto out_dir; ++ ++ insert_inode_hash(inode); ++ d_instantiate(dentry, inode); ++ ubifs_release_ino_clean(c, dir, &req); ++ return 0; ++ ++out_dir: ++ dir->i_size -= sz_change; ++out_inode: ++ make_bad_inode(inode); ++ iput(inode); ++out_budg: ++ ubifs_cancel_ino_op(c, dir, &req); ++ return err; ++} ++ ++static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry, ++ struct inode *new_dir, struct dentry *new_dentry) ++{ ++ struct ubifs_info *c = old_dir->i_sb->s_fs_info; ++ struct inode *old_inode = old_dentry->d_inode; ++ struct inode *new_inode = new_dentry->d_inode; ++ int err, move = (new_dir != old_dir); ++ int is_dir = S_ISDIR(old_inode->i_mode); ++ int unlink = !!new_inode; ++ int dirsync = (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)); ++ int new_sz = CALC_DENT_SIZE(new_dentry->d_name.len); ++ int old_sz = CALC_DENT_SIZE(old_dentry->d_name.len); ++ struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1 }; ++ struct timespec time = ubifs_current_time(old_dir); ++ ++ dbg_gen("dent '%.*s' ino %lu in dir ino %lu to dent '%.*s' in " ++ "dir ino %lu", old_dentry->d_name.len, old_dentry->d_name.name, ++ old_inode->i_ino, old_dir->i_ino, new_dentry->d_name.len, ++ new_dentry->d_name.name, new_dir->i_ino); ++ ++ if (unlink && is_dir) { ++ err = check_dir_empty(c, new_inode); ++ if (err) ++ return err; ++ } ++ ++ if (move) { ++ req.dirtied_ino = 1; ++ if (unlink) { ++ req.dirtied_ino += 2; ++ req.dirtied_ino_d = ubifs_inode(new_inode)->data_len; ++ } ++ } ++ ++ /* ++ * Note, rename may write @new_dir inode if the directory entry is ++ * moved there. And if the @new_dir is dirty, we do not bother to make ++ * it clean. It could be done, but requires extra coding which does not ++ * seem to be really worth it. ++ */ ++ err = ubifs_budget_inode_op(c, old_dir, &req); ++ if (err) ++ return err; ++ ++ /* ++ * Like most other Unix systems, set the ctime for inodes on a ++ * rename. ++ */ ++ old_inode->i_ctime = time; ++ ++ /* ++ * If we moved a directory to another parent directory, decrement ++ * 'i_nlink' of the old parent. Also, update 'i_size' of the old parent ++ * as well as its [mc]time. ++ */ ++ if (is_dir && move) ++ drop_nlink(old_dir); ++ old_dir->i_size -= old_sz; ++ old_dir->i_mtime = old_dir->i_ctime = time; ++ new_dir->i_mtime = new_dir->i_ctime = time; ++ ++ /* ++ * If we moved a directory object to new directory, parent's 'i_nlink' ++ * should be adjusted. ++ */ ++ if (move && is_dir) ++ inc_nlink(new_dir); ++ ++ /* ++ * And finally, if we unlinked a direntry which happened to have the ++ * same name as the moved direntry, we have to decrement 'i_nlink' of ++ * the unlinked inode and change its ctime. ++ */ ++ if (unlink) { ++ /* ++ * Directories cannot have hard-links, so if this is a ++ * directory, decrement its 'i_nlink' twice because an empty ++ * directory has 'i_nlink' 2. ++ */ ++ if (is_dir) ++ drop_nlink(new_inode); ++ new_inode->i_ctime = time; ++ drop_nlink(new_inode); ++ } else ++ new_dir->i_size += new_sz; ++ ++ err = ubifs_jnl_rename(c, old_dir, old_dentry, new_dir, new_dentry, ++ dirsync); ++ if (err) ++ goto out_inode; ++ ++ ubifs_release_ino_clean(c, old_dir, &req); ++ return 0; ++ ++out_inode: ++ if (unlink) { ++ if (is_dir) ++ inc_nlink(new_inode); ++ inc_nlink(new_inode); ++ } else ++ new_dir->i_size -= new_sz; ++ old_dir->i_size += old_sz; ++ if (is_dir && move) { ++ drop_nlink(new_dir); ++ inc_nlink(old_dir); ++ } ++ ubifs_cancel_ino_op(c, old_dir, &req); ++ return err; ++} ++ ++int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry, ++ struct kstat *stat) ++{ ++ struct inode *inode = dentry->d_inode; ++ loff_t size; ++ ++ stat->dev = inode->i_sb->s_dev; ++ stat->ino = inode->i_ino; ++ stat->mode = inode->i_mode; ++ stat->nlink = inode->i_nlink; ++ stat->uid = inode->i_uid; ++ stat->gid = inode->i_gid; ++ stat->rdev = inode->i_rdev; ++ stat->atime = inode->i_atime; ++ stat->mtime = inode->i_mtime; ++ stat->ctime = inode->i_ctime; ++ stat->blksize = UBIFS_BLOCK_SIZE; ++ stat->size = i_size_read(inode); ++ ++ spin_lock(&inode->i_lock); ++ size = ubifs_inode(inode)->xattr_size; ++ spin_unlock(&inode->i_lock); ++ ++ /* ++ * Unfortunately, the 'stat()' system call was designed for block ++ * device based file systems, and it is not appropriate for UBIFS, ++ * because UBIFS does not have notion of "block". For example, it is ++ * difficult to tell how many block a directory takes - it actually ++ * takes less than 300 bytes, but we have to round it to block size, ++ * which introduces large mistake. This makes utilities like 'du' to ++ * report completely senseless numbers. This is the reason why UBIFS ++ * goes the same way as JFFS2 - it reports zero blocks for everything ++ * but regular files, which makes more sense than reporting completely ++ * wrong sizes. ++ */ ++ if (S_ISREG(inode->i_mode)) ++ size += stat->size; ++ ++ size = ALIGN(size, UBIFS_BLOCK_SIZE); ++ /* ++ * Note, user-space expects 512-byte blocks count irrespectively of what ++ * was reported in @stat->size. ++ */ ++ stat->blocks = size >> 9; ++ ++ return 0; ++} ++ ++struct inode_operations ubifs_dir_inode_operations = { ++ .lookup = ubifs_lookup, ++ .create = ubifs_create, ++ .link = ubifs_link, ++ .symlink = ubifs_symlink, ++ .unlink = ubifs_unlink, ++ .mkdir = ubifs_mkdir, ++ .rmdir = ubifs_rmdir, ++ .mknod = ubifs_mknod, ++ .rename = ubifs_rename, ++ .setattr = ubifs_setattr, ++ .getattr = ubifs_getattr, ++#ifdef CONFIG_UBIFS_FS_XATTR ++ .setxattr = ubifs_setxattr, ++ .getxattr = ubifs_getxattr, ++ .listxattr = ubifs_listxattr, ++ .removexattr = ubifs_removexattr, ++#endif ++}; ++ ++struct file_operations ubifs_dir_operations = { ++ .llseek = ubifs_dir_llseek, ++ .release = ubifs_dir_release, ++ .read = generic_read_dir, ++ .readdir = ubifs_readdir, ++ .fsync = ubifs_fsync, ++ .unlocked_ioctl = ubifs_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = ubifs_compat_ioctl, ++#endif ++}; +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/file.c avr32-2.6/fs/ubifs/file.c +--- linux-2.6.25.6/fs/ubifs/file.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/file.c 2008-06-12 15:09:45.364399968 +0200 +@@ -0,0 +1,960 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Artem Bityutskiy (Битюцкий Артём) ++ * Adrian Hunter ++ */ ++ ++/* ++ * This file implements VFS file and inode operations of regular files, device ++ * nodes and symlinks as well as address space operations. ++ * ++ * UBIFS uses 2 page flags: PG_private and PG_checked. PG_private is set if the ++ * page is dirty and is used for budgeting purposes - dirty pages should not be ++ * budgeted. The PG_checked flag is set if full budgeting is required for the ++ * page e.g., when it corresponds to a file hole or it is just beyond the file ++ * size. The budgeting is done in 'ubifs_write_begin()', because it is OK to ++ * fail in this function, and the budget is released in 'ubifs_write_end()'. So ++ * the PG_private and PG_checked flags carry the information about how the page ++ * was budgeted, to make it possible to release the budget properly. ++ * ++ * A thing to keep in mind: inode's 'i_mutex' is locked in most VFS operations ++ * we implement. However, this is not true for '->writepage()', which might be ++ * called with 'i_mutex' unlocked. For example, when pdflush is performing ++ * write-back, it calls 'writepage()' with unlocked 'i_mutex', although the ++ * inode has 'I_LOCK' flag in this case. At "normal" work-paths 'i_mutex' is ++ * locked in '->writepage', e.g. in "sys_write -> alloc_pages -> direct reclaim ++ * path'. So, in '->writepage()' we are only guaranteed that the page is ++ * locked. ++ * ++ * Similarly, 'i_mutex' does not have to be locked in readpage(), e.g., ++ * readahead path does not have it locked ("sys_read -> generic_file_aio_read ++ * -> ondemand_readahead -> readpage"). In case of readahead, 'I_LOCK' flag is ++ * not set as well. ++ * ++ * This, for example means that there might be 2 concurrent '->writepage()' ++ * calls for the same inode, but different inode dirty pages. ++ */ ++ ++#include "ubifs.h" ++#include <linux/mount.h> ++ ++static int read_block(struct inode *inode, void *addr, unsigned int block, ++ struct ubifs_data_node *dn) ++{ ++ struct ubifs_info *c = inode->i_sb->s_fs_info; ++ int err, len, out_len; ++ union ubifs_key key; ++ unsigned int dlen; ++ ++ data_key_init(c, &key, inode->i_ino, block); ++ err = ubifs_tnc_lookup(c, &key, dn); ++ if (err) { ++ if (err == -ENOENT) ++ /* Not found, so it must be a hole */ ++ memset(addr, 0, UBIFS_BLOCK_SIZE); ++ return err; ++ } ++ ++ ubifs_assert(dn->ch.sqnum > ubifs_inode(inode)->creat_sqnum); ++ ++ len = le32_to_cpu(dn->size); ++ if (len <= 0 || len > UBIFS_BLOCK_SIZE) ++ goto dump; ++ ++ dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ; ++ out_len = UBIFS_BLOCK_SIZE; ++ err = ubifs_decompress(&dn->data, dlen, addr, &out_len, ++ le16_to_cpu(dn->compr_type)); ++ if (err || len != out_len) ++ goto dump; ++ ++ /* ++ * Data length can be less than a full block, even for blocks that are ++ * not the last in the file (e.g., as a result of making a hole and ++ * appending data). Ensure that the remainder is zeroed out. ++ */ ++ if (len < UBIFS_BLOCK_SIZE) ++ memset(addr + len, 0, UBIFS_BLOCK_SIZE - len); ++ ++ return 0; ++ ++dump: ++ ubifs_err("bad data node (block %u, inode %lu)", ++ block, inode->i_ino); ++ dbg_dump_node(c, dn); ++ return -EINVAL; ++} ++ ++static int do_readpage(struct page *page) ++{ ++ void *addr; ++ int err = 0, i; ++ unsigned int block, beyond; ++ struct ubifs_data_node *dn; ++ struct inode *inode = page->mapping->host; ++ loff_t i_size = i_size_read(inode); ++ ++ dbg_gen("ino %lu, pg %lu, i_size %lld, flags %#lx", ++ inode->i_ino, page->index, i_size, page->flags); ++ ubifs_assert(!PageChecked(page)); ++ ubifs_assert(!PagePrivate(page)); ++ ++ addr = kmap(page); ++ ++ block = page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT; ++ beyond = (i_size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT; ++ if (block >= beyond) { ++ /* Reading beyond inode */ ++ SetPageChecked(page); ++ memset(addr, 0, PAGE_CACHE_SIZE); ++ goto out; ++ } ++ ++ dn = kmalloc(UBIFS_MAX_DATA_NODE_SZ, GFP_NOFS); ++ if (!dn) { ++ err = -ENOMEM; ++ goto error; ++ } ++ ++ i = 0; ++ while (1) { ++ int ret; ++ ++ if (block >= beyond) { ++ /* Reading beyond inode */ ++ err = -ENOENT; ++ memset(addr, 0, UBIFS_BLOCK_SIZE); ++ } else { ++ ret = read_block(inode, addr, block, dn); ++ if (ret) { ++ err = ret; ++ if (err != -ENOENT) ++ break; ++ } ++ } ++ if (++i >= UBIFS_BLOCKS_PER_PAGE) ++ break; ++ block += 1; ++ addr += UBIFS_BLOCK_SIZE; ++ } ++ if (err) { ++ if (err == -ENOENT) { ++ /* Not found, so it must be a hole */ ++ SetPageChecked(page); ++ dbg_gen("hole"); ++ goto out_free; ++ } ++ ubifs_err("cannot read page %lu of inode %lu, error %d", ++ page->index, inode->i_ino, err); ++ goto error; ++ } ++ ++out_free: ++ kfree(dn); ++out: ++ SetPageUptodate(page); ++ ClearPageError(page); ++ flush_dcache_page(page); ++ kunmap(page); ++ return 0; ++ ++error: ++ kfree(dn); ++ ClearPageUptodate(page); ++ SetPageError(page); ++ flush_dcache_page(page); ++ kunmap(page); ++ return err; ++} ++ ++static int ubifs_write_begin(struct file *file, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned flags, ++ struct page **pagep, void **fsdata) ++{ ++ struct inode *inode = mapping->host; ++ struct ubifs_info *c = inode->i_sb->s_fs_info; ++ pgoff_t index = pos >> PAGE_CACHE_SHIFT; ++ struct ubifs_budget_req req = { .new_page = 1 }; ++ loff_t i_size = i_size_read(inode); ++ int uninitialized_var(err); ++ struct page *page; ++ ++ ubifs_assert(!(inode->i_sb->s_flags & MS_RDONLY)); ++ ++ if (unlikely(c->ro_media)) ++ return -EROFS; ++ ++ /* ++ * We are about to have a page of data written and we have to budget for ++ * this. The very important point here is that we have to budget before ++ * locking the page, because budgeting may force write-back, which ++ * would wait on locked pages and deadlock if we had the page locked. ++ * ++ * At this point we do not know anything about the page of data we are ++ * going to change, so assume the biggest budget (i.e., assume that ++ * this is a new page of data and it does not override an older page of ++ * data in the inode). Later the budget will be amended if this is not ++ * true. ++ */ ++ if (pos + len > i_size) ++ /* ++ * We are writing beyond the file which means we are going to ++ * change inode size and make the inode dirty. And in turn, ++ * this means we have to budget for making the inode dirty. ++ * ++ * Note, if the inode is already dirty, ++ * 'ubifs_budget_inode_op()' will not allocate any budget, ++ * but will just lock the @budg_mutex of the inode to prevent ++ * it from becoming clean before we have changed its size, ++ * which is going to happen in 'ubifs_write_end()'. ++ */ ++ err = ubifs_budget_inode_op(c, inode, &req); ++ else ++ /* ++ * The inode is not going to be marked as dirty by this write ++ * operation, do not budget for this. ++ */ ++ err = ubifs_budget_space(c, &req); ++ if (unlikely(err)) ++ return err; ++ ++ page = __grab_cache_page(mapping, index); ++ if (unlikely(!page)) { ++ err = -ENOMEM; ++ goto out_release; ++ } ++ ++ if (!PageUptodate(page)) { ++ /* ++ * The page is not loaded from the flash and has to be loaded ++ * unless we are writing all of it. ++ */ ++ if (!(pos & PAGE_CACHE_MASK) && len == PAGE_CACHE_SIZE) ++ /* ++ * Set the PG_checked flag to make the further code ++ * assume the page is new. ++ */ ++ SetPageChecked(page); ++ else { ++ err = do_readpage(page); ++ if (err) ++ goto out_unlock; ++ } ++ ++ SetPageUptodate(page); ++ ClearPageError(page); ++ } ++ ++ if (PagePrivate(page)) ++ /* ++ * The page is dirty, which means it was budgeted twice: ++ * o first time the budget was allocated by the task which ++ * made the page dirty and set the PG_private flag; ++ * o and then we budgeted for it for the second time at the ++ * very beginning of this function. ++ * ++ * So what we have to do is to release the page budget we ++ * allocated. ++ * ++ * Note, the page write operation may change the inode length, ++ * which makes it dirty and means the budget should be ++ * allocated. This was done above in the "pos + len > i_size" ++ * case. If this was done, we do not free the the inode budget, ++ * because we cannot as we are really going to mark it dirty in ++ * the 'ubifs_write_end()' function. ++ */ ++ ubifs_release_new_page_budget(c); ++ else if (!PageChecked(page)) ++ /* ++ * The page is not new, which means we are changing the page ++ * which already exists on the media. This means that changing ++ * the page does not make the amount of indexing information ++ * larger, and this part of the budget which we have already ++ * acquired may be released. ++ */ ++ ubifs_convert_page_budget(c); ++ ++ *pagep = page; ++ return 0; ++ ++out_unlock: ++ unlock_page(page); ++ page_cache_release(page); ++out_release: ++ if (pos + len > i_size) ++ ubifs_cancel_ino_op(c, inode, &req); ++ else ++ ubifs_release_budget(c, &req); ++ return err; ++} ++ ++static int ubifs_write_end(struct file *file, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned copied, ++ struct page *page, void *fsdata) ++{ ++ struct inode *inode = mapping->host; ++ struct ubifs_inode *ui = ubifs_inode(inode); ++ struct ubifs_info *c = inode->i_sb->s_fs_info; ++ loff_t i_size = i_size_read(inode); ++ ++ dbg_gen("ino %lu, pos %llu, pg %lu, len %u, copied %d, i_size %lld", ++ inode->i_ino, pos, page->index, len, copied, i_size); ++ ++ if (unlikely(copied < len && len == PAGE_CACHE_SIZE)) { ++ /* ++ * VFS copied less data to the page that it intended and ++ * declared in its '->write_begin()' call via the @len ++ * argument. If the page was not up-to-date, and @len was ++ * @PAGE_CACHE_SIZE, the 'ubifs_write_begin()' function did ++ * not load it from the media (for optimization reasons). This ++ * means that part of the page contains garbage. So read the ++ * page now. ++ */ ++ dbg_gen("copied %d instead of %d, read page and repeat", ++ copied, len); ++ ++ if (pos + len > i_size) ++ /* See a comment below about this hacky unlock */ ++ mutex_unlock(&ui->budg_mutex); ++ ++ copied = do_readpage(page); ++ ++ /* ++ * Return 0 to force VFS to repeat the whole operation, or the ++ * error code if 'do_readpage()' failed. ++ */ ++ goto out; ++ } ++ ++ if (!PagePrivate(page)) { ++ SetPagePrivate(page); ++ atomic_long_inc(&c->dirty_pg_cnt); ++ __set_page_dirty_nobuffers(page); ++ } ++ ++ if (pos + len > i_size) { ++ i_size_write(inode, pos + len); ++ ++ /* ++ * Note, we do not set @I_DIRTY_PAGES (which means that the ++ * inode has dirty pages), this has been done in ++ * '__set_page_dirty_nobuffers()'. ++ */ ++ mark_inode_dirty_sync(inode); ++ ++ /* ++ * The inode has been marked dirty, unlock it. This is a bit ++ * hacky because normally we would have to call ++ * 'ubifs_release_ino_dirty()'. But we know there is nothing ++ * to release because page's budget will be released in ++ * 'ubifs_write_page()' and inode's budget will be released in ++ * 'ubifs_write_inode()', so just unlock the inode here for ++ * optimization. ++ */ ++ mutex_unlock(&ui->budg_mutex); ++ } ++ ++out: ++ unlock_page(page); ++ page_cache_release(page); ++ return copied; ++} ++ ++static int ubifs_readpage(struct file *file, struct page *page) ++{ ++ do_readpage(page); ++ unlock_page(page); ++ return 0; ++} ++ ++/** ++ * release_existing_page_budget - release budget of an existing page. ++ * @c: UBIFS file-system description object ++ * ++ * This is a helper function which releases budget corresponding to the budget ++ * of changing one one page of data which already exists on the flash media. ++ * ++ * This function was not moved to "budget.c" because there is only one user. ++ */ ++static void release_existing_page_budget(struct ubifs_info *c) ++{ ++ struct ubifs_budget_req req = { .dd_growth = c->page_budget}; ++ ++ ubifs_release_budget(c, &req); ++} ++ ++static int do_writepage(struct page *page, int len) ++{ ++ int err = 0, i, blen; ++ unsigned int block; ++ void *addr; ++ union ubifs_key key; ++ struct inode *inode = page->mapping->host; ++ struct ubifs_info *c = inode->i_sb->s_fs_info; ++ ++ /* Update radix tree tags */ ++ set_page_writeback(page); ++ ++ addr = kmap(page); ++ ++ block = page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT; ++ i = 0; ++ while (len) { ++ blen = min_t(int, len, UBIFS_BLOCK_SIZE); ++ data_key_init(c, &key, inode->i_ino, block); ++ err = ubifs_jnl_write_data(c, inode, &key, addr, blen); ++ if (err) ++ break; ++ if (++i >= UBIFS_BLOCKS_PER_PAGE) ++ break; ++ block += 1; ++ addr += blen; ++ len -= blen; ++ } ++ if (err) { ++ SetPageError(page); ++ ubifs_err("cannot write page %lu of inode %lu, error %d", ++ page->index, inode->i_ino, err); ++ ubifs_ro_mode(c, err); ++ } ++ ++ ubifs_assert(PagePrivate(page)); ++ if (PageChecked(page)) ++ ubifs_release_new_page_budget(c); ++ else ++ release_existing_page_budget(c); ++ ++ atomic_long_dec(&c->dirty_pg_cnt); ++ ClearPagePrivate(page); ++ ClearPageChecked(page); ++ ++ kunmap(page); ++ unlock_page(page); ++ end_page_writeback(page); ++ ++ return err; ++} ++ ++static int ubifs_writepage(struct page *page, struct writeback_control *wbc) ++{ ++ struct inode *inode = page->mapping->host; ++ loff_t i_size = i_size_read(inode); ++ pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; ++ int len; ++ void *kaddr; ++ ++ dbg_gen("ino %lu, pg %lu, pg flags %#lx", ++ inode->i_ino, page->index, page->flags); ++ ubifs_assert(PagePrivate(page)); ++ ++ /* Is the page fully inside i_size? */ ++ if (page->index < end_index) ++ return do_writepage(page, PAGE_CACHE_SIZE); ++ ++ /* Is the page fully outside i_size? (truncate in progress) */ ++ len = i_size & (PAGE_CACHE_SIZE - 1); ++ if (page->index >= end_index + 1 || !len) { ++ unlock_page(page); ++ return 0; ++ } ++ ++ /* ++ * The page straddles i_size. It must be zeroed out on each and every ++ * writepage invocation because it may be mmapped. "A file is mapped ++ * in multiples of the page size. For a file that is not a multiple of ++ * the page size, the remaining memory is zeroed when mapped, and ++ * writes to that region are not written out to the file." ++ */ ++ kaddr = kmap_atomic(page, KM_USER0); ++ memset(kaddr + len, 0, PAGE_CACHE_SIZE - len); ++ flush_dcache_page(page); ++ kunmap_atomic(kaddr, KM_USER0); ++ ++ return do_writepage(page, len); ++} ++ ++static int ubifs_trunc(struct inode *inode, loff_t new_size) ++{ ++ loff_t old_size; ++ int err; ++ ++ dbg_gen("ino %lu, size %lld -> %lld", ++ inode->i_ino, inode->i_size, new_size); ++ old_size = inode->i_size; ++ ++ err = vmtruncate(inode, new_size); ++ if (err) ++ return err; ++ ++ if (new_size < old_size) { ++ struct ubifs_info *c = inode->i_sb->s_fs_info; ++ int offset = new_size & (UBIFS_BLOCK_SIZE - 1); ++ ++ if (offset) { ++ pgoff_t index = new_size >> PAGE_CACHE_SHIFT; ++ struct page *page; ++ ++ page = find_lock_page(inode->i_mapping, index); ++ if (page) { ++ if (PageDirty(page)) { ++ ubifs_assert(PagePrivate(page)); ++ ++ clear_page_dirty_for_io(page); ++ if (UBIFS_BLOCKS_PER_PAGE_SHIFT) ++ offset = new_size & ++ (PAGE_CACHE_SIZE - 1); ++ err = do_writepage(page, offset); ++ page_cache_release(page); ++ if (err) ++ return err; ++ /* ++ * We could now tell ubifs_jnl_truncate ++ * not to read the last block. ++ */ ++ } else { ++ /* ++ * We could 'kmap()' the page and ++ * pass the data to ubifs_jnl_truncate ++ * to save it from having to read it. ++ */ ++ unlock_page(page); ++ page_cache_release(page); ++ } ++ } ++ } ++ err = ubifs_jnl_truncate(c, inode->i_ino, old_size, new_size); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} ++ ++int ubifs_setattr(struct dentry *dentry, struct iattr *attr) ++{ ++ unsigned int ia_valid = attr->ia_valid; ++ struct inode *inode = dentry->d_inode; ++ struct ubifs_info *c = inode->i_sb->s_fs_info; ++ struct ubifs_budget_req req; ++ int truncation, err = 0; ++ ++ dbg_gen("ino %lu, ia_valid %#x", inode->i_ino, ia_valid); ++ err = inode_change_ok(inode, attr); ++ if (err) ++ return err; ++ ++ memset(&req, 0, sizeof(struct ubifs_budget_req)); ++ ++ /* ++ * If this is truncation, and we do not truncate on a block boundary, ++ * budget for changing one data block, because the last block will be ++ * re-written. ++ */ ++ truncation = (ia_valid & ATTR_SIZE) && attr->ia_size != inode->i_size; ++ if (truncation && attr->ia_size < inode->i_size && ++ (attr->ia_size & (UBIFS_BLOCK_SIZE - 1))) ++ req.dirtied_page = 1; ++ ++ err = ubifs_budget_inode_op(c, inode, &req); ++ if (err) ++ return err; ++ ++ if (truncation) { ++ err = ubifs_trunc(inode, attr->ia_size); ++ if (err) { ++ ubifs_cancel_ino_op(c, inode, &req); ++ return err; ++ } ++ ++ inode->i_mtime = inode->i_ctime = ubifs_current_time(inode); ++ } ++ ++ if (ia_valid & ATTR_UID) ++ inode->i_uid = attr->ia_uid; ++ if (ia_valid & ATTR_GID) ++ inode->i_gid = attr->ia_gid; ++ if (ia_valid & ATTR_ATIME) ++ inode->i_atime = timespec_trunc(attr->ia_atime, ++ inode->i_sb->s_time_gran); ++ if (ia_valid & ATTR_MTIME) ++ inode->i_mtime = timespec_trunc(attr->ia_mtime, ++ inode->i_sb->s_time_gran); ++ if (ia_valid & ATTR_CTIME) ++ inode->i_ctime = timespec_trunc(attr->ia_ctime, ++ inode->i_sb->s_time_gran); ++ if (ia_valid & ATTR_MODE) { ++ umode_t mode = attr->ia_mode; ++ ++ if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) ++ mode &= ~S_ISGID; ++ inode->i_mode = mode; ++ } ++ ++ mark_inode_dirty_sync(inode); ++ ubifs_release_ino_dirty(c, inode, &req); ++ ++ if (req.dirtied_page) { ++ /* ++ * Truncation code does not make the reenacted page dirty, it ++ * just changes it on journal level, so we have to release page ++ * change budget. ++ */ ++ memset(&req, 0, sizeof(struct ubifs_budget_req)); ++ req.dd_growth = c->page_budget; ++ ubifs_release_budget(c, &req); ++ } ++ ++ if (IS_SYNC(inode)) ++ err = write_inode_now(inode, 1); ++ ++ return err; ++} ++ ++static void ubifs_invalidatepage(struct page *page, unsigned long offset) ++{ ++ struct inode *inode = page->mapping->host; ++ struct ubifs_info *c = inode->i_sb->s_fs_info; ++ struct ubifs_budget_req req; ++ ++ ubifs_assert(PagePrivate(page)); ++ if (offset) ++ /* Partial page remains dirty */ ++ return; ++ ++ memset(&req, 0, sizeof(struct ubifs_budget_req)); ++ if (PageChecked(page)) { ++ req.new_page = 1; ++ req.idx_growth = -1; ++ req.data_growth = c->page_budget; ++ } else ++ req.dd_growth = c->page_budget; ++ ubifs_release_budget(c, &req); ++ ++ atomic_long_dec(&c->dirty_pg_cnt); ++ ClearPagePrivate(page); ++ ClearPageChecked(page); ++} ++ ++static void *ubifs_follow_link(struct dentry *dentry, struct nameidata *nd) ++{ ++ struct ubifs_inode *ui = ubifs_inode(dentry->d_inode); ++ ++ nd_set_link(nd, ui->data); ++ return NULL; ++} ++ ++int ubifs_fsync(struct file *file, struct dentry *dentry, int datasync) ++{ ++ struct inode *inode = dentry->d_inode; ++ struct ubifs_info *c = inode->i_sb->s_fs_info; ++ int err; ++ ++ dbg_gen("syncing inode %lu", inode->i_ino); ++ ++ /* Synchronize the inode and dirty pages */ ++ err = write_inode_now(inode, 1); ++ if (err) ++ return err; ++ ++ /* ++ * Some data related to this inode may still sit in a write-buffer. ++ * Flush them. ++ */ ++ err = ubifs_sync_wbufs_by_inodes(c, &inode, 1); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++/** ++ * mctime_update_needed - check if mtime or ctime update is needed. ++ * @inode: the inode to do the check for ++ * @now: current time ++ * ++ * This helper function checks if the inode mtime/ctime should be updated or ++ * not. If current values of the time-stamps are within the UBIFS inode time ++ * granularity, they are not updated. This is an optimization. ++ */ ++static inline int mctime_update_needed(const struct inode *inode, ++ const struct timespec *now) ++{ ++ if (!timespec_equal(&inode->i_mtime, now) || ++ !timespec_equal(&inode->i_ctime, now)) ++ return 1; ++ return 0; ++} ++ ++/** ++ * update_ctime - update mtime and ctime of an inode. ++ * @c: UBIFS file-system description object ++ * @inode: inode to update ++ * ++ * This function updates mtime and ctime of the inode if it is not equivalent to ++ * current time. Returns zero in case of success and a negative error code in ++ * case of failure. ++ */ ++static int update_mctime(struct ubifs_info *c, struct inode *inode) ++{ ++ struct timespec now = ubifs_current_time(inode); ++ ++ if (mctime_update_needed(inode, &now)) { ++ struct ubifs_budget_req req; ++ int err; ++ ++ memset(&req, 0, sizeof(struct ubifs_budget_req)); ++ err = ubifs_budget_inode_op(c, inode, &req); ++ if (err) ++ return err; ++ ++ inode->i_mtime = inode->i_ctime = now; ++ mark_inode_dirty_sync(inode); ++ mutex_unlock(&ubifs_inode(inode)->budg_mutex); ++ } ++ ++ return 0; ++} ++ ++static ssize_t ubifs_write(struct file *file, const char __user *buf, ++ size_t len, loff_t *ppos) ++{ ++ int err; ++ ssize_t ret; ++ struct inode *inode = file->f_mapping->host; ++ struct ubifs_info *c = inode->i_sb->s_fs_info; ++ ++ err = update_mctime(c, inode); ++ if (err) ++ return err; ++ ++ ret = do_sync_write(file, buf, len, ppos); ++ if (ret < 0) ++ return ret; ++ ++ if (ret > 0 && IS_SYNC(inode)) { ++ err = ubifs_sync_wbufs_by_inodes(c, &inode, 1); ++ if (err) ++ return err; ++ } ++ ++ return ret; ++} ++ ++static ssize_t ubifs_aio_write(struct kiocb *iocb, const struct iovec *iov, ++ unsigned long nr_segs, loff_t pos) ++{ ++ int err; ++ ssize_t ret; ++ struct inode *inode = iocb->ki_filp->f_mapping->host; ++ struct ubifs_info *c = inode->i_sb->s_fs_info; ++ ++ err = update_mctime(c, inode); ++ if (err) ++ return err; ++ ++ ret = generic_file_aio_write(iocb, iov, nr_segs, pos); ++ if (ret < 0) ++ return ret; ++ ++ if (ret > 0 && IS_SYNC(inode)) { ++ err = ubifs_sync_wbufs_by_inodes(c, &inode, 1); ++ if (err) ++ return err; ++ } ++ ++ return ret; ++} ++ ++static int ubifs_set_page_dirty(struct page *page) ++{ ++ int ret; ++ ++ ret = __set_page_dirty_nobuffers(page); ++ /* ++ * An attempt to dirty a page without budgeting for it - should not ++ * happen. ++ */ ++ ubifs_assert(ret == 0); ++ return ret; ++} ++ ++static int ubifs_releasepage(struct page *page, gfp_t unused_gfp_flags) ++{ ++ /* ++ * An attempt to release a dirty page without budgeting for it - should ++ * not happen. ++ */ ++ if (PageWriteback(page)) ++ return 0; ++ ubifs_assert(PagePrivate(page)); ++ ubifs_assert(0); ++ ClearPagePrivate(page); ++ ClearPageChecked(page); ++ return 1; ++} ++ ++/* ++ * mmap()d file has taken write protection fault and is being made ++ * writable. UBIFS must ensure page is budgeted for. ++ */ ++static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page) ++{ ++ struct inode *inode = vma->vm_file->f_path.dentry->d_inode; ++ struct ubifs_info *c = inode->i_sb->s_fs_info; ++ struct timespec now = ubifs_current_time(inode); ++ struct ubifs_budget_req req = { .new_page = 1 }; ++ int err, update_time; ++ ++ dbg_gen("ino %lu, pg %lu, i_size %lld", inode->i_ino, page->index, ++ i_size_read(inode)); ++ ubifs_assert(!(inode->i_sb->s_flags & MS_RDONLY)); ++ ++ if (unlikely(c->ro_media)) ++ return -EROFS; ++ ++ /* ++ * We have not locked @page so far so we may budget for changing the ++ * page. Note, we cannot do this after we locked the page, because ++ * budgeting may cause write-back which would cause deadlock. ++ * ++ * At the moment we do not know whether the page is dirty or not, so we ++ * assume that it is not and budget for a new page. We could look at ++ * the @PG_private flag and figure this out, but we may race with write ++ * back and the page state may change by the time we lock it, so this ++ * would need additional care. We do not bother with this at the ++ * moment, although it might be good idea to do. Instead, we allocate ++ * budget for a new page and amend it later on if the page was in fact ++ * dirty. ++ * ++ * The budgeting-related logic of this function is similar to what we ++ * do in 'ubifs_write_begin()' and 'ubifs_write_end()'. Glance there ++ * for more comments. ++ */ ++ if (mctime_update_needed(inode, &now)) { ++ /* ++ * We have to change inode time stamp which requires extra ++ * budgeting. ++ */ ++ update_time = 1; ++ err = ubifs_budget_inode_op(c, inode, &req); ++ } else { ++ update_time = 0; ++ err = ubifs_budget_space(c, &req); ++ } ++ if (unlikely(err)) { ++ if (err == -ENOSPC) ++ ubifs_warn("out of space for mmapped file " ++ "(inode number %lu)", inode->i_ino); ++ return err; ++ } ++ ++ lock_page(page); ++ if (unlikely(page->mapping != inode->i_mapping || ++ page_offset(page) > i_size_read(inode))) { ++ /* Page got truncated out from underneath us */ ++ err = -EINVAL; ++ goto out_unlock; ++ } ++ ++ if (PagePrivate(page)) ++ ubifs_release_new_page_budget(c); ++ else { ++ if (!PageChecked(page)) ++ ubifs_convert_page_budget(c); ++ SetPagePrivate(page); ++ atomic_long_inc(&c->dirty_pg_cnt); ++ __set_page_dirty_nobuffers(page); ++ } ++ ++ if (update_time) { ++ inode->i_mtime = inode->i_ctime = now; ++ mark_inode_dirty_sync(inode); ++ mutex_unlock(&ubifs_inode(inode)->budg_mutex); ++ } ++ ++ unlock_page(page); ++ return 0; ++ ++out_unlock: ++ unlock_page(page); ++ if (update_time) ++ ubifs_cancel_ino_op(c, inode, &req); ++ else ++ ubifs_release_budget(c, &req); ++ return err; ++} ++ ++struct vm_operations_struct ubifs_file_vm_ops = { ++ .fault = filemap_fault, ++ .page_mkwrite = ubifs_vm_page_mkwrite, ++}; ++ ++static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ int err; ++ ++ /* 'generic_file_mmap()' takes care of NOMMU case */ ++ err = generic_file_mmap(file, vma); ++ if (err) ++ return err; ++ vma->vm_ops = &ubifs_file_vm_ops; ++ return 0; ++} ++ ++struct address_space_operations ubifs_file_address_operations = { ++ .readpage = ubifs_readpage, ++ .writepage = ubifs_writepage, ++ .write_begin = ubifs_write_begin, ++ .write_end = ubifs_write_end, ++ .invalidatepage = ubifs_invalidatepage, ++ .set_page_dirty = ubifs_set_page_dirty, ++ .releasepage = ubifs_releasepage, ++}; ++ ++struct inode_operations ubifs_file_inode_operations = { ++ .setattr = ubifs_setattr, ++ .getattr = ubifs_getattr, ++#ifdef CONFIG_UBIFS_FS_XATTR ++ .setxattr = ubifs_setxattr, ++ .getxattr = ubifs_getxattr, ++ .listxattr = ubifs_listxattr, ++ .removexattr = ubifs_removexattr, ++#endif ++}; ++ ++struct inode_operations ubifs_symlink_inode_operations = { ++ .readlink = generic_readlink, ++ .follow_link = ubifs_follow_link, ++ .setattr = ubifs_setattr, ++ .getattr = ubifs_getattr, ++}; ++ ++struct file_operations ubifs_file_operations = { ++ .llseek = generic_file_llseek, ++ .read = do_sync_read, ++ .write = ubifs_write, ++ .aio_read = generic_file_aio_read, ++ .aio_write = ubifs_aio_write, ++ .mmap = ubifs_file_mmap, ++ .fsync = ubifs_fsync, ++ .unlocked_ioctl = ubifs_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = ubifs_compat_ioctl, ++#endif ++}; +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/find.c avr32-2.6/fs/ubifs/find.c +--- linux-2.6.25.6/fs/ubifs/find.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/find.c 2008-06-12 15:09:45.364399968 +0200 +@@ -0,0 +1,977 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Artem Bityutskiy (Битюцкий Артём) ++ * Adrian Hunter ++ */ ++ ++/* ++ * This file contains functions for finding LEBs for various purposes e.g. ++ * garbage collection. In general, lprops category heaps and lists are used ++ * for fast access, falling back on scanning the LPT as a last resort. ++ */ ++ ++#include <linux/sort.h> ++#include "ubifs.h" ++ ++/** ++ * struct scan_data - data provided to scan callback functions ++ * @min_space: minimum number of bytes for which to scan ++ * @pick_free: whether it is OK to scan for empty LEBs ++ * @lnum: LEB number found is returned here ++ * @exclude_index: whether to exclude index LEBs ++ */ ++struct scan_data { ++ int min_space; ++ int pick_free; ++ int lnum; ++ int exclude_index; ++}; ++ ++/** ++ * valuable - determine whether LEB properties are valuable. ++ * @c: the UBIFS file-system description object ++ * @lprops: LEB properties ++ * ++ * This function return %1 if the LEB properties should be added to the LEB ++ * properties tree in memory. Otherwise %0 is returned. ++ */ ++static int valuable(struct ubifs_info *c, const struct ubifs_lprops *lprops) ++{ ++ int n, cat = lprops->flags & LPROPS_CAT_MASK; ++ struct ubifs_lpt_heap *heap; ++ ++ switch (cat) { ++ case LPROPS_DIRTY: ++ case LPROPS_DIRTY_IDX: ++ case LPROPS_FREE: ++ heap = &c->lpt_heap[cat - 1]; ++ if (heap->cnt < heap->max_cnt) ++ return 1; ++ if (lprops->free + lprops->dirty >= c->dark_wm) ++ return 1; ++ return 0; ++ case LPROPS_EMPTY: ++ n = c->lst.empty_lebs + c->freeable_cnt - ++ c->lst.taken_empty_lebs; ++ if (n < c->lsave_cnt) ++ return 1; ++ return 0; ++ case LPROPS_FREEABLE: ++ return 1; ++ case LPROPS_FRDI_IDX: ++ return 1; ++ } ++ return 0; ++} ++ ++/** ++ * scan_for_dirty_cb - dirty space scan callback. ++ * @c: the UBIFS file-system description object ++ * @lprops: LEB properties to scan ++ * @in_tree: whether the LEB properties are in main memory ++ * @data: information passed to and from the caller of the scan ++ * ++ * This function returns a code that indicates whether the scan should continue ++ * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree ++ * in main memory (%LPT_SCAN_ADD), or whether the scan should stop ++ * (%LPT_SCAN_STOP). ++ */ ++static int scan_for_dirty_cb(struct ubifs_info *c, ++ const struct ubifs_lprops *lprops, int in_tree, ++ struct scan_data *data) ++{ ++ int ret = LPT_SCAN_CONTINUE; ++ ++ /* Exclude LEBs that are currently in use */ ++ if (lprops->flags & LPROPS_TAKEN) ++ return LPT_SCAN_CONTINUE; ++ /* Determine whether to add these LEB properties to the tree */ ++ if (!in_tree && valuable(c, lprops)) ++ ret |= LPT_SCAN_ADD; ++ /* Exclude LEBs with too little space */ ++ if (lprops->free + lprops->dirty < data->min_space) ++ return ret; ++ /* If specified, exclude index LEBs */ ++ if (data->exclude_index && lprops->flags & LPROPS_INDEX) ++ return ret; ++ /* If specified, exclude empty or freeable LEBs */ ++ if (lprops->free + lprops->dirty == c->leb_size) { ++ if (!data->pick_free) ++ return ret; ++ /* Exclude LEBs with too little dirty space (unless it is empty) */ ++ } else if (lprops->dirty < c->dead_wm) ++ return ret; ++ /* Finally we found space */ ++ data->lnum = lprops->lnum; ++ return LPT_SCAN_ADD | LPT_SCAN_STOP; ++} ++ ++/** ++ * scan_for_dirty - find a data LEB with free space. ++ * @c: the UBIFS file-system description object ++ * @min_space: minimum amount free plus dirty space the returned LEB has to ++ * have ++ * @pick_free: if it is OK to return a free or freeable LEB ++ * @exclude_index: whether to exclude index LEBs ++ * ++ * This function returns a pointer to the LEB properties found or a negative ++ * error code. ++ */ ++static const struct ubifs_lprops *scan_for_dirty(struct ubifs_info *c, ++ int min_space, int pick_free, ++ int exclude_index) ++{ ++ const struct ubifs_lprops *lprops; ++ struct ubifs_lpt_heap *heap; ++ struct scan_data data; ++ int err, i; ++ ++ /* There may be an LEB with enough dirty space on the free heap */ ++ heap = &c->lpt_heap[LPROPS_FREE - 1]; ++ for (i = 0; i < heap->cnt; i++) { ++ lprops = heap->arr[i]; ++ if (lprops->free + lprops->dirty < min_space) ++ continue; ++ if (lprops->dirty < c->dead_wm) ++ continue; ++ return lprops; ++ } ++ /* ++ * A LEB may have fallen off of the bottom of the dirty heap, and ended ++ * up as uncategorized even though it has enough dirty space for us now, ++ * so check the uncategorized list. N.B. neither empty nor freeable LEBs ++ * can end up as uncategorized because they are kept on lists not ++ * finite-sized heaps. ++ */ ++ list_for_each_entry(lprops, &c->uncat_list, list) { ++ if (lprops->flags & LPROPS_TAKEN) ++ continue; ++ if (lprops->free + lprops->dirty < min_space) ++ continue; ++ if (exclude_index && (lprops->flags & LPROPS_INDEX)) ++ continue; ++ if (lprops->dirty < c->dead_wm) ++ continue; ++ return lprops; ++ } ++ /* We have looked everywhere in main memory, now scan the flash */ ++ if (c->pnodes_have >= c->pnode_cnt) ++ /* All pnodes are in memory, so skip scan */ ++ return ERR_PTR(-ENOSPC); ++ data.min_space = min_space; ++ data.pick_free = pick_free; ++ data.lnum = -1; ++ data.exclude_index = exclude_index; ++ err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum, ++ (ubifs_lpt_scan_callback)scan_for_dirty_cb, ++ &data); ++ if (err) ++ return ERR_PTR(err); ++ ubifs_assert(data.lnum >= c->main_first && data.lnum < c->leb_cnt); ++ c->lscan_lnum = data.lnum; ++ lprops = ubifs_lpt_lookup_dirty(c, data.lnum); ++ if (IS_ERR(lprops)) ++ return lprops; ++ ubifs_assert(lprops->lnum == data.lnum); ++ ubifs_assert(lprops->free + lprops->dirty >= min_space); ++ ubifs_assert(lprops->dirty >= c->dead_wm || ++ (pick_free && ++ lprops->free + lprops->dirty == c->leb_size)); ++ ubifs_assert(!(lprops->flags & LPROPS_TAKEN)); ++ ubifs_assert(!(lprops->flags & LPROPS_INDEX)); ++ return lprops; ++} ++ ++/** ++ * ubifs_find_dirty_leb - find a dirty LEB for the Garbage Collector. ++ * @c: the UBIFS file-system description object ++ * @ret_lp: LEB properties are returned here on exit ++ * @min_space: minimum amount free plus dirty space the returned LEB has to ++ * have ++ * @pick_free: controls whether it is OK to pick empty or index LEBs ++ * ++ * This function tries to find a dirty logical eraseblock which has at least ++ * @min_space free and dirty space. It prefers to take an LEB from the dirty or ++ * dirty index heap, and it falls-back to LPT scanning if the heaps are empty ++ * or do not have an LEB which satisfies the @min_space criteria. ++ * ++ * Note: ++ * o LEBs which have less than dead watermark of dirty space are never picked ++ * by this function; ++ * ++ * Returns zero and the LEB properties of ++ * found dirty LEB in case of success, %-ENOSPC if no dirty LEB was found and a ++ * negative error code in case of other failures. The returned LEB is marked as ++ * "taken". ++ * ++ * The additional @pick_free argument controls if this function has to return a ++ * free or freeable LEB if one is present. For example, GC must to set it to %1, ++ * when called from the journal space reservation function, because the ++ * appearance of free space may coincide with the loss of enough dirty space ++ * for GC to succeed anyway. ++ * ++ * In contrast, if the Garbage Collector is called from budgeting, it should ++ * just make free space, not return LEBs which are already free or freeable. ++ * ++ * In addition @pick_free is set to %2 by the recovery process in order to ++ * recover gc_lnum in which case an index LEB must not be returned. ++ */ ++int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp, ++ int min_space, int pick_free) ++{ ++ int err = 0, sum, exclude_index = pick_free == 2 ? 1 : 0; ++ const struct ubifs_lprops *lp = NULL, *idx_lp = NULL; ++ struct ubifs_lpt_heap *heap, *idx_heap; ++ ++ ubifs_get_lprops(c); ++ ++ if (pick_free) { ++ int lebs, rsvd_idx_lebs = 0; ++ ++ spin_lock(&c->space_lock); ++ lebs = c->lst.empty_lebs; ++ lebs += c->freeable_cnt - c->lst.taken_empty_lebs; ++ ++ /* ++ * Note, the index may consume more LEBs than have been reserved ++ * for it. It is OK because it might be consolidated by GC. ++ * But if the index takes fewer LEBs than it is reserved for it, ++ * this function must avoid picking those reserved LEBs. ++ */ ++ if (c->min_idx_lebs >= c->lst.idx_lebs) { ++ rsvd_idx_lebs = c->min_idx_lebs - c->lst.idx_lebs; ++ exclude_index = 1; ++ } ++ spin_unlock(&c->space_lock); ++ ++ /* Check if there are enough free LEBs for the index */ ++ if (rsvd_idx_lebs < lebs) { ++ /* OK, try to find an empty LEB */ ++ lp = ubifs_fast_find_empty(c); ++ if (lp) ++ goto found; ++ ++ /* Or a freeable LEB */ ++ lp = ubifs_fast_find_freeable(c); ++ if (lp) ++ goto found; ++ } else ++ /* ++ * We cannot pick free/freeable LEBs in the below code. ++ */ ++ pick_free = 0; ++ } else { ++ spin_lock(&c->space_lock); ++ exclude_index = (c->min_idx_lebs >= c->lst.idx_lebs); ++ spin_unlock(&c->space_lock); ++ } ++ ++ /* Look on the dirty and dirty index heaps */ ++ heap = &c->lpt_heap[LPROPS_DIRTY - 1]; ++ idx_heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1]; ++ ++ if (idx_heap->cnt && !exclude_index) { ++ idx_lp = idx_heap->arr[0]; ++ sum = idx_lp->free + idx_lp->dirty; ++ /* ++ * Since we reserve twice as more space for the index than it ++ * actually takes, it does not make sense to pick indexing LEBs ++ * with less than half LEB of dirty space. ++ */ ++ if (sum < min_space || sum < c->half_leb_size) ++ idx_lp = NULL; ++ } ++ ++ if (heap->cnt) { ++ lp = heap->arr[0]; ++ if (lp->dirty + lp->free < min_space) ++ lp = NULL; ++ } ++ ++ /* Pick the LEB with most space */ ++ if (idx_lp && lp) { ++ if (idx_lp->free + idx_lp->dirty >= lp->free + lp->dirty) ++ lp = idx_lp; ++ } else if (idx_lp && !lp) ++ lp = idx_lp; ++ ++ if (lp) { ++ ubifs_assert(lp->dirty >= c->dead_wm); ++ goto found; ++ } ++ ++ /* Did not find a dirty LEB on the dirty heaps, have to scan */ ++ dbg_find("scanning LPT for a dirty LEB"); ++ lp = scan_for_dirty(c, min_space, pick_free, exclude_index); ++ if (IS_ERR(lp)) { ++ err = PTR_ERR(lp); ++ goto out; ++ } ++ ubifs_assert(lp->dirty >= c->dead_wm || ++ (pick_free && lp->free + lp->dirty == c->leb_size)); ++ ++found: ++ dbg_find("found LEB %d, free %d, dirty %d, flags %#x", ++ lp->lnum, lp->free, lp->dirty, lp->flags); ++ ++ lp = ubifs_change_lp(c, lp, LPROPS_NC, LPROPS_NC, ++ lp->flags | LPROPS_TAKEN, 0); ++ if (IS_ERR(lp)) { ++ err = PTR_ERR(lp); ++ goto out; ++ } ++ ++ memcpy(ret_lp, lp, sizeof(struct ubifs_lprops)); ++ ++out: ++ ubifs_release_lprops(c); ++ return err; ++} ++ ++/** ++ * scan_for_free_cb - free space scan callback. ++ * @c: the UBIFS file-system description object ++ * @lprops: LEB properties to scan ++ * @in_tree: whether the LEB properties are in main memory ++ * @data: information passed to and from the caller of the scan ++ * ++ * This function returns a code that indicates whether the scan should continue ++ * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree ++ * in main memory (%LPT_SCAN_ADD), or whether the scan should stop ++ * (%LPT_SCAN_STOP). ++ */ ++static int scan_for_free_cb(struct ubifs_info *c, ++ const struct ubifs_lprops *lprops, int in_tree, ++ struct scan_data *data) ++{ ++ int ret = LPT_SCAN_CONTINUE; ++ ++ /* Exclude LEBs that are currently in use */ ++ if (lprops->flags & LPROPS_TAKEN) ++ return LPT_SCAN_CONTINUE; ++ /* Determine whether to add these LEB properties to the tree */ ++ if (!in_tree && valuable(c, lprops)) ++ ret |= LPT_SCAN_ADD; ++ /* Exclude index LEBs */ ++ if (lprops->flags & LPROPS_INDEX) ++ return ret; ++ /* Exclude LEBs with too little space */ ++ if (lprops->free < data->min_space) ++ return ret; ++ /* If specified, exclude empty LEBs */ ++ if (!data->pick_free && lprops->free == c->leb_size) ++ return ret; ++ /* ++ * LEBs that have only free and dirty space must not be allocated ++ * because they may have been unmapped already or they may have data ++ * that is obsolete only because of nodes that are still sitting in a ++ * wbuf. ++ */ ++ if (lprops->free + lprops->dirty == c->leb_size && lprops->dirty > 0) ++ return ret; ++ /* Finally we found space */ ++ data->lnum = lprops->lnum; ++ return LPT_SCAN_ADD | LPT_SCAN_STOP; ++} ++ ++/** ++ * do_find_free_space - find a data LEB with free space. ++ * @c: the UBIFS file-system description object ++ * @min_space: minimum amount of free space required ++ * @pick_free: whether it is OK to scan for empty LEBs ++ * @squeeze: whether to try to find space in a non-empty LEB first ++ * ++ * This function returns a pointer to the LEB properties found or a negative ++ * error code. ++ */ ++static ++const struct ubifs_lprops *do_find_free_space(struct ubifs_info *c, ++ int min_space, int pick_free, ++ int squeeze) ++{ ++ const struct ubifs_lprops *lprops; ++ struct ubifs_lpt_heap *heap; ++ struct scan_data data; ++ int err, i; ++ ++ if (squeeze) { ++ lprops = ubifs_fast_find_free(c); ++ if (lprops && lprops->free >= min_space) ++ return lprops; ++ } ++ if (pick_free) { ++ lprops = ubifs_fast_find_empty(c); ++ if (lprops) ++ return lprops; ++ } ++ if (!squeeze) { ++ lprops = ubifs_fast_find_free(c); ++ if (lprops && lprops->free >= min_space) ++ return lprops; ++ } ++ /* There may be an LEB with enough free space on the dirty heap */ ++ heap = &c->lpt_heap[LPROPS_DIRTY - 1]; ++ for (i = 0; i < heap->cnt; i++) { ++ lprops = heap->arr[i]; ++ if (lprops->free >= min_space) ++ return lprops; ++ } ++ /* ++ * A LEB may have fallen off of the bottom of the free heap, and ended ++ * up as uncategorized even though it has enough free space for us now, ++ * so check the uncategorized list. N.B. neither empty nor freeable LEBs ++ * can end up as uncategorized because they are kept on lists not ++ * finite-sized heaps. ++ */ ++ list_for_each_entry(lprops, &c->uncat_list, list) { ++ if (lprops->flags & LPROPS_TAKEN) ++ continue; ++ if (lprops->flags & LPROPS_INDEX) ++ continue; ++ if (lprops->free >= min_space) ++ return lprops; ++ } ++ /* We have looked everywhere in main memory, now scan the flash */ ++ if (c->pnodes_have >= c->pnode_cnt) ++ /* All pnodes are in memory, so skip scan */ ++ return ERR_PTR(-ENOSPC); ++ data.min_space = min_space; ++ data.pick_free = pick_free; ++ data.lnum = -1; ++ err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum, ++ (ubifs_lpt_scan_callback)scan_for_free_cb, ++ &data); ++ if (err) ++ return ERR_PTR(err); ++ ubifs_assert(data.lnum >= c->main_first && data.lnum < c->leb_cnt); ++ c->lscan_lnum = data.lnum; ++ lprops = ubifs_lpt_lookup_dirty(c, data.lnum); ++ if (IS_ERR(lprops)) ++ return lprops; ++ ubifs_assert(lprops->lnum == data.lnum); ++ ubifs_assert(lprops->free >= min_space); ++ ubifs_assert(!(lprops->flags & LPROPS_TAKEN)); ++ ubifs_assert(!(lprops->flags & LPROPS_INDEX)); ++ return lprops; ++} ++ ++/** ++ * ubifs_find_free_space - find a data LEB with free space. ++ * @c: the UBIFS file-system description object ++ * @min_space: minimum amount of required free space ++ * @free: contains amount of free space in the LEB on exit ++ * @squeeze: whether to try to find space in a non-empty LEB first ++ * ++ * This function looks for an LEB with at least @min_space bytes of free space. ++ * It tries to find an empty LEB if possible. If no empty LEBs are available, ++ * this function searches for a non-empty data LEB. The returned LEB is marked ++ * as "taken". ++ * ++ * This function returns found LEB number in case of success, %-ENOSPC if it ++ * failed to find a LEB with @min_space bytes of free space and other a negative ++ * error codes in case of failure. ++ */ ++int ubifs_find_free_space(struct ubifs_info *c, int min_space, int *free, ++ int squeeze) ++{ ++ const struct ubifs_lprops *lprops; ++ int lebs, rsvd_idx_lebs, pick_free = 0, err, lnum, flags; ++ ++ dbg_find("min_space %d", min_space); ++ ubifs_assert(min_space > 0 && min_space <= c->dark_wm); ++ ++ ubifs_get_lprops(c); ++ ++ /* Check if there are enough empty LEBs for commit */ ++ spin_lock(&c->space_lock); ++ if (c->min_idx_lebs > c->lst.idx_lebs) ++ rsvd_idx_lebs = c->min_idx_lebs - c->lst.idx_lebs; ++ else ++ rsvd_idx_lebs = 0; ++ lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt - ++ c->lst.taken_empty_lebs; ++ ubifs_assert(lebs + c->lst.idx_lebs >= c->min_idx_lebs); ++ if (rsvd_idx_lebs < lebs) ++ /* ++ * OK to allocate an empty LEB, but we still don't want to go ++ * looking for one if there aren't any. ++ */ ++ if (c->lst.empty_lebs - c->lst.taken_empty_lebs > 0) { ++ pick_free = 1; ++ /* ++ * Because we release the space lock, we must account ++ * for this allocation here. After the LEB properties ++ * flags have been updated, we subtract one. Note, the ++ * result of this is that lprops also decreases ++ * @taken_empty_lebs in 'ubifs_change_lp()', so it is ++ * off by one for a short period of time which may ++ * introduce a small disturbance to budgeting ++ * calculations, but this is harmless because at the ++ * worst case this would make the budgeting subsystem ++ * be more pessimistic than needed. ++ * ++ * Fundamentally, this is about serialization of the ++ * budgeting and lprops subsystems. We could make the ++ * @space_lock a mutex and avoid dropping it before ++ * calling 'ubifs_change_lp()', but mutex is more ++ * heavy-weight, and we want budgeting to be as fast as ++ * possible. ++ */ ++ c->lst.taken_empty_lebs += 1; ++ } ++ spin_unlock(&c->space_lock); ++ ++ lprops = do_find_free_space(c, min_space, pick_free, squeeze); ++ if (IS_ERR(lprops)) { ++ err = PTR_ERR(lprops); ++ goto out; ++ } ++ ++ lnum = lprops->lnum; ++ flags = lprops->flags | LPROPS_TAKEN; ++ ++ lprops = ubifs_change_lp(c, lprops, LPROPS_NC, LPROPS_NC, flags, 0); ++ if (IS_ERR(lprops)) { ++ err = PTR_ERR(lprops); ++ goto out; ++ } ++ ++ if (pick_free) { ++ spin_lock(&c->space_lock); ++ c->lst.taken_empty_lebs -= 1; ++ spin_unlock(&c->space_lock); ++ } ++ ++ *free = lprops->free; ++ ubifs_release_lprops(c); ++ ++ if (*free == c->leb_size) { ++ /* ++ * Ensure that empty LEBs have been unmapped. They may not have ++ * been, for example, because of an unclean unmount. Also ++ * LEBs that were freeable LEBs (free + dirty == leb_size) will ++ * not have been unmapped. ++ */ ++ err = ubifs_leb_unmap(c, lnum); ++ if (err) ++ return err; ++ } ++ ++ dbg_find("found LEB %d, free %d", lnum, *free); ++ ubifs_assert(*free >= min_space); ++ return lnum; ++ ++out: ++ if (pick_free) { ++ spin_lock(&c->space_lock); ++ c->lst.taken_empty_lebs -= 1; ++ spin_unlock(&c->space_lock); ++ } ++ ubifs_release_lprops(c); ++ return err; ++} ++ ++/** ++ * scan_for_idx_cb - callback used by the scan for a free LEB for the index. ++ * @c: the UBIFS file-system description object ++ * @lprops: LEB properties to scan ++ * @in_tree: whether the LEB properties are in main memory ++ * @data: information passed to and from the caller of the scan ++ * ++ * This function returns a code that indicates whether the scan should continue ++ * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree ++ * in main memory (%LPT_SCAN_ADD), or whether the scan should stop ++ * (%LPT_SCAN_STOP). ++ */ ++static int scan_for_idx_cb(struct ubifs_info *c, ++ const struct ubifs_lprops *lprops, int in_tree, ++ struct scan_data *data) ++{ ++ int ret = LPT_SCAN_CONTINUE; ++ ++ /* Exclude LEBs that are currently in use */ ++ if (lprops->flags & LPROPS_TAKEN) ++ return LPT_SCAN_CONTINUE; ++ /* Determine whether to add these LEB properties to the tree */ ++ if (!in_tree && valuable(c, lprops)) ++ ret |= LPT_SCAN_ADD; ++ /* Exclude index LEBS */ ++ if (lprops->flags & LPROPS_INDEX) ++ return ret; ++ /* Exclude LEBs that cannot be made empty */ ++ if (lprops->free + lprops->dirty != c->leb_size) ++ return ret; ++ /* ++ * We are allocating for the index so it is safe to allocate LEBs with ++ * only free and dirty space, because write buffers are sync'd at commit ++ * start. ++ */ ++ data->lnum = lprops->lnum; ++ return LPT_SCAN_ADD | LPT_SCAN_STOP; ++} ++ ++/** ++ * scan_for_leb_for_idx - scan for a free LEB for the index. ++ * @c: the UBIFS file-system description object ++ */ ++static const struct ubifs_lprops *scan_for_leb_for_idx(struct ubifs_info *c) ++{ ++ struct ubifs_lprops *lprops; ++ struct scan_data data; ++ int err; ++ ++ data.lnum = -1; ++ err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum, ++ (ubifs_lpt_scan_callback)scan_for_idx_cb, ++ &data); ++ if (err) ++ return ERR_PTR(err); ++ ubifs_assert(data.lnum >= c->main_first && data.lnum < c->leb_cnt); ++ c->lscan_lnum = data.lnum; ++ lprops = ubifs_lpt_lookup_dirty(c, data.lnum); ++ if (IS_ERR(lprops)) ++ return lprops; ++ ubifs_assert(lprops->lnum == data.lnum); ++ ubifs_assert(lprops->free + lprops->dirty == c->leb_size); ++ ubifs_assert(!(lprops->flags & LPROPS_TAKEN)); ++ ubifs_assert(!(lprops->flags & LPROPS_INDEX)); ++ return lprops; ++} ++ ++/** ++ * ubifs_find_free_leb_for_idx - find a free LEB for the index. ++ * @c: the UBIFS file-system description object ++ * ++ * This function looks for a free LEB and returns that LEB number. The returned ++ * LEB is marked as "taken", "index". ++ * ++ * Only empty LEBs are allocated. This is for two reasons. First, the commit ++ * calculates the number of LEBs to allocate based on the assumption that they ++ * will be empty. Secondly, free space at the end of an index LEB is not ++ * guaranteed to be empty because it may have been used by the in-the-gaps ++ * method prior to an unclean unmount. ++ * ++ * If no LEB is found %-ENOSPC is returned. For other failures another negative ++ * error code is returned. ++ */ ++int ubifs_find_free_leb_for_idx(struct ubifs_info *c) ++{ ++ const struct ubifs_lprops *lprops; ++ int lnum = -1, err, flags; ++ ++ ubifs_get_lprops(c); ++ ++ lprops = ubifs_fast_find_empty(c); ++ if (!lprops) { ++ lprops = ubifs_fast_find_freeable(c); ++ if (!lprops) { ++ ubifs_assert(c->freeable_cnt == 0); ++ if (c->lst.empty_lebs - c->lst.taken_empty_lebs > 0) { ++ lprops = scan_for_leb_for_idx(c); ++ if (IS_ERR(lprops)) { ++ err = PTR_ERR(lprops); ++ goto out; ++ } ++ } ++ } ++ } ++ ++ if (!lprops) { ++ err = -ENOSPC; ++ goto out; ++ } ++ ++ lnum = lprops->lnum; ++ ++ dbg_find("found LEB %d, free %d, dirty %d, flags %#x", ++ lnum, lprops->free, lprops->dirty, lprops->flags); ++ ++ flags = lprops->flags | LPROPS_TAKEN | LPROPS_INDEX; ++ lprops = ubifs_change_lp(c, lprops, c->leb_size, 0, flags, 0); ++ if (IS_ERR(lprops)) { ++ err = PTR_ERR(lprops); ++ goto out; ++ } ++ ++ ubifs_release_lprops(c); ++ ++ /* ++ * Ensure that empty LEBs have been unmapped. They may not have been, ++ * for example, because of an unclean unmount. Also LEBs that were ++ * freeable LEBs (free + dirty == leb_size) will not have been unmapped. ++ */ ++ err = ubifs_leb_unmap(c, lnum); ++ if (err) { ++ ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0, ++ LPROPS_TAKEN | LPROPS_INDEX, 0); ++ return err; ++ } ++ ++ return lnum; ++ ++out: ++ ubifs_release_lprops(c); ++ return err; ++} ++ ++static int cmp_dirty_idx(const struct ubifs_lprops **a, ++ const struct ubifs_lprops **b) ++{ ++ const struct ubifs_lprops *lpa = *a; ++ const struct ubifs_lprops *lpb = *b; ++ ++ return lpa->dirty + lpa->free - lpb->dirty - lpb->free; ++} ++ ++static void swap_dirty_idx(struct ubifs_lprops **a, struct ubifs_lprops **b, ++ int size) ++{ ++ struct ubifs_lprops *t = *a; ++ ++ *a = *b; ++ *b = t; ++} ++ ++/** ++ * ubifs_save_dirty_idx_lnums - save an array of the most dirty index LEB nos. ++ * @c: the UBIFS file-system description object ++ * ++ * This function is called each commit to create an array of LEB numbers of ++ * dirty index LEBs sorted in order of dirty and free space. This is used by ++ * the in-the-gaps method of TNC commit. ++ */ ++int ubifs_save_dirty_idx_lnums(struct ubifs_info *c) ++{ ++ int i; ++ ++ ubifs_get_lprops(c); ++ /* Copy the LPROPS_DIRTY_IDX heap */ ++ c->dirty_idx.cnt = c->lpt_heap[LPROPS_DIRTY_IDX - 1].cnt; ++ memcpy(c->dirty_idx.arr, c->lpt_heap[LPROPS_DIRTY_IDX - 1].arr, ++ sizeof(void *) * c->dirty_idx.cnt); ++ /* Sort it so that the dirtiest is now at the end */ ++ sort(c->dirty_idx.arr, c->dirty_idx.cnt, sizeof(void *), ++ (int (*)(const void *, const void *))cmp_dirty_idx, ++ (void (*)(void *, void *, int))swap_dirty_idx); ++ dbg_find("found %d dirty index LEBs", c->dirty_idx.cnt); ++ if (c->dirty_idx.cnt) ++ dbg_find("dirtiest index LEB is %d with dirty %d and free %d", ++ c->dirty_idx.arr[c->dirty_idx.cnt - 1]->lnum, ++ c->dirty_idx.arr[c->dirty_idx.cnt - 1]->dirty, ++ c->dirty_idx.arr[c->dirty_idx.cnt - 1]->free); ++ /* Replace the lprops pointers with LEB numbers */ ++ for (i = 0; i < c->dirty_idx.cnt; i++) ++ c->dirty_idx.arr[i] = (void *)(size_t)c->dirty_idx.arr[i]->lnum; ++ ubifs_release_lprops(c); ++ return 0; ++} ++ ++/** ++ * scan_dirty_idx_cb - callback used by the scan for a dirty index LEB. ++ * @c: the UBIFS file-system description object ++ * @lprops: LEB properties to scan ++ * @in_tree: whether the LEB properties are in main memory ++ * @data: information passed to and from the caller of the scan ++ * ++ * This function returns a code that indicates whether the scan should continue ++ * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree ++ * in main memory (%LPT_SCAN_ADD), or whether the scan should stop ++ * (%LPT_SCAN_STOP). ++ */ ++static int scan_dirty_idx_cb(struct ubifs_info *c, ++ const struct ubifs_lprops *lprops, int in_tree, ++ struct scan_data *data) ++{ ++ int ret = LPT_SCAN_CONTINUE; ++ ++ /* Exclude LEBs that are currently in use */ ++ if (lprops->flags & LPROPS_TAKEN) ++ return LPT_SCAN_CONTINUE; ++ /* Determine whether to add these LEB properties to the tree */ ++ if (!in_tree && valuable(c, lprops)) ++ ret |= LPT_SCAN_ADD; ++ /* Exclude non-index LEBs */ ++ if (!(lprops->flags & LPROPS_INDEX)) ++ return ret; ++ /* Exclude LEBs with too little space */ ++ if (lprops->free + lprops->dirty < c->min_idx_node_sz) ++ return ret; ++ /* Finally we found space */ ++ data->lnum = lprops->lnum; ++ return LPT_SCAN_ADD | LPT_SCAN_STOP; ++} ++ ++/** ++ * find_dirty_idx_leb - find a dirty index LEB. ++ * @c: the UBIFS file-system description object ++ * ++ * This function returns LEB number upon success and a negative error code upon ++ * failure. In particular, -ENOSPC is returned if a dirty index LEB is not ++ * found. ++ * ++ * Note that this function scans the entire LPT but it is called very rarely. ++ */ ++static int find_dirty_idx_leb(struct ubifs_info *c) ++{ ++ const struct ubifs_lprops *lprops; ++ struct ubifs_lpt_heap *heap; ++ struct scan_data data; ++ int err, i, ret; ++ ++ /* Check all structures in memory first */ ++ data.lnum = -1; ++ heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1]; ++ for (i = 0; i < heap->cnt; i++) { ++ lprops = heap->arr[i]; ++ ret = scan_dirty_idx_cb(c, lprops, 1, &data); ++ if (ret & LPT_SCAN_STOP) ++ goto found; ++ } ++ list_for_each_entry(lprops, &c->frdi_idx_list, list) { ++ ret = scan_dirty_idx_cb(c, lprops, 1, &data); ++ if (ret & LPT_SCAN_STOP) ++ goto found; ++ } ++ list_for_each_entry(lprops, &c->uncat_list, list) { ++ ret = scan_dirty_idx_cb(c, lprops, 1, &data); ++ if (ret & LPT_SCAN_STOP) ++ goto found; ++ } ++ if (c->pnodes_have >= c->pnode_cnt) ++ /* All pnodes are in memory, so skip scan */ ++ return -ENOSPC; ++ err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum, ++ (ubifs_lpt_scan_callback)scan_dirty_idx_cb, ++ &data); ++ if (err) ++ return err; ++found: ++ ubifs_assert(data.lnum >= c->main_first && data.lnum < c->leb_cnt); ++ c->lscan_lnum = data.lnum; ++ lprops = ubifs_lpt_lookup_dirty(c, data.lnum); ++ if (IS_ERR(lprops)) ++ return PTR_ERR(lprops); ++ ubifs_assert(lprops->lnum == data.lnum); ++ ubifs_assert(lprops->free + lprops->dirty >= c->min_idx_node_sz); ++ ubifs_assert(!(lprops->flags & LPROPS_TAKEN)); ++ ubifs_assert((lprops->flags & LPROPS_INDEX)); ++ ++ dbg_find("found dirty LEB %d, free %d, dirty %d, flags %#x", ++ lprops->lnum, lprops->free, lprops->dirty, lprops->flags); ++ ++ lprops = ubifs_change_lp(c, lprops, LPROPS_NC, LPROPS_NC, ++ lprops->flags | LPROPS_TAKEN, 0); ++ if (IS_ERR(lprops)) ++ return PTR_ERR(lprops); ++ ++ return lprops->lnum; ++} ++ ++/** ++ * get_idx_gc_leb - try to get a LEB number from trivial GC. ++ * @c: the UBIFS file-system description object ++ */ ++static int get_idx_gc_leb(struct ubifs_info *c) ++{ ++ const struct ubifs_lprops *lp; ++ int err, lnum; ++ ++ err = ubifs_get_idx_gc_leb(c); ++ if (err < 0) ++ return err; ++ lnum = err; ++ /* ++ * The LEB was due to be unmapped after the commit but ++ * it is needed now for this commit. ++ */ ++ lp = ubifs_lpt_lookup_dirty(c, lnum); ++ if (unlikely(IS_ERR(lp))) ++ return PTR_ERR(lp); ++ lp = ubifs_change_lp(c, lp, LPROPS_NC, LPROPS_NC, ++ lp->flags | LPROPS_INDEX, -1); ++ if (unlikely(IS_ERR(lp))) ++ return PTR_ERR(lp); ++ dbg_find("LEB %d, dirty %d and free %d flags %#x", ++ lp->lnum, lp->dirty, lp->free, lp->flags); ++ return lnum; ++} ++ ++/** ++ * find_dirtiest_idx_leb - find dirtiest index LEB from dirtiest array. ++ * @c: the UBIFS file-system description object ++ */ ++static int find_dirtiest_idx_leb(struct ubifs_info *c) ++{ ++ const struct ubifs_lprops *lp; ++ int lnum; ++ ++ while (1) { ++ if (!c->dirty_idx.cnt) ++ return -ENOSPC; ++ /* The lprops pointers were replaced by LEB numbers */ ++ lnum = (size_t)c->dirty_idx.arr[--c->dirty_idx.cnt]; ++ lp = ubifs_lpt_lookup(c, lnum); ++ if (IS_ERR(lp)) ++ return PTR_ERR(lp); ++ if ((lp->flags & LPROPS_TAKEN) || !(lp->flags & LPROPS_INDEX)) ++ continue; ++ lp = ubifs_change_lp(c, lp, LPROPS_NC, LPROPS_NC, ++ lp->flags | LPROPS_TAKEN, 0); ++ if (IS_ERR(lp)) ++ return PTR_ERR(lp); ++ break; ++ } ++ dbg_find("LEB %d, dirty %d and free %d flags %#x", lp->lnum, lp->dirty, ++ lp->free, lp->flags); ++ ubifs_assert(lp->flags | LPROPS_TAKEN); ++ ubifs_assert(lp->flags | LPROPS_INDEX); ++ return lnum; ++} ++ ++/** ++ * ubifs_find_dirty_idx_leb - try to find dirtiest index LEB as at last commit. ++ * @c: the UBIFS file-system description object ++ * ++ * This function attempts to find an untaken index LEB with the most free and ++ * dirty space that can be used without overwriting index nodes that were in the ++ * last index committed. ++ */ ++int ubifs_find_dirty_idx_leb(struct ubifs_info *c) ++{ ++ int err; ++ ++ ubifs_get_lprops(c); ++ ++ /* ++ * We made an array of the dirtiest index LEB numbers as at the start of ++ * last commit. Try that array first. ++ */ ++ err = find_dirtiest_idx_leb(c); ++ ++ /* Next try scanning the entire LPT */ ++ if (err == -ENOSPC) ++ err = find_dirty_idx_leb(c); ++ ++ /* Finally take any index LEBs awaiting trivial GC */ ++ if (err == -ENOSPC) ++ err = get_idx_gc_leb(c); ++ ++ ubifs_release_lprops(c); ++ return err; ++} +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/gc.c avr32-2.6/fs/ubifs/gc.c +--- linux-2.6.25.6/fs/ubifs/gc.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/gc.c 2008-06-12 15:09:45.367815766 +0200 +@@ -0,0 +1,762 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Adrian Hunter ++ * Artem Bityutskiy (Битюцкий Артём) ++ */ ++ ++/* ++ * This file implements garbage collection. The procedure for garbage collection ++ * is different depending on whether a LEB as an index LEB (contains index ++ * nodes) or not. For non-index LEBs, garbage collection finds a LEB which ++ * contains a lot of dirty space (obsolete nodes), and copies the non-obsolete ++ * nodes to the journal, at which point the garbage-collected LEB is free to be ++ * reused. For index LEBs, garbage collection marks the non-obsolete index nodes ++ * dirty in the TNC, and after the next commit, the garbage-collected LEB is ++ * to be reused. Garbage collection will cause the number of dirty index nodes ++ * to grow, however sufficient space is reserved for the index to ensure the ++ * commit will never run out of space. ++ */ ++ ++#include <linux/pagemap.h> ++#include "ubifs.h" ++ ++/* ++ * GC tries to optimize the way it fit nodes to available space, and it sorts ++ * nodes a little. The below constants are watermarks which define "large", ++ * "medium", and "small" nodes. ++ */ ++#define MEDIUM_NODE_WM (UBIFS_BLOCK_SIZE / 4) ++#define SMALL_NODE_WM UBIFS_MAX_DENT_NODE_SZ ++ ++/* ++ * GC may need to move more then one LEB to make progress. The below constants ++ * define "soft" and "hard" limits on the number of LEBs the garbage collector ++ * may move. ++ */ ++#define SOFT_LEBS_LIMIT 4 ++#define HARD_LEBS_LIMIT 32 ++ ++/** ++ * switch_gc_head - switch the garbage collection journal head. ++ * @c: UBIFS file-system description object ++ * @buf: buffer to write ++ * @len: length of the buffer to write ++ * @lnum: LEB number written is returned here ++ * @offs: offset written is returned here ++ * ++ * This function switch the GC head to the next LEB which is reserved in ++ * @c->gc_lnum. Returns %0 in case of success, %-EAGAIN if commit is required, ++ * and other negative error code in case of failures. ++ */ ++static int switch_gc_head(struct ubifs_info *c) ++{ ++ int err, gc_lnum = c->gc_lnum; ++ struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf; ++ ++ ubifs_assert(gc_lnum != -1); ++ dbg_gc("switch GC head from LEB %d:%d to LEB %d (waste %d bytes)", ++ wbuf->lnum, wbuf->offs + wbuf->used, gc_lnum, ++ c->leb_size - wbuf->offs - wbuf->used); ++ ++ err = ubifs_wbuf_sync_nolock(wbuf); ++ if (err) ++ return err; ++ ++ /* ++ * The GC write-buffer was synchronized, we may safely unmap ++ * 'c->gc_lnum'. ++ */ ++ err = ubifs_leb_unmap(c, gc_lnum); ++ if (err) ++ return err; ++ ++ err = ubifs_add_bud_to_log(c, GCHD, gc_lnum, 0); ++ if (err) ++ return err; ++ ++ c->gc_lnum = -1; ++ err = ubifs_wbuf_seek_nolock(wbuf, gc_lnum, 0, UBI_LONGTERM); ++ return err; ++} ++ ++/** ++ * move_nodes - move nodes. ++ * @c: UBIFS file-system description object ++ * @sleb: describes nodes to move ++ * ++ * This function moves valid nodes from data LEB described by @sleb to the GC ++ * journal head. The obsolete nodes are dropped. ++ * ++ * When moving nodes we have to deal with classical bin-packing problem: the ++ * space in the current GC journal head LEB and in @c->gc_lnum are the "bins", ++ * where the nodes in the @sleb->nodes list are the elements which should be ++ * fit optimally to the bins. This function uses the "first fit decreasing" ++ * strategy, although it does not really sort the nodes but just split them on ++ * 3 classes - large, medium, and small, so they are roughly sorted. ++ * ++ * This function returns zero in case of success, %-EAGAIN if commit is ++ * required, and other negative error codes in case of other failures. ++ */ ++static int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb) ++{ ++ struct ubifs_scan_node *snod, *tmp; ++ struct list_head large, medium, small; ++ struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf; ++ int avail, err, min = INT_MAX; ++ ++ INIT_LIST_HEAD(&large); ++ INIT_LIST_HEAD(&medium); ++ INIT_LIST_HEAD(&small); ++ ++ list_for_each_entry_safe(snod, tmp, &sleb->nodes, list) { ++ struct list_head *lst; ++ ++ ubifs_assert(snod->type != UBIFS_IDX_NODE); ++ ubifs_assert(snod->type != UBIFS_REF_NODE); ++ ubifs_assert(snod->type != UBIFS_CS_NODE); ++ ++ err = ubifs_tnc_has_node(c, &snod->key, 0, sleb->lnum, ++ snod->offs, 0); ++ if (err < 0) ++ goto out; ++ ++ lst = &snod->list; ++ list_del(lst); ++ if (!err) { ++ /* The node is obsolete, remove it from the list */ ++ kfree(snod); ++ continue; ++ } ++ ++ /* ++ * Sort the list of nodes so that large nodes go first, and ++ * small nodes go last. ++ */ ++ if (snod->len > MEDIUM_NODE_WM) ++ list_add(lst, &large); ++ else if (snod->len > SMALL_NODE_WM) ++ list_add(lst, &medium); ++ else ++ list_add(lst, &small); ++ ++ /* And find the smallest node */ ++ if (snod->len < min) ++ min = snod->len; ++ } ++ ++ /* ++ * Join the tree lists so that we'd have one roughly sorted list ++ * ('large' will be the head of the joined list). ++ */ ++ list_splice(&medium, large.prev); ++ list_splice(&small, large.prev); ++ ++ if (wbuf->lnum == -1) { ++ /* ++ * The GC journal head is not set, because it is the first GC ++ * invocation since mount. ++ */ ++ err = switch_gc_head(c); ++ if (err) ++ goto out; ++ } ++ ++ /* Write nodes to their new location. Use the first-fit strategy */ ++ while (1) { ++ avail = c->leb_size - wbuf->offs - wbuf->used; ++ list_for_each_entry_safe(snod, tmp, &large, list) { ++ int new_lnum, new_offs; ++ ++ if (avail < min) ++ break; ++ ++ if (snod->len > avail) ++ /* This node does not fit */ ++ continue; ++ ++ cond_resched(); ++ ++ new_lnum = wbuf->lnum; ++ new_offs = wbuf->offs + wbuf->used; ++ err = ubifs_wbuf_write_nolock(wbuf, snod->node, ++ snod->len); ++ ++ err = ubifs_tnc_replace(c, &snod->key, sleb->lnum, ++ snod->offs, new_lnum, new_offs, ++ snod->len); ++ if (err) ++ goto out; ++ ++ avail = c->leb_size - wbuf->offs - wbuf->used; ++ list_del(&snod->list); ++ kfree(snod); ++ } ++ ++ if (list_empty(&large)) ++ break; ++ ++ /* ++ * Waste the rest of the space in the LEB and switch to the ++ * next LEB. ++ */ ++ err = switch_gc_head(c); ++ if (err) ++ goto out; ++ } ++ ++ return 0; ++ ++out: ++ list_for_each_entry_safe(snod, tmp, &large, list) { ++ list_del(&snod->list); ++ kfree(snod); ++ } ++ return err; ++} ++ ++/** ++ * gc_sync_wbufs - sync write-buffers for GC. ++ * @c: UBIFS file-system description object ++ * ++ * We must guarantee that obsoleting nodes are on flash. Unfortunately they may ++ * be in a write-buffer instead. That is, a node could be written to a ++ * write-buffer, obsoleting another node in a LEB that is GC'd. If that LEB is ++ * erased before the write-buffer is sync'd and then there is an unclean ++ * unmount, then an existing node is lost. To avoid this, we sync all ++ * write-buffers. ++ * ++ * This function returns %0 on success or a negative error code on failure. ++ */ ++static int gc_sync_wbufs(struct ubifs_info *c) ++{ ++ int err, i; ++ ++ for (i = 0; i < c->jhead_cnt; i++) { ++ if (i == GCHD) ++ continue; ++ err = ubifs_wbuf_sync(&c->jheads[i].wbuf); ++ if (err) ++ return err; ++ } ++ return 0; ++} ++ ++/** ++ * ubifs_garbage_collect_leb - garbage-collect a logical eraseblock. ++ * @c: UBIFS file-system description object ++ * @lp: describes the LEB to garbage collect ++ * ++ * This function garbage-collects an LEB and returns one of the @LEB_FREED, ++ * @LEB_RETAINED, etc positive codes in case of success, %-EAGAIN if commit is ++ * required, and other negative error codes in case of failures. ++ */ ++int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp) ++{ ++ struct ubifs_scan_leb *sleb; ++ struct ubifs_scan_node *snod; ++ struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf; ++ int err = 0, lnum = lp->lnum; ++ ++ ubifs_assert(c->gc_lnum != -1 || wbuf->offs + wbuf->used == 0 || ++ c->need_recovery); ++ ubifs_assert(c->gc_lnum != lnum); ++ ubifs_assert(wbuf->lnum != lnum); ++ ++ /* ++ * We scan the entire LEB even though we only really need to scan up to ++ * (c->leb_size - lp->free). ++ */ ++ sleb = ubifs_scan(c, lnum, 0, c->sbuf); ++ if (IS_ERR(sleb)) ++ return PTR_ERR(sleb); ++ ++ ubifs_assert(!list_empty(&sleb->nodes)); ++ snod = list_entry(sleb->nodes.next, struct ubifs_scan_node, list); ++ ++ if (snod->type == UBIFS_IDX_NODE) { ++ struct ubifs_gced_idx_leb *idx_gc; ++ ++ dbg_gc("indexing LEB %d (free %d, dirty %d)", ++ lnum, lp->free, lp->dirty); ++ list_for_each_entry(snod, &sleb->nodes, list) { ++ struct ubifs_idx_node *idx = snod->node; ++ int level = le16_to_cpu(idx->level); ++ ++ ubifs_assert(snod->type == UBIFS_IDX_NODE); ++ key_read(c, ubifs_idx_key(c, idx), &snod->key); ++ err = ubifs_dirty_idx_node(c, &snod->key, level, lnum, ++ snod->offs); ++ if (err) ++ goto out; ++ } ++ ++ idx_gc = kmalloc(sizeof(struct ubifs_gced_idx_leb), GFP_NOFS); ++ if (!idx_gc) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ idx_gc->lnum = lnum; ++ idx_gc->unmap = 0; ++ list_add(&idx_gc->list, &c->idx_gc); ++ ++ /* ++ * Don't release the LEB until after the next commit, because ++ * it may contain date which is needed for recovery. So ++ * although we freed this LEB, it will become usable only after ++ * the commit. ++ */ ++ err = ubifs_change_one_lp(c, lnum, c->leb_size, 0, 0, ++ LPROPS_INDEX, 1); ++ if (err) ++ goto out; ++ err = LEB_FREED_IDX; ++ } else { ++ dbg_gc("data LEB %d (free %d, dirty %d)", ++ lnum, lp->free, lp->dirty); ++ ++ err = move_nodes(c, sleb); ++ if (err) ++ goto out; ++ ++ err = gc_sync_wbufs(c); ++ if (err) ++ goto out; ++ ++ err = ubifs_change_one_lp(c, lnum, c->leb_size, 0, 0, 0, 0); ++ if (err) ++ goto out; ++ ++ if (c->gc_lnum == -1) { ++ c->gc_lnum = lnum; ++ err = LEB_RETAINED; ++ } else { ++ err = ubifs_wbuf_sync_nolock(wbuf); ++ if (err) ++ goto out; ++ ++ err = ubifs_leb_unmap(c, lnum); ++ if (err) ++ goto out; ++ ++ err = LEB_FREED; ++ } ++ } ++ ++out: ++ ubifs_scan_destroy(sleb); ++ return err; ++} ++ ++/** ++ * ubifs_garbage_collect - UBIFS garbage collector. ++ * @c: UBIFS file-system description object ++ * @anyway: do GC even if there are free LEBs ++ * ++ * This function does out-of-place garbage collection. The return codes are: ++ * o positive LEB number if the LEB has been freed and may be used; ++ * o %-EAGAIN if the caller has to run commit; ++ * o %-ENOSPC if GC failed to make any progress; ++ * o other negative error codes in case of other errors. ++ * ++ * Garbage collector writes data to the journal when GC'ing data LEBs, and just ++ * marking indexing nodes dirty when GC'ing indexing LEBs. Thus, at some point ++ * commit may be required. But commit cannot be run from inside GC, because the ++ * caller might be holding the commit lock, so %-EAGAIN is returned instead; ++ * And this error code means that the caller has to run commit, and re-run GC ++ * if there is still no free space. ++ * ++ * There are many reasons why this function may return %-EAGAIN: ++ * o the log is full and there is no space to write an LEB reference for ++ * @c->gc_lnum; ++ * o the journal is too large and exceeds size limitations; ++ * o GC moved indexing LEBs, but they can be used only after the commit; ++ * o the shrinker fails to find clean znodes to free and requests the commit; ++ * o etc. ++ * ++ * Note, if the file-system is close to be full, this function may return ++ * %-EAGAIN infinitely, so the caller has to limit amount of re-invocations of ++ * the function. E.g., this happens if the limits on the journal size are too ++ * tough and GC writes too much to the journal before an LEB is freed. This ++ * might also mean that the journal is too large, and the TNC becomes to big, ++ * so that the shrinker is constantly called, finds not clean znodes to free, ++ * and requests commit. Well, this may also happen if the journal is all right, ++ * but another kernel process consumes too much memory. Anyway, infinite ++ * %-EAGAIN may happen, but in some extreme/misconfiguration cases. ++ */ ++int ubifs_garbage_collect(struct ubifs_info *c, int anyway) ++{ ++ int i, err, ret, min_space = c->dead_wm; ++ struct ubifs_lprops lp; ++ struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf; ++ ++ ubifs_assert_cmt_locked(c); ++ ++ if (ubifs_gc_should_commit(c)) ++ return -EAGAIN; ++ ++ mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); ++ /* We expect the write-buffer to be empty on entry */ ++ ubifs_assert(!wbuf->used); ++ ++ for (i = 0; ; i++) { ++ int space_before = c->leb_size - wbuf->offs - wbuf->used; ++ int space_after; ++ ++ cond_resched(); ++ ++ /* Give the commit an opportunity to run */ ++ if (ubifs_gc_should_commit(c)) { ++ ret = -EAGAIN; ++ break; ++ } ++ ++ if (i > SOFT_LEBS_LIMIT && !list_empty(&c->idx_gc)) { ++ /* ++ * We've done enough iterations. Indexing LEBs were ++ * moved and will be available after the commit. ++ */ ++ dbg_gc("soft limit, some index LEBs GC'ed, -EAGAIN"); ++ ubifs_commit_required(c); ++ ret = -EAGAIN; ++ break; ++ } ++ ++ if (i > HARD_LEBS_LIMIT) { ++ /* ++ * We've moved too many LEBs and have not made ++ * progress, give up. ++ */ ++ dbg_gc("hard limit, -ENOSPC"); ++ ret = -ENOSPC; ++ break; ++ } ++ ++ /* ++ * Empty and freeable LEBs can turn up while we waited for ++ * the wbuf lock, or while we have been running GC. In that ++ * case, we should just return one of those instead of ++ * continuing to GC dirty LEBs. Hence we request ++ * 'ubifs_find_dirty_leb()' to return an empty LEB if it can. ++ */ ++ ret = ubifs_find_dirty_leb(c, &lp, min_space, anyway ? 0 : 1); ++ if (ret) { ++ if (ret == -ENOSPC) ++ dbg_gc("no more dirty LEBs"); ++ break; ++ } ++ ++ dbg_gc("found LEB %d: free %d, dirty %d, sum %d " ++ "(min. space %d)", lp.lnum, lp.free, lp.dirty, ++ lp.free + lp.dirty, min_space); ++ ++ if (lp.free + lp.dirty == c->leb_size) { ++ /* An empty LEB was returned */ ++ dbg_gc("LEB %d is free, return it", lp.lnum); ++ /* ++ * ubifs_find_dirty_leb() doesn't return freeable index ++ * LEBs. ++ */ ++ ubifs_assert(!(lp.flags & LPROPS_INDEX)); ++ if (lp.free != c->leb_size) { ++ /* ++ * Write buffers must be sync'd before ++ * unmapping freeable LEBs, because one of them ++ * may contain data which obsoletes something ++ * in 'lp.pnum'. ++ */ ++ ret = gc_sync_wbufs(c); ++ if (ret) ++ goto out; ++ ret = ubifs_change_one_lp(c, lp.lnum, ++ c->leb_size, 0, 0, 0, ++ 0); ++ if (ret) ++ goto out; ++ } ++ ret = ubifs_leb_unmap(c, lp.lnum); ++ if (ret) ++ goto out; ++ ret = lp.lnum; ++ break; ++ } ++ ++ space_before = c->leb_size - wbuf->offs - wbuf->used; ++ if (wbuf->lnum == -1) ++ space_before = 0; ++ ++ ret = ubifs_garbage_collect_leb(c, &lp); ++ if (ret < 0) { ++ if (ret == -EAGAIN || ret == -ENOSPC) { ++ /* ++ * These codes are not errors, so we have to ++ * return the LEB to lprops. But if the ++ * 'ubifs_return_leb()' function fails, its ++ * failure code is propagated to the caller ++ * instead of the original '-EAGAIN' or ++ * '-ENOSPC'. ++ */ ++ err = ubifs_return_leb(c, lp.lnum); ++ if (err) ++ ret = err; ++ break; ++ } ++ goto out; ++ } ++ ++ if (ret == LEB_FREED) { ++ /* An LEB has been freed and is ready for use */ ++ dbg_gc("LEB %d freed, return", lp.lnum); ++ ret = lp.lnum; ++ break; ++ } ++ ++ if (ret == LEB_FREED_IDX) { ++ /* ++ * This was an indexing LEB and it cannot be ++ * immediately used. And instead of requesting the ++ * commit straight away, we try to garbage collect some ++ * more. ++ */ ++ dbg_gc("indexing LEB %d freed, continue", lp.lnum); ++ continue; ++ } ++ ++ ubifs_assert(ret == LEB_RETAINED); ++ space_after = c->leb_size - wbuf->offs - wbuf->used; ++ dbg_gc("LEB %d retained, freed %d bytes", lp.lnum, ++ space_after - space_before); ++ ++ if (space_after > space_before) { ++ /* GC makes progress, keep working */ ++ min_space >>= 1; ++ if (min_space < c->dead_wm) ++ min_space = c->dead_wm; ++ continue; ++ } ++ ++ dbg_gc("did not make progress"); ++ ++ /* ++ * GC moved an LEB bud have not done any progress. This means ++ * that the previous GC head LEB contained too few free space ++ * and the LEB which was GC'ed contained only large nodes which ++ * did not fit that space. ++ * ++ * We can do 2 things: ++ * 1. pick another LEB in a hope it'll contain a small node ++ * which will fit the space we have at the end of current GC ++ * head LEB, but there is no guarantee, so we try this out ++ * unless we have already been working for too long; ++ * 2. request an LEB with more dirty space, which will force ++ * 'ubifs_find_dirty_leb()' to start scanning the lprops ++ * table, instead of just picking one from the heap ++ * (previously it already picked the dirtiest LEB). ++ */ ++ if (i < SOFT_LEBS_LIMIT) { ++ dbg_gc("try again"); ++ continue; ++ } ++ ++ min_space <<= 1; ++ if (min_space > c->dark_wm) ++ min_space = c->dark_wm; ++ dbg_gc("set min. space to %d", min_space); ++ } ++ ++ if (ret == -ENOSPC && !list_empty(&c->idx_gc)) { ++ dbg_gc("no space, some index LEBs GC'ed, -EAGAIN"); ++ ubifs_commit_required(c); ++ ret = -EAGAIN; ++ } ++ ++ err = ubifs_wbuf_sync_nolock(wbuf); ++ if (!err) ++ err = ubifs_leb_unmap(c, c->gc_lnum); ++ if (err) ++ ret = err; ++ mutex_unlock(&wbuf->io_mutex); ++ return ret; ++ ++out: ++ ubifs_assert(ret < 0); ++ ubifs_assert(ret != -ENOSPC && ret != -EAGAIN); ++ ubifs_wbuf_sync_nolock(wbuf); ++ mutex_unlock(&wbuf->io_mutex); ++ ubifs_return_leb(c, lp.lnum); ++ return ret; ++} ++ ++/** ++ * ubifs_gc_start_commit - garbage collection at start of commit. ++ * @c: UBIFS file-system description object ++ * ++ * If a LEB has only dirty and free space, then we may safely unmap it and make ++ * it free. Note, we cannot do this with indexing LEBs because dirty space may ++ * correspond index nodes that are required for recovery. In that case, the ++ * LEB cannot be unmapped until after the next commit. ++ * ++ * This function returns %0 upon success and a negative error code upon failure. ++ */ ++int ubifs_gc_start_commit(struct ubifs_info *c) ++{ ++ struct ubifs_gced_idx_leb *idx_gc; ++ const struct ubifs_lprops *lp; ++ int err = 0, flags; ++ ++ ubifs_get_lprops(c); ++ ++ /* ++ * Unmap (non-index) freeable LEBs. Note that recovery requires that all ++ * wbufs are sync'd before this, which is done in 'do_commit()'. ++ */ ++ while (1) { ++ lp = ubifs_fast_find_freeable(c); ++ if (unlikely(IS_ERR(lp))) { ++ err = PTR_ERR(lp); ++ goto out; ++ } ++ if (!lp) ++ break; ++ ubifs_assert(!(lp->flags & LPROPS_TAKEN)); ++ ubifs_assert(!(lp->flags & LPROPS_INDEX)); ++ err = ubifs_leb_unmap(c, lp->lnum); ++ if (err) ++ goto out; ++ lp = ubifs_change_lp(c, lp, c->leb_size, 0, lp->flags, 0); ++ if (unlikely(IS_ERR(lp))) { ++ err = PTR_ERR(lp); ++ goto out; ++ } ++ ubifs_assert(!(lp->flags & LPROPS_TAKEN)); ++ ubifs_assert(!(lp->flags & LPROPS_INDEX)); ++ } ++ ++ /* Mark GC'd index LEBs OK to unmap after this commit finishes */ ++ list_for_each_entry(idx_gc, &c->idx_gc, list) ++ idx_gc->unmap = 1; ++ ++ /* Record index freeable LEBs for unmapping after commit */ ++ while (1) { ++ lp = ubifs_fast_find_frdi_idx(c); ++ if (unlikely(IS_ERR(lp))) { ++ err = PTR_ERR(lp); ++ goto out; ++ } ++ if (!lp) ++ break; ++ idx_gc = kmalloc(sizeof(struct ubifs_gced_idx_leb), GFP_NOFS); ++ if (!idx_gc) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ubifs_assert(!(lp->flags & LPROPS_TAKEN)); ++ ubifs_assert(lp->flags & LPROPS_INDEX); ++ /* Don't release the LEB until after the next commit */ ++ flags = (lp->flags | LPROPS_TAKEN) ^ LPROPS_INDEX; ++ lp = ubifs_change_lp(c, lp, c->leb_size, 0, flags, 1); ++ if (unlikely(IS_ERR(lp))) { ++ err = PTR_ERR(lp); ++ kfree(idx_gc); ++ goto out; ++ } ++ ubifs_assert(lp->flags & LPROPS_TAKEN); ++ ubifs_assert(!(lp->flags & LPROPS_INDEX)); ++ idx_gc->lnum = lp->lnum; ++ idx_gc->unmap = 1; ++ list_add(&idx_gc->list, &c->idx_gc); ++ } ++out: ++ ubifs_release_lprops(c); ++ return err; ++} ++ ++/** ++ * ubifs_gc_end_commit - garbage collection at end of commit. ++ * @c: UBIFS file-system description object ++ * ++ * This function completes out-of-place garbage collection of index LEBs. ++ */ ++int ubifs_gc_end_commit(struct ubifs_info *c) ++{ ++ struct ubifs_gced_idx_leb *idx_gc, *tmp; ++ struct ubifs_wbuf *wbuf; ++ int err = 0; ++ ++ wbuf = &c->jheads[GCHD].wbuf; ++ mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); ++ list_for_each_entry_safe(idx_gc, tmp, &c->idx_gc, list) ++ if (idx_gc->unmap) { ++ dbg_gc("LEB %d", idx_gc->lnum); ++ err = ubifs_leb_unmap(c, idx_gc->lnum); ++ if (err) ++ goto out; ++ err = ubifs_change_one_lp(c, idx_gc->lnum, LPROPS_NC, ++ LPROPS_NC, 0, LPROPS_TAKEN, -1); ++ if (err) ++ goto out; ++ list_del(&idx_gc->list); ++ kfree(idx_gc); ++ } ++out: ++ mutex_unlock(&wbuf->io_mutex); ++ return err; ++} ++ ++/** ++ * ubifs_destroy_idx_gc - destroy idx_gc list. ++ * @c: UBIFS file-system description object ++ * ++ * This function destroys the idx_gc list. It is called when unmounting or ++ * remounting read-only so locks are not needed. ++ */ ++void ubifs_destroy_idx_gc(struct ubifs_info *c) ++{ ++ while (!list_empty(&c->idx_gc)) { ++ struct ubifs_gced_idx_leb *idx_gc; ++ ++ idx_gc = list_entry(c->idx_gc.next, struct ubifs_gced_idx_leb, ++ list); ++ c->idx_gc_cnt -= 1; ++ list_del(&idx_gc->list); ++ kfree(idx_gc); ++ } ++ ++} ++ ++/** ++ * ubifs_get_idx_gc_leb - get a LEB from GC'd index LEB list. ++ * @c: UBIFS file-system description object ++ * ++ * Called during start commit so locks are not needed. ++ */ ++int ubifs_get_idx_gc_leb(struct ubifs_info *c) ++{ ++ struct ubifs_gced_idx_leb *idx_gc; ++ int lnum; ++ ++ if (list_empty(&c->idx_gc)) ++ return -ENOSPC; ++ idx_gc = list_entry(c->idx_gc.next, struct ubifs_gced_idx_leb, list); ++ lnum = idx_gc->lnum; ++ /* c->idx_gc_cnt is updated by the caller when lprops are updated */ ++ list_del(&idx_gc->list); ++ kfree(idx_gc); ++ return lnum; ++} +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/io.c avr32-2.6/fs/ubifs/io.c +--- linux-2.6.25.6/fs/ubifs/io.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/io.c 2008-06-12 15:09:45.367815766 +0200 +@@ -0,0 +1,921 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * Copyright (C) 2006, 2007 University of Szeged, Hungary ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Artem Bityutskiy (Битюцкий Артём) ++ * Adrian Hunter ++ * Zoltan Sogor ++ */ ++ ++/* ++ * This file implements UBIFS I/O subsystem which provides various I/O-related ++ * helper functions (reading/writing/checking/validating nodes) and implements ++ * write-buffering support. Write buffers help to save space which otherwise ++ * would have been wasted for padding to the nearest minimal I/O unit boundary. ++ * Instead, data first goes to the write-buffer and is flushed when the ++ * buffer is full or when it is not used for some time (by timer). This is ++ * similarto the mechanism is used by JFFS2. ++ * ++ * Write-buffers are defined by 'struct ubifs_wbuf' objects and protected by ++ * mutexes defined inside these objects. Since sometimes upper-level code ++ * has to lock the write-buffer (e.g. journal space reservation code), many ++ * functions related to write-buffers have "nolock" suffix which means that the ++ * caller has to lock the write-buffer before calling this function. ++ * ++ * UBIFS stores nodes at 64 bit-aligned addresses. If the node length is not ++ * aligned, UBIFS starts the next node from the aligned address, and the padded ++ * bytes may contain any rubbish. In other words, UBIFS does not put padding ++ * bytes in those small gaps. Common headers of nodes store real node lengths, ++ * not aligned lengths. Indexing nodes also store real lengths in branches. ++ * ++ * UBIFS uses padding when it pads to the next min. I/O unit. In this case it ++ * uses padding nodes or padding bytes, if the padding node does not fit. ++ * ++ * All UBIFS nodes are protected by CRC checksums and UBIFS checks all nodes ++ * every time they are read from the flash media. ++ */ ++ ++#include <linux/crc32.h> ++#include "ubifs.h" ++ ++/** ++ * ubifs_check_node - check node. ++ * @c: UBIFS file-system description object ++ * @buf: node to check ++ * @lnum: logical eraseblock number ++ * @offs: offset within the logical eraseblock ++ * @quiet: print no messages ++ * ++ * This function checks node magic number and CRC checksum. This function also ++ * validates node length to prevent UBIFS from becoming crazy when an attacker ++ * feeds it a file-system image with incorrect nodes. For example, too large ++ * node length in the common header could cause UBIFS to read memory outside of ++ * allocated buffer when checking the CRC checksum. ++ * ++ * This function returns zero in case of success %-EUCLEAN in case of bad CRC ++ * or magic. ++ */ ++int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum, ++ int offs, int quiet) ++{ ++ int err = -EINVAL, type, node_len; ++ uint32_t crc, node_crc, magic; ++ const struct ubifs_ch *ch = buf; ++ ++ ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0); ++ ubifs_assert(!(offs & 7) && offs < c->leb_size); ++ ++ magic = le32_to_cpu(ch->magic); ++ if (magic != UBIFS_NODE_MAGIC) { ++ if (!quiet) ++ ubifs_err("bad magic %#08x, expected %#08x", ++ magic, UBIFS_NODE_MAGIC); ++ err = -EUCLEAN; ++ goto out; ++ } ++ ++ type = ch->node_type; ++ if (type < 0 || type >= UBIFS_NODE_TYPES_CNT) { ++ if (!quiet) ++ ubifs_err("bad node type %d", type); ++ goto out; ++ } ++ ++ node_len = le32_to_cpu(ch->len); ++ if (node_len + offs > c->leb_size) ++ goto out_len; ++ ++ if (c->ranges[type].max_len == 0) { ++ if (node_len != c->ranges[type].len) ++ goto out_len; ++ } else if (node_len < c->ranges[type].min_len || ++ node_len > c->ranges[type].max_len) ++ goto out_len; ++ ++ crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8); ++ node_crc = le32_to_cpu(ch->crc); ++ if (crc != node_crc) { ++ if (!quiet) ++ ubifs_err("bad CRC: calculated %#08x, read %#08x", ++ crc, node_crc); ++ err = -EUCLEAN; ++ goto out; ++ } ++ ++ return 0; ++ ++out_len: ++ if (!quiet) ++ ubifs_err("bad node length %d", node_len); ++out: ++ if (!quiet) { ++ ubifs_err("bad node at LEB %d:%d", lnum, offs); ++ dbg_dump_node(c, buf); ++ dbg_dump_stack(); ++ } ++ return err; ++} ++ ++/** ++ * ubifs_pad - pad flash space. ++ * @c: UBIFS file-system description object ++ * @buf: buffer to put padding to ++ * @pad: how many bytes to pad ++ * ++ * The flash media obliges us to write only in chunks of %c->min_io_size and ++ * when we have to write less data we add padding node to the write-buffer and ++ * pad it to the next minimal I/O unit's boundary. Padding nodes help when the ++ * media is being scanned. If the amount of wasted space is not enough to fit a ++ * padding node which takes %UBIFS_PAD_NODE_SZ bytes, we write padding bytes ++ * pattern (%UBIFS_PADDING_BYTE). ++ * ++ * Padding nodes are also used to fill gaps when the "commit-in-gaps" method is ++ * used. ++ */ ++void ubifs_pad(const struct ubifs_info *c, void *buf, int pad) ++{ ++ uint32_t crc; ++ ++ ubifs_assert(pad >= 0 && !(pad & 7)); ++ ++ if (pad >= UBIFS_PAD_NODE_SZ) { ++ struct ubifs_ch *ch = buf; ++ struct ubifs_pad_node *pad_node = buf; ++ ++ ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC); ++ ch->node_type = UBIFS_PAD_NODE; ++ ch->group_type = UBIFS_NO_NODE_GROUP; ++ ch->padding[0] = ch->padding[1] = 0; ++ ch->sqnum = 0; ++ ch->len = cpu_to_le32(UBIFS_PAD_NODE_SZ); ++ pad -= UBIFS_PAD_NODE_SZ; ++ pad_node->pad_len = cpu_to_le32(pad); ++ crc = crc32(UBIFS_CRC32_INIT, buf + 8, UBIFS_PAD_NODE_SZ - 8); ++ ch->crc = cpu_to_le32(crc); ++ memset(buf + UBIFS_PAD_NODE_SZ, 0, pad); ++ } else if (pad > 0) ++ /* Too little space, padding node won't fit */ ++ memset(buf, UBIFS_PADDING_BYTE, pad); ++} ++ ++/** ++ * next_sqnum - get next sequence number. ++ * @c: UBIFS file-system description object ++ */ ++static unsigned long long next_sqnum(struct ubifs_info *c) ++{ ++ unsigned long long sqnum; ++ ++ spin_lock(&c->cnt_lock); ++ sqnum = ++c->max_sqnum; ++ spin_unlock(&c->cnt_lock); ++ ++ if (unlikely(sqnum >= SQNUM_WARN_WATERMARK)) { ++ if (sqnum >= SQNUM_WATERMARK) { ++ ubifs_err("sequence number overflow %llu, end of life", ++ sqnum); ++ ubifs_ro_mode(c, -EINVAL); ++ } ++ ubifs_warn("running out of sequence numbers, end of life soon"); ++ } ++ ++ return sqnum; ++} ++ ++/** ++ * ubifs_prepare_node - prepare node to be written to flash. ++ * @c: UBIFS file-system description object ++ * @node: the node to pad ++ * @len: node length ++ * @pad: if the buffer has to be padded ++ * ++ * This function prepares node at @node to be written to the media - it ++ * calculates node CRC, fills the common header, and adds proper padding up to ++ * the next minimum I/O unit if @pad is not zero. ++ */ ++void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad) ++{ ++ uint32_t crc; ++ struct ubifs_ch *ch = node; ++ unsigned long long sqnum = next_sqnum(c); ++ ++ ubifs_assert(len >= UBIFS_CH_SZ); ++ ++ ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC); ++ ch->len = cpu_to_le32(len); ++ ch->group_type = UBIFS_NO_NODE_GROUP; ++ ch->sqnum = cpu_to_le64(sqnum); ++ ch->padding[0] = ch->padding[1] = 0; ++ crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8); ++ ch->crc = cpu_to_le32(crc); ++ ++ if (pad) { ++ len = ALIGN(len, 8); ++ pad = ALIGN(len, c->min_io_size) - len; ++ ubifs_pad(c, node + len, pad); ++ } ++} ++ ++/** ++ * ubifs_prep_grp_node - prepare node of a group to be written to flash. ++ * @c: UBIFS file-system description object ++ * @node: the node to pad ++ * @len: node length ++ * @last: indicates the last node of the group ++ * ++ * This function prepares node at @node to be written to the media - it ++ * calculates node CRC and fills the common header. ++ */ ++void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last) ++{ ++ uint32_t crc; ++ struct ubifs_ch *ch = node; ++ unsigned long long sqnum = next_sqnum(c); ++ ++ ubifs_assert(len >= UBIFS_CH_SZ); ++ ++ ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC); ++ ch->len = cpu_to_le32(len); ++ if (last) ++ ch->group_type = UBIFS_LAST_OF_NODE_GROUP; ++ else ++ ch->group_type = UBIFS_IN_NODE_GROUP; ++ ch->sqnum = cpu_to_le64(sqnum); ++ ch->padding[0] = ch->padding[1] = 0; ++ crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8); ++ ch->crc = cpu_to_le32(crc); ++} ++ ++/** ++ * wbuf_timer_callback - write-buffer timer callback function. ++ * @data: timer data (write-buffer descriptor) ++ * ++ * This function is called when the write-buffer timer expires. ++ */ ++static void wbuf_timer_callback_nolock(unsigned long data) ++{ ++ struct ubifs_wbuf *wbuf = (struct ubifs_wbuf *)data; ++ ++ wbuf->need_sync = 1; ++ wbuf->c->need_wbuf_sync = 1; ++ ubifs_wake_up_bgt(wbuf->c); ++} ++ ++/** ++ * new_wbuf_timer - start new write-buffer timer. ++ * @wbuf: write-buffer descriptor ++ */ ++static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf) ++{ ++ ubifs_assert(!timer_pending(&wbuf->timer)); ++ ++ if (!wbuf->timeout) ++ return; ++ ++ wbuf->timer.expires = jiffies + wbuf->timeout; ++ add_timer(&wbuf->timer); ++} ++ ++/** ++ * cancel_wbuf_timer - cancel write-buffer timer. ++ * @wbuf: write-buffer descriptor ++ */ ++static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf) ++{ ++ /* ++ * If the syncer is waiting for the lock (from the background thread's ++ * context) and another task is changing write-buffer then the syncing ++ * should be canceled. ++ */ ++ wbuf->need_sync = 0; ++ del_timer(&wbuf->timer); ++} ++ ++/** ++ * ubifs_wbuf_sync_nolock - synchronize write-buffer. ++ * @wbuf: write-buffer to synchronize ++ * ++ * This function synchronizes write-buffer @buf and returns zero in case of ++ * success or a negative error code in case of failure. ++ */ ++int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf) ++{ ++ struct ubifs_info *c = wbuf->c; ++ int err, dirt; ++ ++ cancel_wbuf_timer_nolock(wbuf); ++ if (!wbuf->used || wbuf->lnum == -1) ++ /* Write-buffer is empty or not seeked */ ++ return 0; ++ ++ dbg_io("LEB %d:%d, %d bytes", ++ wbuf->lnum, wbuf->offs, wbuf->used); ++ ubifs_assert(!(c->vfs_sb->s_flags & MS_RDONLY)); ++ ubifs_assert(!(wbuf->avail & 7)); ++ ubifs_assert(wbuf->offs + c->min_io_size <= c->leb_size); ++ ++ if (c->ro_media) ++ return -EROFS; ++ ++ ubifs_pad(c, wbuf->buf + wbuf->used, wbuf->avail); ++ err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs, ++ c->min_io_size, wbuf->dtype); ++ if (err) { ++ ubifs_err("cannot write %d bytes to LEB %d:%d", ++ c->min_io_size, wbuf->lnum, wbuf->offs); ++ dbg_dump_stack(); ++ return err; ++ } ++ ++ dirt = wbuf->avail; ++ ++ spin_lock(&wbuf->lock); ++ wbuf->offs += c->min_io_size; ++ wbuf->avail = c->min_io_size; ++ wbuf->used = 0; ++ wbuf->next_ino = 0; ++ spin_unlock(&wbuf->lock); ++ ++ if (wbuf->sync_callback) ++ err = wbuf->sync_callback(c, wbuf->lnum, ++ c->leb_size - wbuf->offs, dirt); ++ return err; ++} ++ ++/** ++ * ubifs_wbuf_seek_nolock - seek write-buffer. ++ * @wbuf: write-buffer ++ * @lnum: logical eraseblock number to seek to ++ * @offs: logical eraseblock offset to seek to ++ * @dtype: data type ++ * ++ * This function targets the write buffer to logical eraseblock @lnum:@offs. ++ * The write-buffer is synchronized if it is not empty. Returns zero in case of ++ * success and a negative error code in case of failure. ++ */ ++int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs, ++ int dtype) ++{ ++ const struct ubifs_info *c = wbuf->c; ++ ++ dbg_io("LEB %d:%d", lnum, offs); ++ ubifs_assert(lnum >= 0 && lnum < c->leb_cnt); ++ ubifs_assert(offs >= 0 && offs <= c->leb_size); ++ ubifs_assert(offs % c->min_io_size == 0 && !(offs & 7)); ++ ubifs_assert(lnum != wbuf->lnum); ++ ++ if (wbuf->used > 0) { ++ int err = ubifs_wbuf_sync_nolock(wbuf); ++ ++ if (err) ++ return err; ++ } ++ ++ spin_lock(&wbuf->lock); ++ wbuf->lnum = lnum; ++ wbuf->offs = offs; ++ wbuf->avail = c->min_io_size; ++ wbuf->used = 0; ++ spin_unlock(&wbuf->lock); ++ wbuf->dtype = dtype; ++ ++ return 0; ++} ++ ++/** ++ * ubifs_bg_wbufs_sync - synchronize write-buffers. ++ * @c: UBIFS file-system description object ++ * ++ * This function is called by background thread to synchronize write-buffers. ++ * Returns zero in case of success and a negative error code in case of ++ * failure. ++ */ ++int ubifs_bg_wbufs_sync(struct ubifs_info *c) ++{ ++ int err, i; ++ ++ if (!c->need_wbuf_sync) ++ return 0; ++ c->need_wbuf_sync = 0; ++ ++ if (c->ro_media) { ++ err = -EROFS; ++ goto out_timers; ++ } ++ ++ dbg_io("synchronize"); ++ for (i = 0; i < c->jhead_cnt; i++) { ++ struct ubifs_wbuf *wbuf = &c->jheads[i].wbuf; ++ ++ cond_resched(); ++ ++ /* ++ * If the mutex is locked then wbuf is being changed, so ++ * synchronization is not necessary. ++ */ ++ if (mutex_is_locked(&wbuf->io_mutex)) ++ continue; ++ ++ mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); ++ if (!wbuf->need_sync) { ++ mutex_unlock(&wbuf->io_mutex); ++ continue; ++ } ++ ++ err = ubifs_wbuf_sync_nolock(wbuf); ++ mutex_unlock(&wbuf->io_mutex); ++ if (err) { ++ ubifs_err("cannot sync write-buffer, error %d", err); ++ ubifs_ro_mode(c, err); ++ goto out_timers; ++ } ++ } ++ ++ return 0; ++ ++out_timers: ++ /* Cancel all timers to prevent repeated errors */ ++ for (i = 0; i < c->jhead_cnt; i++) { ++ struct ubifs_wbuf *wbuf = &c->jheads[i].wbuf; ++ ++ mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); ++ cancel_wbuf_timer_nolock(wbuf); ++ mutex_unlock(&wbuf->io_mutex); ++ } ++ return err; ++} ++ ++/** ++ * ubifs_wbuf_write_nolock - write data to flash via write-buffer. ++ * @wbuf: write-buffer ++ * @buf: node to write ++ * @len: node length ++ * ++ * This function writes data to flash via write-buffer @wbuf. This means that ++ * the last piece of the node won't reach the flash media immediately if it ++ * does not take whole minimal I/O unit. Instead, the node will sit in RAM ++ * until the write-buffer is synchronized (e.g., by timer). ++ * ++ * This function returns zero in case of success and a negative error code in ++ * case of failure. If the node cannot be written because there is no more ++ * space in this logical eraseblock, %-ENOSPC is returned. ++ */ ++int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len) ++{ ++ struct ubifs_info *c = wbuf->c; ++ int err, written, n, aligned_len = ALIGN(len, 8), offs; ++ ++ dbg_io("%d bytes (%s) to wbuf at LEB %d:%d", len, ++ dbg_ntype(((struct ubifs_ch *)buf)->node_type), wbuf->lnum, ++ wbuf->offs + wbuf->used); ++ ubifs_assert(len > 0 && wbuf->lnum >= 0 && wbuf->lnum < c->leb_cnt); ++ ubifs_assert(wbuf->offs >= 0 && wbuf->offs % c->min_io_size == 0); ++ ubifs_assert(!(wbuf->offs & 7) && wbuf->offs <= c->leb_size); ++ ubifs_assert(wbuf->avail > 0 && wbuf->avail <= c->min_io_size); ++ ubifs_assert(mutex_is_locked(&wbuf->io_mutex)); ++ ++ if (c->leb_size - wbuf->offs - wbuf->used < aligned_len) { ++ err = -ENOSPC; ++ goto out; ++ } ++ ++ cancel_wbuf_timer_nolock(wbuf); ++ ++ if (c->ro_media) ++ return -EROFS; ++ ++ if (aligned_len <= wbuf->avail) { ++ /* ++ * The node is not very large and fits entirely within ++ * write-buffer. ++ */ ++ memcpy(wbuf->buf + wbuf->used, buf, len); ++ ++ if (aligned_len == wbuf->avail) { ++ dbg_io("flush wbuf to LEB %d:%d", wbuf->lnum, ++ wbuf->offs); ++ err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, ++ wbuf->offs, c->min_io_size, ++ wbuf->dtype); ++ if (err) ++ goto out; ++ ++ spin_lock(&wbuf->lock); ++ wbuf->offs += c->min_io_size; ++ wbuf->avail = c->min_io_size; ++ wbuf->used = 0; ++ wbuf->next_ino = 0; ++ spin_unlock(&wbuf->lock); ++ } else { ++ spin_lock(&wbuf->lock); ++ wbuf->avail -= aligned_len; ++ wbuf->used += aligned_len; ++ spin_unlock(&wbuf->lock); ++ } ++ ++ goto exit; ++ } ++ ++ /* ++ * The node is large enough and does not fit entirely within current ++ * minimal I/O unit. We have to fill and flush write-buffer and switch ++ * to the next min. I/O unit. ++ */ ++ dbg_io("flush wbuf to LEB %d:%d", wbuf->lnum, wbuf->offs); ++ memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail); ++ err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs, ++ c->min_io_size, wbuf->dtype); ++ if (err) ++ goto out; ++ ++ offs = wbuf->offs + c->min_io_size; ++ len -= wbuf->avail; ++ aligned_len -= wbuf->avail; ++ written = wbuf->avail; ++ ++ /* ++ * The remaining data may take more whole min. I/O units, so write the ++ * remains multiple to min. I/O unit size directly to the flash media. ++ * We align node length to 8-byte boundary because we anyway flash wbuf ++ * if the remaining space is less than 8 bytes. ++ */ ++ n = aligned_len >> c->min_io_shift; ++ if (n) { ++ n <<= c->min_io_shift; ++ dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum, offs); ++ err = ubi_leb_write(c->ubi, wbuf->lnum, buf + written, offs, n, ++ wbuf->dtype); ++ if (err) ++ goto out; ++ offs += n; ++ aligned_len -= n; ++ len -= n; ++ written += n; ++ } ++ ++ spin_lock(&wbuf->lock); ++ if (aligned_len) ++ /* ++ * And now we have what's left and what does not take whole ++ * min. I/O unit, so write it to the write-buffer and we are ++ * done. ++ */ ++ memcpy(wbuf->buf, buf + written, len); ++ ++ wbuf->offs = offs; ++ wbuf->used = aligned_len; ++ wbuf->avail = c->min_io_size - aligned_len; ++ wbuf->next_ino = 0; ++ spin_unlock(&wbuf->lock); ++ ++exit: ++ if (wbuf->sync_callback) { ++ int free = c->leb_size - wbuf->offs - wbuf->used; ++ ++ err = wbuf->sync_callback(c, wbuf->lnum, free, 0); ++ if (err) ++ goto out; ++ } ++ ++ if (wbuf->used) ++ new_wbuf_timer_nolock(wbuf); ++ ++ return 0; ++ ++out: ++ ubifs_err("cannot write %d bytes to LEB %d:%d, error %d", ++ len, wbuf->lnum, wbuf->offs, err); ++ dbg_dump_node(c, buf); ++ dbg_dump_stack(); ++ dbg_dump_leb(c, wbuf->lnum); ++ return err; ++} ++ ++/** ++ * ubifs_write_node - write node to the media. ++ * @c: UBIFS file-system description object ++ * @buf: the node to write ++ * @len: node length ++ * @lnum: logical eraseblock number ++ * @offs: offset within the logical eraseblock ++ * @dtype: node life-time hint (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN) ++ * ++ * This function automatically fills node magic number, assigns sequence ++ * number, and calculates node CRC checksum. The length of the @buf buffer has ++ * to be aligned to the minimal I/O unit size. This function automatically ++ * appends padding node and padding bytes if needed. Returns zero in case of ++ * success and a negative error code in case of failure. ++ */ ++int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum, ++ int offs, int dtype) ++{ ++ int err, buf_len = ALIGN(len, c->min_io_size); ++ ++ dbg_io("LEB %d:%d, %s, length %d (aligned %d)", ++ lnum, offs, dbg_ntype(((struct ubifs_ch *)buf)->node_type), len, ++ buf_len); ++ ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0); ++ ubifs_assert(offs % c->min_io_size == 0 && offs < c->leb_size); ++ ++ if (c->ro_media) ++ return -EROFS; ++ ++ ubifs_prepare_node(c, buf, len, 1); ++ err = ubi_leb_write(c->ubi, lnum, buf, offs, buf_len, dtype); ++ if (err) { ++ ubifs_err("cannot write %d bytes to LEB %d:%d, error %d", ++ buf_len, lnum, offs, err); ++ dbg_dump_node(c, buf); ++ dbg_dump_stack(); ++ } ++ ++ return err; ++} ++ ++/** ++ * ubifs_read_node_wbuf - read node from the media or write-buffer. ++ * @wbuf: wbuf to check for un-written data ++ * @buf: buffer to read to ++ * @type: node type ++ * @len: node length ++ * @lnum: logical eraseblock number ++ * @offs: offset within the logical eraseblock ++ * ++ * This function reads a node of known type and length, checks it and stores ++ * in @buf. If the node partially or fully sits in the write-buffer, this ++ * function takes data from the buffer, otherwise it reads the flash media. ++ * Returns zero in case of success, %-EUCLEAN if CRC mismatched and a negative ++ * error code in case of failure. ++ */ ++int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len, ++ int lnum, int offs) ++{ ++ const struct ubifs_info *c = wbuf->c; ++ int err, rlen, overlap; ++ struct ubifs_ch *ch = buf; ++ ++ dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len); ++ ubifs_assert(wbuf && lnum >= 0 && lnum < c->leb_cnt && offs >= 0); ++ ubifs_assert(!(offs & 7) && offs < c->leb_size); ++ ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT); ++ ++ spin_lock(&wbuf->lock); ++ overlap = (lnum == wbuf->lnum && offs + len > wbuf->offs); ++ if (!overlap) { ++ /* We may safely unlock the write-buffer and read the data */ ++ spin_unlock(&wbuf->lock); ++ return ubifs_read_node(c, buf, type, len, lnum, offs); ++ } ++ ++ /* Don't read under wbuf */ ++ rlen = wbuf->offs - offs; ++ if (rlen < 0) ++ rlen = 0; ++ ++ /* Copy the rest from the write-buffer */ ++ memcpy(buf + rlen, wbuf->buf + offs + rlen - wbuf->offs, len - rlen); ++ spin_unlock(&wbuf->lock); ++ ++ if (rlen > 0) { ++ /* Read everything that goes before write-buffer */ ++ err = ubi_read(c->ubi, lnum, buf, offs, rlen); ++ if (err && err != -EBADMSG) { ++ ubifs_err("failed to read node %d from LEB %d:%d, " ++ "error %d", type, lnum, offs, err); ++ dbg_dump_stack(); ++ return err; ++ } ++ } ++ ++ err = ubifs_check_node(c, buf, lnum, offs, 0); ++ if (err) { ++ ubifs_err("expected node type %d", type); ++ return err; ++ } ++ ++ if (type != ch->node_type) { ++ ubifs_err("bad node type (%d but expected %d)", ++ ch->node_type, type); ++ goto out; ++ } ++ ++ rlen = le32_to_cpu(ch->len); ++ if (rlen != len) { ++ ubifs_err("bad node length %d, expected %d", rlen, len); ++ goto out; ++ } ++ ++ return 0; ++ ++out: ++ ubifs_err("bad node at LEB %d:%d", lnum, offs); ++ dbg_dump_node(c, buf); ++ dbg_dump_stack(); ++ return -EINVAL; ++} ++ ++/** ++ * ubifs_read_node - read node. ++ * @c: UBIFS file-system description object ++ * @buf: buffer to read to ++ * @type: node type ++ * @len: node length (not aligned) ++ * @lnum: logical eraseblock number ++ * @offs: offset within the logical eraseblock ++ * ++ * This function reads a node of known type and and length, checks it and ++ * stores in @buf. Returns zero in case of success, %-EUCLEAN if CRC mismatched ++ * and a negative error code in case of failure. ++ */ ++int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len, ++ int lnum, int offs) ++{ ++ int err, l; ++ struct ubifs_ch *ch = buf; ++ ++ dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len); ++ ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0); ++ ubifs_assert(len >= UBIFS_CH_SZ && offs + len <= c->leb_size); ++ ubifs_assert(!(offs & 7) && offs < c->leb_size); ++ ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT); ++ ++ err = ubi_read(c->ubi, lnum, buf, offs, len); ++ if (err && err != -EBADMSG) { ++ ubifs_err("cannot read node %d from LEB %d:%d, error %d", ++ type, lnum, offs, err); ++ return err; ++ } ++ ++ err = ubifs_check_node(c, buf, lnum, offs, 0); ++ if (err) { ++ ubifs_err("expected node type %d", type); ++ return err; ++ } ++ ++ if (type != ch->node_type) { ++ ubifs_err("bad node type (%d but expected %d)", ++ ch->node_type, type); ++ goto out; ++ } ++ ++ l = le32_to_cpu(ch->len); ++ if (l != len) { ++ ubifs_err("bad node length %d, expected %d", l, len); ++ goto out; ++ } ++ ++ return 0; ++ ++out: ++ ubifs_err("bad node at LEB %d:%d", lnum, offs); ++ dbg_dump_node(c, buf); ++ dbg_dump_stack(); ++ return -EINVAL; ++} ++ ++/** ++ * ubifs_wbuf_init - initialize write-buffer. ++ * @c: UBIFS file-system description object ++ * @wbuf: write-buffer to initialize ++ * ++ * This function initializes write buffer. Returns zero in case of success ++ * %-ENOMEM in case of failure. ++ */ ++int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf) ++{ ++ size_t size; ++ ++ wbuf->buf = kmalloc(c->min_io_size, GFP_KERNEL); ++ if (!wbuf->buf) ++ return -ENOMEM; ++ ++ size = (c->min_io_size / UBIFS_CH_SZ + 1) * sizeof(ino_t); ++ wbuf->inodes = kmalloc(size, GFP_KERNEL); ++ if (!wbuf->inodes) { ++ kfree(wbuf->buf); ++ wbuf->buf = NULL; ++ return -ENOMEM; ++ } ++ ++ wbuf->used = 0; ++ wbuf->lnum = wbuf->offs = -1; ++ wbuf->avail = c->min_io_size; ++ wbuf->dtype = UBI_UNKNOWN; ++ wbuf->sync_callback = NULL; ++ mutex_init(&wbuf->io_mutex); ++ spin_lock_init(&wbuf->lock); ++ ++ wbuf->c = c; ++ init_timer(&wbuf->timer); ++ wbuf->timer.function = wbuf_timer_callback_nolock; ++ wbuf->timer.data = (unsigned long)wbuf; ++ wbuf->timeout = DEFAULT_WBUF_TIMEOUT; ++ wbuf->next_ino = 0; ++ ++ return 0; ++} ++ ++/** ++ * ubifs_wbuf_add_ino_nolock - add an inode number into the wbuf inode array. ++ * @wbuf: the write-buffer whereto add ++ * @inum: the inode number ++ * ++ * This function adds an inode number to the inode array of the write-buffer. ++ */ ++void ubifs_wbuf_add_ino_nolock(struct ubifs_wbuf *wbuf, ino_t inum) ++{ ++ if (!wbuf->buf) ++ /* NOR flash or something similar */ ++ return; ++ ++ spin_lock(&wbuf->lock); ++ if (wbuf->used) ++ wbuf->inodes[wbuf->next_ino++] = inum; ++ spin_unlock(&wbuf->lock); ++} ++ ++/** ++ * wbuf_has_ino - returns if the wbuf contains data from the inode. ++ * @wbuf: the write-buffer ++ * @inum: the inode number ++ * ++ * This function returns with %1 if the write-buffer contains some data from the ++ * given inode otherwise it returns with %0. ++ */ ++static int wbuf_has_ino(struct ubifs_wbuf *wbuf, ino_t inum) ++{ ++ int i, ret = 0; ++ ++ spin_lock(&wbuf->lock); ++ for (i = 0; i < wbuf->next_ino; i++) ++ if (inum == wbuf->inodes[i]) { ++ ret = 1; ++ break; ++ } ++ spin_unlock(&wbuf->lock); ++ ++ return ret; ++} ++ ++/** ++ * ubifs_sync_wbufs_by_inodes - synchronize write-buffers which have data. ++ * belonging to specified inodes. ++ * @c: UBIFS file-system description object ++ * @inodes: array of inodes ++ * @count: number of elements in @inodes ++ * ++ * This function synchronizes write-buffers which contain nodes belonging to ++ * any inode specified in @inodes array. Returns zero in case of success and a ++ * negative error code in case of failure. ++ */ ++int ubifs_sync_wbufs_by_inodes(struct ubifs_info *c, ++ struct inode * const *inodes, int count) ++{ ++ int i, j, err = 0; ++ ++ ubifs_assert(count); ++ ++ for (i = 0; i < c->jhead_cnt; i++) { ++ struct ubifs_wbuf *wbuf = &c->jheads[i].wbuf; ++ ++ if (i == GCHD) ++ /* ++ * GC head is special, do not look at it. Even if the ++ * head contains something related to this inode, it is ++ * a _copy_ of corresponding on-flash node which sits ++ * somewhere else. ++ */ ++ continue; ++ ++ for (j = 0; j < count && !err; j++) ++ if (wbuf_has_ino(wbuf, inodes[j]->i_ino)) { ++ mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); ++ if (wbuf_has_ino(wbuf, inodes[j]->i_ino)) ++ err = ubifs_wbuf_sync_nolock(wbuf); ++ mutex_unlock(&wbuf->io_mutex); ++ break; ++ } ++ ++ if (err) { ++ ubifs_ro_mode(c, err); ++ break; ++ } ++ } ++ ++ return err; ++} +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/ioctl.c avr32-2.6/fs/ubifs/ioctl.c +--- linux-2.6.25.6/fs/ubifs/ioctl.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/ioctl.c 2008-06-12 15:09:45.367815766 +0200 +@@ -0,0 +1,204 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * Copyright (C) 2006, 2007 University of Szeged, Hungary ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Zoltan Sogor ++ * Artem Bityutskiy (Битюцкий Артём) ++ * Adrian Hunter ++ */ ++ ++/* This file implements EXT2-compatible extended attribute ioctl() calls */ ++ ++#include <linux/compat.h> ++#include <linux/smp_lock.h> ++#include "ubifs.h" ++ ++/** ++ * ubifs_set_inode_flags - set VFS inode flags. ++ * @inode: VFS inode to set flags for ++ * ++ * This function propagates flags from UBIFS inode object to VFS inode object. ++ */ ++void ubifs_set_inode_flags(struct inode *inode) ++{ ++ unsigned int flags = ubifs_inode(inode)->flags; ++ ++ inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE | S_DIRSYNC); ++ if (flags & UBIFS_SYNC_FL) ++ inode->i_flags |= S_SYNC; ++ if (flags & UBIFS_APPEND_FL) ++ inode->i_flags |= S_APPEND; ++ if (flags & UBIFS_IMMUTABLE_FL) ++ inode->i_flags |= S_IMMUTABLE; ++ if (flags & UBIFS_DIRSYNC_FL) ++ inode->i_flags |= S_DIRSYNC; ++} ++ ++/* ++ * ioctl2ubifs - convert ioctl inode flags to UBIFS inode flags. ++ * @ioctl_flags: flags to convert ++ * ++ * This function convert ioctl flags (@FS_COMPR_FL, etc) to UBIFS inode flags ++ * (@UBIFS_COMPR_FL, etc). ++ */ ++static int ioctl2ubifs(int ioctl_flags) ++{ ++ int ubifs_flags = 0; ++ ++ if (ioctl_flags & FS_COMPR_FL) ++ ubifs_flags |= UBIFS_COMPR_FL; ++ if (ioctl_flags & FS_SYNC_FL) ++ ubifs_flags |= UBIFS_SYNC_FL; ++ if (ioctl_flags & FS_APPEND_FL) ++ ubifs_flags |= UBIFS_APPEND_FL; ++ if (ioctl_flags & FS_IMMUTABLE_FL) ++ ubifs_flags |= UBIFS_IMMUTABLE_FL; ++ if (ioctl_flags & FS_DIRSYNC_FL) ++ ubifs_flags |= UBIFS_DIRSYNC_FL; ++ ++ return ubifs_flags; ++} ++ ++/* ++ * ubifs2ioctl - convert UBIFS inode flags to ioctl inode flags. ++ * @ubifs_flags: flags to convert ++ * ++ * This function convert UBIFS (@UBIFS_COMPR_FL, etc) to ioctl flags ++ * (@FS_COMPR_FL, etc). ++ */ ++static int ubifs2ioctl(int ubifs_flags) ++{ ++ int ioctl_flags = 0; ++ ++ if (ubifs_flags & UBIFS_COMPR_FL) ++ ioctl_flags |= FS_COMPR_FL; ++ if (ubifs_flags & UBIFS_SYNC_FL) ++ ioctl_flags |= FS_SYNC_FL; ++ if (ubifs_flags & UBIFS_APPEND_FL) ++ ioctl_flags |= FS_APPEND_FL; ++ if (ubifs_flags & UBIFS_IMMUTABLE_FL) ++ ioctl_flags |= FS_IMMUTABLE_FL; ++ if (ubifs_flags & UBIFS_DIRSYNC_FL) ++ ioctl_flags |= FS_DIRSYNC_FL; ++ ++ return ioctl_flags; ++} ++ ++static int setflags(struct inode *inode, int flags) ++{ ++ struct ubifs_inode *ui = ubifs_inode(inode); ++ struct ubifs_info *c = inode->i_sb->s_fs_info; ++ struct ubifs_budget_req req; ++ int oldflags, err; ++ ++ mutex_lock(&inode->i_mutex); ++ ++ memset(&req, 0 , sizeof(struct ubifs_budget_req)); ++ err = ubifs_budget_inode_op(c, inode, &req); ++ if (err) ++ goto out; ++ ++ /* ++ * The IMMUTABLE and APPEND_ONLY flags can only be changed by ++ * the relevant capability. ++ */ ++ oldflags = ubifs2ioctl(ui->flags); ++ if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) { ++ if (!capable(CAP_LINUX_IMMUTABLE)) { ++ err = -EPERM; ++ goto out_budg; ++ } ++ } ++ ++ ui->flags = ioctl2ubifs(flags); ++ ubifs_set_inode_flags(inode); ++ ++ inode->i_ctime = ubifs_current_time(inode); ++ mark_inode_dirty_sync(inode); ++ ++ ubifs_release_ino_dirty(c, inode, &req); ++ ++ if (IS_SYNC(inode)) ++ err = write_inode_now(inode, 1); ++ ++ mutex_unlock(&inode->i_mutex); ++ return err; ++ ++out_budg: ++ ubifs_cancel_ino_op(c, inode, &req); ++out: ++ ubifs_err("can't modify inode %lu attributes", inode->i_ino); ++ mutex_unlock(&inode->i_mutex); ++ return err; ++} ++ ++long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ int flags; ++ struct inode *inode = file->f_path.dentry->d_inode; ++ ++ switch (cmd) { ++ case FS_IOC_GETFLAGS: ++ flags = ubifs2ioctl(ubifs_inode(inode)->flags); ++ ++ return put_user(flags, (int __user *) arg); ++ ++ case FS_IOC_SETFLAGS: { ++ if (IS_RDONLY(inode)) ++ return -EROFS; ++ ++ if (!is_owner_or_cap(inode)) ++ return -EACCES; ++ ++ if (get_user(flags, (int __user *) arg)) ++ return -EFAULT; ++ ++ if (!S_ISDIR(inode->i_mode)) ++ flags &= ~FS_DIRSYNC_FL; ++ ++ return setflags(inode, flags); ++ } ++ ++ default: ++ return -ENOTTY; ++ } ++} ++ ++#ifdef CONFIG_COMPAT ++long ubifs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ int err; ++ ++ switch (cmd) { ++ case FS_IOC32_GETFLAGS: ++ cmd = FS_IOC_GETFLAGS; ++ break; ++ case FS_IOC32_SETFLAGS: ++ cmd = FS_IOC_SETFLAGS; ++ break; ++ default: ++ return -ENOIOCTLCMD; ++ } ++ ++ lock_kernel(); ++ err = ubifs_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); ++ unlock_kernel(); ++ ++ return err; ++} ++#endif +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/journal.c avr32-2.6/fs/ubifs/journal.c +--- linux-2.6.25.6/fs/ubifs/journal.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/journal.c 2008-06-12 15:09:45.367815766 +0200 +@@ -0,0 +1,1286 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Artem Bityutskiy (Битюцкий Артём) ++ * Adrian Hunter ++ */ ++ ++/* ++ * This file implements UBIFS journal. ++ * ++ * The journal consists of 2 parts - the log and bud LEBs. The log has fixed ++ * length and position, while a bud logical eraseblock is any LEB in the main ++ * area. Buds contain file system data - data nodes, inode nodes, etc. The log ++ * contains only references to buds and some other stuff like commit ++ * start node. The idea is that when we commit the journal, we do ++ * not copy the data, the buds just become indexed. Since after the commit the ++ * nodes in bud eraseblocks become leaf nodes of the file system index tree, we ++ * use term "bud". Analogy is obvious, bud eraseblocks contain nodes which will ++ * become leafs in the future. ++ * ++ * The journal is multi-headed because we want to write data to the journal as ++ * optimally as possible. It is nice to have nodes belonging to the same inode ++ * in one LEB, so we may write data owned by different inodes to different ++ * journal heads, although at present only one data head is used. ++ * ++ * For recovery reasons, the base head contains all inode nodes, all directory ++ * entry nodes and all truncate nodes. This means that the other heads contain ++ * only data nodes. ++ * ++ * Bud LEBs may be half-indexed. For example, if the bud was not full at the ++ * time of commit, the bud is retained to continue to be used in the journal, ++ * even though the "front" of the LEB is now indexed. In that case, the log ++ * reference contains the offset where the bud starts for the purposes of the ++ * journal. ++ * ++ * The journal size has to be limited, because the larger is the journal, the ++ * longer it takes to mount UBIFS (scanning the journal) and the more memory it ++ * takes (indexing in the TNC). ++ * ++ * Note, all the journal write operations like 'ubifs_jnl_update()' here, which ++ * write multiple UBIFS nodes to the journal at one go, are atomic with respect ++ * to unclean reboots. Should the unclean reboot happen, the recovery code drops ++ * all the nodes. ++ */ ++ ++#include "ubifs.h" ++ ++/** ++ * zero_ino_node_unused - zero out unused fields of an on-flash inode node. ++ * @ino: the inode to zero out ++ */ ++static inline void zero_ino_node_unused(struct ubifs_ino_node *ino) ++{ ++ memset(ino->padding, 0, 26); ++} ++ ++/** ++ * zero_dent_node_unused - zero out unused fields of an on-flash directory ++ * entry node. ++ * @ino: the directory entry to zero out ++ */ ++static inline void zero_dent_node_unused(struct ubifs_dent_node *dent) ++{ ++ dent->padding1 = 0; ++ memset(dent->padding2, 0, 4); ++} ++ ++/** ++ * zero_data_node_unused - zero out unused fields of an on-flash data node. ++ * @ino: the data node to zero out ++ */ ++static inline void zero_data_node_unused(struct ubifs_data_node *data) ++{ ++ memset(data->padding, 0, 2); ++} ++ ++/** ++ * zero_trun_node_unused - zero out unused fields of an on-flash truncation ++ * node. ++ * @ino: the truncation node to zero out ++ */ ++static inline void zero_trun_node_unused(struct ubifs_trun_node *trun) ++{ ++ memset(trun->padding, 0, 12); ++} ++ ++/** ++ * reserve_space - reserve space in the journal. ++ * @c: UBIFS file-system description object ++ * @jhead: journal head number ++ * @len: node length ++ * ++ * This function reserves space in journal head @head. If the reservation ++ * succeeded, the journal head stays locked and later has to be unlocked using ++ * 'release_head()'. 'write_node()' and 'write_head()' functions also unlock ++ * it. Returns zero in case of success, %-EAGAIN if commit has to be done, and ++ * other negative error codes in case of other failures. ++ */ ++static int reserve_space(struct ubifs_info *c, int jhead, int len) ++{ ++ int err = 0, err1, retries = 0, avail, lnum, offs, free, squeeze; ++ struct ubifs_wbuf *wbuf = &c->jheads[jhead].wbuf; ++ ++ /* ++ * Typically, the base head has smaller nodes written to it, so it is ++ * better to try to allocate space at the ends of eraseblocks. This is ++ * what the squeeze parameter does. ++ */ ++ squeeze = (jhead == BASEHD); ++again: ++ mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); ++ avail = c->leb_size - wbuf->offs - wbuf->used; ++ ++ if (wbuf->lnum != -1 && avail >= len) ++ return 0; ++ ++ /* ++ * Write buffer wasn't seek'ed or there is no enough space - look for an ++ * LEB with some empty space. ++ */ ++ lnum = ubifs_find_free_space(c, len, &free, squeeze); ++ if (lnum >= 0) { ++ /* Found an LEB, add it to the journal head */ ++ offs = c->leb_size - free; ++ err = ubifs_add_bud_to_log(c, jhead, lnum, offs); ++ if (err) ++ goto out_return; ++ /* A new bud was successfully allocated and added to the log */ ++ goto out; ++ } ++ ++ err = lnum; ++ if (err != -ENOSPC) ++ goto out_unlock; ++ ++ /* ++ * No free space, we have to run garbage collector to make ++ * some. But the write-buffer mutex has to be unlocked because ++ * GC have to sync write buffers, which may lead a deadlock. ++ */ ++ dbg_jnl("no free space jhead %d, run GC", jhead); ++ mutex_unlock(&wbuf->io_mutex); ++ ++ lnum = ubifs_garbage_collect(c, 0); ++ if (lnum < 0) { ++ err = lnum; ++ if (err != -ENOSPC) ++ return err; ++ ++ /* ++ * GC could not make a free LEB. But someone else may ++ * have allocated new bud for this journal head, ++ * because we dropped the 'io_mutex', so try once ++ * again. ++ */ ++ dbg_jnl("GC couldn't make a free LEB for jhead %d", jhead); ++ if (retries++ < 2) { ++ dbg_jnl("retry (%d)", retries); ++ goto again; ++ } ++ ++ dbg_jnl("return -ENOSPC"); ++ return err; ++ } ++ ++ mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); ++ dbg_jnl("got LEB %d for jhead %d", lnum, jhead); ++ avail = c->leb_size - wbuf->offs - wbuf->used; ++ ++ if (wbuf->lnum != -1 && avail >= len) { ++ /* ++ * Someone else has switched the journal head and we have ++ * enough space now. This happens when more then one process is ++ * trying to write to the same journal head at the same time. ++ */ ++ dbg_jnl("return LEB %d back, already have LEB %d:%d", ++ lnum, wbuf->lnum, wbuf->offs + wbuf->used); ++ err = ubifs_return_leb(c, lnum); ++ if (err) ++ goto out_unlock; ++ return 0; ++ } ++ ++ err = ubifs_add_bud_to_log(c, jhead, lnum, 0); ++ if (err) ++ goto out_return; ++ offs = 0; ++ ++out: ++ err = ubifs_wbuf_seek_nolock(wbuf, lnum, offs, UBI_SHORTTERM); ++ if (err) ++ goto out_unlock; ++ ++ return 0; ++ ++out_unlock: ++ mutex_unlock(&wbuf->io_mutex); ++ return err; ++ ++out_return: ++ /* An error occurred and the LEB has to be returned to lprops */ ++ ubifs_assert(err < 0); ++ err1 = ubifs_return_leb(c, lnum); ++ if (err1 && err == -EAGAIN) ++ /* ++ * Return original error code 'err' only if it is not ++ * '-EAGAIN', which is not really an error. Otherwise, return ++ * the error code of 'ubifs_return_leb()'. ++ */ ++ err = err1; ++ mutex_unlock(&wbuf->io_mutex); ++ return err; ++} ++ ++/** ++ * write_node - write node to a journal head. ++ * @c: UBIFS file-system description object ++ * @jhead: journal head ++ * @node: node to write ++ * @len: node length ++ * @lnum: LEB number written is returned here ++ * @offs: offset written is returned here ++ * ++ * This function writes a node to reserved space of journal head @jhead. ++ * Returns zero in case of success and a negative error code in case of ++ * failure. ++ */ ++static int write_node(struct ubifs_info *c, int jhead, void *node, int len, ++ int *lnum, int *offs) ++{ ++ struct ubifs_wbuf *wbuf = &c->jheads[jhead].wbuf; ++ ++ ubifs_assert(jhead != GCHD); ++ ++ *lnum = c->jheads[jhead].wbuf.lnum; ++ *offs = c->jheads[jhead].wbuf.offs + c->jheads[jhead].wbuf.used; ++ ++ dbg_jnl("jhead %d, LEB %d:%d, len %d", jhead, *lnum, *offs, len); ++ ubifs_prepare_node(c, node, len, 0); ++ ++ return ubifs_wbuf_write_nolock(wbuf, node, len); ++} ++ ++/** ++ * write_head - write data to a journal head. ++ * @c: UBIFS file-system description object ++ * @jhead: journal head ++ * @buf: buffer to write ++ * @len: length to write ++ * @lnum: LEB number written is returned here ++ * @offs: offset written is returned here ++ * @sync: non-zero if the write-buffer has to by synchronized ++ * ++ * This function is the same as 'write_node()' but it does not assume the ++ * buffer it is writing is a node, so it does not prepare it (which means ++ * initializing common header and calculating CRC). ++ */ ++static int write_head(struct ubifs_info *c, int jhead, void *buf, int len, ++ int *lnum, int *offs, int sync) ++{ ++ int err; ++ struct ubifs_wbuf *wbuf = &c->jheads[jhead].wbuf; ++ ++ ubifs_assert(jhead != GCHD); ++ ++ *lnum = c->jheads[jhead].wbuf.lnum; ++ *offs = c->jheads[jhead].wbuf.offs + c->jheads[jhead].wbuf.used; ++ dbg_jnl("jhead %d, LEB %d:%d, len %d", jhead, *lnum, *offs, len); ++ ++ err = ubifs_wbuf_write_nolock(wbuf, buf, len); ++ if (err) ++ return err; ++ if (sync) ++ err = ubifs_wbuf_sync_nolock(wbuf); ++ return err; ++} ++ ++/** ++ * make_reservation - reserve journal space. ++ * @c: UBIFS file-system description object ++ * @jhead: journal head ++ * @len: how many bytes to reserve ++ * ++ * This function makes space reservation in journal head @jhead. The function ++ * takes the commit lock and locks the journal head, and the caller has to ++ * unlock the head and finish the reservation with 'finish_reservation()'. ++ * Returns zero in case of success and a negative error code in case of ++ * failure. ++ * ++ * Note, the journal head may be unlocked as soon as the data is written, while ++ * the commit lock has to be released after the data has been added to the ++ * TNC. ++ */ ++static int make_reservation(struct ubifs_info *c, int jhead, int len) ++{ ++ int err, cmt_retries = 0, nospc_retries = 0; ++ ++ ubifs_assert(len <= c->dark_wm); ++ ++again: ++ down_read(&c->commit_sem); ++ err = reserve_space(c, jhead, len); ++ if (!err) ++ return 0; ++ up_read(&c->commit_sem); ++ ++ if (err == -ENOSPC) { ++ /* ++ * GC could not make any progress. We should try to commit ++ * once because it could make some dirty space and GC would ++ * make progress, so make the error -EAGAIN so that the below ++ * will commit and re-try. ++ */ ++ if (nospc_retries++ < 2) { ++ dbg_jnl("no space, retry"); ++ err = -EAGAIN; ++ } ++ ++ /* ++ * This means that the budgeting is incorrect. We always have ++ * to be able to write to the media, because all operations are ++ * budgeted. Deletions are not budgeted, though, but we reserve ++ * an extra LEB for them. ++ */ ++ } ++ ++ if (err != -EAGAIN) ++ goto out; ++ ++ /* ++ * -EAGAIN means that the journal is full or too large, or the above ++ * code wants to do one commit. Do this and re-try. ++ */ ++ if (cmt_retries > 128) { ++ /* ++ * This should not happen unless the journal size limitations ++ * are too tough. ++ */ ++ ubifs_err("stuck in space allocation"); ++ err = -ENOSPC; ++ goto out; ++ } else if (cmt_retries > 32) ++ ubifs_warn("too many space allocation re-tries (%d)", ++ cmt_retries); ++ ++ dbg_jnl("-EAGAIN, commit and retry (retried %d times)", ++ cmt_retries); ++ cmt_retries += 1; ++ ++ err = ubifs_run_commit(c); ++ if (err) ++ return err; ++ goto again; ++ ++out: ++ ubifs_err("cannot reserve %d bytes in jhead %d, error %d", ++ len, jhead, err); ++ if (err == -ENOSPC) { ++ /* This are some budgeting problems, print useful information */ ++ down_write(&c->commit_sem); ++ spin_lock(&c->space_lock); ++ dbg_dump_stack(); ++ dbg_dump_budg(c); ++ spin_unlock(&c->space_lock); ++ dbg_dump_lprops(c); ++ cmt_retries = dbg_check_lprops(c); ++ up_write(&c->commit_sem); ++ } ++ ++ return err; ++} ++ ++/** ++ * release_head - release a journal head. ++ * @c: UBIFS file-system description object ++ * @jhead: journal head ++ * ++ * This function releases journal head @jhead which was locked by ++ * the 'make_reservation()' function. It has to be called after each successful ++ * 'make_reservation()' invocation. ++ */ ++static inline void release_head(struct ubifs_info *c, int jhead) ++{ ++ mutex_unlock(&c->jheads[jhead].wbuf.io_mutex); ++} ++ ++/** ++ * finish_reservation - finish a reservation. ++ * @c: UBIFS file-system description object ++ * ++ * This function finishes journal space reservation. It must be called after ++ * 'make_reservation()'. ++ */ ++static void finish_reservation(struct ubifs_info *c) ++{ ++ up_read(&c->commit_sem); ++} ++ ++/** ++ * get_dent_type - translate VFS inode mode to UBIFS directory entry type. ++ * @mode: inode mode ++ */ ++static int get_dent_type(int mode) ++{ ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ return UBIFS_ITYPE_REG; ++ case S_IFDIR: ++ return UBIFS_ITYPE_DIR; ++ case S_IFLNK: ++ return UBIFS_ITYPE_LNK; ++ case S_IFBLK: ++ return UBIFS_ITYPE_BLK; ++ case S_IFCHR: ++ return UBIFS_ITYPE_CHR; ++ case S_IFIFO: ++ return UBIFS_ITYPE_FIFO; ++ case S_IFSOCK: ++ return UBIFS_ITYPE_SOCK; ++ default: ++ BUG(); ++ } ++ return 0; ++} ++ ++/** ++ * pack_inode - pack an inode node. ++ * @c: UBIFS file-system description object ++ * @ino: buffer in which to pack inode node ++ * @inode: inode to pack ++ * @last: indicates the last node of the group ++ * @last_reference: non-zero if this is a deletion inode ++ */ ++static void pack_inode(struct ubifs_info *c, struct ubifs_ino_node *ino, ++ const struct inode *inode, int last, int last_reference) ++{ ++ int data_len = 0; ++ struct ubifs_inode *ui = ubifs_inode(inode); ++ ++ ino->ch.node_type = UBIFS_INO_NODE; ++ ino_key_init_flash(c, &ino->key, inode->i_ino); ++ ino->creat_sqnum = cpu_to_le64(ui->creat_sqnum); ++ ino->size = cpu_to_le64(i_size_read(inode)); ++ ino->nlink = cpu_to_le32(inode->i_nlink); ++ ino->atime_sec = cpu_to_le64(inode->i_atime.tv_sec); ++ ino->atime_nsec = cpu_to_le32(inode->i_atime.tv_nsec); ++ ino->ctime_sec = cpu_to_le64(inode->i_ctime.tv_sec); ++ ino->ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec); ++ ino->mtime_sec = cpu_to_le64(inode->i_mtime.tv_sec); ++ ino->mtime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec); ++ ino->uid = cpu_to_le32(inode->i_uid); ++ ino->gid = cpu_to_le32(inode->i_gid); ++ ino->mode = cpu_to_le32(inode->i_mode); ++ ino->flags = cpu_to_le32(ui->flags); ++ ino->compr_type = cpu_to_le16(ui->compr_type); ++ ino->xattr_cnt = cpu_to_le32(ui->xattr_cnt); ++ ino->xattr_size = cpu_to_le64(ui->xattr_size); ++ ino->xattr_names = cpu_to_le32(ui->xattr_names); ++ ino->data_len = cpu_to_le32(ui->data_len); ++ zero_ino_node_unused(ino); ++ ++ /* ++ * Drop the attached data if this is a deletion inode, the data is not ++ * needed anymore. ++ */ ++ if (!last_reference) { ++ memcpy(ino->data, ui->data, ui->data_len); ++ data_len = ui->data_len; ++ } ++ ++ ubifs_prep_grp_node(c, ino, UBIFS_INO_NODE_SZ + data_len, last); ++} ++ ++/** ++ * ubifs_jnl_update - update inode. ++ * @c: UBIFS file-system description object ++ * @dir: parent inode or host inode in case of extended attributes ++ * @nm: directory entry name ++ * @inode: inode ++ * @deletion: indicates a directory entry deletion i.e unlink or rmdir ++ * @sync: non-zero if the write-buffer has to be synchronized ++ * @xent: non-zero if the directory entry is an extended attribute entry ++ * ++ * This function updates an inode by writing a directory entry (or extended ++ * attribute entry), the inode itself, and the parent directory inode (or the ++ * host inode) to the journal. ++ * ++ * The function writes the host inode @dir last, which is important in case of ++ * extended attributes. Indeed, then we guarantee that if the host inode gets ++ * synchronized, and the write-buffer it sits in gets flushed, the extended ++ * attribute inode gets flushed too. And this is exactly what the user expects - ++ * synchronizing the host inode synchronizes its extended attributes. ++ * Similarly, this guarantees that if @dir is synchronized, its directory entry ++ * corresponding to @nm gets synchronized too. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, ++ const struct qstr *nm, const struct inode *inode, ++ int deletion, int sync, int xent) ++{ ++ int err, dlen, ilen, len, lnum, ino_offs, dent_offs; ++ int aligned_dlen, aligned_ilen; ++ int last_reference = !!(deletion && inode->i_nlink == 0); ++ struct ubifs_dent_node *dent; ++ struct ubifs_ino_node *ino; ++ union ubifs_key dent_key, ino_key; ++ ++ dbg_jnl("ino %lu, dent '%.*s', data len %d in dir ino %lu", ++ inode->i_ino, nm->len, nm->name, ubifs_inode(inode)->data_len, ++ dir->i_ino); ++ ubifs_assert(ubifs_inode(dir)->data_len == 0); ++ ++ dlen = UBIFS_DENT_NODE_SZ + nm->len + 1; ++ ilen = UBIFS_INO_NODE_SZ; ++ ++ /* ++ * If the last reference to the inode is being deleted, then there is no ++ * need to attach and write inode data, it is being deleted anyway. ++ */ ++ if (!last_reference) ++ ilen += ubifs_inode(inode)->data_len; ++ ++ aligned_dlen = ALIGN(dlen, 8); ++ aligned_ilen = ALIGN(ilen, 8); ++ ++ len = aligned_dlen + aligned_ilen + UBIFS_INO_NODE_SZ; ++ ++ dent = kmalloc(len, GFP_NOFS); ++ if (!dent) ++ return -ENOMEM; ++ ++ /* Make reservation before allocating sequence numbers */ ++ err = make_reservation(c, BASEHD, len); ++ if (err) ++ goto out_free; ++ ++ if (!xent) { ++ dent->ch.node_type = UBIFS_DENT_NODE; ++ dent_key_init(c, &dent_key, dir->i_ino, nm); ++ } else { ++ dent->ch.node_type = UBIFS_XENT_NODE; ++ xent_key_init(c, &dent_key, dir->i_ino, nm); ++ } ++ ++ key_write(c, &dent_key, dent->key); ++ dent->inum = deletion ? 0 : cpu_to_le64(inode->i_ino); ++ dent->type = get_dent_type(inode->i_mode); ++ dent->nlen = cpu_to_le16(nm->len); ++ memcpy(dent->name, nm->name, nm->len); ++ dent->name[nm->len] = '\0'; ++ zero_dent_node_unused(dent); ++ ubifs_prep_grp_node(c, dent, dlen, 0); ++ ++ ino = (void *)dent + aligned_dlen; ++ pack_inode(c, ino, inode, 0, last_reference); ++ ++ ino = (void *)ino + aligned_ilen; ++ pack_inode(c, ino, dir, 1, 0); ++ ++ if (last_reference) { ++ err = ubifs_add_orphan(c, inode->i_ino); ++ if (err) { ++ release_head(c, BASEHD); ++ goto out_finish; ++ } ++ } ++ ++ err = write_head(c, BASEHD, dent, len, &lnum, &dent_offs, sync); ++ if (!sync && !err) { ++ struct ubifs_wbuf *wbuf = &c->jheads[BASEHD].wbuf; ++ ++ ubifs_wbuf_add_ino_nolock(wbuf, inode->i_ino); ++ ubifs_wbuf_add_ino_nolock(wbuf, dir->i_ino); ++ } ++ release_head(c, BASEHD); ++ kfree(dent); ++ if (err) ++ goto out_ro; ++ ++ if (deletion) { ++ err = ubifs_tnc_remove_nm(c, &dent_key, nm); ++ if (err) ++ goto out_ro; ++ err = ubifs_add_dirt(c, lnum, dlen); ++ } else ++ err = ubifs_tnc_add_nm(c, &dent_key, lnum, dent_offs, dlen, nm); ++ if (err) ++ goto out_ro; ++ ++ /* ++ * Note, we do not remove the inode from TNC even if the last reference ++ * to it has just been deleted, because the inode may still be opened. ++ * Instead, the inode has been added to orphan lists and the orphan ++ * subsystem will take further care about it. ++ */ ++ ino_key_init(c, &ino_key, inode->i_ino); ++ ino_offs = dent_offs + aligned_dlen; ++ err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, ilen); ++ if (err) ++ goto out_ro; ++ ++ ino_key_init(c, &ino_key, dir->i_ino); ++ ino_offs += aligned_ilen; ++ err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, UBIFS_INO_NODE_SZ); ++ if (err) ++ goto out_ro; ++ ++ finish_reservation(c); ++ return 0; ++ ++out_finish: ++ finish_reservation(c); ++out_free: ++ kfree(dent); ++ return err; ++ ++out_ro: ++ ubifs_ro_mode(c, err); ++ if (last_reference) ++ ubifs_delete_orphan(c, inode->i_ino); ++ finish_reservation(c); ++ return err; ++} ++ ++/** ++ * ubifs_jnl_write_data - write a data node to the journal. ++ * @c: UBIFS file-system description object ++ * @inode: inode the data node belongs to ++ * @key: node key ++ * @buf: buffer to write ++ * @len: data length (must not exceed %UBIFS_BLOCK_SIZE) ++ * ++ * This function writes a data node to the journal. Returns %0 if the data node ++ * was successfully written, and a negative error code in case of failure. ++ */ ++int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, ++ const union ubifs_key *key, const void *buf, int len) ++{ ++ int err, lnum, offs, compr_type, out_len; ++ int dlen = UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR; ++ const struct ubifs_inode *ui = ubifs_inode(inode); ++ struct ubifs_data_node *data; ++ ++ dbg_jnl("ino %lu, blk %u, len %d, key %s", key_inum(c, key), ++ key_block(c, key), len, DBGKEY(key)); ++ ubifs_assert(len <= UBIFS_BLOCK_SIZE); ++ ++ data = kmalloc(dlen, GFP_NOFS); ++ if (!data) ++ return -ENOMEM; ++ ++ data->ch.node_type = UBIFS_DATA_NODE; ++ key_write(c, key, &data->key); ++ data->size = cpu_to_le32(len); ++ zero_data_node_unused(data); ++ ++ if (!(ui->flags && UBIFS_COMPR_FL)) ++ /* Compression is disabled for this inode */ ++ compr_type = UBIFS_COMPR_NONE; ++ else ++ compr_type = ui->compr_type; ++ ++ out_len = dlen - UBIFS_DATA_NODE_SZ; ++ ubifs_compress(buf, len, &data->data, &out_len, &compr_type); ++ ubifs_assert(out_len <= UBIFS_BLOCK_SIZE); ++ ++ dlen = UBIFS_DATA_NODE_SZ + out_len; ++ data->compr_type = cpu_to_le16(compr_type); ++ ++ /* Make reservation before allocating sequence numbers */ ++ err = make_reservation(c, DATAHD, dlen); ++ if (err) ++ goto out_free; ++ ++ err = write_node(c, DATAHD, data, dlen, &lnum, &offs); ++ if (!err) ++ ubifs_wbuf_add_ino_nolock(&c->jheads[DATAHD].wbuf, ++ key_inum(c, key)); ++ release_head(c, DATAHD); ++ if (err) ++ goto out_ro; ++ ++ err = ubifs_tnc_add(c, key, lnum, offs, dlen); ++ if (err) ++ goto out_ro; ++ ++ finish_reservation(c); ++ kfree(data); ++ return 0; ++ ++out_ro: ++ ubifs_ro_mode(c, err); ++ finish_reservation(c); ++out_free: ++ kfree(data); ++ return err; ++} ++ ++/** ++ * ubifs_jnl_write_inode - flush inode to the journal. ++ * @c: UBIFS file-system description object ++ * @inode: inode to flush ++ * @last_reference: inode has been deleted ++ * @sync: non-zero if the write-buffer has to be synchronized ++ * ++ * This function writes inode @inode to the journal (to the base head). Returns ++ * zero in case of success and a negative error code in case of failure. ++ */ ++int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode, ++ int last_reference, int sync) ++{ ++ int err, len, lnum, offs; ++ struct ubifs_ino_node *ino; ++ struct ubifs_inode *ui = ubifs_inode(inode); ++ ++ dbg_jnl("ino %lu%s", inode->i_ino, ++ last_reference ? " (last reference)" : ""); ++ if (last_reference) ++ ubifs_assert(inode->i_nlink == 0); ++ ++ /* If the inode is deleted, do not write the attached data */ ++ len = UBIFS_INO_NODE_SZ; ++ if (!last_reference) ++ len += ui->data_len; ++ ino = kmalloc(len, GFP_NOFS); ++ if (!ino) ++ return -ENOMEM; ++ ++ /* Make reservation before allocating sequence numbers */ ++ err = make_reservation(c, BASEHD, len); ++ if (err) ++ goto out_free; ++ ++ pack_inode(c, ino, inode, 1, last_reference); ++ ++ err = write_head(c, BASEHD, ino, len, &lnum, &offs, sync); ++ if (!sync && !err) ++ ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, ++ inode->i_ino); ++ release_head(c, BASEHD); ++ if (err) ++ goto out_ro; ++ ++ if (last_reference) { ++ err = ubifs_tnc_remove_ino(c, inode->i_ino); ++ if (err) ++ goto out_ro; ++ ubifs_delete_orphan(c, inode->i_ino); ++ err = ubifs_add_dirt(c, lnum, len); ++ } else { ++ union ubifs_key key; ++ ++ ino_key_init(c, &key, inode->i_ino); ++ err = ubifs_tnc_add(c, &key, lnum, offs, len); ++ } ++ if (err) ++ goto out_ro; ++ ++ finish_reservation(c); ++ kfree(ino); ++ return 0; ++ ++out_ro: ++ ubifs_ro_mode(c, err); ++ finish_reservation(c); ++out_free: ++ kfree(ino); ++ return err; ++} ++ ++/** ++ * ubifs_jnl_rename - rename a directory entry. ++ * @c: UBIFS file-system description object ++ * @old_dir: parent inode of directory entry to rename ++ * @old_dentry: directory entry to rename ++ * @new_dir: parent inode of directory entry to rename ++ * @new_dentry: new directory entry (or directory entry to replace) ++ * @sync: non-zero if the write-buffer has to be synchronized ++ * ++ * Returns zero in case of success and a negative error code in case of failure. ++ */ ++int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, ++ const struct dentry *old_dentry, ++ const struct inode *new_dir, ++ const struct dentry *new_dentry, int sync) ++{ ++ const struct inode *old_inode = old_dentry->d_inode; ++ const struct inode *new_inode = new_dentry->d_inode; ++ int err, dlen1, dlen2, ilen, lnum, offs, len; ++ int aligned_dlen1, aligned_dlen2, plen = UBIFS_INO_NODE_SZ; ++ int last_reference = !!(new_inode && new_inode->i_nlink == 0); ++ struct ubifs_dent_node *dent, *dent2; ++ void *p; ++ union ubifs_key key; ++ ++ dbg_jnl("dent '%.*s' in dir ino %lu to dent '%.*s' in dir ino %lu", ++ old_dentry->d_name.len, old_dentry->d_name.name, ++ old_dir->i_ino, new_dentry->d_name.len, ++ new_dentry->d_name.name, new_dir->i_ino); ++ ++ ubifs_assert(ubifs_inode(old_dir)->data_len == 0); ++ ubifs_assert(ubifs_inode(new_dir)->data_len == 0); ++ ++ dlen1 = UBIFS_DENT_NODE_SZ + new_dentry->d_name.len + 1; ++ dlen2 = UBIFS_DENT_NODE_SZ + old_dentry->d_name.len + 1; ++ if (new_inode) { ++ ilen = UBIFS_INO_NODE_SZ; ++ if (!last_reference) ++ ilen += ubifs_inode(new_inode)->data_len; ++ } else ++ ilen = 0; ++ ++ aligned_dlen1 = ALIGN(dlen1, 8); ++ aligned_dlen2 = ALIGN(dlen2, 8); ++ ++ len = aligned_dlen1 + aligned_dlen2 + ALIGN(ilen, 8) + ALIGN(plen, 8); ++ if (old_dir != new_dir) ++ len += plen; ++ ++ dent = kmalloc(len, GFP_NOFS); ++ if (!dent) ++ return -ENOMEM; ++ ++ /* Make reservation before allocating sequence numbers */ ++ err = make_reservation(c, BASEHD, len); ++ if (err) ++ goto out_free; ++ ++ /* Make new dent */ ++ dent->ch.node_type = UBIFS_DENT_NODE; ++ dent_key_init_flash(c, &dent->key, new_dir->i_ino, &new_dentry->d_name); ++ dent->inum = cpu_to_le64(old_inode->i_ino); ++ dent->type = get_dent_type(old_inode->i_mode); ++ dent->nlen = cpu_to_le16(new_dentry->d_name.len); ++ memcpy(dent->name, new_dentry->d_name.name, new_dentry->d_name.len); ++ dent->name[new_dentry->d_name.len] = '\0'; ++ zero_dent_node_unused(dent); ++ ubifs_prep_grp_node(c, dent, dlen1, 0); ++ ++ dent2 = (void *)dent + aligned_dlen1; ++ ++ /* Make deletion dent */ ++ dent2->ch.node_type = UBIFS_DENT_NODE; ++ dent_key_init_flash(c, &dent2->key, old_dir->i_ino, ++ &old_dentry->d_name); ++ dent2->inum = 0; ++ dent2->type = DT_UNKNOWN; ++ dent2->nlen = cpu_to_le16(old_dentry->d_name.len); ++ memcpy(dent2->name, old_dentry->d_name.name, old_dentry->d_name.len); ++ dent2->name[old_dentry->d_name.len] = '\0'; ++ zero_dent_node_unused(dent2); ++ ubifs_prep_grp_node(c, dent2, dlen2, 0); ++ ++ p = (void *)dent2 + aligned_dlen2; ++ if (new_inode) { ++ pack_inode(c, p, new_inode, 0, last_reference); ++ p += ALIGN(ilen, 8); ++ } ++ ++ if (old_dir == new_dir) ++ pack_inode(c, p, old_dir, 1, 0); ++ else { ++ pack_inode(c, p, old_dir, 0, 0); ++ p += ALIGN(plen, 8); ++ pack_inode(c, p, new_dir, 1, 0); ++ } ++ ++ if (last_reference) { ++ err = ubifs_add_orphan(c, new_inode->i_ino); ++ if (err) { ++ release_head(c, BASEHD); ++ goto out_finish; ++ } ++ } ++ ++ err = write_head(c, BASEHD, dent, len, &lnum, &offs, sync); ++ if (!sync && !err) { ++ struct ubifs_wbuf *wbuf = &c->jheads[BASEHD].wbuf; ++ ++ ubifs_wbuf_add_ino_nolock(wbuf, new_dir->i_ino); ++ ubifs_wbuf_add_ino_nolock(wbuf, old_dir->i_ino); ++ if (new_inode) ++ ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, ++ new_inode->i_ino); ++ } ++ release_head(c, BASEHD); ++ if (err) ++ goto out_ro; ++ ++ dent_key_init(c, &key, new_dir->i_ino, &new_dentry->d_name); ++ err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, &new_dentry->d_name); ++ if (err) ++ goto out_ro; ++ ++ err = ubifs_add_dirt(c, lnum, dlen2); ++ if (err) ++ goto out_ro; ++ ++ dent_key_init(c, &key, old_dir->i_ino, &old_dentry->d_name); ++ err = ubifs_tnc_remove_nm(c, &key, &old_dentry->d_name); ++ if (err) ++ goto out_ro; ++ ++ offs += aligned_dlen1 + aligned_dlen2; ++ if (new_inode) { ++ ino_key_init(c, &key, new_inode->i_ino); ++ err = ubifs_tnc_add(c, &key, lnum, offs, ilen); ++ if (err) ++ goto out_ro; ++ offs += ALIGN(ilen, 8); ++ } ++ ++ ino_key_init(c, &key, old_dir->i_ino); ++ err = ubifs_tnc_add(c, &key, lnum, offs, plen); ++ if (err) ++ goto out_ro; ++ ++ if (old_dir != new_dir) { ++ offs += ALIGN(plen, 8); ++ ino_key_init(c, &key, new_dir->i_ino); ++ err = ubifs_tnc_add(c, &key, lnum, offs, plen); ++ if (err) ++ goto out_ro; ++ } ++ ++ finish_reservation(c); ++ kfree(dent); ++ return 0; ++ ++out_ro: ++ ubifs_ro_mode(c, err); ++ if (last_reference) ++ ubifs_delete_orphan(c, new_inode->i_ino); ++out_finish: ++ finish_reservation(c); ++out_free: ++ kfree(dent); ++ return err; ++} ++ ++/** ++ * recomp_data_node - re-compress a truncated data node. ++ * @dn: data node to re-compress ++ * @new_len: new length ++ * ++ * This function is used when an inode is truncated and the last data node of ++ * the inode has to be re-compressed and re-written. ++ */ ++static int recomp_data_node(struct ubifs_data_node *dn, int *new_len) ++{ ++ void *buf; ++ int err, len, compr_type, out_len; ++ ++ out_len = le32_to_cpu(dn->size); ++ buf = kmalloc(out_len * WORST_COMPR_FACTOR, GFP_NOFS); ++ if (!buf) ++ return -ENOMEM; ++ ++ len = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ; ++ compr_type = le16_to_cpu(dn->compr_type); ++ err = ubifs_decompress(&dn->data, len, buf, &out_len, compr_type); ++ if (err) ++ goto out; ++ ++ ubifs_compress(buf, *new_len, &dn->data, &out_len, &compr_type); ++ ubifs_assert(out_len <= UBIFS_BLOCK_SIZE); ++ dn->compr_type = cpu_to_le16(compr_type); ++ dn->size = cpu_to_le32(*new_len); ++ *new_len = UBIFS_DATA_NODE_SZ + out_len; ++out: ++ kfree(buf); ++ return err; ++} ++ ++/** ++ * ubifs_jnl_truncate - update the journal for a truncation. ++ * @c: UBIFS file-system description object ++ * @inum: inode number of inode being truncated ++ * @old_size: old size ++ * @new_size: new size ++ * ++ * When the size of a file decreases due to truncation, a truncation node is ++ * written, the journal tree is updated, and the last data block is re-written ++ * if it has been affected. ++ * ++ * This function returns %0 in the case of success, and a negative error code in ++ * case of failure. ++ */ ++int ubifs_jnl_truncate(struct ubifs_info *c, ino_t inum, ++ loff_t old_size, loff_t new_size) ++{ ++ union ubifs_key key, to_key; ++ struct ubifs_trun_node *trun; ++ struct ubifs_data_node *uninitialized_var(dn); ++ int err, dlen, len, lnum, offs, bit, sz; ++ unsigned int blk; ++ ++ dbg_jnl("ino %lu, size %lld -> %lld", inum, old_size, new_size); ++ ++ sz = UBIFS_TRUN_NODE_SZ + UBIFS_MAX_DATA_NODE_SZ * WORST_COMPR_FACTOR; ++ trun = kmalloc(sz, GFP_NOFS); ++ if (!trun) ++ return -ENOMEM; ++ ++ trun->ch.node_type = UBIFS_TRUN_NODE; ++ trun->inum = cpu_to_le32(inum); ++ trun->old_size = cpu_to_le64(old_size); ++ trun->new_size = cpu_to_le64(new_size); ++ zero_trun_node_unused(trun); ++ ++ dlen = new_size & (UBIFS_BLOCK_SIZE - 1); ++ ++ if (dlen) { ++ /* Get last data block so it can be truncated */ ++ dn = (void *)trun + ALIGN(UBIFS_TRUN_NODE_SZ, 8); ++ blk = new_size / UBIFS_BLOCK_SIZE; ++ data_key_init(c, &key, inum, blk); ++ dbg_jnl("last block key %s", DBGKEY(&key)); ++ err = ubifs_tnc_lookup(c, &key, dn); ++ if (err == -ENOENT) ++ dlen = 0; /* Not found (so it is a hole) */ ++ else if (err) ++ goto out_free; ++ else { ++ if (le32_to_cpu(dn->size) <= dlen) ++ dlen = 0; /* Nothing to do */ ++ else { ++ int compr_type = le16_to_cpu(dn->compr_type); ++ ++ if (compr_type != UBIFS_COMPR_NONE) { ++ err = recomp_data_node(dn, &dlen); ++ if (err) ++ goto out_free; ++ } else { ++ dn->size = cpu_to_le32(dlen); ++ dlen += UBIFS_DATA_NODE_SZ; ++ } ++ zero_data_node_unused(dn); ++ } ++ } ++ } ++ ++ if (dlen) ++ len = ALIGN(UBIFS_TRUN_NODE_SZ, 8) + dlen; ++ else ++ len = UBIFS_TRUN_NODE_SZ; ++ ++ /* Must make reservation before allocating sequence numbers */ ++ err = make_reservation(c, BASEHD, len); ++ if (err) ++ goto out_free; ++ ++ ubifs_prepare_node(c, trun, UBIFS_TRUN_NODE_SZ, 0); ++ if (dlen) ++ ubifs_prepare_node(c, dn, dlen, 0); ++ ++ err = write_head(c, BASEHD, trun, len, &lnum, &offs, 0); ++ if (!err) ++ ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, inum); ++ release_head(c, BASEHD); ++ if (err) ++ goto out_ro; ++ ++ if (dlen) { ++ offs += ALIGN(UBIFS_TRUN_NODE_SZ, 8); ++ err = ubifs_tnc_add(c, &key, lnum, offs, dlen); ++ if (err) ++ goto out_ro; ++ } ++ ++ err = ubifs_add_dirt(c, lnum, UBIFS_TRUN_NODE_SZ); ++ if (err) ++ goto out_ro; ++ ++ bit = new_size & (UBIFS_BLOCK_SIZE - 1); ++ ++ blk = new_size / UBIFS_BLOCK_SIZE + (bit ? 1 : 0); ++ data_key_init(c, &key, inum, blk); ++ ++ bit = old_size & (UBIFS_BLOCK_SIZE - 1); ++ ++ blk = old_size / UBIFS_BLOCK_SIZE - (bit ? 0: 1); ++ data_key_init(c, &to_key, inum, blk); ++ ++ err = ubifs_tnc_remove_range(c, &key, &to_key); ++ if (err) ++ goto out_ro; ++ ++ finish_reservation(c); ++ kfree(trun); ++ return 0; ++ ++out_ro: ++ ubifs_ro_mode(c, err); ++ finish_reservation(c); ++out_free: ++ kfree(trun); ++ return err; ++} ++ ++#ifdef CONFIG_UBIFS_FS_XATTR ++ ++int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host, ++ const struct inode *inode, const struct qstr *nm, ++ int sync) ++{ ++ int err, xlen, hlen, len, lnum, xent_offs, aligned_xlen; ++ struct ubifs_dent_node *xent; ++ struct ubifs_ino_node *ino; ++ union ubifs_key xent_key, key1, key2; ++ ++ dbg_jnl("host %lu, xattr ino %lu, name '%s', data len %d", ++ host->i_ino, inode->i_ino, nm->name, ++ ubifs_inode(inode)->data_len); ++ ubifs_assert(inode->i_nlink == 0); ++ ++ /* ++ * Since we are deleting the inode, we do not bother to attach any data ++ * to it and assume its length is %UBIFS_INO_NODE_SZ. ++ */ ++ xlen = UBIFS_DENT_NODE_SZ + nm->len + 1; ++ aligned_xlen = ALIGN(xlen, 8); ++ hlen = ubifs_inode(host)->data_len + UBIFS_INO_NODE_SZ; ++ len = aligned_xlen + UBIFS_INO_NODE_SZ + ALIGN(hlen, 8); ++ ++ xent = kmalloc(len, GFP_NOFS); ++ if (!xent) ++ return -ENOMEM; ++ ++ /* Make reservation before allocating sequence numbers */ ++ err = make_reservation(c, BASEHD, len); ++ if (err) { ++ kfree(xent); ++ return err; ++ } ++ ++ xent->ch.node_type = UBIFS_XENT_NODE; ++ xent_key_init(c, &xent_key, host->i_ino, nm); ++ key_write(c, &xent_key, xent->key); ++ xent->inum = 0; ++ xent->type = get_dent_type(inode->i_mode); ++ xent->nlen = cpu_to_le16(nm->len); ++ memcpy(xent->name, nm->name, nm->len); ++ xent->name[nm->len] = '\0'; ++ zero_dent_node_unused(xent); ++ ubifs_prep_grp_node(c, xent, xlen, 0); ++ ++ ino = (void *)xent + aligned_xlen; ++ pack_inode(c, ino, inode, 0, 1); ++ ++ ino = (void *)ino + UBIFS_INO_NODE_SZ; ++ pack_inode(c, ino, host, 1, 0); ++ ++ err = write_head(c, BASEHD, xent, len, &lnum, &xent_offs, sync); ++ if (!sync && !err) ++ ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, host->i_ino); ++ release_head(c, BASEHD); ++ kfree(xent); ++ if (err) ++ goto out_ro; ++ ++ /* Remove the extended attribute entry from TNC */ ++ err = ubifs_tnc_remove_nm(c, &xent_key, nm); ++ if (err) ++ goto out_ro; ++ err = ubifs_add_dirt(c, lnum, xlen); ++ if (err) ++ goto out_ro; ++ ++ /* ++ * Remove all nodes belonging to the extended attribute inode from TNC. ++ * Well, there actually must be only one node - the inode itself. ++ */ ++ lowest_ino_key(c, &key1, inode->i_ino); ++ highest_ino_key(c, &key2, inode->i_ino); ++ err = ubifs_tnc_remove_range(c, &key1, &key2); ++ if (err) ++ goto out_ro; ++ err = ubifs_add_dirt(c, lnum, UBIFS_INO_NODE_SZ); ++ if (err) ++ goto out_ro; ++ ++ /* And update TNC with the new host inode position */ ++ ino_key_init(c, &key1, host->i_ino); ++ err = ubifs_tnc_add(c, &key1, lnum, xent_offs + len - hlen, hlen); ++ if (err) ++ goto out_ro; ++ ++ finish_reservation(c); ++ return 0; ++ ++out_ro: ++ ubifs_ro_mode(c, err); ++ finish_reservation(c); ++ return err; ++} ++ ++/** ++ * ubifs_jnl_write_2_inodes - write 2 inodes to the journal. ++ * @c: UBIFS file-system description object ++ * @inode1: first inode to write ++ * @inode2: second inode to write ++ * @sync: non-zero if the write-buffer has to be synchronized ++ * ++ * This function writes 2 inodes @inode1 and @inode2 to the journal (to the ++ * base head - first @inode1, then @inode2). Returns zero in case of success ++ * and a negative error code in case of failure. ++ */ ++int ubifs_jnl_write_2_inodes(struct ubifs_info *c, const struct inode *inode1, ++ const struct inode *inode2, int sync) ++{ ++ int err, len1, len2, aligned_len, aligned_len1, lnum, offs; ++ struct ubifs_ino_node *ino; ++ union ubifs_key key; ++ ++ dbg_jnl("ino %lu, ino %lu", inode1->i_ino, inode2->i_ino); ++ ubifs_assert(inode1->i_nlink > 0); ++ ubifs_assert(inode2->i_nlink > 0); ++ ++ len1 = UBIFS_INO_NODE_SZ + ubifs_inode(inode1)->data_len; ++ len2 = UBIFS_INO_NODE_SZ + ubifs_inode(inode2)->data_len; ++ aligned_len1 = ALIGN(len1, 8); ++ aligned_len = aligned_len1 + ALIGN(len2, 8); ++ ++ ino = kmalloc(aligned_len, GFP_NOFS); ++ if (!ino) ++ return -ENOMEM; ++ ++ /* Make reservation before allocating sequence numbers */ ++ err = make_reservation(c, BASEHD, aligned_len); ++ if (err) ++ goto out_free; ++ ++ pack_inode(c, ino, inode1, 0, 0); ++ pack_inode(c, (void *)ino + aligned_len1, inode2, 1, 0); ++ ++ err = write_head(c, BASEHD, ino, aligned_len, &lnum, &offs, 0); ++ if (!sync && !err) { ++ struct ubifs_wbuf *wbuf = &c->jheads[BASEHD].wbuf; ++ ++ ubifs_wbuf_add_ino_nolock(wbuf, inode1->i_ino); ++ ubifs_wbuf_add_ino_nolock(wbuf, inode2->i_ino); ++ } ++ release_head(c, BASEHD); ++ if (err) ++ goto out_ro; ++ ++ ino_key_init(c, &key, inode1->i_ino); ++ err = ubifs_tnc_add(c, &key, lnum, offs, len1); ++ if (err) ++ goto out_ro; ++ ++ ino_key_init(c, &key, inode2->i_ino); ++ err = ubifs_tnc_add(c, &key, lnum, offs + aligned_len1, len2); ++ if (err) ++ goto out_ro; ++ ++ finish_reservation(c); ++ kfree(ino); ++ return 0; ++ ++out_ro: ++ ubifs_ro_mode(c, err); ++ finish_reservation(c); ++out_free: ++ kfree(ino); ++ return err; ++} ++ ++#endif /* CONFIG_UBIFS_FS_XATTR */ +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/Kconfig avr32-2.6/fs/ubifs/Kconfig +--- linux-2.6.25.6/fs/ubifs/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/Kconfig 2008-06-12 15:09:45.311815896 +0200 +@@ -0,0 +1,72 @@ ++config UBIFS_FS ++ tristate "UBIFS file system support" ++ select CRC16 ++ select CRC32 ++ select CRYPTO if UBIFS_FS_ADVANCED_COMPR ++ select CRYPTO if UBIFS_FS_LZO ++ select CRYPTO if UBIFS_FS_ZLIB ++ select CRYPTO_LZO if UBIFS_FS_LZO ++ select CRYPTO_DEFLATE if UBIFS_FS_ZLIB ++ depends on MTD_UBI + help -+ This provides a backlight control internal to the Atmel LCDC -+ driver. If the LCD "contrast control" on your board is wired -+ so it controls the backlight brightness, select this option to -+ export this as a PWM-based backlight control. -+ -+ If in doubt, it's safe to enable this option; it doesn't kick -+ in unless the board's description says it's wired that way. -+ - config BACKLIGHT_CORGI - tristate "Generic (aka Sharp Corgi) Backlight Driver" - depends on BACKLIGHT_CLASS_DEVICE ---- a/drivers/video/console/Kconfig -+++ b/drivers/video/console/Kconfig -@@ -6,7 +6,7 @@ - - config VGA_CONSOLE - bool "VGA text console" if EMBEDDED || !X86 -- depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BLACKFIN -+ depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BLACKFIN && !AVR32 - default y - help - Saying Y here will allow you to use Linux in text mode through a ---- a/drivers/watchdog/Kconfig -+++ b/drivers/watchdog/Kconfig -@@ -223,7 +223,7 @@ - - config AT32AP700X_WDT - tristate "AT32AP700x watchdog" -- depends on CPU_AT32AP7000 -+ depends on CPU_AT32AP700X - help - Watchdog timer embedded into AT32AP700x devices. This will reboot - your system when the timeout is reached. ---- a/include/asm-avr32/arch-at32ap/at32ap7000.h -+++ /dev/null -@@ -1,35 +0,0 @@ ++ UBIFS is a file system for flash devices which works on top of UBI. ++ ++config UBIFS_FS_XATTR ++ bool "Extended attributes support" ++ depends on UBIFS_FS ++ help ++ This option enables support of extended attributes. ++ ++config UBIFS_FS_ADVANCED_COMPR ++ bool "Advanced compression options" ++ depends on UBIFS_FS ++ help ++ This option allows to explicitly choose which compressions, if any, ++ are enabled in UBIFS. Removing compressors means inbility to read ++ existing file systems. ++ ++ If unsure, say 'N'. ++ ++config UBIFS_FS_LZO ++ bool "LZO compression support" if UBIFS_FS_ADVANCED_COMPR ++ depends on UBIFS_FS ++ default y ++ help ++ LZO compressor is generally faster then zlib but compresses worse. ++ Say 'Y' if unsure. ++ ++config UBIFS_FS_ZLIB ++ bool "ZLIB compression support" if UBIFS_FS_ADVANCED_COMPR ++ depends on UBIFS_FS ++ default y ++ help ++ Zlib copresses better then LZO but it is slower. Say 'Y' if unsure. ++ ++# Debugging-related stuff ++config UBIFS_FS_DEBUG ++ bool "Enable debugging" ++ depends on UBIFS_FS ++ select DEBUG_FS ++ select KALLSYMS_ALL ++ help ++ This option enables UBIFS debugging. ++ ++config UBIFS_FS_DEBUG_MSG_LVL ++ int "Default message level (0 = no extra messages, 3 = lots)" ++ depends on UBIFS_FS_DEBUG ++ default "0" ++ help ++ This controls the amount of debugging messages produced by UBIFS. ++ If reporting bugs, please try to have available a full dump of the ++ messages at level 1 while the misbehaviour was occurring. Level 2 ++ may become necessary if level 1 messages were not enough to find the ++ bug. Generally Level 3 should be avoided. ++ ++config UBIFS_FS_DEBUG_CHKS ++ bool "Enable extra checks" ++ depends on UBIFS_FS_DEBUG ++ help ++ If extra checks are enabled UBIFS will check the consistency of its ++ internal data structures during operation. However, UBIFS performance ++ is dramatically slower when this option is selected especially if the ++ file system is large. +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/key.h avr32-2.6/fs/ubifs/key.h +--- linux-2.6.25.6/fs/ubifs/key.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/key.h 2008-06-12 15:09:45.367815766 +0200 +@@ -0,0 +1,533 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Artem Bityutskiy (Битюцкий Артём) ++ * Adrian Hunter ++ */ ++ ++/* ++ * This header contains various key-related definitions and helper function. ++ * UBIFS allows several key schemes, so we access key fields only via these ++ * helpers. At the moment only one key scheme is supported. ++ * ++ * Simple key scheme ++ * ~~~~~~~~~~~~~~~~~ ++ * ++ * Keys are 64-bits long. First 32-bits are inode number (parent inode number ++ * in case of direntry key). Next 3 bits are node type. The last 29 bits are ++ * 4KiB offset in case of inode node, and direntry hash in case of a direntry ++ * node. We use "r5" hash borrowed from reiserfs. ++ */ ++ ++#ifndef __UBIFS_KEY_H__ ++#define __UBIFS_KEY_H__ ++ ++/** ++ * key_r5_hash - R5 hash function (borrowed from reiserfs). ++ * @s: direntry name ++ * @len: name length ++ */ ++static inline uint32_t key_r5_hash(const char *s, int len) ++{ ++ uint32_t a = 0; ++ const signed char *str = (const signed char *)s; ++ ++ while (*str) { ++ a += *str << 4; ++ a += *str >> 4; ++ a *= 11; ++ str++; ++ } ++ ++ a &= UBIFS_S_KEY_HASH_MASK; ++ ++ /* ++ * We use hash values as offset in directories, so values %0 and %1 are ++ * reserved for "." and "..". %2 is reserved for "end of readdir" ++ * marker. ++ */ ++ if (unlikely(a >= 0 && a <= 2)) ++ a += 3; ++ return a; ++} ++ ++/** ++ * key_test_hash - testing hash function. ++ * @str: direntry name ++ * @len: name length ++ */ ++static inline uint32_t key_test_hash(const char *str, int len) ++{ ++ uint32_t a = 0; ++ ++ len = min_t(uint32_t, len, 4); ++ memcpy(&a, str, len); ++ a &= UBIFS_S_KEY_HASH_MASK; ++ if (unlikely(a >= 0 && a <= 2)) ++ a += 3; ++ return a; ++} ++ ++/** ++ * ino_key_init - initialize inode key. ++ * @c: UBIFS file-system description object ++ * @key: key to initialize ++ * @inum: inode number ++ */ ++static inline void ino_key_init(const struct ubifs_info *c, ++ union ubifs_key *key, ino_t inum) ++{ ++ key->u32[0] = inum; ++ key->u32[1] = UBIFS_INO_KEY << UBIFS_S_KEY_BLOCK_BITS; ++} ++ ++/** ++ * ino_key_init_flash - initialize on-flash inode key. ++ * @c: UBIFS file-system description object ++ * @k: key to initialize ++ * @inum: inode number ++ */ ++static inline void ino_key_init_flash(const struct ubifs_info *c, void *k, ++ ino_t inum) ++{ ++ union ubifs_key *key = k; ++ ++ key->j32[0] = cpu_to_le32(inum); ++ key->j32[1] = cpu_to_le32(UBIFS_INO_KEY << UBIFS_S_KEY_BLOCK_BITS); ++ memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8); ++} ++ ++/** ++ * lowest_ino_key - get the lowest possible inode key. ++ * @c: UBIFS file-system description object ++ * @key: key to initialize ++ * @inum: inode number ++ */ ++static inline void lowest_ino_key(const struct ubifs_info *c, ++ union ubifs_key *key, ino_t inum) ++{ ++ key->u32[0] = inum; ++ key->u32[1] = 0; ++} ++ ++/** ++ * highest_ino_key - get the highest possible inode key. ++ * @c: UBIFS file-system description object ++ * @key: key to initialize ++ * @inum: inode number ++ */ ++static inline void highest_ino_key(const struct ubifs_info *c, ++ union ubifs_key *key, ino_t inum) ++{ ++ key->u32[0] = inum; ++ key->u32[1] = 0xffffffff; ++} ++ ++/** ++ * dent_key_init - initialize directory entry key. ++ * @c: UBIFS file-system description object ++ * @key: key to initialize ++ * @inum: parent inode number ++ * @nm: direntry name and length ++ */ ++static inline void dent_key_init(const struct ubifs_info *c, ++ union ubifs_key *key, ino_t inum, ++ const struct qstr *nm) ++{ ++ uint32_t hash = c->key_hash(nm->name, nm->len); ++ ++ ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK)); ++ key->u32[0] = inum; ++ key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS); ++} ++ ++/** ++ * dent_key_init_hash - initialize directory entry key without re-calculating ++ * hash function. ++ * @c: UBIFS file-system description object ++ * @key: key to initialize ++ * @inum: parent inode number ++ * @hash: direntry name hash ++ */ ++static inline void dent_key_init_hash(const struct ubifs_info *c, ++ union ubifs_key *key, ino_t inum, ++ uint32_t hash) ++{ ++ ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK)); ++ key->u32[0] = inum; ++ key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS); ++} ++ ++/** ++ * dent_key_init_flash - initialize on-flash directory entry key. ++ * @c: UBIFS file-system description object ++ * @k: key to initialize ++ * @inum: parent inode number ++ * @nm: direntry name and length ++ */ ++static inline void dent_key_init_flash(const struct ubifs_info *c, void *k, ++ ino_t inum, const struct qstr *nm) ++{ ++ union ubifs_key *key = k; ++ uint32_t hash = c->key_hash(nm->name, nm->len); ++ ++ ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK)); ++ key->j32[0] = cpu_to_le32(inum); ++ key->j32[1] = cpu_to_le32(hash | ++ (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS)); ++ memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8); ++} ++ ++/** ++ * lowest_dent_key - get the lowest possible directory entry key. ++ * @c: UBIFS file-system description object ++ * @key: where to store the lowest key ++ * @inum: parent inode number ++ */ ++static inline void lowest_dent_key(const struct ubifs_info *c, ++ union ubifs_key *key, ino_t inum) ++{ ++ key->u32[0] = inum; ++ key->u32[1] = UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS; ++} ++ ++/** ++ * xent_key_init - initialize extended attribute entry key. ++ * @c: UBIFS file-system description object ++ * @key: key to initialize ++ * @inum: host inode number ++ * @nm: extended attribute entry name and length ++ */ ++static inline void xent_key_init(const struct ubifs_info *c, ++ union ubifs_key *key, ino_t inum, ++ const struct qstr *nm) ++{ ++ uint32_t hash = c->key_hash(nm->name, nm->len); ++ ++ ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK)); ++ key->u32[0] = inum; ++ key->u32[1] = hash | (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS); ++} ++ ++/** ++ * xent_key_init_hash - initialize extended attribute entry key without ++ * re-calculating hash function. ++ * @c: UBIFS file-system description object ++ * @key: key to initialize ++ * @inum: host inode number ++ * @hash: extended attribute entry name hash ++ */ ++static inline void xent_key_init_hash(const struct ubifs_info *c, ++ union ubifs_key *key, ino_t inum, ++ uint32_t hash) ++{ ++ ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK)); ++ key->u32[0] = inum; ++ key->u32[1] = hash | (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS); ++} ++ ++/** ++ * xent_key_init_flash - initialize on-flash extended attribute entry key. ++ * @c: UBIFS file-system description object ++ * @k: key to initialize ++ * @inum: host inode number ++ * @nm: extended attribute entry name and length ++ */ ++static inline void xent_key_init_flash(const struct ubifs_info *c, void *k, ++ ino_t inum, const struct qstr *nm) ++{ ++ union ubifs_key *key = k; ++ uint32_t hash = c->key_hash(nm->name, nm->len); ++ ++ ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK)); ++ key->j32[0] = cpu_to_le32(inum); ++ key->j32[1] = cpu_to_le32(hash | ++ (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS)); ++ memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8); ++} ++ ++/** ++ * lowest_xent_key - get the lowest possible extended attribute entry key. ++ * @c: UBIFS file-system description object ++ * @key: where to store the lowest key ++ * @inum: host inode number ++ */ ++static inline void lowest_xent_key(const struct ubifs_info *c, ++ union ubifs_key *key, ino_t inum) ++{ ++ key->u32[0] = inum; ++ key->u32[1] = UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS; ++} ++ ++/** ++ * data_key_init - initialize data key. ++ * @c: UBIFS file-system description object ++ * @key: key to initialize ++ * @inum: inode number ++ * @block: block number ++ */ ++static inline void data_key_init(const struct ubifs_info *c, ++ union ubifs_key *key, ino_t inum, ++ unsigned int block) ++{ ++ ubifs_assert(!(block & ~UBIFS_S_KEY_BLOCK_MASK)); ++ key->u32[0] = inum; ++ key->u32[1] = block | (UBIFS_DATA_KEY << UBIFS_S_KEY_BLOCK_BITS); ++} ++ ++/** ++ * data_key_init_flash - initialize on-flash data key. ++ * @c: UBIFS file-system description object ++ * @k: key to initialize ++ * @inum: inode number ++ * @block: block number ++ */ ++static inline void data_key_init_flash(const struct ubifs_info *c, void *k, ++ ino_t inum, unsigned int block) ++{ ++ union ubifs_key *key = k; ++ ++ ubifs_assert(!(block & ~UBIFS_S_KEY_BLOCK_MASK)); ++ key->j32[0] = cpu_to_le32(inum); ++ key->j32[1] = cpu_to_le32(block | ++ (UBIFS_DATA_KEY << UBIFS_S_KEY_BLOCK_BITS)); ++ memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8); ++} ++ ++/** ++ * trun_key_init - initialize truncation node key. ++ * @c: UBIFS file-system description object ++ * @key: key to initialize ++ * @inum: inode number ++ * ++ * Note, UBIFS does not have truncation keys on the media and this function is ++ * only used for purposes of replay. ++ */ ++static inline void trun_key_init(const struct ubifs_info *c, ++ union ubifs_key *key, ino_t inum) ++{ ++ key->u32[0] = inum; ++ key->u32[1] = UBIFS_TRUN_KEY << UBIFS_S_KEY_BLOCK_BITS; ++} ++ ++/** ++ * key_type - get key type. ++ * @c: UBIFS file-system description object ++ * @key: key to get type of ++ */ ++static inline int key_type(const struct ubifs_info *c, ++ const union ubifs_key *key) ++{ ++ return key->u32[1] >> UBIFS_S_KEY_BLOCK_BITS; ++} ++ ++/** ++ * key_type_flash - get type of a on-flash formatted key. ++ * @c: UBIFS file-system description object ++ * @k: key to get type of ++ */ ++static inline int key_type_flash(const struct ubifs_info *c, const void *k) ++{ ++ const union ubifs_key *key = k; ++ ++ return le32_to_cpu(key->u32[1]) >> UBIFS_S_KEY_BLOCK_BITS; ++} ++ ++/** ++ * key_inum - fetch inode number from key. ++ * @c: UBIFS file-system description object ++ * @k: key to fetch inode number from ++ */ ++static inline ino_t key_inum(const struct ubifs_info *c, const void *k) ++{ ++ const union ubifs_key *key = k; ++ ++ return key->u32[0]; ++} ++ ++/** ++ * key_inum_flash - fetch inode number from an on-flash formatted key. ++ * @c: UBIFS file-system description object ++ * @k: key to fetch inode number from ++ */ ++static inline ino_t key_inum_flash(const struct ubifs_info *c, const void *k) ++{ ++ const union ubifs_key *key = k; ++ ++ return le32_to_cpu(key->j32[0]); ++} ++ ++/** ++ * key_hash - get directory entry hash. ++ * @c: UBIFS file-system description object ++ * @key: the key to get hash from ++ */ ++static inline int key_hash(const struct ubifs_info *c, ++ const union ubifs_key *key) ++{ ++ return key->u32[1] & UBIFS_S_KEY_HASH_MASK; ++} ++ ++/** ++ * key_hash_flash - get directory entry hash from an on-flash formatted key. ++ * @c: UBIFS file-system description object ++ * @k: the key to get hash from ++ */ ++static inline int key_hash_flash(const struct ubifs_info *c, const void *k) ++{ ++ const union ubifs_key *key = k; ++ ++ return le32_to_cpu(key->j32[1]) & UBIFS_S_KEY_HASH_MASK; ++} ++ ++/** ++ * key_block - get data block number. ++ * @c: UBIFS file-system description object ++ * @key: the key to get the block number from ++ */ ++static inline unsigned int key_block(const struct ubifs_info *c, ++ const union ubifs_key *key) ++{ ++ return key->u32[1] & UBIFS_S_KEY_BLOCK_MASK; ++} ++ ++/** ++ * key_block_flash - get data block number from an on-flash formatted key. ++ * @c: UBIFS file-system description object ++ * @k: the key to get the block number from ++ */ ++static inline unsigned int key_block_flash(const struct ubifs_info *c, ++ const void *k) ++{ ++ const union ubifs_key *key = k; ++ ++ return le32_to_cpu(key->u32[1]) & UBIFS_S_KEY_BLOCK_MASK; ++} ++ ++/** ++ * key_read - transform a key to in-memory format. ++ * @c: UBIFS file-system description object ++ * @from: the key to transform ++ * @to: the key to store the result ++ */ ++static inline void key_read(const struct ubifs_info *c, const void *from, ++ union ubifs_key *to) ++{ ++ const union ubifs_key *f = from; ++ ++ to->u32[0] = le32_to_cpu(f->j32[0]); ++ to->u32[1] = le32_to_cpu(f->j32[1]); ++} ++ ++/** ++ * key_write - transform a key from in-memory format. ++ * @c: UBIFS file-system description object ++ * @from: the key to transform ++ * @to: the key to store the result ++ */ ++static inline void key_write(const struct ubifs_info *c, ++ const union ubifs_key *from, void *to) ++{ ++ union ubifs_key *t = to; ++ ++ t->j32[0] = cpu_to_le32(from->u32[0]); ++ t->j32[1] = cpu_to_le32(from->u32[1]); ++ memset(to + 8, 0, UBIFS_MAX_KEY_LEN - 8); ++} ++ ++/** ++ * key_write_idx - transform a key from in-memory format for the index. ++ * @c: UBIFS file-system description object ++ * @from: the key to transform ++ * @to: the key to store the result ++ */ ++static inline void key_write_idx(const struct ubifs_info *c, ++ const union ubifs_key *from, void *to) ++{ ++ union ubifs_key *t = to; ++ ++ t->j32[0] = cpu_to_le32(from->u32[0]); ++ t->j32[1] = cpu_to_le32(from->u32[1]); ++} ++ ++/** ++ * key_copy - copy a key. ++ * @c: UBIFS file-system description object ++ * @from: the key to copy from ++ * @to: the key to copy to ++ */ ++static inline void key_copy(const struct ubifs_info *c, ++ const union ubifs_key *from, union ubifs_key *to) ++{ ++ to->u64[0] = from->u64[0]; ++} ++ ++/** ++ * keys_cmp - compare keys. ++ * @c: UBIFS file-system description object ++ * @key1: the first key to compare ++ * @key2: the second key to compare ++ * ++ * This function compares 2 keys and returns %-1 if @key1 is less than ++ * @key2, 0 if the keys are equivalent and %1 if @key1 is greater than @key2. ++ */ ++static inline int keys_cmp(const struct ubifs_info *c, ++ const union ubifs_key *key1, ++ const union ubifs_key *key2) ++{ ++ if (key1->u32[0] < key2->u32[0]) ++ return -1; ++ if (key1->u32[0] > key2->u32[0]) ++ return 1; ++ if (key1->u32[1] < key2->u32[1]) ++ return -1; ++ if (key1->u32[1] > key2->u32[1]) ++ return 1; ++ ++ return 0; ++} ++ ++/** ++ * is_hash_key - is a key vulnerable to hash collisions. ++ * @c: UBIFS file-system description object ++ * @key: key ++ * ++ * This function returns %1 if @key is a hashed key or %0 otherwise. ++ */ ++static inline int is_hash_key(const struct ubifs_info *c, ++ const union ubifs_key *key) ++{ ++ int type = key_type(c, key); ++ ++ return type == UBIFS_DENT_KEY || type == UBIFS_XENT_KEY; ++} ++ ++/** ++ * key_max_inode_size - get maximum file size allowed by current key format. ++ * @c: UBIFS file-system description object ++ */ ++static inline unsigned long long key_max_inode_size(const struct ubifs_info *c) ++{ ++ switch (c->key_fmt) { ++ case UBIFS_SIMPLE_KEY_FMT: ++ return (1ULL << UBIFS_S_KEY_BLOCK_BITS) * UBIFS_BLOCK_SIZE; ++ default: ++ return 0; ++ } ++} ++#endif /* !__UBIFS_KEY_H__ */ +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/log.c avr32-2.6/fs/ubifs/log.c +--- linux-2.6.25.6/fs/ubifs/log.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/log.c 2008-06-12 15:09:45.367815766 +0200 +@@ -0,0 +1,799 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Artem Bityutskiy (Битюцкий Артём) ++ * Adrian Hunter ++ */ ++ ++/* ++ * This file is a part of UBIFS journal implementation and contains various ++ * functions which manipulate the log. The log is a fixed area on the flash ++ * which does not contain any data but refers to buds. The log is a part of the ++ * journal. ++ */ ++ ++#include "ubifs.h" ++ ++#ifdef CONFIG_UBIFS_FS_DEBUG ++static int dbg_check_bud_bytes(struct ubifs_info *c); ++#else ++#define dbg_check_bud_bytes(c) 0 ++#endif ++ ++/** ++ * ubifs_search_bud - search bud LEB. ++ * @c: UBIFS file-system description object ++ * @lnum: logical eraseblock number to search ++ * ++ * This function searches bud LEB @lnum. Returns bud description object in case ++ * of success and %NULL if there is no bud with this LEB number. ++ */ ++struct ubifs_bud *ubifs_search_bud(struct ubifs_info *c, int lnum) ++{ ++ struct rb_node *p; ++ struct ubifs_bud *bud; ++ ++ spin_lock(&c->buds_lock); ++ p = c->buds.rb_node; ++ while (p) { ++ bud = rb_entry(p, struct ubifs_bud, rb); ++ if (lnum < bud->lnum) ++ p = p->rb_left; ++ else if (lnum > bud->lnum) ++ p = p->rb_right; ++ else { ++ spin_unlock(&c->buds_lock); ++ return bud; ++ } ++ } ++ spin_unlock(&c->buds_lock); ++ return NULL; ++} ++ ++/** ++ * ubifs_get_wbuf - get the wbuf associated with a LEB, if there is one. ++ * @c: UBIFS file-system description object ++ * @lnum: logical eraseblock number to search ++ * ++ * This functions returns the wbuf for @lnum or %NULL if there is not one. ++ */ ++struct ubifs_wbuf *ubifs_get_wbuf(struct ubifs_info *c, int lnum) ++{ ++ struct rb_node *p; ++ struct ubifs_bud *bud; ++ int jhead; ++ ++ if (!c->jheads) ++ return NULL; ++ ++ spin_lock(&c->buds_lock); ++ p = c->buds.rb_node; ++ while (p) { ++ bud = rb_entry(p, struct ubifs_bud, rb); ++ if (lnum < bud->lnum) ++ p = p->rb_left; ++ else if (lnum > bud->lnum) ++ p = p->rb_right; ++ else { ++ jhead = bud->jhead; ++ spin_unlock(&c->buds_lock); ++ return &c->jheads[jhead].wbuf; ++ } ++ } ++ spin_unlock(&c->buds_lock); ++ return NULL; ++} ++ ++/** ++ * next_log_lnum - switch to the next log LEB. ++ * @c: UBIFS file-system description object ++ * @lnum: current log LEB ++ */ ++static inline int next_log_lnum(const struct ubifs_info *c, int lnum) ++{ ++ lnum += 1; ++ if (lnum > c->log_last) ++ lnum = UBIFS_LOG_LNUM; ++ ++ return lnum; ++} ++ ++/** ++ * empty_log_bytes - calculate amount of empty space in the log. ++ * @c: UBIFS file-system description object ++ */ ++static inline long long empty_log_bytes(const struct ubifs_info *c) ++{ ++ long long h, t; ++ ++ h = c->lhead_lnum * c->leb_size + c->lhead_offs; ++ t = c->ltail_lnum * c->leb_size; ++ ++ if (h >= t) ++ return c->log_bytes - h + t; ++ else ++ return t - h; ++} ++ ++/** ++ * ubifs_add_bud - add bud LEB to the tree of buds and its journal head list. ++ * @c: UBIFS file-system description object ++ * @bud: the bud to add ++ */ ++void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud) ++{ ++ struct rb_node **p, *parent = NULL; ++ struct ubifs_bud *b; ++ struct ubifs_jhead *jhead; ++ ++ spin_lock(&c->buds_lock); ++ p = &c->buds.rb_node; ++ while (*p) { ++ parent = *p; ++ b = rb_entry(parent, struct ubifs_bud, rb); ++ ubifs_assert(bud->lnum != b->lnum); ++ if (bud->lnum < b->lnum) ++ p = &(*p)->rb_left; ++ else ++ p = &(*p)->rb_right; ++ } ++ ++ rb_link_node(&bud->rb, parent, p); ++ rb_insert_color(&bud->rb, &c->buds); ++ if (c->jheads) { ++ jhead = &c->jheads[bud->jhead]; ++ list_add_tail(&bud->list, &jhead->buds_list); ++ } else ++ ubifs_assert(c->replaying && (c->vfs_sb->s_flags & MS_RDONLY)); ++ ++ /* ++ * Note, although this is a new bud, we anyway account this space now, ++ * before any data has been written to it, because this is about to ++ * guarantee fixed mount time, and this bud will anyway be read and ++ * scanned. ++ */ ++ c->bud_bytes += c->leb_size - bud->start; ++ ++ dbg_log("LEB %d:%d, jhead %d, bud_bytes %lld", bud->lnum, ++ bud->start, bud->jhead, c->bud_bytes); ++ spin_unlock(&c->buds_lock); ++} ++ ++/** ++ * ubifs_create_buds_lists - create journal head buds lists for remount rw. ++ * @c: UBIFS file-system description object ++ */ ++void ubifs_create_buds_lists(struct ubifs_info *c) ++{ ++ struct rb_node *p; ++ ++ spin_lock(&c->buds_lock); ++ p = rb_first(&c->buds); ++ while (p) { ++ struct ubifs_bud *bud = rb_entry(p, struct ubifs_bud, rb); ++ struct ubifs_jhead *jhead = &c->jheads[bud->jhead]; ++ ++ list_add_tail(&bud->list, &jhead->buds_list); ++ p = rb_next(p); ++ } ++ spin_unlock(&c->buds_lock); ++} ++ ++/** ++ * ubifs_add_bud_to_log - add a new bud to the log. ++ * @c: UBIFS file-system description object ++ * @jhead: journal head the bud belongs to ++ * @lnum: LEB number of the bud ++ * @offs: starting offset of the bud ++ * ++ * This function writes reference node for the new bud LEB @lnum it to the log, ++ * and adds it to the buds tress. It also makes sure that log size does not ++ * exceed the 'c->max_bud_bytes' limit. Returns zero in case of success, ++ * %-EAGAIN if commit is required, and a negative error codes in case of ++ * failure. ++ */ ++int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs) ++{ ++ int err; ++ struct ubifs_bud *bud; ++ struct ubifs_ref_node *ref; ++ ++ bud = kmalloc(sizeof(struct ubifs_bud), GFP_NOFS); ++ if (!bud) ++ return -ENOMEM; ++ ref = kzalloc(c->ref_node_alsz, GFP_NOFS); ++ if (!ref) { ++ kfree(bud); ++ return -ENOMEM; ++ } ++ ++ mutex_lock(&c->log_mutex); ++ /* Make sure we have enough space in the log */ ++ if (empty_log_bytes(c) - c->ref_node_alsz < c->min_log_bytes) { ++ dbg_log("not enough log space - %lld, required %d", ++ empty_log_bytes(c), c->min_log_bytes); ++ ubifs_commit_required(c); ++ err = -EAGAIN; ++ goto out_unlock; ++ } ++ ++ /* ++ * Make sure the the amount of space in buds will not exceed ++ * 'c->max_bud_bytes' limit, because we want to guarantee mount time ++ * limits. ++ * ++ * It is not necessary to hold @c->buds_lock when reading @c->bud_bytes ++ * because we are holding @c->log_mutex. All @c->bud_bytes take place ++ * when both @c->log_mutex and @c->bud_bytes are locked. ++ */ ++ if (c->bud_bytes + c->leb_size - offs > c->max_bud_bytes) { ++ dbg_log("bud bytes %lld (%lld max), require commit", ++ c->bud_bytes, c->max_bud_bytes); ++ ubifs_commit_required(c); ++ err = -EAGAIN; ++ goto out_unlock; ++ } ++ ++ /* ++ * If the journal is full enough - start background commit. Note, it is ++ * OK to read 'c->cmt_state' without spinlock because integer reads ++ * are atomic in the kernel. ++ */ ++ if (c->bud_bytes >= c->bg_bud_bytes && ++ c->cmt_state == COMMIT_RESTING) { ++ dbg_log("bud bytes %lld (%lld max), initiate BG commit", ++ c->bud_bytes, c->max_bud_bytes); ++ ubifs_request_bg_commit(c); ++ } ++ ++ bud->lnum = lnum; ++ bud->start = offs; ++ bud->jhead = jhead; ++ ++ ref->ch.node_type = UBIFS_REF_NODE; ++ ref->lnum = cpu_to_le32(bud->lnum); ++ ref->offs = cpu_to_le32(bud->start); ++ ref->jhead = cpu_to_le32(jhead); ++ ++ if (c->lhead_offs > c->leb_size - c->ref_node_alsz) { ++ c->lhead_lnum = next_log_lnum(c, c->lhead_lnum); ++ c->lhead_offs = 0; ++ } ++ ++ if (c->lhead_offs == 0) { ++ /* Must ensure next log LEB has been unmapped */ ++ err = ubifs_leb_unmap(c, c->lhead_lnum); ++ if (err) ++ goto out_unlock; ++ } ++ ++ if (bud->start == 0) { ++ /* ++ * Before writing the LEB reference which refers an empty LEB ++ * to the log, we have to make sure it is mapped, because ++ * otherwise we'd risk to refer an LEB with garbage in case of ++ * an unclean reboot, because the target LEB might have been ++ * unmapped, but not yet physically erased. ++ */ ++ err = ubi_leb_map(c->ubi, bud->lnum, UBI_SHORTTERM); ++ if (err) ++ goto out_unlock; ++ } ++ ++ dbg_log("write ref LEB %d:%d", ++ c->lhead_lnum, c->lhead_offs); ++ err = ubifs_write_node(c, ref, UBIFS_REF_NODE_SZ, c->lhead_lnum, ++ c->lhead_offs, UBI_SHORTTERM); ++ c->lhead_offs += c->ref_node_alsz; ++ if (err) ++ goto out_unlock; ++ ++ ubifs_add_bud(c, bud); ++ ++ mutex_unlock(&c->log_mutex); ++ kfree(ref); ++ return 0; ++ ++out_unlock: ++ mutex_unlock(&c->log_mutex); ++ kfree(ref); ++ kfree(bud); ++ return err; ++} ++ ++/** ++ * remove_buds - remove used buds. ++ * @c: UBIFS file-system description object ++ * ++ * This function removes use buds from the buds tree. It does not remove the ++ * buds which are pointed to by journal heads. ++ */ ++static void remove_buds(struct ubifs_info *c) ++{ ++ struct rb_node *p; ++ ++ ubifs_assert(list_empty(&c->old_buds)); ++ c->cmt_bud_bytes = 0; ++ spin_lock(&c->buds_lock); ++ p = rb_first(&c->buds); ++ while (p) { ++ struct rb_node *p1 = p; ++ struct ubifs_bud *bud; ++ struct ubifs_wbuf *wbuf; ++ ++ p = rb_next(p); ++ bud = rb_entry(p1, struct ubifs_bud, rb); ++ wbuf = &c->jheads[bud->jhead].wbuf; ++ ++ if (wbuf->lnum == bud->lnum) { ++ /* ++ * Do not remove buds which are pointed to by journal ++ * heads (non-closed buds). ++ */ ++ c->cmt_bud_bytes += wbuf->offs - bud->start; ++ dbg_log("preserve %d:%d, jhead %d, bud bytes %d, " ++ "cmt_bud_bytes %lld", bud->lnum, bud->start, ++ bud->jhead, wbuf->offs - bud->start, ++ c->cmt_bud_bytes); ++ bud->start = wbuf->offs; ++ } else { ++ c->cmt_bud_bytes += c->leb_size - bud->start; ++ dbg_log("remove %d:%d, jhead %d, bud bytes %d, " ++ "cmt_bud_bytes %lld", bud->lnum, bud->start, ++ bud->jhead, c->leb_size - bud->start, ++ c->cmt_bud_bytes); ++ rb_erase(p1, &c->buds); ++ list_del(&bud->list); ++ /* ++ * If the commit does not finish, the recovery will need ++ * to replay the journal, in which case the old buds ++ * must be unchanged. Do not release them until post ++ * commit i.e. do not allow them to be garbage ++ * collected. ++ */ ++ list_add(&bud->list, &c->old_buds); ++ } ++ } ++ spin_unlock(&c->buds_lock); ++} ++ ++/** ++ * ubifs_log_start_commit - start commit. ++ * @c: UBIFS file-system description object ++ * @ltail_lnum: return new log tail LEB number ++ * ++ * The commit operation starts with writing "commit start" node to the log and ++ * reference nodes for all journal heads which will define new journal after ++ * the commit has been finished. The commit start and reference nodes are ++ * written in one go to the nearest empty log LEB (hence, when commit is ++ * finished UBIFS may safely unmap all the previous log LEBs). This function ++ * returns zero in case of success and a negative error code in case of ++ * failure. ++ */ ++int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum) ++{ ++ void *buf; ++ struct ubifs_cs_node *cs; ++ struct ubifs_ref_node *ref; ++ int err, i, max_len, len; ++ ++ err = dbg_check_bud_bytes(c); ++ if (err) ++ return err; ++ ++ max_len = UBIFS_CS_NODE_SZ + c->jhead_cnt * UBIFS_REF_NODE_SZ; ++ max_len = ALIGN(max_len, c->min_io_size); ++ buf = cs = kmalloc(max_len, GFP_NOFS); ++ if (!buf) ++ return -ENOMEM; ++ ++ cs->ch.node_type = UBIFS_CS_NODE; ++ cs->cmt_no = cpu_to_le64(c->cmt_no + 1); ++ ubifs_prepare_node(c, cs, UBIFS_CS_NODE_SZ, 0); ++ ++ /* ++ * Note, we do not lock 'c->log_mutex' because this is the commit start ++ * phase and we are exclusively using the log. And we do not lock ++ * write-buffer because nobody can write to the file-system at this ++ * phase. ++ */ ++ ++ len = UBIFS_CS_NODE_SZ; ++ for (i = 0; i < c->jhead_cnt; i++) { ++ int lnum = c->jheads[i].wbuf.lnum; ++ int offs = c->jheads[i].wbuf.offs; ++ ++ if (lnum == -1 || offs == c->leb_size) ++ continue; ++ ++ dbg_log("add ref to LEB %d:%d for jhead %d", lnum, offs, i); ++ ref = buf + len; ++ ref->ch.node_type = UBIFS_REF_NODE; ++ ref->lnum = cpu_to_le32(lnum); ++ ref->offs = cpu_to_le32(offs); ++ ref->jhead = cpu_to_le32(i); ++ ++ ubifs_prepare_node(c, ref, UBIFS_REF_NODE_SZ, 0); ++ len += UBIFS_REF_NODE_SZ; ++ } ++ ++ ubifs_pad(c, buf + len, ALIGN(len, c->min_io_size) - len); ++ ++ /* Switch to the next log LEB */ ++ if (c->lhead_offs) { ++ c->lhead_lnum = next_log_lnum(c, c->lhead_lnum); ++ c->lhead_offs = 0; ++ } ++ ++ if (c->lhead_offs == 0) { ++ /* Must ensure next LEB has been unmapped */ ++ err = ubifs_leb_unmap(c, c->lhead_lnum); ++ if (err) ++ goto out; ++ } ++ ++ len = ALIGN(len, c->min_io_size); ++ dbg_log("writing commit start at LEB %d:0, len %d", c->lhead_lnum, len); ++ err = ubifs_leb_write(c, c->lhead_lnum, cs, 0, len, UBI_SHORTTERM); ++ if (err) ++ goto out; ++ ++ *ltail_lnum = c->lhead_lnum; ++ ++ c->lhead_offs += len; ++ if (c->lhead_offs == c->leb_size) { ++ c->lhead_lnum = next_log_lnum(c, c->lhead_lnum); ++ c->lhead_offs = 0; ++ } ++ ++ remove_buds(c); ++ ++ /* ++ * We have started the commit and now users may use the rest of the log ++ * for new writes. ++ */ ++ c->min_log_bytes = 0; ++ ++out: ++ kfree(buf); ++ return err; ++} ++ ++/** ++ * ubifs_log_end_commit - end commit. ++ * @c: UBIFS file-system description object ++ * @ltail_lnum: new log tail LEB number ++ * ++ * This function is called on when the commit operation was finished. It ++ * moves log tail to new position and unmaps LEBs which contain obsolete data. ++ * Returns zero in case of success and a negative error code in case of ++ * failure. ++ */ ++int ubifs_log_end_commit(struct ubifs_info *c, int ltail_lnum) ++{ ++ int err; ++ ++ /* ++ * At this phase we have to lock 'c->log_mutex' because UBIFS allows FS ++ * writes during commit. Its only short "commit" start phase when ++ * writers are blocked. ++ */ ++ mutex_lock(&c->log_mutex); ++ ++ dbg_log("old tail was LEB %d:0, new tail is LEB %d:0", ++ c->ltail_lnum, ltail_lnum); ++ ++ c->ltail_lnum = ltail_lnum; ++ /* ++ * The commit is finished and from now on it must be guaranteed that ++ * there is always enough space for the next commit. ++ */ ++ c->min_log_bytes = c->leb_size; ++ ++ spin_lock(&c->buds_lock); ++ c->bud_bytes -= c->cmt_bud_bytes; ++ spin_unlock(&c->buds_lock); ++ ++ err = dbg_check_bud_bytes(c); ++ ++ mutex_unlock(&c->log_mutex); ++ return err; ++} ++ ++/** ++ * ubifs_log_post_commit - things to do after commit is completed. ++ * @c: UBIFS file-system description object ++ * @old_ltail_lnum: old log tail LEB number ++ * ++ * Release buds only after commit is completed, because they must be unchanged ++ * if recovery is needed. ++ * ++ * Unmap log LEBs only after commit is completed, because they may be needed for ++ * recovery. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum) ++{ ++ int lnum, err = 0; ++ ++ while (!list_empty(&c->old_buds)) { ++ struct ubifs_bud *bud; ++ ++ bud = list_entry(c->old_buds.next, struct ubifs_bud, list); ++ err = ubifs_return_leb(c, bud->lnum); ++ if (err) ++ return err; ++ list_del(&bud->list); ++ kfree(bud); ++ } ++ mutex_lock(&c->log_mutex); ++ for (lnum = old_ltail_lnum; lnum != c->ltail_lnum; ++ lnum = next_log_lnum(c, lnum)) { ++ dbg_log("unmap log LEB %d", lnum); ++ err = ubifs_leb_unmap(c, lnum); ++ if (err) ++ goto out; ++ } ++out: ++ mutex_unlock(&c->log_mutex); ++ return err; ++} ++ ++/** ++ * struct done_ref - references that have been done. ++ * @rb: rb-tree node ++ * @lnum: LEB number ++ */ ++struct done_ref { ++ struct rb_node rb; ++ int lnum; ++}; ++ ++/** ++ * done_already - determine if a reference has been done already. ++ * @done_tree: rb-tree to store references that have been done ++ * @lnum: LEB number of reference ++ * ++ * This function returns %1 if the reference has been done, %0 if not, otherwise ++ * a negative error code is returned. ++ */ ++static int done_already(struct rb_root *done_tree, int lnum) ++{ ++ struct rb_node **p = &done_tree->rb_node, *parent = NULL; ++ struct done_ref *dr; ++ ++ while (*p) { ++ parent = *p; ++ dr = rb_entry(parent, struct done_ref, rb); ++ if (lnum < dr->lnum) ++ p = &(*p)->rb_left; ++ else if (lnum > dr->lnum) ++ p = &(*p)->rb_right; ++ else ++ return 1; ++ } ++ ++ dr = kzalloc(sizeof(struct done_ref), GFP_NOFS); ++ if (!dr) ++ return -ENOMEM; ++ ++ dr->lnum = lnum; ++ ++ rb_link_node(&dr->rb, parent, p); ++ rb_insert_color(&dr->rb, done_tree); ++ ++ return 0; ++} ++ ++/** ++ * destroy_done_tree - destroy the done tree. ++ * @done_tree: done tree to destroy ++ */ ++static void destroy_done_tree(struct rb_root *done_tree) ++{ ++ struct rb_node *this = done_tree->rb_node; ++ struct done_ref *dr; ++ ++ while (this) { ++ if (this->rb_left) { ++ this = this->rb_left; ++ continue; ++ } else if (this->rb_right) { ++ this = this->rb_right; ++ continue; ++ } ++ dr = rb_entry(this, struct done_ref, rb); ++ this = rb_parent(this); ++ if (this) { ++ if (this->rb_left == &dr->rb) ++ this->rb_left = NULL; ++ else ++ this->rb_right = NULL; ++ } ++ kfree(dr); ++ } ++} ++ ++/** ++ * add_node - add a node to the consolidated log. ++ * @c: UBIFS file-system description object ++ * @buf: buffer to which to add ++ * @lnum: LEB number to which to write is passed and returned here ++ * @offs: offset to where to write is passed and returned here ++ * @node: node to add ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int add_node(struct ubifs_info *c, void *buf, int *lnum, int *offs, ++ void *node) ++{ ++ struct ubifs_ch *ch = node; ++ int len = le32_to_cpu(ch->len), remains = c->leb_size - *offs; ++ ++ if (len > remains) { ++ int sz = ALIGN(*offs, c->min_io_size), err; ++ ++ ubifs_pad(c, buf + *offs, sz - *offs); ++ err = ubi_leb_change(c->ubi, *lnum, buf, sz, UBI_SHORTTERM); ++ if (err) ++ return err; ++ *lnum = next_log_lnum(c, *lnum); ++ *offs = 0; ++ } ++ memcpy(buf + *offs, node, len); ++ *offs += ALIGN(len, 8); ++ return 0; ++} ++ ++/** ++ * ubifs_consolidate_log - consolidate the log. ++ * @c: UBIFS file-system description object ++ * ++ * Repeated failed commits could cause the log to be full, but at least 1 LEB is ++ * needed for commit. This function rewrites the reference nodes in the log ++ * omitting duplicates, and failed CS nodes, and leaving no gaps. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++int ubifs_consolidate_log(struct ubifs_info *c) ++{ ++ struct ubifs_scan_leb *sleb; ++ struct ubifs_scan_node *snod; ++ struct rb_root done_tree = RB_ROOT; ++ int lnum, err, first = 1, write_lnum, offs = 0; ++ void *buf; ++ ++ dbg_rcvry("log tail LEB %d, log head LEB %d", c->ltail_lnum, ++ c->lhead_lnum); ++ buf = vmalloc(c->leb_size); ++ if (!buf) ++ return -ENOMEM; ++ lnum = c->ltail_lnum; ++ write_lnum = lnum; ++ while (1) { ++ sleb = ubifs_scan(c, lnum, 0, c->sbuf); ++ if (IS_ERR(sleb)) { ++ err = PTR_ERR(sleb); ++ goto out_free; ++ } ++ list_for_each_entry(snod, &sleb->nodes, list) { ++ switch (snod->type) { ++ case UBIFS_REF_NODE: { ++ struct ubifs_ref_node *ref = snod->node; ++ int ref_lnum = le32_to_cpu(ref->lnum); ++ ++ err = done_already(&done_tree, ref_lnum); ++ if (err < 0) ++ goto out_scan; ++ if (err != 1) { ++ err = add_node(c, buf, &write_lnum, ++ &offs, snod->node); ++ if (err) ++ goto out_scan; ++ } ++ break; ++ } ++ case UBIFS_CS_NODE: ++ if (!first) ++ break; ++ err = add_node(c, buf, &write_lnum, &offs, ++ snod->node); ++ if (err) ++ goto out_scan; ++ first = 0; ++ break; ++ } ++ } ++ ubifs_scan_destroy(sleb); ++ if (lnum == c->lhead_lnum) ++ break; ++ lnum = next_log_lnum(c, lnum); ++ } ++ if (offs) { ++ int sz = ALIGN(offs, c->min_io_size); ++ ++ ubifs_pad(c, buf + offs, sz - offs); ++ err = ubi_leb_change(c->ubi, write_lnum, buf, sz, ++ UBI_SHORTTERM); ++ if (err) ++ goto out_free; ++ offs = ALIGN(offs, c->min_io_size); ++ } ++ destroy_done_tree(&done_tree); ++ vfree(buf); ++ if (write_lnum == c->lhead_lnum) { ++ ubifs_err("log is too full"); ++ return -EINVAL; ++ } ++ /* Unmap remaining LEBs */ ++ lnum = write_lnum; ++ do { ++ lnum = next_log_lnum(c, lnum); ++ err = ubifs_leb_unmap(c, lnum); ++ if (err) ++ return err; ++ } while (lnum != c->lhead_lnum); ++ c->lhead_lnum = write_lnum; ++ c->lhead_offs = offs; ++ dbg_rcvry("new log head at %d:%d", c->lhead_lnum, c->lhead_offs); ++ return 0; ++ ++out_scan: ++ ubifs_scan_destroy(sleb); ++out_free: ++ destroy_done_tree(&done_tree); ++ vfree(buf); ++ return err; ++} ++ ++#ifdef CONFIG_UBIFS_FS_DEBUG ++ ++/** ++ * dbg_check_bud_bytes - make sure bud bytes calculation are all right. ++ * @c: UBIFS file-system description object ++ * ++ * This function makes sure the amount of flash space used by closed buds ++ * ('c->bud_bytes' is correct). Returns zero in case of success and %-EINVAL in ++ * case of failure. ++ */ ++static int dbg_check_bud_bytes(struct ubifs_info *c) ++{ ++ int i, err = 0; ++ struct ubifs_bud *bud; ++ long long bud_bytes = 0; ++ ++ if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) ++ return 0; ++ ++ spin_lock(&c->buds_lock); ++ for (i = 0; i < c->jhead_cnt; i++) ++ list_for_each_entry(bud, &c->jheads[i].buds_list, list) ++ bud_bytes += c->leb_size - bud->start; ++ ++ if (c->bud_bytes != bud_bytes) { ++ ubifs_err("bad bud_bytes %lld, calculated %lld", ++ c->bud_bytes, bud_bytes); ++ err = -EINVAL; ++ } ++ spin_unlock(&c->buds_lock); ++ ++ return err; ++} ++ ++#endif /* CONFIG_UBIFS_FS_DEBUG */ +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/lprops.c avr32-2.6/fs/ubifs/lprops.c +--- linux-2.6.25.6/fs/ubifs/lprops.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/lprops.c 2008-06-12 15:09:45.371816276 +0200 +@@ -0,0 +1,1355 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Adrian Hunter ++ * Artem Bityutskiy (Битюцкий Артём) ++ */ ++ ++/* ++ * This file implements the functions that access LEB properties and their ++ * categories. LEBs are categorized based on the needs of UBIFS, and the ++ * categories are stored as either heaps or lists to provide a fast way of ++ * finding a LEB in a particular category. For example, UBIFS may need to find ++ * an empty LEB for the journal, or a very dirty LEB for garbage collection. ++ */ ++ ++#include "ubifs.h" ++ ++/** ++ * get_heap_comp_val - get the LEB properties value for heap comparisons. ++ * @lprops: LEB properties ++ * @cat: LEB category ++ */ ++static int get_heap_comp_val(struct ubifs_lprops *lprops, int cat) ++{ ++ switch (cat) { ++ case LPROPS_FREE: ++ return lprops->free; ++ case LPROPS_DIRTY_IDX: ++ return lprops->free + lprops->dirty; ++ default: ++ return lprops->dirty; ++ } ++} ++ ++/** ++ * move_up_lpt_heap - move a new heap entry up as far as possible. ++ * @c: UBIFS file-system description object ++ * @heap: LEB category heap ++ * @lprops: LEB properties to move ++ * @cat: LEB category ++ * ++ * New entries to a heap are added at the bottom and then moved up until the ++ * parent's value is greater. In the case of LPT's category heaps, the value ++ * is either the amount of free space or the amount of dirty space, depending ++ * on the category. ++ */ ++static void move_up_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, ++ struct ubifs_lprops *lprops, int cat) ++{ ++ int val1, val2, hpos; ++ ++ hpos = lprops->hpos; ++ if (!hpos) ++ return; /* Already top of the heap */ ++ val1 = get_heap_comp_val(lprops, cat); ++ /* Compare to parent and, if greater, move up the heap */ ++ do { ++ int ppos = (hpos - 1) / 2; ++ ++ val2 = get_heap_comp_val(heap->arr[ppos], cat); ++ if (val2 >= val1) ++ return; ++ /* Greater than parent so move up */ ++ heap->arr[ppos]->hpos = hpos; ++ heap->arr[hpos] = heap->arr[ppos]; ++ heap->arr[ppos] = lprops; ++ lprops->hpos = ppos; ++ hpos = ppos; ++ } while (hpos); ++} ++ ++/** ++ * adjust_lpt_heap - move a changed heap entry up or down the heap. ++ * @c: UBIFS file-system description object ++ * @heap: LEB category heap ++ * @lprops: LEB properties to move ++ * @hpos: heap position of @lprops ++ * @cat: LEB category ++ * ++ * Changed entries in a heap are moved up or down until the parent's value is ++ * greater. In the case of LPT's category heaps, the value is either the amount ++ * of free space or the amount of dirty space, depending on the category. ++ */ ++static void adjust_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, ++ struct ubifs_lprops *lprops, int hpos, int cat) ++{ ++ int val1, val2, val3, cpos; ++ ++ val1 = get_heap_comp_val(lprops, cat); ++ /* Compare to parent and, if greater than parent, move up the heap */ ++ if (hpos) { ++ int ppos = (hpos - 1) / 2; ++ ++ val2 = get_heap_comp_val(heap->arr[ppos], cat); ++ if (val1 > val2) { ++ /* Greater than parent so move up */ ++ while (1) { ++ heap->arr[ppos]->hpos = hpos; ++ heap->arr[hpos] = heap->arr[ppos]; ++ heap->arr[ppos] = lprops; ++ lprops->hpos = ppos; ++ hpos = ppos; ++ if (!hpos) ++ return; ++ ppos = (hpos - 1) / 2; ++ val2 = get_heap_comp_val(heap->arr[ppos], cat); ++ if (val1 <= val2) ++ return; ++ /* Still greater than parent so keep going */ ++ } ++ } ++ } ++ /* Not greater than parent, so compare to children */ ++ while (1) { ++ /* Compare to left child */ ++ cpos = hpos * 2 + 1; ++ if (cpos >= heap->cnt) ++ return; ++ val2 = get_heap_comp_val(heap->arr[cpos], cat); ++ if (val1 < val2) { ++ /* Less than left child, so promote biggest child */ ++ if (cpos + 1 < heap->cnt) { ++ val3 = get_heap_comp_val(heap->arr[cpos + 1], ++ cat); ++ if (val3 > val2) ++ cpos += 1; /* Right child is bigger */ ++ } ++ heap->arr[cpos]->hpos = hpos; ++ heap->arr[hpos] = heap->arr[cpos]; ++ heap->arr[cpos] = lprops; ++ lprops->hpos = cpos; ++ hpos = cpos; ++ continue; ++ } ++ /* Compare to right child */ ++ cpos += 1; ++ if (cpos >= heap->cnt) ++ return; ++ val3 = get_heap_comp_val(heap->arr[cpos], cat); ++ if (val1 < val3) { ++ /* Less than right child, so promote right child */ ++ heap->arr[cpos]->hpos = hpos; ++ heap->arr[hpos] = heap->arr[cpos]; ++ heap->arr[cpos] = lprops; ++ lprops->hpos = cpos; ++ hpos = cpos; ++ continue; ++ } ++ return; ++ } ++} ++ ++/** ++ * add_to_lpt_heap - add LEB properties to a LEB category heap. ++ * @c: UBIFS file-system description object ++ * @lprops: LEB properties to add ++ * @cat: LEB category ++ * ++ * This function returns %1 if @lprops is added to the heap for LEB category ++ * @cat, otherwise %0 is returned because the heap is full. ++ */ ++static int add_to_lpt_heap(struct ubifs_info *c, struct ubifs_lprops *lprops, ++ int cat) ++{ ++ struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1]; ++ ++ if (heap->cnt >= heap->max_cnt) { ++ const int b = LPT_HEAP_SZ / 2 - 1; ++ int cpos, val1, val2; ++ ++ /* Compare to some other LEB on the bottom of heap */ ++ /* Pick a position kind of randomly */ ++ cpos = (((size_t)lprops >> 4) & b) + b; ++ ubifs_assert(cpos >= b); ++ ubifs_assert(cpos < LPT_HEAP_SZ); ++ ubifs_assert(cpos < heap->cnt); ++ ++ val1 = get_heap_comp_val(lprops, cat); ++ val2 = get_heap_comp_val(heap->arr[cpos], cat); ++ if (val1 > val2) { ++ struct ubifs_lprops *lp; ++ ++ lp = heap->arr[cpos]; ++ lp->flags &= ~LPROPS_CAT_MASK; ++ lp->flags |= LPROPS_UNCAT; ++ list_add(&lp->list, &c->uncat_list); ++ lprops->hpos = cpos; ++ heap->arr[cpos] = lprops; ++ move_up_lpt_heap(c, heap, lprops, cat); ++ dbg_check_heap(c, heap, cat, lprops->hpos); ++ return 1; /* Added to heap */ ++ } ++ dbg_check_heap(c, heap, cat, -1); ++ return 0; /* Not added to heap */ ++ } else { ++ lprops->hpos = heap->cnt++; ++ heap->arr[lprops->hpos] = lprops; ++ move_up_lpt_heap(c, heap, lprops, cat); ++ dbg_check_heap(c, heap, cat, lprops->hpos); ++ return 1; /* Added to heap */ ++ } ++} ++ ++/** ++ * remove_from_lpt_heap - remove LEB properties from a LEB category heap. ++ * @c: UBIFS file-system description object ++ * @lprops: LEB properties to remove ++ * @cat: LEB category ++ */ ++static void remove_from_lpt_heap(struct ubifs_info *c, ++ struct ubifs_lprops *lprops, int cat) ++{ ++ struct ubifs_lpt_heap *heap; ++ int hpos = lprops->hpos; ++ ++ heap = &c->lpt_heap[cat - 1]; ++ ubifs_assert(hpos >= 0 && hpos < heap->cnt); ++ ubifs_assert(heap->arr[hpos] == lprops); ++ heap->cnt -= 1; ++ if (hpos < heap->cnt) { ++ heap->arr[hpos] = heap->arr[heap->cnt]; ++ heap->arr[hpos]->hpos = hpos; ++ adjust_lpt_heap(c, heap, heap->arr[hpos], hpos, cat); ++ } ++ dbg_check_heap(c, heap, cat, -1); ++} ++ ++/** ++ * lpt_heap_replace - replace lprops in a category heap. ++ * @c: UBIFS file-system description object ++ * @old_lprops: LEB properties to replace ++ * @new_lprops: LEB properties with which to replace ++ * @cat: LEB category ++ * ++ * During commit it is sometimes necessary to copy a pnode (see dirty_cow_pnode) ++ * and the lprops that the pnode contains. When that happens, references in ++ * the category heaps to those lprops must be updated to point to the new ++ * lprops. This function does that. ++ */ ++static void lpt_heap_replace(struct ubifs_info *c, ++ struct ubifs_lprops *old_lprops, ++ struct ubifs_lprops *new_lprops, int cat) ++{ ++ struct ubifs_lpt_heap *heap; ++ int hpos = new_lprops->hpos; ++ ++ heap = &c->lpt_heap[cat - 1]; ++ heap->arr[hpos] = new_lprops; ++} ++ ++/** ++ * ubifs_add_to_cat - add LEB properties to a category list or heap. ++ * @c: UBIFS file-system description object ++ * @lprops: LEB properties to add ++ * @cat: LEB category to which to add ++ * ++ * LEB properties are categorized to enable fast find operations. ++ */ ++void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops, ++ int cat) ++{ ++ switch (cat) { ++ case LPROPS_DIRTY: ++ case LPROPS_DIRTY_IDX: ++ case LPROPS_FREE: ++ if (add_to_lpt_heap(c, lprops, cat)) ++ break; ++ /* No more room on heap so make it uncategorized */ ++ cat = LPROPS_UNCAT; ++ /* Fall through */ ++ case LPROPS_UNCAT: ++ list_add(&lprops->list, &c->uncat_list); ++ break; ++ case LPROPS_EMPTY: ++ list_add(&lprops->list, &c->empty_list); ++ break; ++ case LPROPS_FREEABLE: ++ list_add(&lprops->list, &c->freeable_list); ++ c->freeable_cnt += 1; ++ break; ++ case LPROPS_FRDI_IDX: ++ list_add(&lprops->list, &c->frdi_idx_list); ++ break; ++ default: ++ ubifs_assert(0); ++ } ++ lprops->flags &= ~LPROPS_CAT_MASK; ++ lprops->flags |= cat; ++} ++ ++/** ++ * ubifs_remove_from_cat - remove LEB properties from a category list or heap. ++ * @c: UBIFS file-system description object ++ * @lprops: LEB properties to remove ++ * @cat: LEB category from which to remove ++ * ++ * LEB properties are categorized to enable fast find operations. ++ */ ++static void ubifs_remove_from_cat(struct ubifs_info *c, ++ struct ubifs_lprops *lprops, int cat) ++{ ++ switch (cat) { ++ case LPROPS_DIRTY: ++ case LPROPS_DIRTY_IDX: ++ case LPROPS_FREE: ++ remove_from_lpt_heap(c, lprops, cat); ++ break; ++ case LPROPS_FREEABLE: ++ c->freeable_cnt -= 1; ++ ubifs_assert(c->freeable_cnt >= 0); ++ /* Fall through */ ++ case LPROPS_UNCAT: ++ case LPROPS_EMPTY: ++ case LPROPS_FRDI_IDX: ++ ubifs_assert(!list_empty(&lprops->list)); ++ list_del(&lprops->list); ++ break; ++ default: ++ ubifs_assert(0); ++ } ++} ++ ++/** ++ * ubifs_replace_cat - replace lprops in a category list or heap. ++ * @c: UBIFS file-system description object ++ * @old_lprops: LEB properties to replace ++ * @new_lprops: LEB properties with which to replace ++ * ++ * During commit it is sometimes necessary to copy a pnode (see dirty_cow_pnode) ++ * and the lprops that the pnode contains. When that happens, references in ++ * category lists and heaps must be replaced. This function does that. ++ */ ++void ubifs_replace_cat(struct ubifs_info *c, struct ubifs_lprops *old_lprops, ++ struct ubifs_lprops *new_lprops) ++{ ++ int cat; ++ ++ cat = new_lprops->flags & LPROPS_CAT_MASK; ++ switch (cat) { ++ case LPROPS_DIRTY: ++ case LPROPS_DIRTY_IDX: ++ case LPROPS_FREE: ++ lpt_heap_replace(c, old_lprops, new_lprops, cat); ++ break; ++ case LPROPS_UNCAT: ++ case LPROPS_EMPTY: ++ case LPROPS_FREEABLE: ++ case LPROPS_FRDI_IDX: ++ list_replace(&old_lprops->list, &new_lprops->list); ++ break; ++ default: ++ ubifs_assert(0); ++ } ++} ++ ++/** ++ * ubifs_ensure_cat - ensure LEB properties are categorized. ++ * @c: UBIFS file-system description object ++ * @lprops: LEB properties ++ * ++ * A LEB may have fallen off of the bottom of a heap, and ended up as ++ * uncategorized even though it has enough space for us now. If that is the case ++ * this function will put the LEB back onto a heap. ++ */ ++void ubifs_ensure_cat(struct ubifs_info *c, struct ubifs_lprops *lprops) ++{ ++ int cat = lprops->flags & LPROPS_CAT_MASK; ++ ++ if (cat != LPROPS_UNCAT) ++ return; ++ cat = ubifs_categorize_lprops(c, lprops); ++ if (cat == LPROPS_UNCAT) ++ return; ++ ubifs_remove_from_cat(c, lprops, LPROPS_UNCAT); ++ ubifs_add_to_cat(c, lprops, cat); ++} ++ ++/** ++ * ubifs_categorize_lprops - categorize LEB properties. ++ * @c: UBIFS file-system description object ++ * @lprops: LEB properties to categorize ++ * ++ * LEB properties are categorized to enable fast find operations. This function ++ * returns the LEB category to which the LEB properties belong. Note however ++ * that if the LEB category is stored as a heap and the heap is full, the ++ * LEB properties may have their category changed to %LPROPS_UNCAT. ++ */ ++int ubifs_categorize_lprops(const struct ubifs_info *c, ++ const struct ubifs_lprops *lprops) ++{ ++ if (lprops->flags & LPROPS_TAKEN) ++ return LPROPS_UNCAT; ++ ++ if (lprops->free == c->leb_size) { ++ ubifs_assert(!(lprops->flags & LPROPS_INDEX)); ++ return LPROPS_EMPTY; ++ } ++ ++ if (lprops->free + lprops->dirty == c->leb_size) { ++ if (lprops->flags & LPROPS_INDEX) ++ return LPROPS_FRDI_IDX; ++ else ++ return LPROPS_FREEABLE; ++ } ++ ++ if (lprops->flags & LPROPS_INDEX) { ++ if (lprops->dirty + lprops->free >= c->min_idx_node_sz) ++ return LPROPS_DIRTY_IDX; ++ } else { ++ if (lprops->dirty >= c->dead_wm && ++ lprops->dirty > lprops->free) ++ return LPROPS_DIRTY; ++ if (lprops->free > 0) ++ return LPROPS_FREE; ++ } ++ ++ return LPROPS_UNCAT; ++} ++ ++/** ++ * change_category - change LEB properties category. ++ * @c: UBIFS file-system description object ++ * @lprops: LEB properties to recategorize ++ * ++ * LEB properties are categorized to enable fast find operations. When the LEB ++ * properties change they must be recategorized. ++ */ ++static void change_category(struct ubifs_info *c, struct ubifs_lprops *lprops) ++{ ++ int old_cat = lprops->flags & LPROPS_CAT_MASK; ++ int new_cat = ubifs_categorize_lprops(c, lprops); ++ ++ if (old_cat == new_cat) { ++ struct ubifs_lpt_heap *heap = &c->lpt_heap[new_cat - 1]; ++ ++ /* lprops on a heap now must be moved up or down */ ++ if (new_cat < 1 || new_cat > LPROPS_HEAP_CNT) ++ return; /* Not on a heap */ ++ heap = &c->lpt_heap[new_cat - 1]; ++ adjust_lpt_heap(c, heap, lprops, lprops->hpos, new_cat); ++ } else { ++ ubifs_remove_from_cat(c, lprops, old_cat); ++ ubifs_add_to_cat(c, lprops, new_cat); ++ } ++} ++ ++/** ++ * ubifs_get_lprops - get reference to LEB properties. ++ * @c: the UBIFS file-system description object ++ * ++ * This function locks lprops. Lprops have to be unlocked by ++ * 'ubifs_release_lprops()'. ++ */ ++void ubifs_get_lprops(struct ubifs_info *c) ++{ ++ mutex_lock(&c->lp_mutex); ++} ++ ++/** ++ * calc_dark - calculate LEB dark space size. ++ * @c: the UBIFS file-system description object ++ * @spc: amount of free and dirty space in the LEB ++ * ++ * This function calculates amount of dark space in an LEB which has @spc bytes ++ * of free and dirty space. Returns the calculations result. ++ * ++ * Dark space is the space which is not always usable - it depends on which ++ * nodes are written in which order. E.g., if an LEB has only 512 free bytes, ++ * it is dark space, because it cannot fit a large data node. So UBIFS cannot ++ * count on this LEB and treat these 512 bytes as usable because it is not true ++ * if, for example, only big chunks of uncompressible data will be written to ++ * the FS. ++ */ ++static int calc_dark(struct ubifs_info *c, int spc) ++{ ++ ubifs_assert(!(spc & 7)); ++ ++ if (spc < c->dark_wm) ++ return spc; ++ ++ /* ++ * If we have slightly more space then the dark space watermark, we can ++ * anyway safely assume it we'll be able to write a node of the ++ * smallest size there. ++ */ ++ if (spc - c->dark_wm < MIN_WRITE_SZ) ++ return spc - MIN_WRITE_SZ; ++ ++ return c->dark_wm; ++} ++ ++/** ++ * is_lprops_dirty - determine if LEB properties are dirty. ++ * @c: the UBIFS file-system description object ++ * @lprops: LEB properties to test ++ */ ++static int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops) ++{ ++ struct ubifs_pnode *pnode; ++ int pos; ++ ++ pos = (lprops->lnum - c->main_first) & (UBIFS_LPT_FANOUT - 1); ++ pnode = (struct ubifs_pnode *)container_of(lprops - pos, ++ struct ubifs_pnode, ++ lprops[0]); ++ return !test_bit(COW_ZNODE, &pnode->flags) && ++ test_bit(DIRTY_CNODE, &pnode->flags); ++} ++ ++/** ++ * ubifs_change_lp - change LEB properties. ++ * @c: the UBIFS file-system description object ++ * @lp: LEB properties to change ++ * @free: new free space amount ++ * @dirty: new dirty space amount ++ * @flags: new flags ++ * @idx_gc_cnt: change to the count of idx_gc list ++ * ++ * This function changes LEB properties. This function does not change a LEB ++ * property (@free, @dirty or @flag) if the value passed is %LPROPS_NC. ++ * ++ * This function returns a pointer to the updated LEB properties on success ++ * and a negative error code on failure. N.B. the LEB properties may have had to ++ * be copied (due to COW) and consequently the pointer returned may not be the ++ * same as the pointer passed. ++ */ ++const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c, ++ const struct ubifs_lprops *lp, ++ int free, int dirty, int flags, ++ int idx_gc_cnt) ++{ ++ /* ++ * This is the only function that is allowed to change lprops, so we ++ * discard the const qualifier. ++ */ ++ struct ubifs_lprops *lprops = (struct ubifs_lprops *)lp; ++ ++ dbg_lp("LEB %d, free %d, dirty %d, flags %d", ++ lprops->lnum, free, dirty, flags); ++ ++ ubifs_assert(mutex_is_locked(&c->lp_mutex)); ++ ubifs_assert(c->lst.empty_lebs >= 0 && ++ c->lst.empty_lebs <= c->main_lebs); ++ ubifs_assert(c->freeable_cnt >= 0); ++ ubifs_assert(c->freeable_cnt <= c->main_lebs); ++ ubifs_assert(c->lst.taken_empty_lebs >= 0); ++ ubifs_assert(c->lst.taken_empty_lebs <= c->lst.empty_lebs); ++ ubifs_assert(!(c->lst.total_free & 7) && !(c->lst.total_dirty & 7)); ++ ubifs_assert(!(c->lst.total_dead & 7) && !(c->lst.total_dark & 7)); ++ ubifs_assert(!(c->lst.total_used & 7)); ++ ubifs_assert(free == LPROPS_NC || free >= 0); ++ ubifs_assert(dirty == LPROPS_NC || dirty >= 0); ++ ++ if (!is_lprops_dirty(c, lprops)) { ++ lprops = ubifs_lpt_lookup_dirty(c, lprops->lnum); ++ if (IS_ERR(lprops)) ++ return lprops; ++ } else ++ ubifs_assert(lprops == ubifs_lpt_lookup_dirty(c, lprops->lnum)); ++ ++ ubifs_assert(!(lprops->free & 7) && !(lprops->dirty & 7)); ++ ++ spin_lock(&c->space_lock); ++ ++ if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size) ++ c->lst.taken_empty_lebs -= 1; ++ ++ if (!(lprops->flags & LPROPS_INDEX)) { ++ int old_spc; ++ ++ old_spc = lprops->free + lprops->dirty; ++ if (old_spc < c->dead_wm) ++ c->lst.total_dead -= old_spc; ++ else ++ c->lst.total_dark -= calc_dark(c, old_spc); ++ ++ c->lst.total_used -= c->leb_size - old_spc; ++ } ++ ++ if (free != LPROPS_NC) { ++ free = ALIGN(free, 8); ++ c->lst.total_free += free - lprops->free; ++ ++ /* Increase or decrease empty LEBs counter if needed */ ++ if (free == c->leb_size) { ++ if (lprops->free != c->leb_size) ++ c->lst.empty_lebs += 1; ++ } else if (lprops->free == c->leb_size) ++ c->lst.empty_lebs -= 1; ++ lprops->free = free; ++ } ++ ++ if (dirty != LPROPS_NC) { ++ dirty = ALIGN(dirty, 8); ++ c->lst.total_dirty += dirty - lprops->dirty; ++ lprops->dirty = dirty; ++ } ++ ++ if (flags != LPROPS_NC) { ++ /* Take care about indexing LEBs counter if needed */ ++ if ((lprops->flags & LPROPS_INDEX)) { ++ if (!(flags & LPROPS_INDEX)) ++ c->lst.idx_lebs -= 1; ++ } else if (flags & LPROPS_INDEX) ++ c->lst.idx_lebs += 1; ++ lprops->flags = flags; ++ } ++ ++ if (!(lprops->flags & LPROPS_INDEX)) { ++ int new_spc; ++ ++ new_spc = lprops->free + lprops->dirty; ++ if (new_spc < c->dead_wm) ++ c->lst.total_dead += new_spc; ++ else ++ c->lst.total_dark += calc_dark(c, new_spc); ++ ++ c->lst.total_used += c->leb_size - new_spc; ++ } ++ ++ if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size) ++ c->lst.taken_empty_lebs += 1; ++ ++ change_category(c, lprops); ++ ++ c->idx_gc_cnt += idx_gc_cnt; ++ ++ spin_unlock(&c->space_lock); ++ ++ return lprops; ++} ++ ++/** ++ * ubifs_release_lprops - release lprops lock. ++ * @c: the UBIFS file-system description object ++ * ++ * This function has to be called after each 'ubifs_get_lprops()' call to ++ * unlock lprops. ++ */ ++void ubifs_release_lprops(struct ubifs_info *c) ++{ ++ ubifs_assert(mutex_is_locked(&c->lp_mutex)); ++ ubifs_assert(c->lst.empty_lebs >= 0 && ++ c->lst.empty_lebs <= c->main_lebs); ++ ++ mutex_unlock(&c->lp_mutex); ++} ++ ++/** ++ * ubifs_get_lp_stats - get lprops statistics. ++ * @c: UBIFS file-system description object ++ * @st: return statistics ++ */ ++void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *st) ++{ ++ spin_lock(&c->space_lock); ++ memcpy(st, &c->lst, sizeof(struct ubifs_lp_stats)); ++ spin_unlock(&c->space_lock); ++} ++ ++/** ++ * ubifs_change_one_lp - change LEB properties. ++ * @c: the UBIFS file-system description object ++ * @lnum: LEB to change properties for ++ * @free: amount of free space ++ * @dirty: amount of dirty space ++ * @flags_set: flags to set ++ * @flags_clean: flags to clean ++ * @idx_gc_cnt: change to the count of idx_gc list ++ * ++ * This function changes properties of LEB @lnum. It is a helper wrapper over ++ * 'ubifs_change_lp()' which hides lprops get/release. The arguments are the ++ * same as in case of 'ubifs_change_lp()'. Returns zero in case of success and ++ * a negative error code in case of failure. ++ */ ++int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty, ++ int flags_set, int flags_clean, int idx_gc_cnt) ++{ ++ int err = 0, flags; ++ const struct ubifs_lprops *lp; ++ ++ ubifs_get_lprops(c); ++ ++ lp = ubifs_lpt_lookup_dirty(c, lnum); ++ if (IS_ERR(lp)) { ++ err = PTR_ERR(lp); ++ goto out; ++ } ++ ++ flags = (lp->flags | flags_set) & ~flags_clean; ++ lp = ubifs_change_lp(c, lp, free, dirty, flags, idx_gc_cnt); ++ if (IS_ERR(lp)) ++ err = PTR_ERR(lp); ++ ++out: ++ ubifs_release_lprops(c); ++ return err; ++} ++ ++/** ++ * ubifs_update_one_lp - update LEB properties. ++ * @c: the UBIFS file-system description object ++ * @lnum: LEB to change properties for ++ * @free: amount of free space ++ * @dirty: amount of dirty space to add ++ * @flags_set: flags to set ++ * @flags_clean: flags to clean ++ * ++ * This function is the same as 'ubifs_change_one_lp()' but @dirty is added to ++ * current dirty space, not substitutes it. ++ */ ++int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty, ++ int flags_set, int flags_clean) ++{ ++ int err = 0, flags; ++ const struct ubifs_lprops *lp; ++ ++ ubifs_get_lprops(c); ++ ++ lp = ubifs_lpt_lookup_dirty(c, lnum); ++ if (IS_ERR(lp)) { ++ err = PTR_ERR(lp); ++ goto out; ++ } ++ ++ flags = (lp->flags | flags_set) & ~flags_clean; ++ lp = ubifs_change_lp(c, lp, free, lp->dirty + dirty, flags, 0); ++ if (IS_ERR(lp)) ++ err = PTR_ERR(lp); ++ ++out: ++ ubifs_release_lprops(c); ++ return err; ++} ++ ++/** ++ * ubifs_read_one_lp - read LEB properties. ++ * @c: the UBIFS file-system description object ++ * @lnum: LEB to read properties for ++ * @lp: where to store read properties ++ * ++ * This helper function reads properties of a LEB @lnum and stores them in @lp. ++ * Returns zero in case of success and a negative error code in case of ++ * failure. ++ */ ++int ubifs_read_one_lp(struct ubifs_info *c, int lnum, struct ubifs_lprops *lp) ++{ ++ int err = 0; ++ const struct ubifs_lprops *lpp; ++ ++ ubifs_get_lprops(c); ++ ++ lpp = ubifs_lpt_lookup(c, lnum); ++ if (IS_ERR(lpp)) { ++ err = PTR_ERR(lpp); ++ goto out; ++ } ++ ++ memcpy(lp, lpp, sizeof(struct ubifs_lprops)); ++ ++out: ++ ubifs_release_lprops(c); ++ return err; ++} ++ ++/** ++ * ubifs_fast_find_free - try to find a LEB with free space quickly. ++ * @c: the UBIFS file-system description object ++ * ++ * This function returns LEB properties for a LEB with free space or %NULL if ++ * the function is unable to find a LEB quickly. ++ */ ++const struct ubifs_lprops *ubifs_fast_find_free(struct ubifs_info *c) ++{ ++ struct ubifs_lprops *lprops; ++ struct ubifs_lpt_heap *heap; ++ ++ ubifs_assert(mutex_is_locked(&c->lp_mutex)); ++ ++ heap = &c->lpt_heap[LPROPS_FREE - 1]; ++ if (heap->cnt == 0) ++ return NULL; ++ ++ lprops = heap->arr[0]; ++ ubifs_assert(!(lprops->flags & LPROPS_TAKEN)); ++ ubifs_assert(!(lprops->flags & LPROPS_INDEX)); ++ return lprops; ++} ++ ++/** ++ * ubifs_fast_find_empty - try to find an empty LEB quickly. ++ * @c: the UBIFS file-system description object ++ * ++ * This function returns LEB properties for an empty LEB or %NULL if the ++ * function is unable to find an empty LEB quickly. ++ */ ++const struct ubifs_lprops *ubifs_fast_find_empty(struct ubifs_info *c) ++{ ++ struct ubifs_lprops *lprops; ++ ++ ubifs_assert(mutex_is_locked(&c->lp_mutex)); ++ ++ if (list_empty(&c->empty_list)) ++ return NULL; ++ ++ lprops = list_entry(c->empty_list.next, struct ubifs_lprops, list); ++ ubifs_assert(!(lprops->flags & LPROPS_TAKEN)); ++ ubifs_assert(!(lprops->flags & LPROPS_INDEX)); ++ ubifs_assert(lprops->free == c->leb_size); ++ return lprops; ++} ++ ++/** ++ * ubifs_fast_find_freeable - try to find a freeable LEB quickly. ++ * @c: the UBIFS file-system description object ++ * ++ * This function returns LEB properties for a freeable LEB or %NULL if the ++ * function is unable to find a freeable LEB quickly. ++ */ ++const struct ubifs_lprops *ubifs_fast_find_freeable(struct ubifs_info *c) ++{ ++ struct ubifs_lprops *lprops; ++ ++ ubifs_assert(mutex_is_locked(&c->lp_mutex)); ++ ++ if (list_empty(&c->freeable_list)) ++ return NULL; ++ ++ lprops = list_entry(c->freeable_list.next, struct ubifs_lprops, list); ++ ubifs_assert(!(lprops->flags & LPROPS_TAKEN)); ++ ubifs_assert(!(lprops->flags & LPROPS_INDEX)); ++ ubifs_assert(lprops->free + lprops->dirty == c->leb_size); ++ ubifs_assert(c->freeable_cnt > 0); ++ return lprops; ++} ++ ++/** ++ * ubifs_fast_find_frdi_idx - try to find a freeable index LEB quickly. ++ * @c: the UBIFS file-system description object ++ * ++ * This function returns LEB properties for a freeable index LEB or %NULL if the ++ * function is unable to find a freeable index LEB quickly. ++ */ ++const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c) ++{ ++ struct ubifs_lprops *lprops; ++ ++ ubifs_assert(mutex_is_locked(&c->lp_mutex)); ++ ++ if (list_empty(&c->frdi_idx_list)) ++ return NULL; ++ ++ lprops = list_entry(c->frdi_idx_list.next, struct ubifs_lprops, list); ++ ubifs_assert(!(lprops->flags & LPROPS_TAKEN)); ++ ubifs_assert((lprops->flags & LPROPS_INDEX)); ++ ubifs_assert(lprops->free + lprops->dirty == c->leb_size); ++ return lprops; ++} ++ ++#ifdef CONFIG_UBIFS_FS_DEBUG ++ ++/** ++ * dbg_check_cats - check category heaps and lists. ++ * @c: UBIFS file-system description object ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++int dbg_check_cats(struct ubifs_info *c) ++{ ++ struct ubifs_lprops *lprops; ++ struct list_head *pos; ++ int i, cat; ++ ++ if (!(ubifs_chk_flags & (UBIFS_CHK_GEN | UBIFS_CHK_LPROPS))) ++ return 0; ++ ++ list_for_each_entry(lprops, &c->empty_list, list) { ++ if (lprops->free != c->leb_size) { ++ ubifs_err("non-empty LEB %d on empty list " ++ "(free %d dirty %d flags %d)", lprops->lnum, ++ lprops->free, lprops->dirty, lprops->flags); ++ return -EINVAL; ++ } ++ if (lprops->flags & LPROPS_TAKEN) { ++ ubifs_err("taken LEB %d on empty list " ++ "(free %d dirty %d flags %d)", lprops->lnum, ++ lprops->free, lprops->dirty, lprops->flags); ++ return -EINVAL; ++ } ++ } ++ ++ i = 0; ++ list_for_each_entry(lprops, &c->freeable_list, list) { ++ if (lprops->free + lprops->dirty != c->leb_size) { ++ ubifs_err("non-freeable LEB %d on freeable list " ++ "(free %d dirty %d flags %d)", lprops->lnum, ++ lprops->free, lprops->dirty, lprops->flags); ++ return -EINVAL; ++ } ++ if (lprops->flags & LPROPS_TAKEN) { ++ ubifs_err("taken LEB %d on freeable list " ++ "(free %d dirty %d flags %d)", lprops->lnum, ++ lprops->free, lprops->dirty, lprops->flags); ++ return -EINVAL; ++ } ++ i += 1; ++ } ++ if (i != c->freeable_cnt) { ++ ubifs_err("freeable list count %d expected %d", i, ++ c->freeable_cnt); ++ return -EINVAL; ++ } ++ ++ i = 0; ++ list_for_each(pos, &c->idx_gc) ++ i += 1; ++ if (i != c->idx_gc_cnt) { ++ ubifs_err("idx_gc list count %d expected %d", i, ++ c->idx_gc_cnt); ++ return -EINVAL; ++ } ++ ++ list_for_each_entry(lprops, &c->frdi_idx_list, list) { ++ if (lprops->free + lprops->dirty != c->leb_size) { ++ ubifs_err("non-freeable LEB %d on frdi_idx list " ++ "(free %d dirty %d flags %d)", lprops->lnum, ++ lprops->free, lprops->dirty, lprops->flags); ++ return -EINVAL; ++ } ++ if (lprops->flags & LPROPS_TAKEN) { ++ ubifs_err("taken LEB %d on frdi_idx list " ++ "(free %d dirty %d flags %d)", lprops->lnum, ++ lprops->free, lprops->dirty, lprops->flags); ++ return -EINVAL; ++ } ++ if (!(lprops->flags & LPROPS_INDEX)) { ++ ubifs_err("non-index LEB %d on frdi_idx list " ++ "(free %d dirty %d flags %d)", lprops->lnum, ++ lprops->free, lprops->dirty, lprops->flags); ++ return -EINVAL; ++ } ++ } ++ ++ for (cat = 1; cat <= LPROPS_HEAP_CNT; cat++) { ++ struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1]; ++ ++ for (i = 0; i < heap->cnt; i++) { ++ lprops = heap->arr[i]; ++ if (!lprops) { ++ ubifs_err("null ptr in LPT heap cat %d", cat); ++ return -EINVAL; ++ } ++ if (lprops->hpos != i) { ++ ubifs_err("bad ptr in LPT heap cat %d", cat); ++ return -EINVAL; ++ } ++ if (lprops->flags & LPROPS_TAKEN) { ++ ubifs_err("taken LEB in LPT heap cat %d", cat); ++ return -EINVAL; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat, ++ int add_pos) ++{ ++ int i = 0, j, err = 0; ++ ++ if (!(ubifs_chk_flags & (UBIFS_CHK_GEN | UBIFS_CHK_LPROPS))) ++ return; ++ ++ for (i = 0; i < heap->cnt; i++) { ++ struct ubifs_lprops *lprops = heap->arr[i]; ++ struct ubifs_lprops *lp; ++ ++ if (i != add_pos) ++ if ((lprops->flags & LPROPS_CAT_MASK) != cat) { ++ err = 1; ++ goto out; ++ } ++ if (lprops->hpos != i) { ++ err = 2; ++ goto out; ++ } ++ lp = ubifs_lpt_lookup(c, lprops->lnum); ++ if (IS_ERR(lp)) { ++ err = 3; ++ goto out; ++ } ++ if (lprops != lp) { ++ dbg_msg("lprops %zx lp %zx lprops->lnum %d lp->lnum %d", ++ (size_t)lprops, (size_t)lp, lprops->lnum, ++ lp->lnum); ++ err = 4; ++ goto out; ++ } ++ for (j = 0; j < i; j++) { ++ lp = heap->arr[j]; ++ if (lp == lprops) { ++ err = 5; ++ goto out; ++ } ++ if (lp->lnum == lprops->lnum) { ++ err = 6; ++ goto out; ++ } ++ } ++ } ++out: ++ if (err) { ++ dbg_msg("failed cat %d hpos %d err %d", cat, i, err); ++ dbg_dump_stack(); ++ dbg_dump_heap(c, heap, cat); ++ } ++} ++ ++/** ++ * struct scan_check_data - data provided to scan callback function. ++ * @lst: LEB properties statistics ++ * @err: error code ++ */ ++struct scan_check_data { ++ struct ubifs_lp_stats lst; ++ int err; ++}; ++ ++/** ++ * scan_check_cb - scan callback. ++ * @c: the UBIFS file-system description object ++ * @lp: LEB properties to scan ++ * @in_tree: whether the LEB properties are in main memory ++ * @data: information passed to and from the caller of the scan ++ * ++ * This function returns a code that indicates whether the scan should continue ++ * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree ++ * in main memory (%LPT_SCAN_ADD), or whether the scan should stop ++ * (%LPT_SCAN_STOP). ++ */ ++static int scan_check_cb(struct ubifs_info *c, ++ const struct ubifs_lprops *lp, int in_tree, ++ struct scan_check_data *data) ++{ ++ struct ubifs_scan_leb *sleb; ++ struct ubifs_scan_node *snod; ++ struct ubifs_lp_stats *lst = &data->lst; ++ int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty; ++ ++ cat = lp->flags & LPROPS_CAT_MASK; ++ if (cat != LPROPS_UNCAT) { ++ cat = ubifs_categorize_lprops(c, lp); ++ if (cat != (lp->flags & LPROPS_CAT_MASK)) { ++ ubifs_err("bad LEB category %d expected %d", ++ (lp->flags & LPROPS_CAT_MASK), cat); ++ goto out; ++ } ++ } ++ ++ /* Check lp is on its category list (if it has one) */ ++ if (in_tree) { ++ struct list_head *list = NULL; ++ ++ switch (cat) { ++ case LPROPS_EMPTY: ++ list = &c->empty_list; ++ break; ++ case LPROPS_FREEABLE: ++ list = &c->freeable_list; ++ break; ++ case LPROPS_FRDI_IDX: ++ list = &c->frdi_idx_list; ++ break; ++ case LPROPS_UNCAT: ++ list = &c->uncat_list; ++ break; ++ } ++ if (list) { ++ struct ubifs_lprops *lprops; ++ int found = 0; ++ ++ list_for_each_entry(lprops, list, list) { ++ if (lprops == lp) { ++ found = 1; ++ break; ++ } ++ } ++ if (!found) { ++ ubifs_err("bad LPT list (category %d)", cat); ++ goto out; ++ } ++ } ++ } ++ ++ /* Check lp is on its category heap (if it has one) */ ++ if (in_tree && cat > 0 && cat <= LPROPS_HEAP_CNT) { ++ struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1]; ++ ++ if ((lp->hpos != -1 && heap->arr[lp->hpos]->lnum != lnum) || ++ lp != heap->arr[lp->hpos]) { ++ ubifs_err("bad LPT heap (category %d)", cat); ++ goto out; ++ } ++ } ++ ++ sleb = ubifs_scan(c, lnum, 0, c->dbg_buf); ++ if (IS_ERR(sleb)) { ++ /* ++ * After an unclean unmount, empty and freeable LEBs ++ * may contain garbage. ++ */ ++ if (lp->free == c->leb_size) { ++ ubifs_err("scan errors were in empty LEB " ++ "- continuing checking"); ++ lst->empty_lebs += 1; ++ lst->total_free += c->leb_size; ++ lst->total_dark += calc_dark(c, c->leb_size); ++ return LPT_SCAN_CONTINUE; ++ } ++ ++ if (lp->free + lp->dirty == c->leb_size && ++ !(lp->flags & LPROPS_INDEX)) { ++ ubifs_err("scan errors were in freeable LEB " ++ "- continuing checking"); ++ lst->total_free += lp->free; ++ lst->total_dirty += lp->dirty; ++ lst->total_dark += calc_dark(c, c->leb_size); ++ return LPT_SCAN_CONTINUE; ++ } ++ data->err = PTR_ERR(sleb); ++ return LPT_SCAN_STOP; ++ } ++ ++ is_idx = -1; ++ list_for_each_entry(snod, &sleb->nodes, list) { ++ int found, level = 0; ++ ++ cond_resched(); ++ ++ if (is_idx == -1) ++ is_idx = (snod->type == UBIFS_IDX_NODE) ? 1 : 0; ++ ++ if (is_idx && snod->type != UBIFS_IDX_NODE) { ++ ubifs_err("indexing node in data LEB %d:%d", ++ lnum, snod->offs); ++ goto out_destroy; ++ } ++ ++ if (snod->type == UBIFS_IDX_NODE) { ++ struct ubifs_idx_node *idx = snod->node; ++ ++ key_read(c, ubifs_idx_key(c, idx), &snod->key); ++ level = le16_to_cpu(idx->level); ++ } ++ ++ found = ubifs_tnc_has_node(c, &snod->key, level, lnum, ++ snod->offs, is_idx); ++ if (found) { ++ if (found < 0) ++ goto out_destroy; ++ used += ALIGN(snod->len, 8); ++ } ++ } ++ ++ free = c->leb_size - sleb->endpt; ++ dirty = sleb->endpt - used; ++ ++ if (free > c->leb_size || free < 0 || dirty > c->leb_size || ++ dirty < 0) { ++ ubifs_err("bad calculated accounting for LEB %d: " ++ "free %d, dirty %d", lnum, free, dirty); ++ goto out_destroy; ++ } ++ ++ if (lp->free + lp->dirty == c->leb_size && ++ free + dirty == c->leb_size) ++ if ((is_idx && !(lp->flags & LPROPS_INDEX)) || ++ (!is_idx && free == c->leb_size)) { ++ /* ++ * Empty or freeable LEBs could contain index ++ * nodes from an uncompleted commit due to an ++ * unclean unmount. Or they could be empty for ++ * the same reason. ++ */ ++ free = lp->free; ++ dirty = lp->dirty; ++ is_idx = 0; ++ } ++ ++ if (is_idx && lp->free + lp->dirty == free + dirty && ++ lnum != c->ihead_lnum) { ++ /* ++ * After an unclean unmount, an index LEB could have a different ++ * amount of free space than the value recorded by lprops. That ++ * is because the in-the-gaps method may use free space or ++ * create free space (as a side-effect of using ubi_leb_change ++ * and not writing the whole LEB). The incorrect free space ++ * value is not a problem because the index is only ever ++ * allocated empty LEBs, so there will never be an attempt to ++ * write to the free space at the end of an index LEB - except ++ * by the in-the-gaps method for which it is not a problem. ++ */ ++ free = lp->free; ++ dirty = lp->dirty; ++ } ++ ++ if (lp->free != free || lp->dirty != dirty) ++ goto out_print; ++ ++ if (is_idx && !(lp->flags & LPROPS_INDEX)) { ++ if (free == c->leb_size) ++ /* Free but not unmapped LEB, it's fine */ ++ is_idx = 0; ++ else { ++ ubifs_err("indexing node without indexing " ++ "flag"); ++ goto out_print; ++ } ++ } ++ ++ if (!is_idx && (lp->flags & LPROPS_INDEX)) { ++ ubifs_err("data node with indexing flag"); ++ goto out_print; ++ } ++ ++ if (free == c->leb_size) ++ lst->empty_lebs += 1; ++ ++ if (is_idx) ++ lst->idx_lebs += 1; ++ ++ if (!(lp->flags & LPROPS_INDEX)) ++ lst->total_used += c->leb_size - free - dirty; ++ lst->total_free += free; ++ lst->total_dirty += dirty; ++ ++ if (!(lp->flags & LPROPS_INDEX)) { ++ int spc = free + dirty; ++ ++ if (spc < c->dead_wm) ++ lst->total_dead += spc; ++ else ++ lst->total_dark += calc_dark(c, spc); ++ } ++ ++ ubifs_scan_destroy(sleb); ++ ++ return LPT_SCAN_CONTINUE; ++ ++out_print: ++ ubifs_err("bad accounting of LEB %d: free %d, dirty %d flags %#x, " ++ "should be free %d, dirty %d", ++ lnum, lp->free, lp->dirty, lp->flags, free, dirty); ++ dbg_dump_leb(c, lnum); ++out_destroy: ++ ubifs_scan_destroy(sleb); ++out: ++ data->err = -EINVAL; ++ return LPT_SCAN_STOP; ++} ++ ++/** ++ * dbg_check_lprops - check all LEB properties. ++ * @c: UBIFS file-system description object ++ * ++ * This function checks all LEB properties and makes sure they are all correct. ++ * It returns zero if everything is fine, %-EINVAL if there is an inconsistency ++ * and other negative error codes in case of other errors. This function is ++ * called while the file system is locked (because of commit start), so no ++ * additional locking is required. Note that locking the LPT mutex would cause ++ * a circular lock dependency with the TNC mutex. ++ */ ++int dbg_check_lprops(struct ubifs_info *c) ++{ ++ int i, err; ++ struct scan_check_data data; ++ struct ubifs_lp_stats *lst = &data.lst; ++ ++ if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) ++ return 0; ++ ++ /* ++ * As we are going to scan the media, the write buffers have to be ++ * synchronized. ++ */ ++ for (i = 0; i < c->jhead_cnt; i++) { ++ err = ubifs_wbuf_sync(&c->jheads[i].wbuf); ++ if (err) ++ return err; ++ } ++ ++ memset(lst, 0, sizeof(struct ubifs_lp_stats)); ++ ++ data.err = 0; ++ err = ubifs_lpt_scan_nolock(c, c->main_first, c->leb_cnt - 1, ++ (ubifs_lpt_scan_callback)scan_check_cb, ++ &data); ++ if (err && err != -ENOSPC) ++ goto out; ++ if (data.err) { ++ err = data.err; ++ goto out; ++ } ++ ++ if (lst->empty_lebs != c->lst.empty_lebs || ++ lst->idx_lebs != c->lst.idx_lebs || ++ lst->total_free != c->lst.total_free || ++ lst->total_dirty != c->lst.total_dirty || ++ lst->total_used != c->lst.total_used) { ++ ubifs_err("bad overall accounting"); ++ ubifs_err("calculated: empty_lebs %d, idx_lebs %d, " ++ "total_free %lld, total_dirty %lld, total_used %lld", ++ lst->empty_lebs, lst->idx_lebs, lst->total_free, ++ lst->total_dirty, lst->total_used); ++ ubifs_err("read from lprops: empty_lebs %d, idx_lebs %d, " ++ "total_free %lld, total_dirty %lld, total_used %lld", ++ c->lst.empty_lebs, c->lst.idx_lebs, c->lst.total_free, ++ c->lst.total_dirty, c->lst.total_used); ++ err = -EINVAL; ++ goto out; ++ } ++ ++ if (lst->total_dead != c->lst.total_dead || ++ lst->total_dark != c->lst.total_dark) { ++ ubifs_err("bad dead/dark space accounting"); ++ ubifs_err("calculated: total_dead %lld, total_dark %lld", ++ lst->total_dead, lst->total_dark); ++ ubifs_err("read from lprops: total_dead %lld, total_dark %lld", ++ c->lst.total_dead, c->lst.total_dark); ++ err = -EINVAL; ++ goto out; ++ } ++ ++ err = dbg_check_cats(c); ++out: ++ return err; ++} ++ ++#endif /* CONFIG_UBIFS_FS_DEBUG */ +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/lpt.c avr32-2.6/fs/ubifs/lpt.c +--- linux-2.6.25.6/fs/ubifs/lpt.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/lpt.c 2008-06-12 15:09:45.475816115 +0200 +@@ -0,0 +1,2241 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Adrian Hunter ++ * Artem Bityutskiy (Битюцкий Артём) ++ */ ++ ++/* ++ * This file implements the LEB properties tree (LPT) area. The LPT area ++ * contains the LEB properties tree, a table of LPT area eraseblocks (ltab), and ++ * (for the "big" model) a table of saved LEB numbers (lsave). The LPT area sits ++ * between the log and the orphan area. ++ * ++ * The LPT area is like a miniature self-contained file system. It is required ++ * that it never runs out of space, is fast to access and update, and scales ++ * logarithmically. The LEB properties tree is implemented as a wandering tree ++ * much like the TNC, and the LPT area has its own garbage collection. ++ * ++ * The LPT has two slightly different forms called the "small model" and the ++ * "big model". The small model is used when the entire LEB properties table ++ * can be written into a single eraseblock. In that case, garbage collection ++ * consists of just writing the whole table, which therefore makes all other ++ * eraseblocks reusable. In the case of the big model, dirty eraseblocks are ++ * selected for garbage collection, which consists are marking the nodes in ++ * that LEB as dirty, and then only the dirty nodes are written out. Also, in ++ * the case of the big model, a table of LEB numbers is saved so that the entire ++ * LPT does not to be scanned looking for empty eraseblocks when UBIFS is first ++ * mounted. ++ */ ++ ++#include <linux/crc16.h> ++#include "ubifs.h" ++ ++/** ++ * do_calc_lpt_geom - calculate sizes for the LPT area. ++ * @c: the UBIFS file-system description object ++ * ++ * Calculate the sizes of LPT bit fields, nodes, and tree, based on the ++ * properties of the flash and whether LPT is "big" (c->big_lpt). ++ */ ++static void do_calc_lpt_geom(struct ubifs_info *c) ++{ ++ int i, n, bits, per_leb_wastage, max_pnode_cnt; ++ long long sz, tot_wastage; ++ ++ n = c->main_lebs + c->max_leb_cnt - c->leb_cnt; ++ max_pnode_cnt = DIV_ROUND_UP(n, UBIFS_LPT_FANOUT); ++ ++ c->lpt_hght = 1; ++ n = UBIFS_LPT_FANOUT; ++ while (n < max_pnode_cnt) { ++ c->lpt_hght += 1; ++ n <<= UBIFS_LPT_FANOUT_SHIFT; ++ } ++ ++ c->pnode_cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT); ++ ++ n = DIV_ROUND_UP(c->pnode_cnt, UBIFS_LPT_FANOUT); ++ c->nnode_cnt = n; ++ for (i = 1; i < c->lpt_hght; i++) { ++ n = DIV_ROUND_UP(n, UBIFS_LPT_FANOUT); ++ c->nnode_cnt += n; ++ } ++ ++ c->space_bits = fls(c->leb_size) - 3; ++ c->lpt_lnum_bits = fls(c->lpt_lebs); ++ c->lpt_offs_bits = fls(c->leb_size - 1); ++ c->lpt_spc_bits = fls(c->leb_size); ++ ++ n = DIV_ROUND_UP(c->max_leb_cnt, UBIFS_LPT_FANOUT); ++ c->pcnt_bits = fls(n - 1); ++ ++ c->lnum_bits = fls(c->max_leb_cnt - 1); ++ ++ bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS + ++ (c->big_lpt ? c->pcnt_bits : 0) + ++ (c->space_bits * 2 + 1) * UBIFS_LPT_FANOUT; ++ c->pnode_sz = (bits + 7) / 8; ++ ++ bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS + ++ (c->big_lpt ? c->pcnt_bits : 0) + ++ (c->lpt_lnum_bits + c->lpt_offs_bits) * UBIFS_LPT_FANOUT; ++ c->nnode_sz = (bits + 7) / 8; ++ ++ bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS + ++ c->lpt_lebs * c->lpt_spc_bits * 2; ++ c->ltab_sz = (bits + 7) / 8; ++ ++ bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS + ++ c->lnum_bits * c->lsave_cnt; ++ c->lsave_sz = (bits + 7) / 8; ++ ++ /* Calculate the minimum LPT size */ ++ c->lpt_sz = (long long)c->pnode_cnt * c->pnode_sz; ++ c->lpt_sz += (long long)c->nnode_cnt * c->nnode_sz; ++ c->lpt_sz += c->ltab_sz; ++ c->lpt_sz += c->lsave_sz; ++ ++ /* Add wastage */ ++ sz = c->lpt_sz; ++ per_leb_wastage = max_t(int, c->pnode_sz, c->nnode_sz); ++ sz += per_leb_wastage; ++ tot_wastage = per_leb_wastage; ++ while (sz > c->leb_size) { ++ sz += per_leb_wastage; ++ sz -= c->leb_size; ++ tot_wastage += per_leb_wastage; ++ } ++ tot_wastage += ALIGN(sz, c->min_io_size) - sz; ++ c->lpt_sz += tot_wastage; ++} ++ ++/** ++ * ubifs_calc_lpt_geom - calculate and check sizes for the LPT area. ++ * @c: the UBIFS file-system description object ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++int ubifs_calc_lpt_geom(struct ubifs_info *c) ++{ ++ int lebs_needed; ++ uint64_t sz; ++ ++ do_calc_lpt_geom(c); ++ ++ /* Verify that lpt_lebs is big enough */ ++ sz = c->lpt_sz * 2; /* Must have at least 2 times the size */ ++ sz += c->leb_size - 1; ++ do_div(sz, c->leb_size); ++ lebs_needed = sz; ++ if (lebs_needed > c->lpt_lebs) { ++ ubifs_err("too few LPT LEBs"); ++ return -EINVAL; ++ } ++ ++ /* Verify that ltab fits in a single LEB (since ltab is a single node */ ++ if (c->ltab_sz > c->leb_size) { ++ ubifs_err("LPT ltab too big"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/** ++ * calc_dflt_lpt_geom - calculate default LPT geometry. ++ * @c: the UBIFS file-system description object ++ * @main_lebs: number of main area LEBs is passed and returned here ++ * @big_lpt: whether the LPT area is "big" is returned here ++ * ++ * The size of the LPT area depends on parameters that themselves are dependent ++ * on the size of the LPT area. This function, successively recalculates the LPT ++ * area geometry until the parameters and resultant geometry are consistent. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs, ++ int *big_lpt) ++{ ++ int i, lebs_needed; ++ uint64_t sz; ++ ++ /* Start by assuming the minimum number of LPT LEBs */ ++ c->lpt_lebs = UBIFS_MIN_LPT_LEBS; ++ c->main_lebs = *main_lebs - c->lpt_lebs; ++ if (c->main_lebs <= 0) ++ return -EINVAL; ++ ++ /* And assume we will use the small LPT model */ ++ c->big_lpt = 0; ++ ++ /* ++ * Calculate the geometry based on assumptions above and then see if it ++ * makes sense ++ */ ++ do_calc_lpt_geom(c); ++ ++ /* Small LPT model must have lpt_sz < leb_size */ ++ if (c->lpt_sz > c->leb_size) { ++ /* Nope, so try again using big LPT model */ ++ c->big_lpt = 1; ++ do_calc_lpt_geom(c); ++ } ++ ++ /* Now check there are enough LPT LEBs */ ++ for (i = 0; i < 64 ; i++) { ++ sz = c->lpt_sz * 4; /* Allow 4 times the size */ ++ sz += c->leb_size - 1; ++ do_div(sz, c->leb_size); ++ lebs_needed = sz; ++ if (lebs_needed > c->lpt_lebs) { ++ /* Not enough LPT LEBs so try again with more */ ++ c->lpt_lebs = lebs_needed; ++ c->main_lebs = *main_lebs - c->lpt_lebs; ++ if (c->main_lebs <= 0) ++ return -EINVAL; ++ do_calc_lpt_geom(c); ++ continue; ++ } ++ if (c->ltab_sz > c->leb_size) { ++ ubifs_err("LPT ltab too big"); ++ return -EINVAL; ++ } ++ *main_lebs = c->main_lebs; ++ *big_lpt = c->big_lpt; ++ return 0; ++ } ++ return -EINVAL; ++} ++ ++/** ++ * pack_bits - pack bit fields end-to-end. ++ * @addr: address at which to pack (passed and next address returned) ++ * @pos: bit position at which to pack (passed and next position returned) ++ * @val: value to pack ++ * @nrbits: number of bits of value to pack (1-32) ++ */ ++static void pack_bits(uint8_t **addr, int *pos, uint32_t val, int nrbits) ++{ ++ uint8_t *p = *addr; ++ int b = *pos; ++ ++ ubifs_assert(nrbits > 0); ++ ubifs_assert(nrbits <= 32); ++ ubifs_assert(*pos >= 0); ++ ubifs_assert(*pos < 8); ++ ubifs_assert((val >> nrbits) == 0 || nrbits == 32); ++ if (b) { ++ *p |= ((uint8_t)val) << b; ++ nrbits += b; ++ if (nrbits > 8) { ++ *++p = (uint8_t)(val >>= (8 - b)); ++ if (nrbits > 16) { ++ *++p = (uint8_t)(val >>= 8); ++ if (nrbits > 24) { ++ *++p = (uint8_t)(val >>= 8); ++ if (nrbits > 32) ++ *++p = (uint8_t)(val >>= 8); ++ } ++ } ++ } ++ } else { ++ *p = (uint8_t)val; ++ if (nrbits > 8) { ++ *++p = (uint8_t)(val >>= 8); ++ if (nrbits > 16) { ++ *++p = (uint8_t)(val >>= 8); ++ if (nrbits > 24) ++ *++p = (uint8_t)(val >>= 8); ++ } ++ } ++ } ++ b = nrbits & 7; ++ if (b == 0) ++ p++; ++ *addr = p; ++ *pos = b; ++} ++ ++/** ++ * ubifs_unpack_bits - unpack bit fields. ++ * @addr: address at which to unpack (passed and next address returned) ++ * @pos: bit position at which to unpack (passed and next position returned) ++ * @nrbits: number of bits of value to unpack (1-32) ++ * ++ * This functions returns the value unpacked. ++ */ ++uint32_t ubifs_unpack_bits(uint8_t **addr, int *pos, int nrbits) ++{ ++ const int k = 32 - nrbits; ++ uint8_t *p = *addr; ++ int b = *pos; ++ uint32_t val; ++ ++ ubifs_assert(nrbits > 0); ++ ubifs_assert(nrbits <= 32); ++ ubifs_assert(*pos >= 0); ++ ubifs_assert(*pos < 8); ++ if (b) { ++ val = p[1] | ((uint32_t)p[2] << 8) | ((uint32_t)p[3] << 16) | ++ ((uint32_t)p[4] << 24); ++ val <<= (8 - b); ++ val |= *p >> b; ++ nrbits += b; ++ } else ++ val = p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ++ ((uint32_t)p[3] << 24); ++ val <<= k; ++ val >>= k; ++ b = nrbits & 7; ++ p += nrbits / 8; ++ *addr = p; ++ *pos = b; ++ ubifs_assert((val >> nrbits) == 0 || nrbits - b == 32); ++ return val; ++} ++ ++/** ++ * ubifs_pack_pnode - pack all the bit fields of a pnode. ++ * @c: UBIFS file-system description object ++ * @buf: buffer into which to pack ++ * @pnode: pnode to pack ++ */ ++void ubifs_pack_pnode(struct ubifs_info *c, void *buf, ++ struct ubifs_pnode *pnode) ++{ ++ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; ++ int i, pos = 0; ++ uint16_t crc; ++ ++ pack_bits(&addr, &pos, UBIFS_LPT_PNODE, UBIFS_LPT_TYPE_BITS); ++ if (c->big_lpt) ++ pack_bits(&addr, &pos, pnode->num, c->pcnt_bits); ++ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { ++ pack_bits(&addr, &pos, pnode->lprops[i].free >> 3, ++ c->space_bits); ++ pack_bits(&addr, &pos, pnode->lprops[i].dirty >> 3, ++ c->space_bits); ++ if (pnode->lprops[i].flags & LPROPS_INDEX) ++ pack_bits(&addr, &pos, 1, 1); ++ else ++ pack_bits(&addr, &pos, 0, 1); ++ } ++ crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES, ++ c->pnode_sz - UBIFS_LPT_CRC_BYTES); ++ addr = buf; ++ pos = 0; ++ pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS); ++} ++ ++/** ++ * ubifs_pack_nnode - pack all the bit fields of a nnode. ++ * @c: UBIFS file-system description object ++ * @buf: buffer into which to pack ++ * @nnode: nnode to pack ++ */ ++void ubifs_pack_nnode(struct ubifs_info *c, void *buf, ++ struct ubifs_nnode *nnode) ++{ ++ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; ++ int i, pos = 0; ++ uint16_t crc; ++ ++ pack_bits(&addr, &pos, UBIFS_LPT_NNODE, UBIFS_LPT_TYPE_BITS); ++ if (c->big_lpt) ++ pack_bits(&addr, &pos, nnode->num, c->pcnt_bits); ++ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { ++ int lnum = nnode->nbranch[i].lnum; ++ ++ if (lnum == 0) ++ lnum = c->lpt_last + 1; ++ pack_bits(&addr, &pos, lnum - c->lpt_first, c->lpt_lnum_bits); ++ pack_bits(&addr, &pos, nnode->nbranch[i].offs, ++ c->lpt_offs_bits); ++ } ++ crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES, ++ c->nnode_sz - UBIFS_LPT_CRC_BYTES); ++ addr = buf; ++ pos = 0; ++ pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS); ++} ++ ++/** ++ * ubifs_pack_ltab - pack the LPT's own lprops table. ++ * @c: UBIFS file-system description object ++ * @buf: buffer into which to pack ++ * @ltab: LPT's own lprops table to pack ++ */ ++void ubifs_pack_ltab(struct ubifs_info *c, void *buf, ++ struct ubifs_lpt_lprops *ltab) ++{ ++ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; ++ int i, pos = 0; ++ uint16_t crc; ++ ++ pack_bits(&addr, &pos, UBIFS_LPT_LTAB, UBIFS_LPT_TYPE_BITS); ++ for (i = 0; i < c->lpt_lebs; i++) { ++ pack_bits(&addr, &pos, ltab[i].free, c->lpt_spc_bits); ++ pack_bits(&addr, &pos, ltab[i].dirty, c->lpt_spc_bits); ++ } ++ crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES, ++ c->ltab_sz - UBIFS_LPT_CRC_BYTES); ++ addr = buf; ++ pos = 0; ++ pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS); ++} ++ ++/** ++ * ubifs_pack_lsave - pack the LPT's save table. ++ * @c: UBIFS file-system description object ++ * @buf: buffer into which to pack ++ * @lsave: LPT's save table to pack ++ */ ++void ubifs_pack_lsave(struct ubifs_info *c, void *buf, int *lsave) ++{ ++ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; ++ int i, pos = 0; ++ uint16_t crc; ++ ++ pack_bits(&addr, &pos, UBIFS_LPT_LSAVE, UBIFS_LPT_TYPE_BITS); ++ for (i = 0; i < c->lsave_cnt; i++) ++ pack_bits(&addr, &pos, lsave[i], c->lnum_bits); ++ crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES, ++ c->lsave_sz - UBIFS_LPT_CRC_BYTES); ++ addr = buf; ++ pos = 0; ++ pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS); ++} ++ ++/** ++ * ubifs_add_lpt_dirt - add dirty space to LPT LEB properties. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number to which to add dirty space ++ * @dirty: amount of dirty space to add ++ */ ++void ubifs_add_lpt_dirt(struct ubifs_info *c, int lnum, int dirty) ++{ ++ if (!dirty || !lnum) ++ return; ++ dbg_lp("LEB %d add %d to %d", ++ lnum, dirty, c->ltab[lnum - c->lpt_first].dirty); ++ ubifs_assert(lnum >= c->lpt_first && lnum <= c->lpt_last); ++ c->ltab[lnum - c->lpt_first].dirty += dirty; ++} ++ ++/** ++ * set_ltab - set LPT LEB properties. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number ++ * @free: amount of free space ++ * @dirty: amount of dirty space ++ */ ++static void set_ltab(struct ubifs_info *c, int lnum, int free, int dirty) ++{ ++ dbg_lp("LEB %d free %d dirty %d to %d %d", ++ lnum, c->ltab[lnum - c->lpt_first].free, ++ c->ltab[lnum - c->lpt_first].dirty, free, dirty); ++ ubifs_assert(lnum >= c->lpt_first && lnum <= c->lpt_last); ++ c->ltab[lnum - c->lpt_first].free = free; ++ c->ltab[lnum - c->lpt_first].dirty = dirty; ++} ++ ++/** ++ * ubifs_add_nnode_dirt - add dirty space to LPT LEB properties. ++ * @c: UBIFS file-system description object ++ * @nnode: nnode for which to add dirt ++ */ ++void ubifs_add_nnode_dirt(struct ubifs_info *c, struct ubifs_nnode *nnode) ++{ ++ struct ubifs_nnode *np = nnode->parent; ++ ++ if (np) ++ ubifs_add_lpt_dirt(c, np->nbranch[nnode->iip].lnum, ++ c->nnode_sz); ++ else { ++ ubifs_add_lpt_dirt(c, c->lpt_lnum, c->nnode_sz); ++ if (!(c->lpt_drty_flgs & LTAB_DIRTY)) { ++ c->lpt_drty_flgs |= LTAB_DIRTY; ++ ubifs_add_lpt_dirt(c, c->ltab_lnum, c->ltab_sz); ++ } ++ } ++} ++ ++/** ++ * add_pnode_dirt - add dirty space to LPT LEB properties. ++ * @c: UBIFS file-system description object ++ * @pnode: pnode for which to add dirt ++ */ ++static void add_pnode_dirt(struct ubifs_info *c, struct ubifs_pnode *pnode) ++{ ++ ubifs_add_lpt_dirt(c, pnode->parent->nbranch[pnode->iip].lnum, ++ c->pnode_sz); ++} ++ ++/** ++ * calc_nnode_num - calculate nnode number. ++ * @row: the row in the tree (root is zero) ++ * @col: the column in the row (leftmost is zero) ++ * ++ * The nnode number is a number that uniquely identifies a nnode and can be used ++ * easily to traverse the tree from the root to that nnode. ++ * ++ * This function calculates and returns the nnode number for the nnode at @row ++ * and @col. ++ */ ++static int calc_nnode_num(int row, int col) ++{ ++ int num, bits; ++ ++ num = 1; ++ while (row--) { ++ bits = (col & (UBIFS_LPT_FANOUT - 1)); ++ col >>= UBIFS_LPT_FANOUT_SHIFT; ++ num <<= UBIFS_LPT_FANOUT_SHIFT; ++ num |= bits; ++ } ++ return num; ++} ++ ++/** ++ * calc_nnode_num_from_parent - calculate nnode number. ++ * @c: UBIFS file-system description object ++ * @parent: parent nnode ++ * @iip: index in parent ++ * ++ * The nnode number is a number that uniquely identifies a nnode and can be used ++ * easily to traverse the tree from the root to that nnode. ++ * ++ * This function calculates and returns the nnode number based on the parent's ++ * nnode number and the index in parent. ++ */ ++static int calc_nnode_num_from_parent(struct ubifs_info *c, ++ struct ubifs_nnode *parent, int iip) ++{ ++ int num, shft; ++ ++ if (!parent) ++ return 1; ++ shft = (c->lpt_hght - parent->level) * UBIFS_LPT_FANOUT_SHIFT; ++ num = parent->num ^ (1 << shft); ++ num |= (UBIFS_LPT_FANOUT + iip) << shft; ++ return num; ++} ++ ++/** ++ * calc_pnode_num_from_parent - calculate pnode number. ++ * @c: UBIFS file-system description object ++ * @parent: parent nnode ++ * @iip: index in parent ++ * ++ * The pnode number is a number that uniquely identifies a pnode and can be used ++ * easily to traverse the tree from the root to that pnode. ++ * ++ * This function calculates and returns the pnode number based on the parent's ++ * nnode number and the index in parent. ++ */ ++static int calc_pnode_num_from_parent(struct ubifs_info *c, ++ struct ubifs_nnode *parent, int iip) ++{ ++ int i, n = c->lpt_hght - 1, pnum = parent->num, num = 0; ++ ++ for (i = 0; i < n; i++) { ++ num <<= UBIFS_LPT_FANOUT_SHIFT; ++ num |= pnum & (UBIFS_LPT_FANOUT - 1); ++ pnum >>= UBIFS_LPT_FANOUT_SHIFT; ++ } ++ num <<= UBIFS_LPT_FANOUT_SHIFT; ++ num |= iip; ++ return num; ++} ++ ++/** ++ * ubifs_create_dflt_lpt - create default LPT. ++ * @c: UBIFS file-system description object ++ * @main_lebs: number of main area LEBs is passed and returned here ++ * @lpt_first: LEB number of first LPT LEB ++ * @lpt_lebs: number of LEBs for LPT is passed and returned here ++ * @big_lpt: use big LPT model is passed and returned here ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, ++ int *lpt_lebs, int *big_lpt) ++{ ++ int lnum, err = 0, node_sz, iopos, i, j, cnt, len, alen, row; ++ int blnum, boffs, bsz, bcnt; ++ struct ubifs_pnode *pnode = NULL; ++ struct ubifs_nnode *nnode = NULL; ++ void *buf = NULL, *p; ++ struct ubifs_lpt_lprops *ltab = NULL; ++ int *lsave = NULL; ++ ++ err = calc_dflt_lpt_geom(c, main_lebs, big_lpt); ++ if (err) ++ return err; ++ *lpt_lebs = c->lpt_lebs; ++ ++ /* Needed by 'ubifs_pack_nnode()' and 'set_ltab()' */ ++ c->lpt_first = lpt_first; ++ /* Needed by 'set_ltab()' */ ++ c->lpt_last = lpt_first + c->lpt_lebs - 1; ++ /* Needed by 'ubifs_pack_lsave()' */ ++ c->main_first = c->leb_cnt - *main_lebs; ++ ++ lsave = kmalloc(sizeof(int) * c->lsave_cnt, GFP_KERNEL); ++ pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_KERNEL); ++ nnode = kzalloc(sizeof(struct ubifs_nnode), GFP_KERNEL); ++ buf = vmalloc(c->leb_size); ++ ltab = vmalloc(sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs); ++ if (!pnode || !nnode || !buf || !ltab || !lsave) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ ubifs_assert(!c->ltab); ++ c->ltab = ltab; /* Needed by set_ltab */ ++ ++ /* Initialize LPT's own lprops */ ++ for (i = 0; i < c->lpt_lebs; i++) { ++ ltab[i].free = c->leb_size; ++ ltab[i].dirty = 0; ++ ltab[i].tgc = 0; ++ ltab[i].cmt = 0; ++ } ++ ++ lnum = lpt_first; ++ p = buf; ++ /* Number of leaf nodes (pnodes) */ ++ cnt = c->pnode_cnt; ++ ++ /* ++ * The first pnode contains the LEB properties for the LEBs that contain ++ * the root inode node and the root index node of the index tree. ++ */ ++ node_sz = ALIGN(ubifs_idx_node_sz(c, 1), 8); ++ iopos = ALIGN(node_sz, c->min_io_size); ++ pnode->lprops[0].free = c->leb_size - iopos; ++ pnode->lprops[0].dirty = iopos - node_sz; ++ pnode->lprops[0].flags = LPROPS_INDEX; ++ ++ node_sz = UBIFS_INO_NODE_SZ; ++ iopos = ALIGN(node_sz, c->min_io_size); ++ pnode->lprops[1].free = c->leb_size - iopos; ++ pnode->lprops[1].dirty = iopos - node_sz; ++ ++ for (i = 2; i < UBIFS_LPT_FANOUT; i++) ++ pnode->lprops[i].free = c->leb_size; ++ ++ /* Add first pnode */ ++ ubifs_pack_pnode(c, p, pnode); ++ p += c->pnode_sz; ++ len = c->pnode_sz; ++ pnode->num += 1; ++ ++ /* Reset pnode values for remaining pnodes */ ++ pnode->lprops[0].free = c->leb_size; ++ pnode->lprops[0].dirty = 0; ++ pnode->lprops[0].flags = 0; ++ ++ pnode->lprops[1].free = c->leb_size; ++ pnode->lprops[1].dirty = 0; ++ ++ /* ++ * To calculate the internal node branches, we keep information about ++ * the level below. ++ */ ++ blnum = lnum; /* LEB number of level below */ ++ boffs = 0; /* Offset of level below */ ++ bcnt = cnt; /* Number of nodes in level below */ ++ bsz = c->pnode_sz; /* Size of nodes in level below */ ++ ++ /* Add all remaining pnodes */ ++ for (i = 1; i < cnt; i++) { ++ if (len + c->pnode_sz > c->leb_size) { ++ alen = ALIGN(len, c->min_io_size); ++ set_ltab(c, lnum, c->leb_size - alen, alen - len); ++ memset(p, 0xff, alen - len); ++ err = ubi_leb_change(c->ubi, lnum++, buf, alen, ++ UBI_SHORTTERM); ++ if (err) ++ goto out; ++ p = buf; ++ len = 0; ++ } ++ ubifs_pack_pnode(c, p, pnode); ++ p += c->pnode_sz; ++ len += c->pnode_sz; ++ /* ++ * pnodes are simply numbered left to right starting at zero, ++ * which means the pnode number can be used easily to traverse ++ * down the tree to the corresponding pnode. ++ */ ++ pnode->num += 1; ++ } ++ ++ row = 0; ++ for (i = UBIFS_LPT_FANOUT; cnt > i; i <<= UBIFS_LPT_FANOUT_SHIFT) ++ row += 1; ++ /* Add all nnodes, one level at a time */ ++ while (1) { ++ /* Number of internal nodes (nnodes) at next level */ ++ cnt = DIV_ROUND_UP(cnt, UBIFS_LPT_FANOUT); ++ for (i = 0; i < cnt; i++) { ++ if (len + c->nnode_sz > c->leb_size) { ++ alen = ALIGN(len, c->min_io_size); ++ set_ltab(c, lnum, c->leb_size - alen, ++ alen - len); ++ memset(p, 0xff, alen - len); ++ err = ubi_leb_change(c->ubi, lnum++, buf, alen, ++ UBI_SHORTTERM); ++ if (err) ++ goto out; ++ p = buf; ++ len = 0; ++ } ++ /* Only 1 nnode at this level, so it is the root */ ++ if (cnt == 1) { ++ c->lpt_lnum = lnum; ++ c->lpt_offs = len; ++ } ++ /* Set branches to the level below */ ++ for (j = 0; j < UBIFS_LPT_FANOUT; j++) { ++ if (bcnt) { ++ if (boffs + bsz > c->leb_size) { ++ blnum += 1; ++ boffs = 0; ++ } ++ nnode->nbranch[j].lnum = blnum; ++ nnode->nbranch[j].offs = boffs; ++ boffs += bsz; ++ bcnt--; ++ } else { ++ nnode->nbranch[j].lnum = 0; ++ nnode->nbranch[j].offs = 0; ++ } ++ } ++ nnode->num = calc_nnode_num(row, i); ++ ubifs_pack_nnode(c, p, nnode); ++ p += c->nnode_sz; ++ len += c->nnode_sz; ++ } ++ /* Only 1 nnode at this level, so it is the root */ ++ if (cnt == 1) ++ break; ++ /* Update the information about the level below */ ++ bcnt = cnt; ++ bsz = c->nnode_sz; ++ row -= 1; ++ } ++ ++ if (*big_lpt) { ++ /* Need to add LPT's save table */ ++ if (len + c->lsave_sz > c->leb_size) { ++ alen = ALIGN(len, c->min_io_size); ++ set_ltab(c, lnum, c->leb_size - alen, alen - len); ++ memset(p, 0xff, alen - len); ++ err = ubi_leb_change(c->ubi, lnum++, buf, alen, ++ UBI_SHORTTERM); ++ if (err) ++ goto out; ++ p = buf; ++ len = 0; ++ } ++ ++ c->lsave_lnum = lnum; ++ c->lsave_offs = len; ++ ++ for (i = 0; i < c->lsave_cnt && i < *main_lebs; i++) ++ lsave[i] = c->main_first + i; ++ for (; i < c->lsave_cnt; i++) ++ lsave[i] = c->main_first; ++ ++ ubifs_pack_lsave(c, p, lsave); ++ p += c->lsave_sz; ++ len += c->lsave_sz; ++ } ++ ++ /* Need to add LPT's own LEB properties table */ ++ if (len + c->ltab_sz > c->leb_size) { ++ alen = ALIGN(len, c->min_io_size); ++ set_ltab(c, lnum, c->leb_size - alen, alen - len); ++ memset(p, 0xff, alen - len); ++ err = ubi_leb_change(c->ubi, lnum++, buf, alen, UBI_SHORTTERM); ++ if (err) ++ goto out; ++ p = buf; ++ len = 0; ++ } ++ ++ c->ltab_lnum = lnum; ++ c->ltab_offs = len; ++ ++ /* Update ltab before packing it */ ++ len += c->ltab_sz; ++ alen = ALIGN(len, c->min_io_size); ++ set_ltab(c, lnum, c->leb_size - alen, alen - len); ++ ++ ubifs_pack_ltab(c, p, ltab); ++ p += c->ltab_sz; ++ ++ /* Write remaining buffer */ ++ memset(p, 0xff, alen - len); ++ err = ubi_leb_change(c->ubi, lnum, buf, alen, UBI_SHORTTERM); ++ if (err) ++ goto out; ++ ++ c->nhead_lnum = lnum; ++ c->nhead_offs = ALIGN(len, c->min_io_size); ++ ++ dbg_lp("space_bits %d", c->space_bits); ++ dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits); ++ dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits); ++ dbg_lp("lpt_spc_bits %d", c->lpt_spc_bits); ++ dbg_lp("pcnt_bits %d", c->pcnt_bits); ++ dbg_lp("lnum_bits %d", c->lnum_bits); ++ dbg_lp("pnode_sz %d", c->pnode_sz); ++ dbg_lp("nnode_sz %d", c->nnode_sz); ++ dbg_lp("ltab_sz %d", c->ltab_sz); ++ dbg_lp("lsave_sz %d", c->lsave_sz); ++ dbg_lp("lsave_cnt %d", c->lsave_cnt); ++ dbg_lp("lpt_hght %d", c->lpt_hght); ++ dbg_lp("big_lpt %d", c->big_lpt); ++ dbg_lp("LPT root is at %d:%d", c->lpt_lnum, c->lpt_offs); ++ dbg_lp("LPT head is at %d:%d", c->nhead_lnum, c->nhead_offs); ++ dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs); ++ if (c->big_lpt) ++ dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs); ++out: ++ c->ltab = NULL; ++ kfree(lsave); ++ vfree(ltab); ++ vfree(buf); ++ kfree(nnode); ++ kfree(pnode); ++ return err; ++} ++ ++/** ++ * update_cats - add LEB properties of a pnode to LEB category lists and heaps. ++ * @c: UBIFS file-system description object ++ * @pnode: pnode ++ * ++ * When a pnode is loaded into memory, the LEB properties it contains are added, ++ * by this function, to the LEB category lists and heaps. ++ */ ++static void update_cats(struct ubifs_info *c, struct ubifs_pnode *pnode) ++{ ++ int i; ++ ++ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { ++ int cat = pnode->lprops[i].flags & LPROPS_CAT_MASK; ++ int lnum = pnode->lprops[i].lnum; ++ ++ if (!lnum) ++ return; ++ ubifs_add_to_cat(c, &pnode->lprops[i], cat); ++ } ++} ++ ++/** ++ * replace_cats - add LEB properties of a pnode to LEB category lists and heaps. ++ * @c: UBIFS file-system description object ++ * @old_pnode: pnode copied ++ * @new_pnode: pnode copy ++ * ++ * During commit it is sometimes necessary to copy a pnode ++ * (see dirty_cow_pnode). When that happens, references in ++ * category lists and heaps must be replaced. This function does that. ++ */ ++static void replace_cats(struct ubifs_info *c, struct ubifs_pnode *old_pnode, ++ struct ubifs_pnode *new_pnode) ++{ ++ int i; ++ ++ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { ++ if (!new_pnode->lprops[i].lnum) ++ return; ++ ubifs_replace_cat(c, &old_pnode->lprops[i], ++ &new_pnode->lprops[i]); ++ } ++} ++ ++/** ++ * check_lpt_crc - check LPT node crc is correct. ++ * @c: UBIFS file-system description object ++ * @buf: buffer containing node ++ * @len: length of node ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int check_lpt_crc(void *buf, int len) ++{ ++ int pos = 0; ++ uint8_t *addr = buf; ++ uint16_t crc, calc_crc; ++ ++ crc = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_CRC_BITS); ++ calc_crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES, ++ len - UBIFS_LPT_CRC_BYTES); ++ if (crc != calc_crc) { ++ ubifs_err("invalid crc in LPT node: crc %hx calc %hx", crc, ++ calc_crc); ++ dbg_dump_stack(); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++/** ++ * check_lpt_type - check LPT node type is correct. ++ * @c: UBIFS file-system description object ++ * @addr: address of type bit field is passed and returned updated here ++ * @pos: position of type bit field is passed and returned updated here ++ * @type: expected type ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int check_lpt_type(uint8_t **addr, int *pos, int type) ++{ ++ int node_type; ++ ++ node_type = ubifs_unpack_bits(addr, pos, UBIFS_LPT_TYPE_BITS); ++ if (node_type != type) { ++ ubifs_err("invalid type (%d) in LPT node type %d", node_type, ++ type); ++ dbg_dump_stack(); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++/** ++ * unpack_pnode - unpack a pnode. ++ * @c: UBIFS file-system description object ++ * @buf: buffer containing packed pnode to unpack ++ * @pnode: pnode structure to fill ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int unpack_pnode(struct ubifs_info *c, void *buf, ++ struct ubifs_pnode *pnode) ++{ ++ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; ++ int i, pos = 0, err; ++ ++ err = check_lpt_type(&addr, &pos, UBIFS_LPT_PNODE); ++ if (err) ++ return err; ++ if (c->big_lpt) ++ pnode->num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits); ++ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { ++ struct ubifs_lprops * const lprops = &pnode->lprops[i]; ++ ++ lprops->free = ubifs_unpack_bits(&addr, &pos, c->space_bits); ++ lprops->free <<= 3; ++ lprops->dirty = ubifs_unpack_bits(&addr, &pos, c->space_bits); ++ lprops->dirty <<= 3; ++ ++ if (ubifs_unpack_bits(&addr, &pos, 1)) ++ lprops->flags = LPROPS_INDEX; ++ else ++ lprops->flags = 0; ++ lprops->flags |= ubifs_categorize_lprops(c, lprops); ++ } ++ err = check_lpt_crc(buf, c->pnode_sz); ++ return err; ++} ++ ++/** ++ * unpack_nnode - unpack a nnode. ++ * @c: UBIFS file-system description object ++ * @buf: buffer containing packed nnode to unpack ++ * @nnode: nnode structure to fill ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int unpack_nnode(struct ubifs_info *c, void *buf, ++ struct ubifs_nnode *nnode) ++{ ++ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; ++ int i, pos = 0, err; ++ ++ err = check_lpt_type(&addr, &pos, UBIFS_LPT_NNODE); ++ if (err) ++ return err; ++ if (c->big_lpt) ++ nnode->num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits); ++ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { ++ int lnum; ++ ++ lnum = ubifs_unpack_bits(&addr, &pos, c->lpt_lnum_bits) + ++ c->lpt_first; ++ if (lnum == c->lpt_last + 1) ++ lnum = 0; ++ nnode->nbranch[i].lnum = lnum; ++ nnode->nbranch[i].offs = ubifs_unpack_bits(&addr, &pos, ++ c->lpt_offs_bits); ++ } ++ err = check_lpt_crc(buf, c->nnode_sz); ++ return err; ++} ++ ++/** ++ * unpack_ltab - unpack the LPT's own lprops table. ++ * @c: UBIFS file-system description object ++ * @buf: buffer from which to unpack ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int unpack_ltab(struct ubifs_info *c, void *buf) ++{ ++ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; ++ int i, pos = 0, err; ++ ++ err = check_lpt_type(&addr, &pos, UBIFS_LPT_LTAB); ++ if (err) ++ return err; ++ for (i = 0; i < c->lpt_lebs; i++) { ++ int free = ubifs_unpack_bits(&addr, &pos, c->lpt_spc_bits); ++ int dirty = ubifs_unpack_bits(&addr, &pos, c->lpt_spc_bits); ++ ++ if (free < 0 || free > c->leb_size || dirty < 0 || ++ dirty > c->leb_size || free + dirty > c->leb_size) ++ return -EINVAL; ++ ++ c->ltab[i].free = free; ++ c->ltab[i].dirty = dirty; ++ c->ltab[i].tgc = 0; ++ c->ltab[i].cmt = 0; ++ } ++ err = check_lpt_crc(buf, c->ltab_sz); ++ return err; ++} ++ ++/** ++ * unpack_lsave - unpack the LPT's save table. ++ * @c: UBIFS file-system description object ++ * @buf: buffer from which to unpack ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int unpack_lsave(struct ubifs_info *c, void *buf) ++{ ++ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; ++ int i, pos = 0, err; ++ ++ err = check_lpt_type(&addr, &pos, UBIFS_LPT_LSAVE); ++ if (err) ++ return err; ++ for (i = 0; i < c->lsave_cnt; i++) { ++ int lnum = ubifs_unpack_bits(&addr, &pos, c->lnum_bits); ++ ++ if (lnum < c->main_first || lnum >= c->leb_cnt) ++ return -EINVAL; ++ c->lsave[i] = lnum; ++ } ++ err = check_lpt_crc(buf, c->lsave_sz); ++ return err; ++} ++ ++/** ++ * validate_nnode - validate a nnode. ++ * @c: UBIFS file-system description object ++ * @nnode: nnode to validate ++ * @parent: parent nnode (or NULL for the root nnode) ++ * @iip: index in parent ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int validate_nnode(struct ubifs_info *c, struct ubifs_nnode *nnode, ++ struct ubifs_nnode *parent, int iip) ++{ ++ int i, lvl, max_offs; ++ ++ if (c->big_lpt) { ++ int num = calc_nnode_num_from_parent(c, parent, iip); ++ ++ if (nnode->num != num) ++ return -EINVAL; ++ } ++ lvl = parent ? parent->level - 1 : c->lpt_hght; ++ if (lvl < 1) ++ return -EINVAL; ++ if (lvl == 1) ++ max_offs = c->leb_size - c->pnode_sz; ++ else ++ max_offs = c->leb_size - c->nnode_sz; ++ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { ++ int lnum = nnode->nbranch[i].lnum; ++ int offs = nnode->nbranch[i].offs; ++ ++ if (lnum == 0) { ++ if (offs != 0) ++ return -EINVAL; ++ continue; ++ } ++ if (lnum < c->lpt_first || lnum > c->lpt_last) ++ return -EINVAL; ++ if (offs < 0 || offs > max_offs) ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++/** ++ * validate_pnode - validate a pnode. ++ * @c: UBIFS file-system description object ++ * @pnode: pnode to validate ++ * @parent: parent nnode ++ * @iip: index in parent ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int validate_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode, ++ struct ubifs_nnode *parent, int iip) ++{ ++ int i; ++ ++ if (c->big_lpt) { ++ int num = calc_pnode_num_from_parent(c, parent, iip); ++ ++ if (pnode->num != num) ++ return -EINVAL; ++ } ++ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { ++ int free = pnode->lprops[i].free; ++ int dirty = pnode->lprops[i].dirty; ++ ++ if (free < 0 || free > c->leb_size || free % c->min_io_size || ++ (free & 7)) ++ return -EINVAL; ++ if (dirty < 0 || dirty > c->leb_size || (dirty & 7)) ++ return -EINVAL; ++ if (dirty + free > c->leb_size) ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++/** ++ * set_pnode_lnum - set LEB numbers on a pnode. ++ * @c: UBIFS file-system description object ++ * @pnode: pnode to update ++ * ++ * This function calculates the LEB numbers for the LEB properties it contains ++ * based on the pnode number. ++ */ ++static void set_pnode_lnum(struct ubifs_info *c, struct ubifs_pnode *pnode) ++{ ++ int i, lnum; ++ ++ lnum = (pnode->num << UBIFS_LPT_FANOUT_SHIFT) + c->main_first; ++ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { ++ if (lnum >= c->leb_cnt) ++ return; ++ pnode->lprops[i].lnum = lnum++; ++ } ++} ++ ++/** ++ * ubifs_read_nnode - read a nnode from flash and link it to the tree in memory. ++ * @c: UBIFS file-system description object ++ * @parent: parent nnode (or NULL for the root) ++ * @iip: index in parent ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip) ++{ ++ struct ubifs_nbranch *branch = NULL; ++ struct ubifs_nnode *nnode = NULL; ++ void *buf = c->lpt_nod_buf; ++ int err, lnum, offs; ++ ++ if (parent) { ++ branch = &parent->nbranch[iip]; ++ lnum = branch->lnum; ++ offs = branch->offs; ++ } else { ++ lnum = c->lpt_lnum; ++ offs = c->lpt_offs; ++ } ++ nnode = kzalloc(sizeof(struct ubifs_nnode), GFP_NOFS); ++ if (!nnode) { ++ err = -ENOMEM; ++ goto out; ++ } ++ if (lnum == 0) { ++ /* ++ * This nnode was not written which just means that the LEB ++ * properties in the subtree below it describe empty LEBs. We ++ * make the nnode as though we had read it, which in fact means ++ * doing almost nothing. ++ */ ++ if (c->big_lpt) ++ nnode->num = calc_nnode_num_from_parent(c, parent, iip); ++ } else { ++ err = ubi_read(c->ubi, lnum, buf, offs, c->nnode_sz); ++ if (err) ++ goto out; ++ err = unpack_nnode(c, buf, nnode); ++ if (err) ++ goto out; ++ } ++ err = validate_nnode(c, nnode, parent, iip); ++ if (err) ++ goto out; ++ if (!c->big_lpt) ++ nnode->num = calc_nnode_num_from_parent(c, parent, iip); ++ if (parent) { ++ branch->nnode = nnode; ++ nnode->level = parent->level - 1; ++ } else { ++ c->nroot = nnode; ++ nnode->level = c->lpt_hght; ++ } ++ nnode->parent = parent; ++ nnode->iip = iip; ++ return 0; ++ ++out: ++ ubifs_err("error %d reading nnode at %d:%d", err, lnum, offs); ++ kfree(nnode); ++ return err; ++} ++ ++/** ++ * read_pnode - read a pnode from flash and link it to the tree in memory. ++ * @c: UBIFS file-system description object ++ * @parent: parent nnode ++ * @iip: index in parent ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip) ++{ ++ struct ubifs_nbranch *branch; ++ struct ubifs_pnode *pnode = NULL; ++ void *buf = c->lpt_nod_buf; ++ int err, lnum, offs; ++ ++ branch = &parent->nbranch[iip]; ++ lnum = branch->lnum; ++ offs = branch->offs; ++ pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_NOFS); ++ if (!pnode) { ++ err = -ENOMEM; ++ goto out; ++ } ++ if (lnum == 0) { ++ /* ++ * This pnode was not written which just means that the LEB ++ * properties in it describe empty LEBs. We make the pnode as ++ * though we had read it. ++ */ ++ int i; ++ ++ if (c->big_lpt) ++ pnode->num = calc_pnode_num_from_parent(c, parent, iip); ++ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { ++ struct ubifs_lprops * const lprops = &pnode->lprops[i]; ++ ++ lprops->free = c->leb_size; ++ lprops->flags = ubifs_categorize_lprops(c, lprops); ++ } ++ } else { ++ err = ubi_read(c->ubi, lnum, buf, offs, c->pnode_sz); ++ if (err) ++ goto out; ++ err = unpack_pnode(c, buf, pnode); ++ if (err) ++ goto out; ++ } ++ err = validate_pnode(c, pnode, parent, iip); ++ if (err) ++ goto out; ++ if (!c->big_lpt) ++ pnode->num = calc_pnode_num_from_parent(c, parent, iip); ++ branch->pnode = pnode; ++ pnode->parent = parent; ++ pnode->iip = iip; ++ set_pnode_lnum(c, pnode); ++ c->pnodes_have += 1; ++ return 0; ++ ++out: ++ ubifs_err("error %d reading pnode at %d:%d", err, lnum, offs); ++ dbg_dump_pnode(c, pnode, parent, iip); ++ dbg_msg("calc num: %d", calc_pnode_num_from_parent(c, parent, iip)); ++ kfree(pnode); ++ return err; ++} ++ ++/** ++ * read_ltab - read LPT's own lprops table. ++ * @c: UBIFS file-system description object ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int read_ltab(struct ubifs_info *c) ++{ ++ int err; ++ void *buf; ++ ++ buf = vmalloc(c->ltab_sz); ++ if (!buf) ++ return -ENOMEM; ++ err = ubi_read(c->ubi, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz); ++ if (err) ++ goto out; ++ err = unpack_ltab(c, buf); ++out: ++ vfree(buf); ++ return err; ++} ++ ++/** ++ * read_lsave - read LPT's save table. ++ * @c: UBIFS file-system description object ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int read_lsave(struct ubifs_info *c) ++{ ++ int err, i; ++ void *buf; ++ ++ buf = vmalloc(c->lsave_sz); ++ if (!buf) ++ return -ENOMEM; ++ err = ubi_read(c->ubi, c->lsave_lnum, buf, c->lsave_offs, c->lsave_sz); ++ if (err) ++ goto out; ++ err = unpack_lsave(c, buf); ++ if (err) ++ goto out; ++ for (i = 0; i < c->lsave_cnt; i++) { ++ int lnum = c->lsave[i]; ++ ++ /* ++ * Due to automatic resizing, the values in the lsave table ++ * could be beyond the volume size - just ignore them. ++ */ ++ if (lnum >= c->leb_cnt) ++ continue; ++ ubifs_lpt_lookup(c, lnum); ++ } ++out: ++ vfree(buf); ++ return err; ++} ++ ++/** ++ * ubifs_get_nnode - get a nnode. ++ * @c: UBIFS file-system description object ++ * @parent: parent nnode (or NULL for the root) ++ * @iip: index in parent ++ * ++ * This function returns a pointer to the nnode on success or a negative error ++ * code on failure. ++ */ ++struct ubifs_nnode *ubifs_get_nnode(struct ubifs_info *c, ++ struct ubifs_nnode *parent, int iip) ++{ ++ struct ubifs_nbranch *branch; ++ struct ubifs_nnode *nnode; ++ int err; ++ ++ branch = &parent->nbranch[iip]; ++ nnode = branch->nnode; ++ if (nnode) ++ return nnode; ++ err = ubifs_read_nnode(c, parent, iip); ++ if (err) ++ return ERR_PTR(err); ++ return branch->nnode; ++} ++ ++/** ++ * ubifs_get_pnode - get a pnode. ++ * @c: UBIFS file-system description object ++ * @parent: parent nnode ++ * @iip: index in parent ++ * ++ * This function returns a pointer to the pnode on success or a negative error ++ * code on failure. ++ */ ++struct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c, ++ struct ubifs_nnode *parent, int iip) ++{ ++ struct ubifs_nbranch *branch; ++ struct ubifs_pnode *pnode; ++ int err; ++ ++ branch = &parent->nbranch[iip]; ++ pnode = branch->pnode; ++ if (pnode) ++ return pnode; ++ err = read_pnode(c, parent, iip); ++ if (err) ++ return ERR_PTR(err); ++ update_cats(c, branch->pnode); ++ return branch->pnode; ++} ++ ++/** ++ * ubifs_lpt_lookup - lookup LEB properties in the LPT. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number to lookup ++ * ++ * This function returns a pointer to the LEB properties on success or a ++ * negative error code on failure. ++ */ ++struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum) ++{ ++ int err, i, h, iip, shft; ++ struct ubifs_nnode *nnode; ++ struct ubifs_pnode *pnode; ++ ++ if (!c->nroot) { ++ err = ubifs_read_nnode(c, NULL, 0); ++ if (err) ++ return ERR_PTR(err); ++ } ++ nnode = c->nroot; ++ i = lnum - c->main_first; ++ shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT; ++ for (h = 1; h < c->lpt_hght; h++) { ++ iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); ++ shft -= UBIFS_LPT_FANOUT_SHIFT; ++ nnode = ubifs_get_nnode(c, nnode, iip); ++ if (IS_ERR(nnode)) ++ return ERR_PTR(PTR_ERR(nnode)); ++ } ++ iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); ++ shft -= UBIFS_LPT_FANOUT_SHIFT; ++ pnode = ubifs_get_pnode(c, nnode, iip); ++ if (IS_ERR(pnode)) ++ return ERR_PTR(PTR_ERR(pnode)); ++ iip = (i & (UBIFS_LPT_FANOUT - 1)); ++ dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum, ++ pnode->lprops[iip].free, pnode->lprops[iip].dirty, ++ pnode->lprops[iip].flags); ++ return &pnode->lprops[iip]; ++} ++ ++/** ++ * dirty_cow_nnode - ensure a nnode is not being committed. ++ * @c: UBIFS file-system description object ++ * @nnode: nnode to check ++ * ++ * Returns dirtied nnode on success or negative error code on failure. ++ */ ++static struct ubifs_nnode *dirty_cow_nnode(struct ubifs_info *c, ++ struct ubifs_nnode *nnode) ++{ ++ struct ubifs_nnode *n; ++ int i; ++ ++ if (!test_bit(COW_CNODE, &nnode->flags)) { ++ /* nnode is not being committed */ ++ if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) { ++ c->dirty_nn_cnt += 1; ++ ubifs_add_nnode_dirt(c, nnode); ++ } ++ return nnode; ++ } ++ ++ /* nnode is being committed, so copy it */ ++ n = kmalloc(sizeof(struct ubifs_nnode), GFP_NOFS); ++ if (unlikely(!n)) ++ return ERR_PTR(-ENOMEM); ++ ++ memcpy(n, nnode, sizeof(struct ubifs_nnode)); ++ n->cnext = NULL; ++ __set_bit(DIRTY_CNODE, &n->flags); ++ __clear_bit(COW_CNODE, &n->flags); ++ ++ /* The children now have new parent */ ++ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { ++ struct ubifs_nbranch *branch = &n->nbranch[i]; ++ ++ if (branch->cnode) ++ branch->cnode->parent = n; ++ } ++ ++ ubifs_assert(!test_bit(OBSOLETE_CNODE, &nnode->flags)); ++ __set_bit(OBSOLETE_CNODE, &nnode->flags); ++ ++ c->dirty_nn_cnt += 1; ++ ubifs_add_nnode_dirt(c, nnode); ++ if (nnode->parent) ++ nnode->parent->nbranch[n->iip].nnode = n; ++ else ++ c->nroot = n; ++ return n; ++} ++ ++/** ++ * dirty_cow_pnode - ensure a pnode is not being committed. ++ * @c: UBIFS file-system description object ++ * @pnode: pnode to check ++ * ++ * Returns dirtied pnode on success or negative error code on failure. ++ */ ++static struct ubifs_pnode *dirty_cow_pnode(struct ubifs_info *c, ++ struct ubifs_pnode *pnode) ++{ ++ struct ubifs_pnode *p; ++ ++ if (!test_bit(COW_CNODE, &pnode->flags)) { ++ /* pnode is not being committed */ ++ if (!test_and_set_bit(DIRTY_CNODE, &pnode->flags)) { ++ c->dirty_pn_cnt += 1; ++ add_pnode_dirt(c, pnode); ++ } ++ return pnode; ++ } ++ ++ /* pnode is being committed, so copy it */ ++ p = kmalloc(sizeof(struct ubifs_pnode), GFP_NOFS); ++ if (unlikely(!p)) ++ return ERR_PTR(-ENOMEM); ++ ++ memcpy(p, pnode, sizeof(struct ubifs_pnode)); ++ p->cnext = NULL; ++ __set_bit(DIRTY_CNODE, &p->flags); ++ __clear_bit(COW_CNODE, &p->flags); ++ replace_cats(c, pnode, p); ++ ++ ubifs_assert(!test_bit(OBSOLETE_CNODE, &pnode->flags)); ++ __set_bit(OBSOLETE_CNODE, &pnode->flags); ++ ++ c->dirty_pn_cnt += 1; ++ add_pnode_dirt(c, pnode); ++ pnode->parent->nbranch[p->iip].pnode = p; ++ return p; ++} ++ ++/** ++ * ubifs_lpt_lookup_dirty - lookup LEB properties in the LPT. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number to lookup ++ * ++ * This function returns a pointer to the LEB properties on success or a ++ * negative error code on failure. ++ */ ++struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum) ++{ ++ int err, i, h, iip, shft; ++ struct ubifs_nnode *nnode; ++ struct ubifs_pnode *pnode; ++ ++ if (!c->nroot) { ++ err = ubifs_read_nnode(c, NULL, 0); ++ if (err) ++ return ERR_PTR(err); ++ } ++ nnode = c->nroot; ++ nnode = dirty_cow_nnode(c, nnode); ++ if (IS_ERR(nnode)) ++ return ERR_PTR(PTR_ERR(nnode)); ++ i = lnum - c->main_first; ++ shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT; ++ for (h = 1; h < c->lpt_hght; h++) { ++ iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); ++ shft -= UBIFS_LPT_FANOUT_SHIFT; ++ nnode = ubifs_get_nnode(c, nnode, iip); ++ if (IS_ERR(nnode)) ++ return ERR_PTR(PTR_ERR(nnode)); ++ nnode = dirty_cow_nnode(c, nnode); ++ if (IS_ERR(nnode)) ++ return ERR_PTR(PTR_ERR(nnode)); ++ } ++ iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); ++ shft -= UBIFS_LPT_FANOUT_SHIFT; ++ pnode = ubifs_get_pnode(c, nnode, iip); ++ if (IS_ERR(pnode)) ++ return ERR_PTR(PTR_ERR(pnode)); ++ pnode = dirty_cow_pnode(c, pnode); ++ if (IS_ERR(pnode)) ++ return ERR_PTR(PTR_ERR(pnode)); ++ iip = (i & (UBIFS_LPT_FANOUT - 1)); ++ dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum, ++ pnode->lprops[iip].free, pnode->lprops[iip].dirty, ++ pnode->lprops[iip].flags); ++ ubifs_assert(test_bit(DIRTY_CNODE, &pnode->flags)); ++ return &pnode->lprops[iip]; ++} ++ ++/** ++ * lpt_init_rd - initialize the LPT for reading. ++ * @c: UBIFS file-system description object ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int lpt_init_rd(struct ubifs_info *c) ++{ ++ int err, i; ++ ++ c->ltab = vmalloc(sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs); ++ if (!c->ltab) ++ return -ENOMEM; ++ ++ i = max_t(int, c->nnode_sz, c->pnode_sz); ++ c->lpt_nod_buf = kmalloc(i, GFP_KERNEL); ++ if (!c->lpt_nod_buf) ++ return -ENOMEM; ++ ++ for (i = 0; i < LPROPS_HEAP_CNT; i++) { ++ c->lpt_heap[i].arr = kmalloc(sizeof(void *) * LPT_HEAP_SZ, ++ GFP_KERNEL); ++ if (!c->lpt_heap[i].arr) ++ return -ENOMEM; ++ c->lpt_heap[i].cnt = 0; ++ c->lpt_heap[i].max_cnt = LPT_HEAP_SZ; ++ } ++ ++ c->dirty_idx.arr = kmalloc(sizeof(void *) * LPT_HEAP_SZ, GFP_KERNEL); ++ if (!c->dirty_idx.arr) ++ return -ENOMEM; ++ c->dirty_idx.cnt = 0; ++ c->dirty_idx.max_cnt = LPT_HEAP_SZ; ++ ++ err = read_ltab(c); ++ if (err) ++ return err; ++ ++ dbg_lp("space_bits %d", c->space_bits); ++ dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits); ++ dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits); ++ dbg_lp("lpt_spc_bits %d", c->lpt_spc_bits); ++ dbg_lp("pcnt_bits %d", c->pcnt_bits); ++ dbg_lp("lnum_bits %d", c->lnum_bits); ++ dbg_lp("pnode_sz %d", c->pnode_sz); ++ dbg_lp("nnode_sz %d", c->nnode_sz); ++ dbg_lp("ltab_sz %d", c->ltab_sz); ++ dbg_lp("lsave_sz %d", c->lsave_sz); ++ dbg_lp("lsave_cnt %d", c->lsave_cnt); ++ dbg_lp("lpt_hght %d", c->lpt_hght); ++ dbg_lp("big_lpt %d", c->big_lpt); ++ dbg_lp("LPT root is at %d:%d", c->lpt_lnum, c->lpt_offs); ++ dbg_lp("LPT head is at %d:%d", c->nhead_lnum, c->nhead_offs); ++ dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs); ++ if (c->big_lpt) ++ dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs); ++ ++ return 0; ++} ++ ++/** ++ * lpt_init_wr - initialize the LPT for writing. ++ * @c: UBIFS file-system description object ++ * ++ * 'lpt_init_rd()' must have been called already. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int lpt_init_wr(struct ubifs_info *c) ++{ ++ int err, i; ++ ++ c->ltab_cmt = vmalloc(sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs); ++ if (!c->ltab_cmt) ++ return -ENOMEM; ++ ++ c->lpt_buf = vmalloc(c->leb_size); ++ if (!c->lpt_buf) ++ return -ENOMEM; ++ ++ if (c->big_lpt) { ++ c->lsave = kmalloc(sizeof(int) * c->lsave_cnt, GFP_NOFS); ++ if (!c->lsave) ++ return -ENOMEM; ++ err = read_lsave(c); ++ if (err) ++ return err; ++ } ++ ++ for (i = 0; i < c->lpt_lebs; i++) ++ if (c->ltab[i].free == c->leb_size) { ++ err = ubifs_leb_unmap(c, i + c->lpt_first); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} ++ ++/** ++ * ubifs_lpt_init - initialize the LPT. ++ * @c: UBIFS file-system description object ++ * @rd: whether to initialize lpt for reading ++ * @wr: whether to initialize lpt for writing ++ * ++ * For mounting 'rw', @rd and @wr are both true. For mounting 'ro', @rd is true ++ * and @wr is false. For mounting from 'ro' to 'rw', @rd is false and @wr is ++ * true. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++int ubifs_lpt_init(struct ubifs_info *c, int rd, int wr) ++{ ++ int err; ++ ++ if (rd) { ++ err = lpt_init_rd(c); ++ if (err) ++ return err; ++ } ++ ++ if (wr) { ++ err = lpt_init_wr(c); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} ++ ++/** ++ * struct lpt_scan_node - somewhere to put nodes while we scan LPT. ++ * @nnode: where to keep a nnode ++ * @pnode: where to keep a pnode ++ * @cnode: where to keep a cnode ++ * @in_tree: is the node in the tree in memory ++ * @ptr.nnode: pointer to the nnode (if it is an nnode) which may be here or in ++ * the tree ++ * @ptr.pnode: ditto for pnode ++ * @ptr.cnode: ditto for cnode ++ */ ++struct lpt_scan_node { ++ union { ++ struct ubifs_nnode nnode; ++ struct ubifs_pnode pnode; ++ struct ubifs_cnode cnode; ++ }; ++ int in_tree; ++ union { ++ struct ubifs_nnode *nnode; ++ struct ubifs_pnode *pnode; ++ struct ubifs_cnode *cnode; ++ } ptr; ++}; ++ ++/** ++ * scan_get_nnode - for the scan, get a nnode from either the tree or flash. ++ * @c: the UBIFS file-system description object ++ * @path: where to put the nnode ++ * @parent: parent of the nnode ++ * @iip: index in parent of the nnode ++ * ++ * This function returns a pointer to the nnode on success or a negative error ++ * code on failure. ++ */ ++static struct ubifs_nnode *scan_get_nnode(struct ubifs_info *c, ++ struct lpt_scan_node *path, ++ struct ubifs_nnode *parent, int iip) ++{ ++ struct ubifs_nbranch *branch; ++ struct ubifs_nnode *nnode; ++ void *buf = c->lpt_nod_buf; ++ int err; ++ ++ branch = &parent->nbranch[iip]; ++ nnode = branch->nnode; ++ if (nnode) { ++ path->in_tree = 1; ++ path->ptr.nnode = nnode; ++ return nnode; ++ } ++ nnode = &path->nnode; ++ path->in_tree = 0; ++ path->ptr.nnode = nnode; ++ memset(nnode, 0, sizeof(struct ubifs_nnode)); ++ if (branch->lnum == 0) { ++ /* ++ * This nnode was not written which just means that the LEB ++ * properties in the subtree below it describe empty LEBs. We ++ * make the nnode as though we had read it, which in fact means ++ * doing almost nothing. ++ */ ++ if (c->big_lpt) ++ nnode->num = calc_nnode_num_from_parent(c, parent, iip); ++ } else { ++ err = ubi_read(c->ubi, branch->lnum, buf, branch->offs, ++ c->nnode_sz); ++ if (err) ++ return ERR_PTR(err); ++ err = unpack_nnode(c, buf, nnode); ++ if (err) ++ return ERR_PTR(err); ++ } ++ err = validate_nnode(c, nnode, parent, iip); ++ if (err) ++ return ERR_PTR(err); ++ if (!c->big_lpt) ++ nnode->num = calc_nnode_num_from_parent(c, parent, iip); ++ nnode->level = parent->level - 1; ++ nnode->parent = parent; ++ nnode->iip = iip; ++ return nnode; ++} ++ ++/** ++ * scan_get_pnode - for the scan, get a pnode from either the tree or flash. ++ * @c: the UBIFS file-system description object ++ * @path: where to put the pnode ++ * @parent: parent of the pnode ++ * @iip: index in parent of the pnode ++ * ++ * This function returns a pointer to the pnode on success or a negative error ++ * code on failure. ++ */ ++static struct ubifs_pnode *scan_get_pnode(struct ubifs_info *c, ++ struct lpt_scan_node *path, ++ struct ubifs_nnode *parent, int iip) ++{ ++ struct ubifs_nbranch *branch; ++ struct ubifs_pnode *pnode; ++ void *buf = c->lpt_nod_buf; ++ int err; ++ ++ branch = &parent->nbranch[iip]; ++ pnode = branch->pnode; ++ if (pnode) { ++ path->in_tree = 1; ++ path->ptr.pnode = pnode; ++ return pnode; ++ } ++ pnode = &path->pnode; ++ path->in_tree = 0; ++ path->ptr.pnode = pnode; ++ memset(pnode, 0, sizeof(struct ubifs_pnode)); ++ if (branch->lnum == 0) { ++ /* ++ * This pnode was not written which just means that the LEB ++ * properties in it describe empty LEBs. We make the pnode as ++ * though we had read it. ++ */ ++ int i; ++ ++ if (c->big_lpt) ++ pnode->num = calc_pnode_num_from_parent(c, parent, iip); ++ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { ++ struct ubifs_lprops * const lprops = &pnode->lprops[i]; ++ ++ lprops->free = c->leb_size; ++ lprops->flags = ubifs_categorize_lprops(c, lprops); ++ } ++ } else { ++ ubifs_assert(branch->lnum >= c->lpt_first && ++ branch->lnum <= c->lpt_last); ++ ubifs_assert(branch->offs >= 0 && branch->offs < c->leb_size); ++ err = ubi_read(c->ubi, branch->lnum, buf, branch->offs, ++ c->pnode_sz); ++ if (err) ++ return ERR_PTR(err); ++ err = unpack_pnode(c, buf, pnode); ++ if (err) ++ return ERR_PTR(err); ++ } ++ err = validate_pnode(c, pnode, parent, iip); ++ if (err) ++ return ERR_PTR(err); ++ if (!c->big_lpt) ++ pnode->num = calc_pnode_num_from_parent(c, parent, iip); ++ pnode->parent = parent; ++ pnode->iip = iip; ++ set_pnode_lnum(c, pnode); ++ return pnode; ++} ++ ++/** ++ * ubifs_lpt_scan_nolock - scan the LPT. ++ * @c: the UBIFS file-system description object ++ * @start_lnum: LEB number from which to start scanning ++ * @end_lnum: LEB number at which to stop scanning ++ * @scan_cb: callback function called for each lprops ++ * @data: data to be passed to the callback function ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++int ubifs_lpt_scan_nolock(struct ubifs_info *c, int start_lnum, int end_lnum, ++ ubifs_lpt_scan_callback scan_cb, void *data) ++{ ++ int err = 0, i, h, iip, shft; ++ struct ubifs_nnode *nnode; ++ struct ubifs_pnode *pnode; ++ struct lpt_scan_node *path; ++ ++ if (start_lnum == -1) { ++ start_lnum = end_lnum + 1; ++ if (start_lnum >= c->leb_cnt) ++ start_lnum = c->main_first; ++ } ++ ++ ubifs_assert(start_lnum >= c->main_first && start_lnum < c->leb_cnt); ++ ubifs_assert(end_lnum >= c->main_first && end_lnum < c->leb_cnt); ++ ++ if (!c->nroot) { ++ err = ubifs_read_nnode(c, NULL, 0); ++ if (err) ++ return err; ++ } ++ ++ path = kmalloc(sizeof(struct lpt_scan_node) * (c->lpt_hght + 1), ++ GFP_NOFS); ++ if (!path) ++ return -ENOMEM; ++ ++ path[0].ptr.nnode = c->nroot; ++ path[0].in_tree = 1; ++again: ++ /* Descend to the pnode containing start_lnum */ ++ nnode = c->nroot; ++ i = start_lnum - c->main_first; ++ shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT; ++ for (h = 1; h < c->lpt_hght; h++) { ++ iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); ++ shft -= UBIFS_LPT_FANOUT_SHIFT; ++ nnode = scan_get_nnode(c, path + h, nnode, iip); ++ if (IS_ERR(nnode)) { ++ err = PTR_ERR(nnode); ++ goto out; ++ } ++ } ++ iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); ++ shft -= UBIFS_LPT_FANOUT_SHIFT; ++ pnode = scan_get_pnode(c, path + h, nnode, iip); ++ if (IS_ERR(pnode)) { ++ err = PTR_ERR(pnode); ++ goto out; ++ } ++ iip = (i & (UBIFS_LPT_FANOUT - 1)); ++ ++ /* Loop for each lprops */ ++ while (1) { ++ struct ubifs_lprops *lprops = &pnode->lprops[iip]; ++ int ret, lnum = lprops->lnum; ++ ++ ret = scan_cb(c, lprops, path[h].in_tree, data); ++ if (ret < 0) { ++ err = ret; ++ goto out; ++ } ++ if (ret & LPT_SCAN_ADD) { ++ /* Add all the nodes in path to the tree in memory */ ++ for (h = 1; h < c->lpt_hght; h++) { ++ const size_t sz = sizeof(struct ubifs_nnode); ++ struct ubifs_nnode *parent; ++ ++ if (path[h].in_tree) ++ continue; ++ nnode = kmalloc(sz, GFP_NOFS); ++ if (!nnode) { ++ err = -ENOMEM; ++ goto out; ++ } ++ memcpy(nnode, &path[h].nnode, sz); ++ parent = nnode->parent; ++ parent->nbranch[nnode->iip].nnode = nnode; ++ path[h].ptr.nnode = nnode; ++ path[h].in_tree = 1; ++ path[h + 1].cnode.parent = nnode; ++ } ++ if (path[h].in_tree) ++ ubifs_ensure_cat(c, lprops); ++ else { ++ const size_t sz = sizeof(struct ubifs_pnode); ++ struct ubifs_nnode *parent; ++ ++ pnode = kmalloc(sz, GFP_NOFS); ++ if (!pnode) { ++ err = -ENOMEM; ++ goto out; ++ } ++ memcpy(pnode, &path[h].pnode, sz); ++ parent = pnode->parent; ++ parent->nbranch[pnode->iip].pnode = pnode; ++ path[h].ptr.pnode = pnode; ++ path[h].in_tree = 1; ++ update_cats(c, pnode); ++ c->pnodes_have += 1; ++ } ++ err = dbg_check_lpt_nodes(c, (struct ubifs_cnode *) ++ c->nroot, 0, 0); ++ if (err) ++ goto out; ++ err = dbg_check_cats(c); ++ if (err) ++ goto out; ++ } ++ if (ret & LPT_SCAN_STOP) { ++ err = 0; ++ break; ++ } ++ /* Get the next lprops */ ++ if (lnum == end_lnum) { ++ /* ++ * We got to the end without finding what we were ++ * looking for ++ */ ++ err = -ENOSPC; ++ goto out; ++ } ++ if (lnum + 1 >= c->leb_cnt) { ++ /* Wrap-around to the beginning */ ++ start_lnum = c->main_first; ++ goto again; ++ } ++ if (iip + 1 < UBIFS_LPT_FANOUT) { ++ /* Next lprops is in the same pnode */ ++ iip += 1; ++ continue; ++ } ++ /* We need to get the next pnode. Go up until we can go right */ ++ iip = pnode->iip; ++ while (1) { ++ h -= 1; ++ ubifs_assert(h >= 0); ++ nnode = path[h].ptr.nnode; ++ if (iip + 1 < UBIFS_LPT_FANOUT) ++ break; ++ iip = nnode->iip; ++ } ++ /* Go right */ ++ iip += 1; ++ /* Descend to the pnode */ ++ h += 1; ++ for (; h < c->lpt_hght; h++) { ++ nnode = scan_get_nnode(c, path + h, nnode, iip); ++ if (IS_ERR(nnode)) { ++ err = PTR_ERR(nnode); ++ goto out; ++ } ++ iip = 0; ++ } ++ pnode = scan_get_pnode(c, path + h, nnode, iip); ++ if (IS_ERR(pnode)) { ++ err = PTR_ERR(pnode); ++ goto out; ++ } ++ iip = 0; ++ } ++out: ++ kfree(path); ++ return err; ++} ++ ++#ifdef CONFIG_UBIFS_FS_DEBUG ++ ++/** ++ * dbg_chk_pnode - check a pnode. ++ * @c: the UBIFS file-system description object ++ * @pnode: pnode to check ++ * @col: pnode column ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int dbg_chk_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode, ++ int col) ++{ ++ int i; ++ ++ if (pnode->num != col) { ++ dbg_err("pnode num %d expected %d parent num %d iip %d", ++ pnode->num, col, pnode->parent->num, pnode->iip); ++ return -EINVAL; ++ } ++ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { ++ struct ubifs_lprops *lp, *lprops = &pnode->lprops[i]; ++ int lnum = (pnode->num << UBIFS_LPT_FANOUT_SHIFT) + i + ++ c->main_first; ++ int found, cat = lprops->flags & LPROPS_CAT_MASK; ++ struct ubifs_lpt_heap *heap; ++ struct list_head *list = NULL; ++ ++ if (lnum >= c->leb_cnt) ++ continue; ++ if (lprops->lnum != lnum) { ++ dbg_err("bad LEB number %d expected %d", ++ lprops->lnum, lnum); ++ return -EINVAL; ++ } ++ if (lprops->flags & LPROPS_TAKEN) { ++ if (cat != LPROPS_UNCAT) { ++ dbg_err("LEB %d taken but not uncat %d", ++ lprops->lnum, cat); ++ return -EINVAL; ++ } ++ continue; ++ } ++ if (lprops->flags & LPROPS_INDEX) { ++ switch (cat) { ++ case LPROPS_UNCAT: ++ case LPROPS_DIRTY_IDX: ++ case LPROPS_FRDI_IDX: ++ break; ++ default: ++ dbg_err("LEB %d index but cat %d", ++ lprops->lnum, cat); ++ return -EINVAL; ++ } ++ } else { ++ switch (cat) { ++ case LPROPS_UNCAT: ++ case LPROPS_DIRTY: ++ case LPROPS_FREE: ++ case LPROPS_EMPTY: ++ case LPROPS_FREEABLE: ++ break; ++ default: ++ dbg_err("LEB %d not index but cat %d", ++ lprops->lnum, cat); ++ return -EINVAL; ++ } ++ } ++ switch (cat) { ++ case LPROPS_UNCAT: ++ list = &c->uncat_list; ++ break; ++ case LPROPS_EMPTY: ++ list = &c->empty_list; ++ break; ++ case LPROPS_FREEABLE: ++ list = &c->freeable_list; ++ break; ++ case LPROPS_FRDI_IDX: ++ list = &c->frdi_idx_list; ++ break; ++ } ++ found = 0; ++ switch (cat) { ++ case LPROPS_DIRTY: ++ case LPROPS_DIRTY_IDX: ++ case LPROPS_FREE: ++ heap = &c->lpt_heap[cat - 1]; ++ if (lprops->hpos < heap->cnt && ++ heap->arr[lprops->hpos] == lprops) ++ found = 1; ++ break; ++ case LPROPS_UNCAT: ++ case LPROPS_EMPTY: ++ case LPROPS_FREEABLE: ++ case LPROPS_FRDI_IDX: ++ list_for_each_entry(lp, list, list) ++ if (lprops == lp) { ++ found = 1; ++ break; ++ } ++ break; ++ } ++ if (!found) { ++ dbg_err("LEB %d cat %d not found in cat heap/list", ++ lprops->lnum, cat); ++ return -EINVAL; ++ } ++ switch (cat) { ++ case LPROPS_EMPTY: ++ if (lprops->free != c->leb_size) { ++ dbg_err("LEB %d cat %d free %d dirty %d", ++ lprops->lnum, cat, lprops->free, ++ lprops->dirty); ++ return -EINVAL; ++ } ++ case LPROPS_FREEABLE: ++ case LPROPS_FRDI_IDX: ++ if (lprops->free + lprops->dirty != c->leb_size) { ++ dbg_err("LEB %d cat %d free %d dirty %d", ++ lprops->lnum, cat, lprops->free, ++ lprops->dirty); ++ return -EINVAL; ++ } ++ } ++ } ++ return 0; ++} ++ ++/** ++ * dbg_check_lpt_nodes - check nnodes and pnodes. ++ * @c: the UBIFS file-system description object ++ * @cnode: next cnode (nnode or pnode) to check ++ * @row: row of cnode (root is zero) ++ * @col: column of cnode (leftmost is zero) ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode, ++ int row, int col) ++{ ++ struct ubifs_nnode *nnode, *nn; ++ struct ubifs_cnode *cn; ++ int num, iip = 0, err; ++ ++ if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) ++ return 0; ++ ++ while (cnode) { ++ ubifs_assert(row >= 0); ++ nnode = cnode->parent; ++ if (cnode->level) { ++ /* cnode is a nnode */ ++ num = calc_nnode_num(row, col); ++ if (cnode->num != num) { ++ dbg_err("nnode num %d expected %d " ++ "parent num %d iip %d", cnode->num, num, ++ (nnode ? nnode->num : 0), cnode->iip); ++ return -EINVAL; ++ } ++ nn = (struct ubifs_nnode *)cnode; ++ while (iip < UBIFS_LPT_FANOUT) { ++ cn = nn->nbranch[iip].cnode; ++ if (cn) { ++ /* Go down */ ++ row += 1; ++ col <<= UBIFS_LPT_FANOUT_SHIFT; ++ col += iip; ++ iip = 0; ++ cnode = cn; ++ break; ++ } ++ /* Go right */ ++ iip += 1; ++ } ++ if (iip < UBIFS_LPT_FANOUT) ++ continue; ++ } else { ++ struct ubifs_pnode *pnode; ++ ++ /* cnode is a pnode */ ++ pnode = (struct ubifs_pnode *)cnode; ++ err = dbg_chk_pnode(c, pnode, col); ++ if (err) ++ return err; ++ } ++ /* Go up and to the right */ ++ row -= 1; ++ col >>= UBIFS_LPT_FANOUT_SHIFT; ++ iip = cnode->iip + 1; ++ cnode = (struct ubifs_cnode *)nnode; ++ } ++ return 0; ++} ++ ++#endif /* CONFIG_UBIFS_FS_DEBUG */ +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/lpt_commit.c avr32-2.6/fs/ubifs/lpt_commit.c +--- linux-2.6.25.6/fs/ubifs/lpt_commit.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/lpt_commit.c 2008-06-12 15:09:45.475816115 +0200 +@@ -0,0 +1,1631 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Adrian Hunter ++ * Artem Bityutskiy (Битюцкий Артём) ++ */ ++ ++/* ++ * This file implements commit-related functionality of the LEB properties ++ * subsystem. ++ */ ++ ++#include <linux/crc16.h> ++#include "ubifs.h" ++ ++/** ++ * first_dirty_cnode - find first dirty cnode. ++ * @c: UBIFS file-system description object ++ * @nnode: nnode at which to start ++ * ++ * This function returns the first dirty cnode or %NULL if there is not one. ++ */ ++static struct ubifs_cnode *first_dirty_cnode(struct ubifs_nnode *nnode) ++{ ++ ubifs_assert(nnode); ++ while (1) { ++ int i, cont = 0; ++ ++ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { ++ struct ubifs_cnode *cnode; ++ ++ cnode = nnode->nbranch[i].cnode; ++ if (cnode && ++ test_bit(DIRTY_CNODE, &cnode->flags)) { ++ if (cnode->level == 0) ++ return cnode; ++ nnode = (struct ubifs_nnode *)cnode; ++ cont = 1; ++ break; ++ } ++ } ++ if (!cont) ++ return (struct ubifs_cnode *)nnode; ++ } ++} ++ ++/** ++ * next_dirty_cnode - find next dirty cnode. ++ * @cnode: cnode from which to begin searching ++ * ++ * This function returns the next dirty cnode or %NULL if there is not one. ++ */ ++static struct ubifs_cnode *next_dirty_cnode(struct ubifs_cnode *cnode) ++{ ++ struct ubifs_nnode *nnode; ++ int i; ++ ++ ubifs_assert(cnode); ++ nnode = cnode->parent; ++ if (!nnode) ++ return NULL; ++ for (i = cnode->iip + 1; i < UBIFS_LPT_FANOUT; i++) { ++ cnode = nnode->nbranch[i].cnode; ++ if (cnode && test_bit(DIRTY_CNODE, &cnode->flags)) { ++ if (cnode->level == 0) ++ return cnode; /* cnode is a pnode */ ++ /* cnode is a nnode */ ++ return first_dirty_cnode((struct ubifs_nnode *)cnode); ++ } ++ } ++ return (struct ubifs_cnode *)nnode; ++} ++ ++/** ++ * get_cnodes_to_commit - create list of dirty cnodes to commit. ++ * @c: UBIFS file-system description object ++ * ++ * This function returns the number of cnodes to commit. ++ */ ++static int get_cnodes_to_commit(struct ubifs_info *c) ++{ ++ struct ubifs_cnode *cnode, *cnext; ++ int cnt = 0; ++ ++ if (!c->nroot) ++ return 0; ++ ++ if (!test_bit(DIRTY_CNODE, &c->nroot->flags)) ++ return 0; ++ ++ c->lpt_cnext = first_dirty_cnode(c->nroot); ++ cnode = c->lpt_cnext; ++ if (!cnode) ++ return 0; ++ cnt += 1; ++ while (1) { ++ ubifs_assert(!test_bit(COW_ZNODE, &cnode->flags)); ++ __set_bit(COW_ZNODE, &cnode->flags); ++ cnext = next_dirty_cnode(cnode); ++ if (!cnext) { ++ cnode->cnext = c->lpt_cnext; ++ break; ++ } ++ cnode->cnext = cnext; ++ cnode = cnext; ++ cnt += 1; ++ } ++ dbg_cmt("committing %d cnodes", cnt); ++ dbg_lp("committing %d cnodes", cnt); ++ ubifs_assert(cnt == c->dirty_nn_cnt + c->dirty_pn_cnt); ++ return cnt; ++} ++ ++/** ++ * upd_ltab - update LPT LEB properties. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number ++ * @free: amount of free space ++ * @dirty: amount of dirty space to add ++ */ ++static void upd_ltab(struct ubifs_info *c, int lnum, int free, int dirty) ++{ ++ dbg_lp("LEB %d free %d dirty %d to %d +%d", ++ lnum, c->ltab[lnum - c->lpt_first].free, ++ c->ltab[lnum - c->lpt_first].dirty, free, dirty); ++ ubifs_assert(lnum >= c->lpt_first && lnum <= c->lpt_last); ++ c->ltab[lnum - c->lpt_first].free = free; ++ c->ltab[lnum - c->lpt_first].dirty += dirty; ++} ++ ++/** ++ * alloc_lpt_leb - allocate an LPT LEB that is empty. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number is passed and returned here ++ * ++ * This function finds the next empty LEB in the ltab starting from @lnum. If a ++ * an empty LEB is found it is returned in @lnum and the function returns %0. ++ * Otherwise the function returns -ENOSPC. Note however, that LPT is designed ++ * never to run out of space. ++ */ ++static int alloc_lpt_leb(struct ubifs_info *c, int *lnum) ++{ ++ int i, n; ++ ++ n = *lnum - c->lpt_first + 1; ++ for (i = n; i < c->lpt_lebs; i++) { ++ if (c->ltab[i].tgc || c->ltab[i].cmt) ++ continue; ++ if (c->ltab[i].free == c->leb_size) { ++ c->ltab[i].cmt = 1; ++ *lnum = i + c->lpt_first; ++ return 0; ++ } ++ } ++ ++ for (i = 0; i < n; i++) { ++ if (c->ltab[i].tgc || c->ltab[i].cmt) ++ continue; ++ if (c->ltab[i].free == c->leb_size) { ++ c->ltab[i].cmt = 1; ++ *lnum = i + c->lpt_first; ++ return 0; ++ } ++ } ++ dbg_err("last LEB %d", *lnum); ++ dump_stack(); ++ return -ENOSPC; ++} ++ ++/** ++ * layout_cnodes - layout cnodes for commit. ++ * @c: UBIFS file-system description object ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int layout_cnodes(struct ubifs_info *c) ++{ ++ int lnum, offs, len, alen, done_lsave, done_ltab, err; ++ struct ubifs_cnode *cnode; ++ ++ cnode = c->lpt_cnext; ++ if (!cnode) ++ return 0; ++ lnum = c->nhead_lnum; ++ offs = c->nhead_offs; ++ /* Try to place lsave and ltab nicely */ ++ done_lsave = !c->big_lpt; ++ done_ltab = 0; ++ if (!done_lsave && offs + c->lsave_sz <= c->leb_size) { ++ done_lsave = 1; ++ c->lsave_lnum = lnum; ++ c->lsave_offs = offs; ++ offs += c->lsave_sz; ++ } ++ ++ if (offs + c->ltab_sz <= c->leb_size) { ++ done_ltab = 1; ++ c->ltab_lnum = lnum; ++ c->ltab_offs = offs; ++ offs += c->ltab_sz; ++ } ++ ++ do { ++ if (cnode->level) { ++ len = c->nnode_sz; ++ c->dirty_nn_cnt -= 1; ++ } else { ++ len = c->pnode_sz; ++ c->dirty_pn_cnt -= 1; ++ } ++ while (offs + len > c->leb_size) { ++ alen = ALIGN(offs, c->min_io_size); ++ upd_ltab(c, lnum, c->leb_size - alen, alen - offs); ++ err = alloc_lpt_leb(c, &lnum); ++ if (err) ++ return err; ++ offs = 0; ++ ubifs_assert(lnum >= c->lpt_first && ++ lnum <= c->lpt_last); ++ /* Try to place lsave and ltab nicely */ ++ if (!done_lsave) { ++ done_lsave = 1; ++ c->lsave_lnum = lnum; ++ c->lsave_offs = offs; ++ offs += c->lsave_sz; ++ continue; ++ } ++ if (!done_ltab) { ++ done_ltab = 1; ++ c->ltab_lnum = lnum; ++ c->ltab_offs = offs; ++ offs += c->ltab_sz; ++ continue; ++ } ++ break; ++ } ++ if (cnode->parent) { ++ cnode->parent->nbranch[cnode->iip].lnum = lnum; ++ cnode->parent->nbranch[cnode->iip].offs = offs; ++ } else { ++ c->lpt_lnum = lnum; ++ c->lpt_offs = offs; ++ } ++ offs += len; ++ cnode = cnode->cnext; ++ } while (cnode && cnode != c->lpt_cnext); ++ ++ /* Make sure to place LPT's save table */ ++ if (!done_lsave) { ++ if (offs + c->lsave_sz > c->leb_size) { ++ alen = ALIGN(offs, c->min_io_size); ++ upd_ltab(c, lnum, c->leb_size - alen, alen - offs); ++ err = alloc_lpt_leb(c, &lnum); ++ if (err) ++ return err; ++ offs = 0; ++ ubifs_assert(lnum >= c->lpt_first && ++ lnum <= c->lpt_last); ++ } ++ done_lsave = 1; ++ c->lsave_lnum = lnum; ++ c->lsave_offs = offs; ++ offs += c->lsave_sz; ++ } ++ ++ /* Make sure to place LPT's own lprops table */ ++ if (!done_ltab) { ++ if (offs + c->ltab_sz > c->leb_size) { ++ alen = ALIGN(offs, c->min_io_size); ++ upd_ltab(c, lnum, c->leb_size - alen, alen - offs); ++ err = alloc_lpt_leb(c, &lnum); ++ if (err) ++ return err; ++ offs = 0; ++ ubifs_assert(lnum >= c->lpt_first && ++ lnum <= c->lpt_last); ++ } ++ done_ltab = 1; ++ c->ltab_lnum = lnum; ++ c->ltab_offs = offs; ++ offs += c->ltab_sz; ++ } ++ ++ alen = ALIGN(offs, c->min_io_size); ++ upd_ltab(c, lnum, c->leb_size - alen, alen - offs); ++ return 0; ++} ++ ++/** ++ * realloc_lpt_leb - allocate an LPT LEB that is empty. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number is passed and returned here ++ * ++ * This function duplicates exactly the results of the function alloc_lpt_leb. ++ * It is used during end commit to reallocate the same LEB numbers that were ++ * allocated by alloc_lpt_leb during start commit. ++ * ++ * This function finds the next LEB that was allocated by the alloc_lpt_leb ++ * function starting from @lnum. If a LEB is found it is returned in @lnum and ++ * the function returns %0. Otherwise the function returns -ENOSPC. ++ * Note however, that LPT is designed never to run out of space. ++ */ ++static int realloc_lpt_leb(struct ubifs_info *c, int *lnum) ++{ ++ int i, n; ++ ++ n = *lnum - c->lpt_first + 1; ++ for (i = n; i < c->lpt_lebs; i++) ++ if (c->ltab[i].cmt) { ++ c->ltab[i].cmt = 0; ++ *lnum = i + c->lpt_first; ++ return 0; ++ } ++ ++ for (i = 0; i < n; i++) ++ if (c->ltab[i].cmt) { ++ c->ltab[i].cmt = 0; ++ *lnum = i + c->lpt_first; ++ return 0; ++ } ++ dbg_err("last LEB %d", *lnum); ++ dump_stack(); ++ return -ENOSPC; ++} ++ ++/** ++ * write_cnodes - write cnodes for commit. ++ * @c: UBIFS file-system description object ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int write_cnodes(struct ubifs_info *c) ++{ ++ int lnum, offs, len, from, err, wlen, alen, done_ltab, done_lsave; ++ struct ubifs_cnode *cnode; ++ void *buf = c->lpt_buf; ++ ++ cnode = c->lpt_cnext; ++ if (!cnode) ++ return 0; ++ lnum = c->nhead_lnum; ++ offs = c->nhead_offs; ++ from = offs; ++ /* Ensure empty LEB is unmapped */ ++ if (offs == 0) { ++ err = ubifs_leb_unmap(c, lnum); ++ if (err) ++ return err; ++ } ++ /* Try to place lsave and ltab nicely */ ++ done_lsave = !c->big_lpt; ++ done_ltab = 0; ++ if (!done_lsave && offs + c->lsave_sz <= c->leb_size) { ++ done_lsave = 1; ++ ubifs_pack_lsave(c, buf + offs, c->lsave); ++ offs += c->lsave_sz; ++ } ++ ++ if (offs + c->ltab_sz <= c->leb_size) { ++ done_ltab = 1; ++ ubifs_pack_ltab(c, buf + offs, c->ltab_cmt); ++ offs += c->ltab_sz; ++ } ++ ++ /* Loop for each cnode */ ++ do { ++ if (cnode->level) ++ len = c->nnode_sz; ++ else ++ len = c->pnode_sz; ++ while (offs + len > c->leb_size) { ++ wlen = offs - from; ++ if (wlen) { ++ alen = ALIGN(wlen, c->min_io_size); ++ memset(buf + offs, 0xff, alen - wlen); ++ err = ubifs_leb_write(c, lnum, buf + from, from, ++ alen, UBI_SHORTTERM); ++ if (err) ++ return err; ++ } ++ err = realloc_lpt_leb(c, &lnum); ++ if (err) ++ return err; ++ offs = 0; ++ from = 0; ++ ubifs_assert(lnum >= c->lpt_first && ++ lnum <= c->lpt_last); ++ err = ubifs_leb_unmap(c, lnum); ++ if (err) ++ return err; ++ /* Try to place lsave and ltab nicely */ ++ if (!done_lsave) { ++ done_lsave = 1; ++ ubifs_pack_lsave(c, buf + offs, c->lsave); ++ offs += c->lsave_sz; ++ continue; ++ } ++ if (!done_ltab) { ++ done_ltab = 1; ++ ubifs_pack_ltab(c, buf + offs, c->ltab_cmt); ++ offs += c->ltab_sz; ++ continue; ++ } ++ break; ++ } ++ if (cnode->level) ++ ubifs_pack_nnode(c, buf + offs, ++ (struct ubifs_nnode *)cnode); ++ else ++ ubifs_pack_pnode(c, buf + offs, ++ (struct ubifs_pnode *)cnode); ++ /* ++ * The reason for the barriers is the same as in case of TNC. ++ * See comment in 'write_index()'. 'dirty_cow_nnode()' and ++ * 'dirty_cow_pnode()' are the functions for which this is ++ * important. ++ */ ++ clear_bit(DIRTY_CNODE, &cnode->flags); ++ smp_mb__before_clear_bit(); ++ clear_bit(COW_ZNODE, &cnode->flags); ++ smp_mb__after_clear_bit(); ++ offs += len; ++ cnode = cnode->cnext; ++ } while (cnode && cnode != c->lpt_cnext); ++ ++ /* Make sure to place LPT's save table */ ++ if (!done_lsave) { ++ if (offs + c->lsave_sz > c->leb_size) { ++ wlen = offs - from; ++ alen = ALIGN(wlen, c->min_io_size); ++ memset(buf + offs, 0xff, alen - wlen); ++ err = ubifs_leb_write(c, lnum, buf + from, from, alen, ++ UBI_SHORTTERM); ++ if (err) ++ return err; ++ err = realloc_lpt_leb(c, &lnum); ++ if (err) ++ return err; ++ offs = 0; ++ ubifs_assert(lnum >= c->lpt_first && ++ lnum <= c->lpt_last); ++ err = ubifs_leb_unmap(c, lnum); ++ if (err) ++ return err; ++ } ++ done_lsave = 1; ++ ubifs_pack_lsave(c, buf + offs, c->lsave); ++ offs += c->lsave_sz; ++ } ++ ++ /* Make sure to place LPT's own lprops table */ ++ if (!done_ltab) { ++ if (offs + c->ltab_sz > c->leb_size) { ++ wlen = offs - from; ++ alen = ALIGN(wlen, c->min_io_size); ++ memset(buf + offs, 0xff, alen - wlen); ++ err = ubifs_leb_write(c, lnum, buf + from, from, alen, ++ UBI_SHORTTERM); ++ if (err) ++ return err; ++ err = realloc_lpt_leb(c, &lnum); ++ if (err) ++ return err; ++ offs = 0; ++ ubifs_assert(lnum >= c->lpt_first && ++ lnum <= c->lpt_last); ++ err = ubifs_leb_unmap(c, lnum); ++ if (err) ++ return err; ++ } ++ done_ltab = 1; ++ ubifs_pack_ltab(c, buf + offs, c->ltab_cmt); ++ offs += c->ltab_sz; ++ } ++ ++ /* Write remaining data in buffer */ ++ wlen = offs - from; ++ alen = ALIGN(wlen, c->min_io_size); ++ memset(buf + offs, 0xff, alen - wlen); ++ err = ubifs_leb_write(c, lnum, buf + from, from, alen, UBI_SHORTTERM); ++ if (err) ++ return err; ++ c->nhead_lnum = lnum; ++ c->nhead_offs = ALIGN(offs, c->min_io_size); ++ ++ dbg_lp("LPT root is at %d:%d", c->lpt_lnum, c->lpt_offs); ++ dbg_lp("LPT head is at %d:%d", c->nhead_lnum, c->nhead_offs); ++ dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs); ++ if (c->big_lpt) ++ dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs); ++ return 0; ++} ++ ++/** ++ * next_pnode - find next pnode. ++ * @c: UBIFS file-system description object ++ * @pnode: pnode ++ * ++ * This function returns the next pnode or %NULL if there are no more pnodes. ++ */ ++static struct ubifs_pnode *next_pnode(struct ubifs_info *c, ++ struct ubifs_pnode *pnode) ++{ ++ struct ubifs_nnode *nnode; ++ int iip; ++ ++ /* Try to go right */ ++ nnode = pnode->parent; ++ iip = pnode->iip + 1; ++ if (iip < UBIFS_LPT_FANOUT) { ++ /* We assume here that LEB zero is never an LPT LEB */ ++ if (nnode->nbranch[iip].lnum) ++ return ubifs_get_pnode(c, nnode, iip); ++ else ++ return NULL; ++ } ++ ++ /* Go up while can't go right */ ++ do { ++ iip = nnode->iip + 1; ++ nnode = nnode->parent; ++ if (!nnode) ++ return NULL; ++ /* We assume here that LEB zero is never an LPT LEB */ ++ } while (iip >= UBIFS_LPT_FANOUT || !nnode->nbranch[iip].lnum); ++ ++ /* Go right */ ++ nnode = ubifs_get_nnode(c, nnode, iip); ++ if (IS_ERR(nnode)) ++ return (void *)nnode; ++ ++ /* Go down to level 1 */ ++ while (nnode->level > 1) { ++ nnode = ubifs_get_nnode(c, nnode, 0); ++ if (IS_ERR(nnode)) ++ return (void *)nnode; ++ } ++ ++ return ubifs_get_pnode(c, nnode, 0); ++} ++ ++/** ++ * pnode_lookup - lookup a pnode in the LPT. ++ * @c: UBIFS file-system description object ++ * @i: pnode number (0 to main_lebs - 1) ++ * ++ * This function returns a pointer to the pnode on success or a negative ++ * error code on failure. ++ */ ++static struct ubifs_pnode *pnode_lookup(struct ubifs_info *c, int i) ++{ ++ int err, h, iip, shft; ++ struct ubifs_nnode *nnode; ++ ++ if (!c->nroot) { ++ err = ubifs_read_nnode(c, NULL, 0); ++ if (err) ++ return ERR_PTR(err); ++ } ++ i <<= UBIFS_LPT_FANOUT_SHIFT; ++ nnode = c->nroot; ++ shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT; ++ for (h = 1; h < c->lpt_hght; h++) { ++ iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); ++ shft -= UBIFS_LPT_FANOUT_SHIFT; ++ nnode = ubifs_get_nnode(c, nnode, iip); ++ if (IS_ERR(nnode)) ++ return ERR_PTR(PTR_ERR(nnode)); ++ } ++ iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); ++ return ubifs_get_pnode(c, nnode, iip); ++} ++ ++/** ++ * add_pnode_dirt - add dirty space to LPT LEB properties. ++ * @c: UBIFS file-system description object ++ * @pnode: pnode for which to add dirt ++ */ ++static void add_pnode_dirt(struct ubifs_info *c, struct ubifs_pnode *pnode) ++{ ++ ubifs_add_lpt_dirt(c, pnode->parent->nbranch[pnode->iip].lnum, ++ c->pnode_sz); ++} ++ ++/** ++ * do_make_pnode_dirty - mark a pnode dirty. ++ * @c: UBIFS file-system description object ++ * @pnode: pnode to mark dirty ++ */ ++static void do_make_pnode_dirty(struct ubifs_info *c, struct ubifs_pnode *pnode) ++{ ++ /* Assumes cnext list is empty i.e. not called during commit */ ++ if (!test_and_set_bit(DIRTY_CNODE, &pnode->flags)) { ++ struct ubifs_nnode *nnode; ++ ++ c->dirty_pn_cnt += 1; ++ add_pnode_dirt(c, pnode); ++ /* Mark parent and ancestors dirty too */ ++ nnode = pnode->parent; ++ while (nnode) { ++ if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) { ++ c->dirty_nn_cnt += 1; ++ ubifs_add_nnode_dirt(c, nnode); ++ nnode = nnode->parent; ++ } else ++ break; ++ } ++ } ++} ++ ++/** ++ * make_tree_dirty - mark the entire LEB properties tree dirty. ++ * @c: UBIFS file-system description object ++ * ++ * This function is used by the "small" LPT model to cause the entire LEB ++ * properties tree to be written. The "small" LPT model does not use LPT ++ * garbage collection because it is more efficient to write the entire tree ++ * (because it is small). ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int make_tree_dirty(struct ubifs_info *c) ++{ ++ struct ubifs_pnode *pnode; ++ ++ pnode = pnode_lookup(c, 0); ++ while (pnode) { ++ do_make_pnode_dirty(c, pnode); ++ pnode = next_pnode(c, pnode); ++ if (IS_ERR(pnode)) ++ return PTR_ERR(pnode); ++ } ++ return 0; ++} ++ ++/** ++ * need_write_all - determine if the LPT area is running out of free space. ++ * @c: UBIFS file-system description object ++ * ++ * This function returns %1 if the LPT area is running out of free space and %0 ++ * if it is not. ++ */ ++static int need_write_all(struct ubifs_info *c) ++{ ++ long long free = 0; ++ int i; ++ ++ for (i = 0; i < c->lpt_lebs; i++) { ++ if (i + c->lpt_first == c->nhead_lnum) ++ free += c->leb_size - c->nhead_offs; ++ else if (c->ltab[i].free == c->leb_size) ++ free += c->leb_size; ++ else if (c->ltab[i].free + c->ltab[i].dirty == c->leb_size) ++ free += c->leb_size; ++ } ++ /* Less than twice the size left */ ++ if (free <= c->lpt_sz * 2) ++ return 1; ++ return 0; ++} ++ ++/** ++ * lpt_tgc_start - start trivial garbage collection of LPT LEBs. ++ * @c: UBIFS file-system description object ++ * ++ * LPT trivial garbage collection is where a LPT LEB contains only dirty and ++ * free space and so may be reused as soon as the next commit is completed. ++ * This function is called during start commit to mark LPT LEBs for trivial GC. ++ */ ++static void lpt_tgc_start(struct ubifs_info *c) ++{ ++ int i; ++ ++ for (i = 0; i < c->lpt_lebs; i++) { ++ if (i + c->lpt_first == c->nhead_lnum) ++ continue; ++ if (c->ltab[i].dirty > 0 && ++ c->ltab[i].free + c->ltab[i].dirty == c->leb_size) { ++ c->ltab[i].tgc = 1; ++ c->ltab[i].free = c->leb_size; ++ c->ltab[i].dirty = 0; ++ dbg_lp("LEB %d", i + c->lpt_first); ++ } ++ } ++} ++ ++/** ++ * lpt_tgc_end - end trivial garbage collection of LPT LEBs. ++ * @c: UBIFS file-system description object ++ * ++ * LPT trivial garbage collection is where a LPT LEB contains only dirty and ++ * free space and so may be reused as soon as the next commit is completed. ++ * This function is called after the commit is completed (master node has been ++ * written) and unmaps LPT LEBs that were marked for trivial GC. ++ */ ++static int lpt_tgc_end(struct ubifs_info *c) ++{ ++ int i, err; ++ ++ for (i = 0; i < c->lpt_lebs; i++) ++ if (c->ltab[i].tgc) { ++ err = ubifs_leb_unmap(c, i + c->lpt_first); ++ if (err) ++ return err; ++ c->ltab[i].tgc = 0; ++ dbg_lp("LEB %d", i + c->lpt_first); ++ } ++ return 0; ++} ++ ++/** ++ * populate_lsave - fill the lsave array with important LEB numbers. ++ * @c: the UBIFS file-system description object ++ * ++ * This function is only called for the "big" model. It records a small number ++ * of LEB numbers of important LEBs. Important LEBs are ones that are (from ++ * most important to least important): empty, freeable, freeable index, dirty ++ * index, dirty or free. Upon mount, we read this list of LEB numbers and bring ++ * their pnodes into memory. That will stop us from having to scan the LPT ++ * straight away. For the "small" model we assume that scanning the LPT is no ++ * big deal. ++ */ ++static void populate_lsave(struct ubifs_info *c) ++{ ++ struct ubifs_lprops *lprops; ++ struct ubifs_lpt_heap *heap; ++ int i, cnt = 0; ++ ++ ubifs_assert(c->big_lpt); ++ if (!(c->lpt_drty_flgs & LSAVE_DIRTY)) { ++ c->lpt_drty_flgs |= LSAVE_DIRTY; ++ ubifs_add_lpt_dirt(c, c->lsave_lnum, c->lsave_sz); ++ } ++ list_for_each_entry(lprops, &c->empty_list, list) { ++ c->lsave[cnt++] = lprops->lnum; ++ if (cnt >= c->lsave_cnt) ++ return; ++ } ++ list_for_each_entry(lprops, &c->freeable_list, list) { ++ c->lsave[cnt++] = lprops->lnum; ++ if (cnt >= c->lsave_cnt) ++ return; ++ } ++ list_for_each_entry(lprops, &c->frdi_idx_list, list) { ++ c->lsave[cnt++] = lprops->lnum; ++ if (cnt >= c->lsave_cnt) ++ return; ++ } ++ heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1]; ++ for (i = 0; i < heap->cnt; i++) { ++ c->lsave[cnt++] = heap->arr[i]->lnum; ++ if (cnt >= c->lsave_cnt) ++ return; ++ } ++ heap = &c->lpt_heap[LPROPS_DIRTY - 1]; ++ for (i = 0; i < heap->cnt; i++) { ++ c->lsave[cnt++] = heap->arr[i]->lnum; ++ if (cnt >= c->lsave_cnt) ++ return; ++ } ++ heap = &c->lpt_heap[LPROPS_FREE - 1]; ++ for (i = 0; i < heap->cnt; i++) { ++ c->lsave[cnt++] = heap->arr[i]->lnum; ++ if (cnt >= c->lsave_cnt) ++ return; ++ } ++ /* Fill it up completely */ ++ while (cnt < c->lsave_cnt) ++ c->lsave[cnt++] = c->main_first; ++} ++ ++/** ++ * ubifs_lpt_start_commit - UBIFS commit starts. ++ * @c: the UBIFS file-system description object ++ * ++ * This function has to be called when UBIFS starts the commit operation. ++ * This function "freezes" all currently dirty LEB properties and does not ++ * change them anymore. Further changes are saved and tracked separately ++ * because they are not part of this commit. This function returns zero in case ++ * of success and a negative error code in case of failure. ++ */ ++int ubifs_lpt_start_commit(struct ubifs_info *c) ++{ ++ int err, cnt; ++ ++ dbg_lp(""); ++ ++ mutex_lock(&c->lp_mutex); ++ err = dbg_check_ltab(c); ++ if (err) ++ goto out; ++ ++ lpt_tgc_start(c); ++ ++ if (!c->dirty_pn_cnt) { ++ dbg_cmt("no cnodes to commit"); ++ err = 0; ++ goto out; ++ } ++ ++ if (!c->big_lpt && need_write_all(c)) { ++ /* If needed, write everything */ ++ err = make_tree_dirty(c); ++ if (err) ++ goto out; ++ lpt_tgc_start(c); ++ } ++ ++ if (c->big_lpt) ++ populate_lsave(c); ++ ++ cnt = get_cnodes_to_commit(c); ++ ubifs_assert(cnt != 0); ++ ++ err = layout_cnodes(c); ++ if (err) ++ goto out; ++ ++ /* Copy the LPT's own lprops for end commit to write */ ++ memcpy(c->ltab_cmt, c->ltab, ++ sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs); ++ c->lpt_drty_flgs &= ~(LTAB_DIRTY | LSAVE_DIRTY); ++ ++out: ++ mutex_unlock(&c->lp_mutex); ++ return err; ++} ++ ++/** ++ * free_obsolete_cnodes - free obsolete cnodes for commit end. ++ * @c: UBIFS file-system description object ++ */ ++static void free_obsolete_cnodes(struct ubifs_info *c) ++{ ++ struct ubifs_cnode *cnode, *cnext; ++ ++ cnext = c->lpt_cnext; ++ if (!cnext) ++ return; ++ do { ++ cnode = cnext; ++ cnext = cnode->cnext; ++ if (test_bit(OBSOLETE_CNODE, &cnode->flags)) ++ kfree(cnode); ++ else ++ cnode->cnext = NULL; ++ } while (cnext != c->lpt_cnext); ++ c->lpt_cnext = NULL; ++} ++ ++/** ++ * ubifs_lpt_end_commit - finish the commit operation. ++ * @c: the UBIFS file-system description object ++ * ++ * This function has to be called when the commit operation finishes. It ++ * flushes the changes which were "frozen" by 'ubifs_lprops_start_commit()' to ++ * the media. Returns zero in case of success and a negative error code in case ++ * of failure. ++ */ ++int ubifs_lpt_end_commit(struct ubifs_info *c) ++{ ++ int err; ++ ++ dbg_lp(""); ++ ++ if (!c->lpt_cnext) ++ return 0; ++ ++ err = write_cnodes(c); ++ if (err) ++ return err; ++ ++ mutex_lock(&c->lp_mutex); ++ free_obsolete_cnodes(c); ++ mutex_unlock(&c->lp_mutex); ++ ++ return 0; ++} ++ ++/** ++ * nnode_lookup - lookup a nnode in the LPT. ++ * @c: UBIFS file-system description object ++ * @i: nnode number ++ * ++ * This function returns a pointer to the nnode on success or a negative ++ * error code on failure. ++ */ ++static struct ubifs_nnode *nnode_lookup(struct ubifs_info *c, int i) ++{ ++ int err, iip; ++ struct ubifs_nnode *nnode; ++ ++ if (!c->nroot) { ++ err = ubifs_read_nnode(c, NULL, 0); ++ if (err) ++ return ERR_PTR(err); ++ } ++ nnode = c->nroot; ++ while (1) { ++ iip = i & (UBIFS_LPT_FANOUT - 1); ++ i >>= UBIFS_LPT_FANOUT_SHIFT; ++ if (!i) ++ break; ++ nnode = ubifs_get_nnode(c, nnode, iip); ++ if (IS_ERR(nnode)) ++ return nnode; ++ } ++ return nnode; ++} ++ ++/** ++ * make_nnode_dirty - find a nnode and, if found, make it dirty. ++ * @c: UBIFS file-system description object ++ * @node_num: nnode number of nnode to make dirty ++ * @lnum: LEB number where nnode was written ++ * @offs: offset where nnode was written ++ * ++ * This function is used by LPT garbage collection. LPT garbage collection is ++ * used only for the "big" LPT model (c->big_lpt == 1). Garbage collection ++ * simply involves marking all the nodes in the LEB being garbage-collected as ++ * dirty. The dirty nodes are written next commit, after which the LEB is free ++ * to be reused. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int make_nnode_dirty(struct ubifs_info *c, int node_num, int lnum, ++ int offs) ++{ ++ struct ubifs_nnode *nnode; ++ ++ nnode = nnode_lookup(c, node_num); ++ if (IS_ERR(nnode)) ++ return PTR_ERR(nnode); ++ if (nnode->parent) { ++ struct ubifs_nbranch *branch; ++ ++ branch = &nnode->parent->nbranch[nnode->iip]; ++ if (branch->lnum != lnum || branch->offs != offs) ++ return 0; /* nnode is obsolete */ ++ } else if (c->lpt_lnum != lnum || c->lpt_offs != offs) ++ return 0; /* nnode is obsolete */ ++ /* Assumes cnext list is empty i.e. not called during commit */ ++ if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) { ++ c->dirty_nn_cnt += 1; ++ ubifs_add_nnode_dirt(c, nnode); ++ /* Mark parent and ancestors dirty too */ ++ nnode = nnode->parent; ++ while (nnode) { ++ if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) { ++ c->dirty_nn_cnt += 1; ++ ubifs_add_nnode_dirt(c, nnode); ++ nnode = nnode->parent; ++ } else ++ break; ++ } ++ } ++ return 0; ++} ++ ++/** ++ * make_pnode_dirty - find a pnode and, if found, make it dirty. ++ * @c: UBIFS file-system description object ++ * @node_num: pnode number of pnode to make dirty ++ * @lnum: LEB number where pnode was written ++ * @offs: offset where pnode was written ++ * ++ * This function is used by LPT garbage collection. LPT garbage collection is ++ * used only for the "big" LPT model (c->big_lpt == 1). Garbage collection ++ * simply involves marking all the nodes in the LEB being garbage-collected as ++ * dirty. The dirty nodes are written next commit, after which the LEB is free ++ * to be reused. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int make_pnode_dirty(struct ubifs_info *c, int node_num, int lnum, ++ int offs) ++{ ++ struct ubifs_pnode *pnode; ++ struct ubifs_nbranch *branch; ++ ++ pnode = pnode_lookup(c, node_num); ++ if (IS_ERR(pnode)) ++ return PTR_ERR(pnode); ++ branch = &pnode->parent->nbranch[pnode->iip]; ++ if (branch->lnum != lnum || branch->offs != offs) ++ return 0; ++ do_make_pnode_dirty(c, pnode); ++ return 0; ++} ++ ++/** ++ * make_ltab_dirty - make ltab node dirty. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number where ltab was written ++ * @offs: offset where ltab was written ++ * ++ * This function is used by LPT garbage collection. LPT garbage collection is ++ * used only for the "big" LPT model (c->big_lpt == 1). Garbage collection ++ * simply involves marking all the nodes in the LEB being garbage-collected as ++ * dirty. The dirty nodes are written next commit, after which the LEB is free ++ * to be reused. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int make_ltab_dirty(struct ubifs_info *c, int lnum, int offs) ++{ ++ if (lnum != c->ltab_lnum || offs != c->ltab_offs) ++ return 0; /* This ltab node is obsolete */ ++ if (!(c->lpt_drty_flgs & LTAB_DIRTY)) { ++ c->lpt_drty_flgs |= LTAB_DIRTY; ++ ubifs_add_lpt_dirt(c, c->ltab_lnum, c->ltab_sz); ++ } ++ return 0; ++} ++ ++/** ++ * make_lsave_dirty - make lsave node dirty. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number where lsave was written ++ * @offs: offset where lsave was written ++ * ++ * This function is used by LPT garbage collection. LPT garbage collection is ++ * used only for the "big" LPT model (c->big_lpt == 1). Garbage collection ++ * simply involves marking all the nodes in the LEB being garbage-collected as ++ * dirty. The dirty nodes are written next commit, after which the LEB is free ++ * to be reused. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int make_lsave_dirty(struct ubifs_info *c, int lnum, int offs) ++{ ++ if (lnum != c->lsave_lnum || offs != c->lsave_offs) ++ return 0; /* This lsave node is obsolete */ ++ if (!(c->lpt_drty_flgs & LSAVE_DIRTY)) { ++ c->lpt_drty_flgs |= LSAVE_DIRTY; ++ ubifs_add_lpt_dirt(c, c->lsave_lnum, c->lsave_sz); ++ } ++ return 0; ++} ++ ++/** ++ * make_node_dirty - make node dirty. ++ * @c: UBIFS file-system description object ++ * @node_type: LPT node type ++ * @node_num: node number ++ * @lnum: LEB number where node was written ++ * @offs: offset where node was written ++ * ++ * This function is used by LPT garbage collection. LPT garbage collection is ++ * used only for the "big" LPT model (c->big_lpt == 1). Garbage collection ++ * simply involves marking all the nodes in the LEB being garbage-collected as ++ * dirty. The dirty nodes are written next commit, after which the LEB is free ++ * to be reused. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int make_node_dirty(struct ubifs_info *c, int node_type, int node_num, ++ int lnum, int offs) ++{ ++ switch (node_type) { ++ case UBIFS_LPT_NNODE: ++ return make_nnode_dirty(c, node_num, lnum, offs); ++ case UBIFS_LPT_PNODE: ++ return make_pnode_dirty(c, node_num, lnum, offs); ++ case UBIFS_LPT_LTAB: ++ return make_ltab_dirty(c, lnum, offs); ++ case UBIFS_LPT_LSAVE: ++ return make_lsave_dirty(c, lnum, offs); ++ } ++ return -EINVAL; ++} ++ ++/** ++ * get_lpt_node_len - return the length of a node based on its type. ++ * @c: UBIFS file-system description object ++ * @node_type: LPT node type ++ */ ++static int get_lpt_node_len(struct ubifs_info *c, int node_type) ++{ ++ switch (node_type) { ++ case UBIFS_LPT_NNODE: ++ return c->nnode_sz; ++ case UBIFS_LPT_PNODE: ++ return c->pnode_sz; ++ case UBIFS_LPT_LTAB: ++ return c->ltab_sz; ++ case UBIFS_LPT_LSAVE: ++ return c->lsave_sz; ++ } ++ return 0; ++} ++ ++/** ++ * get_pad_len - return the length of padding in a buffer. ++ * @c: UBIFS file-system description object ++ * @buf: buffer ++ * @len: length of buffer ++ */ ++static int get_pad_len(struct ubifs_info *c, uint8_t *buf, int len) ++{ ++ int offs, pad_len; ++ ++ if (c->min_io_size == 1) ++ return 0; ++ offs = c->leb_size - len; ++ pad_len = ALIGN(offs, c->min_io_size) - offs; ++ return pad_len; ++} ++ ++/** ++ * get_lpt_node_type - return type (and node number) of a node in a buffer. ++ * @c: UBIFS file-system description object ++ * @buf: buffer ++ * @node_num: node number is returned here ++ */ ++static int get_lpt_node_type(struct ubifs_info *c, uint8_t *buf, int *node_num) ++{ ++ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; ++ int pos = 0, node_type; ++ ++ node_type = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_TYPE_BITS); ++ *node_num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits); ++ return node_type; ++} ++ ++/** ++ * is_a_node - determine if a buffer contains a node. ++ * @c: UBIFS file-system description object ++ * @buf: buffer ++ * @len: length of buffer ++ * ++ * This function returns %1 if the buffer contains a node or %0 if it does not. ++ */ ++static int is_a_node(struct ubifs_info *c, uint8_t *buf, int len) ++{ ++ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; ++ int pos = 0, node_type, node_len; ++ uint16_t crc, calc_crc; ++ ++ node_type = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_TYPE_BITS); ++ if (node_type == UBIFS_LPT_NOT_A_NODE) ++ return 0; ++ node_len = get_lpt_node_len(c, node_type); ++ if (!node_len || node_len > len) ++ return 0; ++ pos = 0; ++ addr = buf; ++ crc = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_CRC_BITS); ++ calc_crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES, ++ node_len - UBIFS_LPT_CRC_BYTES); ++ if (crc != calc_crc) ++ return 0; ++ return 1; ++} ++ ++ ++/** ++ * lpt_gc_lnum - garbage collect a LPT LEB. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number to garbage collect ++ * ++ * LPT garbage collection is used only for the "big" LPT model ++ * (c->big_lpt == 1). Garbage collection simply involves marking all the nodes ++ * in the LEB being garbage-collected as dirty. The dirty nodes are written ++ * next commit, after which the LEB is free to be reused. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int lpt_gc_lnum(struct ubifs_info *c, int lnum) ++{ ++ int err, len = c->leb_size, node_type, node_num, node_len, offs; ++ void *buf = c->lpt_buf; ++ ++ dbg_lp("LEB %d", lnum); ++ err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size); ++ if (err) { ++ ubifs_err("cannot read LEB %d, error %d", lnum, err); ++ return err; ++ } ++ while (1) { ++ if (!is_a_node(c, buf, len)) { ++ int pad_len; ++ ++ pad_len = get_pad_len(c, buf, len); ++ if (pad_len) { ++ buf += pad_len; ++ len -= pad_len; ++ continue; ++ } ++ return 0; ++ } ++ node_type = get_lpt_node_type(c, buf, &node_num); ++ node_len = get_lpt_node_len(c, node_type); ++ offs = c->leb_size - len; ++ ubifs_assert(node_len != 0); ++ mutex_lock(&c->lp_mutex); ++ err = make_node_dirty(c, node_type, node_num, lnum, offs); ++ mutex_unlock(&c->lp_mutex); ++ if (err) ++ return err; ++ buf += node_len; ++ len -= node_len; ++ } ++ return 0; ++} ++ ++/** ++ * lpt_gc - LPT garbage collection. ++ * @c: UBIFS file-system description object ++ * ++ * Select a LPT LEB for LPT garbage collection and call 'lpt_gc_lnum()'. ++ * Returns %0 on success and a negative error code on failure. ++ */ ++static int lpt_gc(struct ubifs_info *c) ++{ ++ int i, lnum = -1, dirty = 0; ++ ++ mutex_lock(&c->lp_mutex); ++ for (i = 0; i < c->lpt_lebs; i++) { ++ ubifs_assert(!c->ltab[i].tgc); ++ if (i + c->lpt_first == c->nhead_lnum || ++ c->ltab[i].free + c->ltab[i].dirty == c->leb_size) ++ continue; ++ if (c->ltab[i].dirty > dirty) { ++ dirty = c->ltab[i].dirty; ++ lnum = i + c->lpt_first; ++ } ++ } ++ mutex_unlock(&c->lp_mutex); ++ if (lnum == -1) ++ return -ENOSPC; ++ return lpt_gc_lnum(c, lnum); ++} ++ ++/** ++ * ubifs_lpt_post_commit - post commit LPT trivial GC and LPT GC. ++ * @c: UBIFS file-system description object ++ * ++ * LPT trivial GC is completed after a commit. Also LPT GC is done after a ++ * commit for the "big" LPT model. ++ */ ++int ubifs_lpt_post_commit(struct ubifs_info *c) ++{ ++ int err; ++ ++ mutex_lock(&c->lp_mutex); ++ err = lpt_tgc_end(c); ++ if (err) ++ goto out; ++ if (c->big_lpt) ++ while (need_write_all(c)) { ++ mutex_unlock(&c->lp_mutex); ++ err = lpt_gc(c); ++ if (err) ++ return err; ++ mutex_lock(&c->lp_mutex); ++ } ++out: ++ mutex_unlock(&c->lp_mutex); ++ return err; ++} ++ ++/** ++ * first_nnode - find the first nnode in memory. ++ * @c: UBIFS file-system description object ++ * @hght: height of tree where nnode found is returned here ++ * ++ * This function returns a pointer to the nnode found or %NULL if no nnode is ++ * found. This function is a helper to 'ubifs_lpt_free()'. ++ */ ++static struct ubifs_nnode *first_nnode(struct ubifs_info *c, int *hght) ++{ ++ struct ubifs_nnode *nnode; ++ int h, i, found; ++ ++ nnode = c->nroot; ++ *hght = 0; ++ if (!nnode) ++ return NULL; ++ for (h = 1; h < c->lpt_hght; h++) { ++ found = 0; ++ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { ++ if (nnode->nbranch[i].nnode) { ++ found = 1; ++ nnode = nnode->nbranch[i].nnode; ++ *hght = h; ++ break; ++ } ++ } ++ if (!found) ++ break; ++ } ++ return nnode; ++} ++ ++/** ++ * next_nnode - find the next nnode in memory. ++ * @c: UBIFS file-system description object ++ * @nnode: nnode from which to start. ++ * @hght: height of tree where nnode is, is passed and returned here ++ * ++ * This function returns a pointer to the nnode found or %NULL if no nnode is ++ * found. This function is a helper to 'ubifs_lpt_free()'. ++ */ ++static struct ubifs_nnode *next_nnode(struct ubifs_info *c, ++ struct ubifs_nnode *nnode, int *hght) ++{ ++ struct ubifs_nnode *parent; ++ int iip, h, i, found; ++ ++ parent = nnode->parent; ++ if (!parent) ++ return NULL; ++ if (nnode->iip == UBIFS_LPT_FANOUT - 1) { ++ *hght -= 1; ++ return parent; ++ } ++ for (iip = nnode->iip + 1; iip < UBIFS_LPT_FANOUT; iip++) { ++ nnode = parent->nbranch[iip].nnode; ++ if (nnode) ++ break; ++ } ++ if (!nnode) { ++ *hght -= 1; ++ return parent; ++ } ++ for (h = *hght + 1; h < c->lpt_hght; h++) { ++ found = 0; ++ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { ++ if (nnode->nbranch[i].nnode) { ++ found = 1; ++ nnode = nnode->nbranch[i].nnode; ++ *hght = h; ++ break; ++ } ++ } ++ if (!found) ++ break; ++ } ++ return nnode; ++} ++ ++/** ++ * ubifs_lpt_free - free resources owned by the LPT. ++ * @c: UBIFS file-system description object ++ * @wr_only: free only resources used for writing ++ */ ++void ubifs_lpt_free(struct ubifs_info *c, int wr_only) ++{ ++ struct ubifs_nnode *nnode; ++ int i, hght; ++ ++ /* Free write-only things first */ ++ ++ free_obsolete_cnodes(c); /* Leftover from a failed commit */ ++ ++ vfree(c->ltab_cmt); ++ c->ltab_cmt = NULL; ++ vfree(c->lpt_buf); ++ c->lpt_buf = NULL; ++ kfree(c->lsave); ++ c->lsave = NULL; ++ ++ if (wr_only) ++ return; ++ ++ /* Now free the rest */ ++ ++ nnode = first_nnode(c, &hght); ++ while (nnode) { ++ for (i = 0; i < UBIFS_LPT_FANOUT; i++) ++ kfree(nnode->nbranch[i].nnode); ++ nnode = next_nnode(c, nnode, &hght); ++ } ++ for (i = 0; i < LPROPS_HEAP_CNT; i++) ++ kfree(c->lpt_heap[i].arr); ++ kfree(c->dirty_idx.arr); ++ kfree(c->nroot); ++ vfree(c->ltab); ++ kfree(c->lpt_nod_buf); ++} ++ ++#ifdef CONFIG_UBIFS_FS_DEBUG ++ ++/** ++ * dbg_is_all_ff - determine if a buffer contains only 0xff bytes. ++ * @buf: buffer ++ * @len: buffer length ++ */ ++static int dbg_is_all_ff(uint8_t *buf, int len) ++{ ++ int i; ++ ++ for (i = 0; i < len; i++) ++ if (buf[i] != 0xff) ++ return 0; ++ return 1; ++} ++ ++/** ++ * dbg_is_nnode_dirty - determine if a nnode is dirty. ++ * @c: the UBIFS file-system description object ++ * @lnum: LEB number where nnode was written ++ * @offs: offset where nnode was written ++ */ ++static int dbg_is_nnode_dirty(struct ubifs_info *c, int lnum, int offs) ++{ ++ struct ubifs_nnode *nnode; ++ int hght; ++ ++ /* Entire tree is in memory so first_nnode / next_nnode are ok */ ++ nnode = first_nnode(c, &hght); ++ for (; nnode; nnode = next_nnode(c, nnode, &hght)) { ++ struct ubifs_nbranch *branch; ++ ++ cond_resched(); ++ if (nnode->parent) { ++ branch = &nnode->parent->nbranch[nnode->iip]; ++ if (branch->lnum != lnum || branch->offs != offs) ++ continue; ++ if (test_bit(DIRTY_CNODE, &nnode->flags)) ++ return 1; ++ return 0; ++ } else { ++ if (c->lpt_lnum != lnum || c->lpt_offs != offs) ++ continue; ++ if (test_bit(DIRTY_CNODE, &nnode->flags)) ++ return 1; ++ return 0; ++ } ++ } ++ return 1; ++} ++ ++/** ++ * dbg_is_pnode_dirty - determine if a pnode is dirty. ++ * @c: the UBIFS file-system description object ++ * @lnum: LEB number where pnode was written ++ * @offs: offset where pnode was written ++ */ ++static int dbg_is_pnode_dirty(struct ubifs_info *c, int lnum, int offs) ++{ ++ int i, cnt; ++ ++ cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT); ++ for (i = 0; i < cnt; i++) { ++ struct ubifs_pnode *pnode; ++ struct ubifs_nbranch *branch; ++ ++ cond_resched(); ++ pnode = pnode_lookup(c, i); ++ if (IS_ERR(pnode)) ++ return PTR_ERR(pnode); ++ branch = &pnode->parent->nbranch[pnode->iip]; ++ if (branch->lnum != lnum || branch->offs != offs) ++ continue; ++ if (test_bit(DIRTY_CNODE, &pnode->flags)) ++ return 1; ++ return 0; ++ } ++ return 1; ++} ++ ++/** ++ * dbg_is_ltab_dirty - determine if a ltab node is dirty. ++ * @c: the UBIFS file-system description object ++ * @lnum: LEB number where ltab node was written ++ * @offs: offset where ltab node was written ++ */ ++static int dbg_is_ltab_dirty(struct ubifs_info *c, int lnum, int offs) ++{ ++ if (lnum != c->ltab_lnum || offs != c->ltab_offs) ++ return 1; ++ return (c->lpt_drty_flgs & LTAB_DIRTY) != 0; ++} ++ ++/** ++ * dbg_is_lsave_dirty - determine if a lsave node is dirty. ++ * @c: the UBIFS file-system description object ++ * @lnum: LEB number where lsave node was written ++ * @offs: offset where lsave node was written ++ */ ++static int dbg_is_lsave_dirty(struct ubifs_info *c, int lnum, int offs) ++{ ++ if (lnum != c->lsave_lnum || offs != c->lsave_offs) ++ return 1; ++ return (c->lpt_drty_flgs & LSAVE_DIRTY) != 0; ++} ++ ++/** ++ * dbg_is_node_dirty - determine if a node is dirty. ++ * @c: the UBIFS file-system description object ++ * @node_type: node type ++ * @lnum: LEB number where node was written ++ * @offs: offset where node was written ++ */ ++static int dbg_is_node_dirty(struct ubifs_info *c, int node_type, int lnum, ++ int offs) ++{ ++ switch (node_type) { ++ case UBIFS_LPT_NNODE: ++ return dbg_is_nnode_dirty(c, lnum, offs); ++ case UBIFS_LPT_PNODE: ++ return dbg_is_pnode_dirty(c, lnum, offs); ++ case UBIFS_LPT_LTAB: ++ return dbg_is_ltab_dirty(c, lnum, offs); ++ case UBIFS_LPT_LSAVE: ++ return dbg_is_lsave_dirty(c, lnum, offs); ++ } ++ return 1; ++} ++ ++/** ++ * dbg_check_ltab_lnum - check the ltab for a LPT LEB number. ++ * @c: the UBIFS file-system description object ++ * @lnum: LEB number where node was written ++ * @offs: offset where node was written ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum) ++{ ++ int err, len = c->leb_size, dirty = 0, node_type, node_num, node_len; ++ int ret; ++ void *buf = c->dbg_buf; ++ ++ dbg_lp("LEB %d", lnum); ++ err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size); ++ if (err) { ++ dbg_msg("ubi_read failed, LEB %d, error %d", lnum, err); ++ return err; ++ } ++ while (1) { ++ if (!is_a_node(c, buf, len)) { ++ int i, pad_len; ++ ++ pad_len = get_pad_len(c, buf, len); ++ if (pad_len) { ++ buf += pad_len; ++ len -= pad_len; ++ dirty += pad_len; ++ continue; ++ } ++ if (!dbg_is_all_ff(buf, len)) { ++ dbg_msg("invalid empty space in LEB %d at %d", ++ lnum, c->leb_size - len); ++ err = -EINVAL; ++ } ++ i = lnum - c->lpt_first; ++ if (len != c->ltab[i].free) { ++ dbg_msg("invalid free space in LEB %d " ++ "(free %d, expected %d)", ++ lnum, len, c->ltab[i].free); ++ err = -EINVAL; ++ } ++ if (dirty != c->ltab[i].dirty) { ++ dbg_msg("invalid dirty space in LEB %d " ++ "(dirty %d, expected %d)", ++ lnum, dirty, c->ltab[i].dirty); ++ err = -EINVAL; ++ } ++ return err; ++ } ++ node_type = get_lpt_node_type(c, buf, &node_num); ++ node_len = get_lpt_node_len(c, node_type); ++ ret = dbg_is_node_dirty(c, node_type, lnum, c->leb_size - len); ++ if (ret == 1) ++ dirty += node_len; ++ buf += node_len; ++ len -= node_len; ++ } ++} ++ ++/** ++ * dbg_check_ltab - check the free and dirty space in the ltab. ++ * @c: the UBIFS file-system description object ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++int dbg_check_ltab(struct ubifs_info *c) ++{ ++ int lnum, err, i, cnt; ++ ++ if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) ++ return 0; ++ ++ /* Bring the entire tree into memory */ ++ cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT); ++ for (i = 0; i < cnt; i++) { ++ struct ubifs_pnode *pnode; ++ ++ pnode = pnode_lookup(c, i); ++ if (IS_ERR(pnode)) ++ return PTR_ERR(pnode); ++ cond_resched(); ++ } ++ ++ /* Check nodes */ ++ err = dbg_check_lpt_nodes(c, (struct ubifs_cnode *)c->nroot, 0, 0); ++ if (err) ++ return err; ++ ++ /* Check each LEB */ ++ for (lnum = c->lpt_first; lnum <= c->lpt_last; lnum++) { ++ err = dbg_check_ltab_lnum(c, lnum); ++ if (err) { ++ dbg_err("failed at LEB %d", lnum); ++ return err; ++ } ++ } ++ ++ dbg_lp("succeeded"); ++ return 0; ++} ++ ++#endif /* CONFIG_UBIFS_FS_DEBUG */ +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/Makefile avr32-2.6/fs/ubifs/Makefile +--- linux-2.6.25.6/fs/ubifs/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/Makefile 2008-06-12 15:09:45.311815896 +0200 +@@ -0,0 +1,9 @@ ++obj-$(CONFIG_UBIFS_FS) += ubifs.o ++ ++ubifs-y += shrinker.o journal.o file.o dir.o super.o sb.o io.o ++ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o ++ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o ++ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o ++ ++ubifs-$(CONFIG_UBIFS_FS_DEBUG) += debug.o ++ubifs-$(CONFIG_UBIFS_FS_XATTR) += xattr.o +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/master.c avr32-2.6/fs/ubifs/master.c +--- linux-2.6.25.6/fs/ubifs/master.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/master.c 2008-06-12 15:09:45.475816115 +0200 +@@ -0,0 +1,387 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Artem Bityutskiy (Битюцкий Артём) ++ * Adrian Hunter ++ */ ++ ++/* This file implements reading and writing the master node */ ++ ++#include "ubifs.h" ++ ++/** ++ * scan_for_master - search the valid master node. ++ * @c: UBIFS file-system description object ++ * ++ * This function scans the master node LEBs and search for the latest master ++ * node. Returns zero in case of success and a negative error code in case of ++ * failure. ++ */ ++static int scan_for_master(struct ubifs_info *c) ++{ ++ struct ubifs_scan_leb *sleb; ++ struct ubifs_scan_node *snod; ++ int lnum, offs = 0, nodes_cnt; ++ ++ lnum = UBIFS_MST_LNUM; ++ ++ sleb = ubifs_scan(c, lnum, 0, c->sbuf); ++ if (IS_ERR(sleb)) ++ return PTR_ERR(sleb); ++ nodes_cnt = sleb->nodes_cnt; ++ if (nodes_cnt > 0) { ++ snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node, ++ list); ++ if (snod->type != UBIFS_MST_NODE) ++ goto out; ++ memcpy(c->mst_node, snod->node, snod->len); ++ offs = snod->offs; ++ } ++ ubifs_scan_destroy(sleb); ++ ++ lnum += 1; ++ ++ sleb = ubifs_scan(c, lnum, 0, c->sbuf); ++ if (IS_ERR(sleb)) ++ return PTR_ERR(sleb); ++ if (sleb->nodes_cnt != nodes_cnt) ++ goto out; ++ if (!sleb->nodes_cnt) ++ goto out; ++ snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node, list); ++ if (snod->type != UBIFS_MST_NODE) ++ goto out; ++ if (snod->offs != offs) ++ goto out; ++ if (memcmp((void *)c->mst_node + UBIFS_CH_SZ, ++ (void *)snod->node + UBIFS_CH_SZ, ++ UBIFS_MST_NODE_SZ - UBIFS_CH_SZ)) ++ goto out; ++ c->mst_offs = offs; ++ ubifs_scan_destroy(sleb); ++ return 0; ++ ++out: ++ ubifs_scan_destroy(sleb); ++ return -EINVAL; ++} ++ ++/** ++ * validate_master - validate master node. ++ * @c: UBIFS file-system description object ++ * ++ * This function validates data which was read from master node. Returns zero ++ * if the data is all right and %-EINVAL if not. ++ */ ++static int validate_master(const struct ubifs_info *c) ++{ ++ unsigned long long main_sz; ++ int err; ++ ++ if (c->max_sqnum >= SQNUM_WATERMARK) { ++ err = 1; ++ goto out; ++ } ++ ++ if (c->cmt_no >= c->max_sqnum) { ++ err = 2; ++ goto out; ++ } ++ ++ if (c->highest_inum >= INUM_WATERMARK) { ++ err = 3; ++ goto out; ++ } ++ ++ if (c->lhead_lnum < UBIFS_LOG_LNUM || ++ c->lhead_lnum >= UBIFS_LOG_LNUM + c->log_lebs || ++ c->lhead_offs < 0 || c->lhead_offs >= c->leb_size || ++ c->lhead_offs & (c->min_io_size - 1)) { ++ err = 4; ++ goto out; ++ } ++ ++ if (c->zroot.lnum >= c->leb_cnt || c->zroot.lnum < c->main_first || ++ c->zroot.offs >= c->leb_size || c->zroot.offs & 7) { ++ err = 5; ++ goto out; ++ } ++ ++ if (c->zroot.len < c->ranges[UBIFS_IDX_NODE].min_len || ++ c->zroot.len > c->ranges[UBIFS_IDX_NODE].max_len) { ++ err = 6; ++ goto out; ++ } ++ ++ if (c->gc_lnum >= c->leb_cnt || c->gc_lnum < c->main_first) { ++ err = 7; ++ goto out; ++ } ++ ++ if (c->ihead_lnum >= c->leb_cnt || c->ihead_lnum < c->main_first || ++ c->ihead_offs % c->min_io_size || c->ihead_offs < 0 || ++ c->ihead_offs > c->leb_size || c->ihead_offs & 7) { ++ err = 8; ++ goto out; ++ } ++ ++ main_sz = c->main_lebs * (unsigned long long)c->leb_size; ++ if (c->old_idx_sz & 7 || c->old_idx_sz >= main_sz) { ++ err = 9; ++ goto out; ++ } ++ ++ if (c->lpt_lnum < c->lpt_first || c->lpt_lnum > c->lpt_last || ++ c->lpt_offs < 0 || c->lpt_offs + c->nnode_sz > c->leb_size) { ++ err = 10; ++ goto out; ++ } ++ ++ if (c->nhead_lnum < c->lpt_first || c->nhead_lnum > c->lpt_last || ++ c->nhead_offs < 0 || c->nhead_offs % c->min_io_size || ++ c->nhead_offs > c->leb_size) { ++ err = 11; ++ goto out; ++ } ++ ++ if (c->ltab_lnum < c->lpt_first || c->ltab_lnum > c->lpt_last || ++ c->ltab_offs < 0 || ++ c->ltab_offs + c->ltab_sz > c->leb_size) { ++ err = 12; ++ goto out; ++ } ++ ++ if (c->big_lpt && (c->lsave_lnum < c->lpt_first || ++ c->lsave_lnum > c->lpt_last || c->lsave_offs < 0 || ++ c->lsave_offs + c->lsave_sz > c->leb_size)) { ++ err = 13; ++ goto out; ++ } ++ ++ if (c->lscan_lnum < c->main_first || c->lscan_lnum >= c->leb_cnt) { ++ err = 14; ++ goto out; ++ } ++ ++ if (c->lst.empty_lebs < 0 || c->lst.empty_lebs > c->main_lebs - 2) { ++ err = 15; ++ goto out; ++ } ++ ++ if (c->lst.idx_lebs < 0 || c->lst.idx_lebs > c->main_lebs - 1) { ++ err = 16; ++ goto out; ++ } ++ ++ if (c->lst.total_free < 0 || c->lst.total_free > main_sz || ++ c->lst.total_free & 7) { ++ err = 17; ++ goto out; ++ } ++ ++ if (c->lst.total_dirty < 0 || (c->lst.total_dirty & 7)) { ++ err = 18; ++ goto out; ++ } ++ ++ if (c->lst.total_used < 0 || (c->lst.total_used & 7)) { ++ err = 19; ++ goto out; ++ } ++ ++ if (c->lst.total_free + c->lst.total_dirty + ++ c->lst.total_used > main_sz) { ++ err = 20; ++ goto out; ++ } ++ ++ if (c->lst.total_dead + c->lst.total_dark + ++ c->lst.total_used + c->old_idx_sz > main_sz) { ++ err = 21; ++ goto out; ++ } ++ ++ if (c->lst.total_dead < 0 || ++ c->lst.total_dead > c->lst.total_free + c->lst.total_dirty || ++ c->lst.total_dead & 7) { ++ err = 22; ++ goto out; ++ } ++ ++ if (c->lst.total_dark < 0 || ++ c->lst.total_dark > c->lst.total_free + c->lst.total_dirty || ++ c->lst.total_dark & 7) { ++ err = 23; ++ goto out; ++ } ++ ++ return 0; ++ ++out: ++ ubifs_err("bad master node at offset %d error %d", c->mst_offs, err); ++ dbg_dump_node(c, c->mst_node); ++ return -EINVAL; ++} ++ ++/** ++ * ubifs_read_master - read master node. ++ * @c: UBIFS file-system description object ++ * ++ * This function finds and reads the master node during file-system mount. If ++ * the flash is empty, it creates default master node as well. Returns zero in ++ * case of success and a negative error code in case of failure. ++ */ ++int ubifs_read_master(struct ubifs_info *c) ++{ ++ int err, old_leb_cnt; ++ ++ c->mst_node = kzalloc(c->mst_node_alsz, GFP_KERNEL); ++ if (!c->mst_node) ++ return -ENOMEM; ++ ++ err = scan_for_master(c); ++ if (err) { ++ err = ubifs_recover_master_node(c); ++ if (err) ++ /* ++ * Note, we do not free 'c->mst_node' here because the ++ * unmount routine will take care of this. ++ */ ++ return err; ++ } ++ ++ /* Make sure that the recovery flag is clear */ ++ c->mst_node->flags &= cpu_to_le32(~UBIFS_MST_RCVRY); ++ ++ c->max_sqnum = le64_to_cpu(c->mst_node->ch.sqnum); ++ c->highest_inum = le64_to_cpu(c->mst_node->highest_inum); ++ c->cmt_no = le64_to_cpu(c->mst_node->cmt_no); ++ c->zroot.lnum = le32_to_cpu(c->mst_node->root_lnum); ++ c->zroot.offs = le32_to_cpu(c->mst_node->root_offs); ++ c->zroot.len = le32_to_cpu(c->mst_node->root_len); ++ c->lhead_lnum = le32_to_cpu(c->mst_node->log_lnum); ++ c->gc_lnum = le32_to_cpu(c->mst_node->gc_lnum); ++ c->ihead_lnum = le32_to_cpu(c->mst_node->ihead_lnum); ++ c->ihead_offs = le32_to_cpu(c->mst_node->ihead_offs); ++ c->old_idx_sz = le64_to_cpu(c->mst_node->index_size); ++ c->lpt_lnum = le32_to_cpu(c->mst_node->lpt_lnum); ++ c->lpt_offs = le32_to_cpu(c->mst_node->lpt_offs); ++ c->nhead_lnum = le32_to_cpu(c->mst_node->nhead_lnum); ++ c->nhead_offs = le32_to_cpu(c->mst_node->nhead_offs); ++ c->ltab_lnum = le32_to_cpu(c->mst_node->ltab_lnum); ++ c->ltab_offs = le32_to_cpu(c->mst_node->ltab_offs); ++ c->lsave_lnum = le32_to_cpu(c->mst_node->lsave_lnum); ++ c->lsave_offs = le32_to_cpu(c->mst_node->lsave_offs); ++ c->lscan_lnum = le32_to_cpu(c->mst_node->lscan_lnum); ++ c->lst.empty_lebs = le32_to_cpu(c->mst_node->empty_lebs); ++ c->lst.idx_lebs = le32_to_cpu(c->mst_node->idx_lebs); ++ old_leb_cnt = le32_to_cpu(c->mst_node->leb_cnt); ++ c->lst.total_free = le64_to_cpu(c->mst_node->total_free); ++ c->lst.total_dirty = le64_to_cpu(c->mst_node->total_dirty); ++ c->lst.total_used = le64_to_cpu(c->mst_node->total_used); ++ c->lst.total_dead = le64_to_cpu(c->mst_node->total_dead); ++ c->lst.total_dark = le64_to_cpu(c->mst_node->total_dark); ++ ++ c->calc_idx_sz = c->old_idx_sz; ++ ++ if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS)) ++ c->no_orphs = 1; ++ ++ if (old_leb_cnt != c->leb_cnt) { ++ /* The file system has been resized */ ++ int growth = c->leb_cnt - old_leb_cnt; ++ ++ if (c->leb_cnt < old_leb_cnt || ++ c->leb_cnt < UBIFS_MIN_LEB_CNT) { ++ ubifs_err("bad leb_cnt on master node"); ++ dbg_dump_node(c, c->mst_node); ++ return -EINVAL; ++ } ++ ++ dbg_mnt("Auto resizing (master) from %d LEBs to %d LEBs", ++ old_leb_cnt, c->leb_cnt); ++ c->lst.empty_lebs += growth; ++ c->lst.total_free += growth * (long long)c->leb_size; ++ c->lst.total_dark += growth * (long long)c->dark_wm; ++ ++ /* ++ * Reflect changes back onto the master node. N.B. the master ++ * node gets written immediately whenever mounting (or ++ * remounting) in read-write mode, so we do not need to write it ++ * here. ++ */ ++ c->mst_node->leb_cnt = cpu_to_le32(c->leb_cnt); ++ c->mst_node->empty_lebs = cpu_to_le32(c->lst.empty_lebs); ++ c->mst_node->total_free = cpu_to_le64(c->lst.total_free); ++ c->mst_node->total_dark = cpu_to_le64(c->lst.total_dark); ++ } ++ ++ err = validate_master(c); ++ if (err) ++ return err; ++ ++ err = dbg_old_index_check_init(c, &c->zroot); ++ ++ return err; ++} ++ ++/** ++ * ubifs_write_master - write master node. ++ * @c: UBIFS file-system description object ++ * ++ * This function writes the master node. The caller has to take the ++ * @c->mst_mutex lock before calling this function. Returns zero in case of ++ * success and a negative error code in case of failure. The master node is ++ * written twice to enable recovery. ++ */ ++int ubifs_write_master(struct ubifs_info *c) ++{ ++ int err, lnum, offs, len; ++ ++ if (c->ro_media) ++ return -EINVAL; ++ ++ lnum = UBIFS_MST_LNUM; ++ offs = c->mst_offs + c->mst_node_alsz; ++ len = UBIFS_MST_NODE_SZ; ++ ++ if (offs + UBIFS_MST_NODE_SZ > c->leb_size) { ++ err = ubifs_leb_unmap(c, lnum); ++ if (err) ++ return err; ++ offs = 0; ++ } ++ ++ c->mst_offs = offs; ++ c->mst_node->highest_inum = cpu_to_le64(c->highest_inum); ++ ++ err = ubifs_write_node(c, c->mst_node, len, lnum, offs, UBI_SHORTTERM); ++ if (err) ++ return err; ++ ++ lnum += 1; ++ ++ if (offs == 0) { ++ err = ubifs_leb_unmap(c, lnum); ++ if (err) ++ return err; ++ } ++ err = ubifs_write_node(c, c->mst_node, len, lnum, offs, UBI_SHORTTERM); ++ ++ return err; ++} +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/misc.h avr32-2.6/fs/ubifs/misc.h +--- linux-2.6.25.6/fs/ubifs/misc.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/misc.h 2008-06-12 15:09:45.475816115 +0200 +@@ -0,0 +1,311 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Artem Bityutskiy (Битюцкий Артём) ++ * Adrian Hunter ++ */ ++ ++/* ++ * This file contains miscellaneous helper functions. ++ */ ++ ++#ifndef __UBIFS_MISC_H__ ++#define __UBIFS_MISC_H__ ++ ++/** ++ * ubifs_zn_dirty - check if znode is dirty. ++ * @znode: znode to check ++ * ++ * This helper function returns %1 if @znode is dirty and %0 otherwise. ++ */ ++static inline int ubifs_zn_dirty(const struct ubifs_znode *znode) ++{ ++ return !!test_bit(DIRTY_ZNODE, &znode->flags); ++} ++ ++/** ++ * ubifs_wake_up_bgt - wake up background thread. ++ * @c: UBIFS file-system description object ++ */ ++static inline void ubifs_wake_up_bgt(struct ubifs_info *c) ++{ ++ if (c->bgt && !c->need_bgt) { ++ c->need_bgt = 1; ++ wake_up_process(c->bgt); ++ } ++} ++ ++/** ++ * ubifs_tnc_find_child - find next child in znode. ++ * @znode: znode to search at ++ * @start: the zbranch index to start at ++ * ++ * This helper function looks for znode child starting at index @start. Returns ++ * the child or %NULL if no children were found. ++ */ ++static inline struct ubifs_znode * ++ubifs_tnc_find_child(struct ubifs_znode *znode, int start) ++{ ++ while (start < znode->child_cnt) { ++ if (znode->zbranch[start].znode) ++ return znode->zbranch[start].znode; ++ start += 1; ++ } ++ ++ return NULL; ++} ++ ++/** ++ * ubifs_inode - get UBIFS inode information by VFS 'struct inode' object. ++ * @inode: the VFS 'struct inode' pointer ++ */ ++static inline struct ubifs_inode *ubifs_inode(const struct inode *inode) ++{ ++ return container_of(inode, struct ubifs_inode, vfs_inode); ++} ++ ++/** ++ * ubifs_ro_mode - switch UBIFS to read read-only mode. ++ * @c: UBIFS file-system description object ++ * @err: error code which is the reason of switching to R/O mode ++ */ ++static inline void ubifs_ro_mode(struct ubifs_info *c, int err) ++{ ++ if (!c->ro_media) { ++ c->ro_media = 1; ++ ubifs_warn("switched to read-only mode, error %d", err); ++ dbg_dump_stack(); ++ } ++} ++ ++/** ++ * ubifs_compr_present - check if compressor was compiled in. ++ * @compr_type: compressor type to check ++ * ++ * This function returns %1 of compressor of type @compr_type is present, and ++ * %0 if not. ++ */ ++static inline int ubifs_compr_present(int compr_type) ++{ ++ ubifs_assert(compr_type >= 0 && compr_type < UBIFS_COMPR_TYPES_CNT); ++ return !!ubifs_compressors[compr_type]->capi_name; ++} ++ ++/** ++ * ubifs_compr_name - get compressor name string by its type. ++ * @compr_type: compressor type ++ * ++ * This function returns compressor type string. ++ */ ++static inline const char *ubifs_compr_name(int compr_type) ++{ ++ ubifs_assert(compr_type >= 0 && compr_type < UBIFS_COMPR_TYPES_CNT); ++ return ubifs_compressors[compr_type]->name; ++} ++ ++/** ++ * ubifs_wbuf_sync - synchronize write-buffer. ++ * @wbuf: write-buffer to synchronize ++ * ++ * This is the same as as 'ubifs_wbuf_sync_nolock()' but it does not assume ++ * that the write-buffer is already locked. ++ */ ++static inline int ubifs_wbuf_sync(struct ubifs_wbuf *wbuf) ++{ ++ int err; ++ ++ mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); ++ err = ubifs_wbuf_sync_nolock(wbuf); ++ mutex_unlock(&wbuf->io_mutex); ++ return err; ++} ++ ++/** ++ * ubifs_leb_unmap - unmap an LEB. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number to unmap ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static inline int ubifs_leb_unmap(const struct ubifs_info *c, int lnum) ++{ ++ int err; ++ ++ err = ubi_leb_unmap(c->ubi, lnum); ++ if (err) { ++ ubifs_err("unmap LEB %d failed, error %d", lnum, err); ++ return err; ++ } ++ ++ return 0; ++} ++ ++/** ++ * ubifs_leb_write - write to a LEB. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number to write ++ * @buf: buffer to write from ++ * @offs: offset within LEB to write to ++ * @len: length to write ++ * @dtype: data type ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static inline int ubifs_leb_write(const struct ubifs_info *c, int lnum, ++ const void *buf, int offs, int len, int dtype) ++{ ++ int err; ++ ++ err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype); ++ if (err) { ++ ubifs_err("writing %d bytes at %d:%d, error %d", ++ len, lnum, offs, err); ++ return err; ++ } ++ ++ return 0; ++} ++ ++/** ++ * ubifs_encode_dev - encode device node IDs. ++ * @dev: UBIFS device node information ++ * @rdev: device IDs to encode ++ * ++ * This is a helper function which encodes major/minor numbers of a device node ++ * into UBIFS device node description. We use standard Linux "new" and "huge" ++ * encodings. ++ */ ++static inline int ubifs_encode_dev(union ubifs_dev_desc *dev, dev_t rdev) ++{ ++ if (new_valid_dev(rdev)) { ++ dev->new = cpu_to_le32(new_encode_dev(rdev)); ++ return sizeof(dev->new); ++ } else { ++ dev->huge = cpu_to_le64(huge_encode_dev(rdev)); ++ return sizeof(dev->huge); ++ } ++} ++ ++/** ++ * ubifs_add_dirt - add dirty space to LEB properties. ++ * @c: the UBIFS file-system description object ++ * @lnum: LEB to add dirty space for ++ * @dirty: dirty space to add ++ * ++ * This is a helper function which increased amount of dirty LEB space. Returns ++ * zero in case of success and a negative error code in case of failure. ++ */ ++static inline int ubifs_add_dirt(struct ubifs_info *c, int lnum, int dirty) ++{ ++ return ubifs_update_one_lp(c, lnum, LPROPS_NC, dirty, 0, 0); ++} ++ ++/** ++ * ubifs_return_leb - return LEB to lprops. ++ * @c: the UBIFS file-system description object ++ * @lnum: LEB to return ++ * ++ * This helper function cleans the "taken" flag of a logical eraseblock in the ++ * lprops. Returns zero in case of success and a negative error code in case of ++ * failure. ++ */ ++static inline int ubifs_return_leb(struct ubifs_info *c, int lnum) ++{ ++ return ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0, ++ LPROPS_TAKEN, 0); ++} ++ ++/** ++ * ubifs_idx_node_sz - return index node size. ++ * @c: the UBIFS file-system description object ++ * @child_cnt: number of children of this index node ++ */ ++static inline int ubifs_idx_node_sz(const struct ubifs_info *c, int child_cnt) ++{ ++ return UBIFS_IDX_NODE_SZ + (UBIFS_BRANCH_SZ + c->key_len) * child_cnt; ++} ++ ++/** ++ * ubifs_idx_branch - return pointer to an index branch. ++ * @c: the UBIFS file-system description object ++ * @idx: index node ++ * @bnum: branch number ++ */ ++static inline ++struct ubifs_branch *ubifs_idx_branch(const struct ubifs_info *c, ++ const struct ubifs_idx_node *idx, ++ int bnum) ++{ ++ return (struct ubifs_branch *)((void *)idx->branches + ++ (UBIFS_BRANCH_SZ + c->key_len) * bnum); ++} ++ ++/** ++ * ubifs_idx_key - return pointer to an index key. ++ * @c: the UBIFS file-system description object ++ * @idx: index node ++ */ ++static inline void *ubifs_idx_key(const struct ubifs_info *c, ++ const struct ubifs_idx_node *idx) ++{ ++ return (void *)((struct ubifs_branch *)idx->branches)->key; ++} ++ ++/** ++ * ubifs_reported_space - calculate reported free space. ++ * @c: the UBIFS file-system description object ++ * @free: amount of free space ++ * ++ * This function calculates amount of free space which will be reported to ++ * user-space. User-space application tend to expect that if the file-system ++ * (e.g., via the 'statfs()' call) reports that it has N bytes available, they ++ * are able to write a file of size N. UBIFS attaches node headers to each data ++ * node and it has to write indexind nodes as well. This introduces additional ++ * overhead, and UBIFS it has to report sligtly less free space to meet the ++ * above expectetion. ++ * ++ * This function assumes free space is made up of uncompressed data nodes and ++ * full index nodes (one per data node, doubled because we always allow enough ++ * space to write the index twice). ++ * ++ * Note, the calculation is pessimistic, which means that most of the time ++ * UBIFS reports less space than it actually has. ++ */ ++static inline long long ubifs_reported_space(const struct ubifs_info *c, ++ uint64_t free) ++{ ++ int divisor, factor; ++ ++ divisor = UBIFS_MAX_DATA_NODE_SZ + (c->max_idx_node_sz << 1); ++ factor = UBIFS_MAX_DATA_NODE_SZ - UBIFS_DATA_NODE_SZ; ++ do_div(free, divisor); ++ ++ return free * factor; ++} ++ ++/** ++ * ubifs_current_time - round current time to time granularity. ++ * @inode: inode ++ */ ++static inline struct timespec ubifs_current_time(struct inode *inode) ++{ ++ return (inode->i_sb->s_time_gran < NSEC_PER_SEC) ? ++ current_fs_time(inode->i_sb) : CURRENT_TIME_SEC; ++} ++ ++#endif /* __UBIFS_MISC_H__ */ +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/orphan.c avr32-2.6/fs/ubifs/orphan.c +--- linux-2.6.25.6/fs/ubifs/orphan.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/orphan.c 2008-06-12 15:09:45.475816115 +0200 +@@ -0,0 +1,958 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Author: Adrian Hunter ++ */ ++ ++#include "ubifs.h" ++ ++/* ++ * An orphan is an inode number whose inode node has been committed to the index ++ * with a link count of zero. That happens when an open file is deleted ++ * (unlinked) and then a commit is run. In the normal course of events the inode ++ * would be deleted when the file is closed. However in the case of an unclean ++ * unmount, orphans need to be accounted for. After an unclean unmount, the ++ * orphans' inodes must be deleted which means either scanning the entire index ++ * looking for them, or keeping a list on flash somewhere. This unit implements ++ * the latter approach. ++ * ++ * The orphan area is a fixed number of LEBs situated between the LPT area and ++ * the main area. The number of orphan area LEBs is specified when the file ++ * system is created. The minimum number is 1. The size of the orphan area ++ * should be so that it can hold the maximum number of orphans that are expected ++ * to ever exist at one time. ++ * ++ * The number of orphans that can fit in a LEB is: ++ * ++ * (c->leb_size - UBIFS_ORPH_NODE_SZ) / sizeof(__le64) ++ * ++ * For example: a 15872 byte LEB can fit 1980 orphans so 1 LEB may be enough. ++ * ++ * Orphans are accumulated in a rb-tree. When an inode's link count drops to ++ * zero, the inode number is added to the rb-tree. It is removed from the tree ++ * when the inode is deleted. Any new orphans that are in the orphan tree when ++ * the commit is run, are written to the orphan area in 1 or more orph nodes. ++ * If the orphan area is full, it is consolidated to make space. There is ++ * always enough space because validation prevents the user from creating more ++ * than the maximum number of orphans allowed. ++ */ ++ ++#ifdef CONFIG_UBIFS_FS_DEBUG ++static int dbg_check_orphans(struct ubifs_info *c); ++#else ++#define dbg_check_orphans(c) 0 ++#endif ++ ++/** ++ * ubifs_add_orphan - add an orphan. ++ * @c: UBIFS file-system description object ++ * @inum: orphan inode number ++ * ++ * Add an orphan. This function is called when an inodes link count drops to ++ * zero. ++ */ ++int ubifs_add_orphan(struct ubifs_info *c, ino_t inum) ++{ ++ struct ubifs_orphan *orphan, *o; ++ struct rb_node **p, *parent = NULL; ++ ++ orphan = kzalloc(sizeof(struct ubifs_orphan), GFP_NOFS); ++ if (!orphan) ++ return -ENOMEM; ++ orphan->inum = inum; ++ orphan->new = 1; ++ ++ spin_lock(&c->orphan_lock); ++ if (c->tot_orphans >= c->max_orphans) { ++ spin_unlock(&c->orphan_lock); ++ kfree(orphan); ++ return -ENFILE; ++ } ++ p = &c->orph_tree.rb_node; ++ while (*p) { ++ parent = *p; ++ o = rb_entry(parent, struct ubifs_orphan, rb); ++ if (inum < o->inum) ++ p = &(*p)->rb_left; ++ else if (inum > o->inum) ++ p = &(*p)->rb_right; ++ else { ++ dbg_err("orphaned twice"); ++ spin_unlock(&c->orphan_lock); ++ kfree(orphan); ++ return 0; ++ } ++ } ++ c->tot_orphans += 1; ++ c->new_orphans += 1; ++ rb_link_node(&orphan->rb, parent, p); ++ rb_insert_color(&orphan->rb, &c->orph_tree); ++ list_add_tail(&orphan->list, &c->orph_list); ++ list_add_tail(&orphan->new_list, &c->orph_new); ++ spin_unlock(&c->orphan_lock); ++ dbg_gen("ino %lu", inum); ++ return 0; ++} ++ ++/** ++ * ubifs_delete_orphan - delete an orphan. ++ * @c: UBIFS file-system description object ++ * @inum: orphan inode number ++ * ++ * Delete an orphan. This function is called when an inode is deleted. ++ */ ++void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum) ++{ ++ struct ubifs_orphan *o; ++ struct rb_node *p; ++ ++ spin_lock(&c->orphan_lock); ++ p = c->orph_tree.rb_node; ++ while (p) { ++ o = rb_entry(p, struct ubifs_orphan, rb); ++ if (inum < o->inum) ++ p = p->rb_left; ++ else if (inum > o->inum) ++ p = p->rb_right; ++ else { ++ if (o->dnext) { ++ spin_unlock(&c->orphan_lock); ++ dbg_gen("deleted twice ino %lu", inum); ++ return; ++ } ++ if (o->cnext) { ++ o->dnext = c->orph_dnext; ++ c->orph_dnext = o; ++ spin_unlock(&c->orphan_lock); ++ dbg_gen("delete later ino %lu", inum); ++ return; ++ } ++ rb_erase(p, &c->orph_tree); ++ list_del(&o->list); ++ c->tot_orphans -= 1; ++ if (o->new) { ++ list_del(&o->new_list); ++ c->new_orphans -= 1; ++ } ++ spin_unlock(&c->orphan_lock); ++ kfree(o); ++ dbg_gen("inum %lu", inum); ++ return; ++ } ++ } ++ spin_unlock(&c->orphan_lock); ++ dbg_err("missing orphan ino %lu", inum); ++ dbg_dump_stack(); ++} ++ ++/** ++ * ubifs_orphan_start_commit - start commit of orphans. ++ * @c: UBIFS file-system description object ++ * ++ * Start commit of orphans. ++ */ ++int ubifs_orphan_start_commit(struct ubifs_info *c) ++{ ++ struct ubifs_orphan *orphan, **last; ++ ++ spin_lock(&c->orphan_lock); ++ last = &c->orph_cnext; ++ list_for_each_entry(orphan, &c->orph_new, new_list) { ++ ubifs_assert(orphan->new); ++ orphan->new = 0; ++ *last = orphan; ++ last = &orphan->cnext; ++ } ++ *last = orphan->cnext; ++ c->cmt_orphans = c->new_orphans; ++ c->new_orphans = 0; ++ dbg_cmt("%d orphans to commit", c->cmt_orphans); ++ INIT_LIST_HEAD(&c->orph_new); ++ if (c->tot_orphans == 0) ++ c->no_orphs = 1; ++ else ++ c->no_orphs = 0; ++ spin_unlock(&c->orphan_lock); ++ return 0; ++} ++ ++/** ++ * avail_orphs - calculate available space. ++ * @c: UBIFS file-system description object ++ * ++ * This function returns the number of orphans that can be written in the ++ * available space. ++ */ ++static int avail_orphs(struct ubifs_info *c) ++{ ++ int avail_lebs, avail, gap; ++ ++ avail_lebs = c->orph_lebs - (c->ohead_lnum - c->orph_first) - 1; ++ avail = avail_lebs * ++ ((c->leb_size - UBIFS_ORPH_NODE_SZ) / sizeof(__le64)); ++ gap = c->leb_size - c->ohead_offs; ++ if (gap >= UBIFS_ORPH_NODE_SZ + sizeof(__le64)) ++ avail += (gap - UBIFS_ORPH_NODE_SZ) / sizeof(__le64); ++ return avail; ++} ++ ++/** ++ * tot_avail_orphs - calculate total space. ++ * @c: UBIFS file-system description object ++ * ++ * This function returns the number of orphans that can be written in half ++ * the total space. That leaves half the space for adding new orphans. ++ */ ++static int tot_avail_orphs(struct ubifs_info *c) ++{ ++ int avail_lebs, avail; ++ ++ avail_lebs = c->orph_lebs; ++ avail = avail_lebs * ++ ((c->leb_size - UBIFS_ORPH_NODE_SZ) / sizeof(__le64)); ++ return avail / 2; ++} ++ ++/** ++ * do_write_orph_node - write a node ++ * @c: UBIFS file-system description object ++ * @len: length of node ++ * @atomic: write atomically ++ * ++ * This function writes a node to the orphan head from the orphan buffer. If ++ * %atomic is not zero, then the write is done atomically. On success, %0 is ++ * returned, otherwise a negative error code is returned. ++ */ ++static int do_write_orph_node(struct ubifs_info *c, int len, int atomic) ++{ ++ int err = 0; ++ ++ if (atomic) { ++ ubifs_assert(c->ohead_offs == 0); ++ ubifs_prepare_node(c, c->orph_buf, len, 1); ++ len = ALIGN(len, c->min_io_size); ++ err = ubi_leb_change(c->ubi, c->ohead_lnum, c->orph_buf, len, ++ UBI_SHORTTERM); ++ } else { ++ if (c->ohead_offs == 0) { ++ /* Ensure LEB has been unmapped */ ++ err = ubifs_leb_unmap(c, c->ohead_lnum); ++ if (err) ++ return err; ++ } ++ err = ubifs_write_node(c, c->orph_buf, len, c->ohead_lnum, ++ c->ohead_offs, UBI_SHORTTERM); ++ } ++ return err; ++} ++ ++/** ++ * write_orph_node - write an orph node ++ * @c: UBIFS file-system description object ++ * @atomic: write atomically ++ * ++ * This function builds an orph node from the cnext list and writes it to the ++ * orphan head. On success, %0 is returned, otherwise a negative error code ++ * is returned. ++ */ ++static int write_orph_node(struct ubifs_info *c, int atomic) ++{ ++ struct ubifs_orphan *orphan, *cnext; ++ struct ubifs_orph_node *orph; ++ int gap, err, len, cnt, i; ++ ++ ubifs_assert(c->cmt_orphans > 0); ++ gap = c->leb_size - c->ohead_offs; ++ if (gap < UBIFS_ORPH_NODE_SZ + sizeof(__le64)) { ++ c->ohead_lnum += 1; ++ c->ohead_offs = 0; ++ gap = c->leb_size; ++ if (c->ohead_lnum > c->orph_last) { ++ /* ++ * We limit the number of orphans so that this should ++ * never happen. ++ */ ++ ubifs_err("out of space in orphan area"); ++ return -EINVAL; ++ } ++ } ++ cnt = (gap - UBIFS_ORPH_NODE_SZ) / sizeof(__le64); ++ if (cnt > c->cmt_orphans) ++ cnt = c->cmt_orphans; ++ len = UBIFS_ORPH_NODE_SZ + cnt * sizeof(__le64); ++ ubifs_assert(c->orph_buf); ++ orph = c->orph_buf; ++ orph->ch.node_type = UBIFS_ORPH_NODE; ++ spin_lock(&c->orphan_lock); ++ cnext = c->orph_cnext; ++ for (i = 0; i < cnt; i++) { ++ orphan = cnext; ++ orph->inos[i] = cpu_to_le64(orphan->inum); ++ cnext = orphan->cnext; ++ orphan->cnext = NULL; ++ } ++ c->orph_cnext = cnext; ++ c->cmt_orphans -= cnt; ++ spin_unlock(&c->orphan_lock); ++ if (c->cmt_orphans) ++ orph->cmt_no = cpu_to_le64(c->cmt_no + 1); ++ else ++ /* Mark the last node of the commit */ ++ orph->cmt_no = cpu_to_le64((c->cmt_no + 1) | (1ULL << 63)); ++ ubifs_assert(c->ohead_offs + len <= c->leb_size); ++ ubifs_assert(c->ohead_lnum >= c->orph_first); ++ ubifs_assert(c->ohead_lnum <= c->orph_last); ++ err = do_write_orph_node(c, len, atomic); ++ c->ohead_offs += ALIGN(len, c->min_io_size); ++ c->ohead_offs = ALIGN(c->ohead_offs, 8); ++ return err; ++} ++ ++/** ++ * write_orph_nodes - write orph nodes until there are no more to commit ++ * @c: UBIFS file-system description object ++ * @atomic: write atomically ++ * ++ * This function writes orph nodes for all the orphans to commit. On success, ++ * %0 is returned, otherwise a negative error code is returned. ++ */ ++static int write_orph_nodes(struct ubifs_info *c, int atomic) ++{ ++ int err; ++ ++ while (c->cmt_orphans > 0) { ++ err = write_orph_node(c, atomic); ++ if (err) ++ return err; ++ } ++ if (atomic) { ++ int lnum; ++ ++ /* Unmap any unused LEBs after consolidation */ ++ lnum = c->ohead_lnum + 1; ++ for (lnum = c->ohead_lnum + 1; lnum <= c->orph_last; lnum++) { ++ err = ubifs_leb_unmap(c, lnum); ++ if (err) ++ return err; ++ } ++ } ++ return 0; ++} ++ ++/** ++ * consolidate - consolidate the orphan area. ++ * @c: UBIFS file-system description object ++ * ++ * This function enables consolidation by putting all the orphans into the list ++ * to commit. The list is in the order that the orphans were added, and the ++ * LEBs are written atomically in order, so at no time can orphans be lost by ++ * an unclean unmount. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int consolidate(struct ubifs_info *c) ++{ ++ int tot_avail = tot_avail_orphs(c), err = 0; ++ ++ spin_lock(&c->orphan_lock); ++ dbg_cmt("there is space for %d orphans and there are %d", ++ tot_avail, c->tot_orphans); ++ if (c->tot_orphans - c->new_orphans <= tot_avail) { ++ struct ubifs_orphan *orphan, **last; ++ int cnt = 0; ++ ++ /* Change the cnext list to include all non-new orphans */ ++ last = &c->orph_cnext; ++ list_for_each_entry(orphan, &c->orph_list, list) { ++ if (orphan->new) ++ continue; ++ *last = orphan; ++ last = &orphan->cnext; ++ cnt += 1; ++ } ++ *last = orphan->cnext; ++ ubifs_assert(cnt == c->tot_orphans - c->new_orphans); ++ c->cmt_orphans = cnt; ++ c->ohead_lnum = c->orph_first; ++ c->ohead_offs = 0; ++ } else { ++ /* ++ * We limit the number of orphans so that this should ++ * never happen. ++ */ ++ ubifs_err("out of space in orphan area"); ++ err = -EINVAL; ++ } ++ spin_unlock(&c->orphan_lock); ++ return err; ++} ++ ++/** ++ * commit_orphans - commit orphans. ++ * @c: UBIFS file-system description object ++ * ++ * This function commits orphans to flash. On success, %0 is returned, ++ * otherwise a negative error code is returned. ++ */ ++static int commit_orphans(struct ubifs_info *c) ++{ ++ int avail, atomic = 0, err; ++ ++ ubifs_assert(c->cmt_orphans > 0); ++ avail = avail_orphs(c); ++ if (avail < c->cmt_orphans) { ++ /* Not enough space to write new orphans, so consolidate */ ++ err = consolidate(c); ++ if (err) ++ return err; ++ atomic = 1; ++ } ++ err = write_orph_nodes(c, atomic); ++ return err; ++} ++ ++/** ++ * erase_deleted - erase the orphans marked for deletion. ++ * @c: UBIFS file-system description object ++ * ++ * During commit, the orphans being committed cannot be deleted, so they are ++ * marked for deletion and deleted by this function. Also, the recovery ++ * adds killed orphans to the deletion list, and therefore they are deleted ++ * here too. ++ */ ++static void erase_deleted(struct ubifs_info *c) ++{ ++ struct ubifs_orphan *orphan, *dnext; ++ ++ spin_lock(&c->orphan_lock); ++ dnext = c->orph_dnext; ++ while (dnext) { ++ orphan = dnext; ++ dnext = orphan->dnext; ++ ubifs_assert(!orphan->new); ++ rb_erase(&orphan->rb, &c->orph_tree); ++ list_del(&orphan->list); ++ c->tot_orphans -= 1; ++ dbg_gen("deleting orphan ino %lu", orphan->inum); ++ kfree(orphan); ++ } ++ c->orph_dnext = NULL; ++ spin_unlock(&c->orphan_lock); ++} ++ ++/** ++ * ubifs_orphan_end_commit - end commit of orphans. ++ * @c: UBIFS file-system description object ++ * ++ * End commit of orphans. ++ */ ++int ubifs_orphan_end_commit(struct ubifs_info *c) ++{ ++ int err; ++ ++ if (c->cmt_orphans != 0) { ++ err = commit_orphans(c); ++ if (err) ++ return err; ++ } ++ erase_deleted(c); ++ err = dbg_check_orphans(c); ++ return err; ++} ++ ++/** ++ * clear_orphans - erase all LEBs used for orphans. ++ * @c: UBIFS file-system description object ++ * ++ * If recovery is not required, then the orphans from the previous session ++ * are not needed. This function locates the LEBs used to record ++ * orphans, and un-maps them. ++ */ ++static int clear_orphans(struct ubifs_info *c) ++{ ++ int lnum, err; ++ ++ for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) { ++ err = ubifs_leb_unmap(c, lnum); ++ if (err) ++ return err; ++ } ++ c->ohead_lnum = c->orph_first; ++ c->ohead_offs = 0; ++ return 0; ++} ++ ++/** ++ * insert_dead_orphan - insert an orphan. ++ * @c: UBIFS file-system description object ++ * @inum: orphan inode number ++ * ++ * This function is a helper to the 'do_kill_orphans()' function. The orphan ++ * must be kept until the next commit, so it is added to the rb-tree and the ++ * deletion list. ++ */ ++static int insert_dead_orphan(struct ubifs_info *c, ino_t inum) ++{ ++ struct ubifs_orphan *orphan, *o; ++ struct rb_node **p, *parent = NULL; ++ ++ orphan = kzalloc(sizeof(struct ubifs_orphan), GFP_KERNEL); ++ if (!orphan) ++ return -ENOMEM; ++ orphan->inum = inum; ++ ++ p = &c->orph_tree.rb_node; ++ while (*p) { ++ parent = *p; ++ o = rb_entry(parent, struct ubifs_orphan, rb); ++ if (inum < o->inum) ++ p = &(*p)->rb_left; ++ else if (inum > o->inum) ++ p = &(*p)->rb_right; ++ else { ++ /* Already added - no problem */ ++ kfree(orphan); ++ return 0; ++ } ++ } ++ c->tot_orphans += 1; ++ rb_link_node(&orphan->rb, parent, p); ++ rb_insert_color(&orphan->rb, &c->orph_tree); ++ list_add_tail(&orphan->list, &c->orph_list); ++ orphan->dnext = c->orph_dnext; ++ c->orph_dnext = orphan; ++ dbg_mnt("ino %lu, new %d, tot %d", ++ inum, c->new_orphans, c->tot_orphans); ++ return 0; ++} ++ ++/** ++ * do_kill_orphans - remove orphan inodes from the index. ++ * @c: UBIFS file-system description object ++ * @sleb: scanned LEB ++ * @last_cmt_no: cmt_no of last orph node read is passed and returned here ++ * @outofdate: whether the LEB is out of date is returned here ++ * @last_flagged: whether the end orph node is encountered ++ * ++ * This function is a helper to the 'kill_orphans()' function. It goes through ++ * every orphan node in a LEB and for every inode number recorded, removes ++ * all keys for that inode from the TNC. ++ */ ++static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb, ++ unsigned long long *last_cmt_no, int *outofdate, ++ int *last_flagged) ++{ ++ struct ubifs_scan_node *snod; ++ struct ubifs_orph_node *orph; ++ unsigned long long cmt_no; ++ ino_t inum; ++ int i, n, err, first = 1; ++ ++ list_for_each_entry(snod, &sleb->nodes, list) { ++ if (snod->type != UBIFS_ORPH_NODE) { ++ ubifs_err("invalid node type %d in orphan area at " ++ "%d:%d", snod->type, sleb->lnum, snod->offs); ++ dbg_dump_node(c, snod->node); ++ return -EINVAL; ++ } ++ ++ orph = snod->node; ++ ++ /* Check commit number */ ++ cmt_no = le64_to_cpu(orph->cmt_no) & LLONG_MAX; ++ /* ++ * The commit number on the master node may be less, because ++ * of a failed commit. If there are several failed commits in a ++ * row, the commit number written on orph nodes will continue to ++ * increase (because the commit number is adjusted here) even ++ * though the commit number on the master node stays the same ++ * because the master node has not been re-written. ++ */ ++ if (cmt_no > c->cmt_no) ++ c->cmt_no = cmt_no; ++ if (cmt_no < *last_cmt_no && *last_flagged) { ++ /* ++ * The last orph node had a higher commit number and was ++ * flagged as the last written for that commit number. ++ * That makes this orph node, out of date. ++ */ ++ if (!first) { ++ ubifs_err("out of order commit number %llu in " ++ "orphan node at %d:%d", ++ cmt_no, sleb->lnum, snod->offs); ++ dbg_dump_node(c, snod->node); ++ return -EINVAL; ++ } ++ dbg_rcvry("out of date LEB %d", sleb->lnum); ++ *outofdate = 1; ++ return 0; ++ } ++ ++ if (first) ++ first = 0; ++ ++ n = (le32_to_cpu(orph->ch.len) - UBIFS_ORPH_NODE_SZ) >> 3; ++ for (i = 0; i < n; i++) { ++ inum = le64_to_cpu(orph->inos[i]); ++ dbg_rcvry("deleting orphaned inode %lu", inum); ++ err = ubifs_tnc_remove_ino(c, inum); ++ if (err) ++ return err; ++ err = insert_dead_orphan(c, inum); ++ if (err) ++ return err; ++ } ++ ++ *last_cmt_no = cmt_no; ++ if (le64_to_cpu(orph->cmt_no) & (1ULL << 63)) { ++ dbg_rcvry("last orph node for commit %llu at %d:%d", ++ cmt_no, sleb->lnum, snod->offs); ++ *last_flagged = 1; ++ } else ++ *last_flagged = 0; ++ } ++ ++ return 0; ++} ++ ++/** ++ * kill_orphans - remove all orphan inodes from the index. ++ * @c: UBIFS file-system description object ++ * ++ * If recovery is required, then orphan inodes recorded during the previous ++ * session (which ended with an unclean unmount) must be deleted from the index. ++ * This is done by updating the TNC, but since the index is not updated until ++ * the next commit, the LEBs where the orphan information is recorded are not ++ * erased until the next commit. ++ */ ++static int kill_orphans(struct ubifs_info *c) ++{ ++ unsigned long long last_cmt_no = 0; ++ int lnum, err = 0, outofdate = 0, last_flagged = 0; ++ ++ c->ohead_lnum = c->orph_first; ++ c->ohead_offs = 0; ++ /* Check no-orphans flag and skip this if no orphans */ ++ if (c->no_orphs) { ++ dbg_rcvry("no orphans"); ++ return 0; ++ } ++ /* ++ * Orph nodes always start at c->orph_first and are written to each ++ * successive LEB in turn. Generally unused LEBs will have been unmapped ++ * but may contain out of date orph nodes if the unmap didn't go ++ * through. In addition, the last orph node written for each commit is ++ * marked (top bit of orph->cmt_no is set to 1). It is possible that ++ * there are orph nodes from the next commit (i.e. the commit did not ++ * complete successfully). In that case, no orphans will have been lost ++ * due to the way that orphans are written, and any orphans added will ++ * be valid orphans anyway and so can be deleted. ++ */ ++ for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) { ++ struct ubifs_scan_leb *sleb; ++ ++ dbg_rcvry("LEB %d", lnum); ++ sleb = ubifs_scan(c, lnum, 0, c->sbuf); ++ if (IS_ERR(sleb)) { ++ sleb = ubifs_recover_leb(c, lnum, 0, c->sbuf, 0); ++ if (IS_ERR(sleb)) { ++ err = PTR_ERR(sleb); ++ break; ++ } ++ } ++ err = do_kill_orphans(c, sleb, &last_cmt_no, &outofdate, ++ &last_flagged); ++ if (err || outofdate) { ++ ubifs_scan_destroy(sleb); ++ break; ++ } ++ if (sleb->endpt) { ++ c->ohead_lnum = lnum; ++ c->ohead_offs = sleb->endpt; ++ } ++ ubifs_scan_destroy(sleb); ++ } ++ return err; ++} ++ ++/** ++ * ubifs_mount_orphans - delete orphan inodes and erase LEBs that recorded them. ++ * @c: UBIFS file-system description object ++ * @unclean: indicates recovery from unclean unmount ++ * @read_only: indicates read only mount ++ * ++ * This function is called when mounting to erase orphans from the previous ++ * session. If UBIFS was not unmounted cleanly, then the inodes recorded as ++ * orphans are deleted. ++ */ ++int ubifs_mount_orphans(struct ubifs_info *c, int unclean, int read_only) ++{ ++ int err = 0; ++ ++ c->max_orphans = tot_avail_orphs(c); ++ ++ if (!read_only) { ++ c->orph_buf = vmalloc(c->leb_size); ++ if (!c->orph_buf) ++ return -ENOMEM; ++ } ++ ++ if (unclean) ++ err = kill_orphans(c); ++ else if (!read_only) ++ err = clear_orphans(c); ++ ++ return err; ++} ++ ++#ifdef CONFIG_UBIFS_FS_DEBUG ++ ++struct check_orphan { ++ struct rb_node rb; ++ ino_t inum; ++}; ++ ++struct check_info { ++ unsigned long last_ino; ++ unsigned long tot_inos; ++ unsigned long missing; ++ unsigned long long leaf_cnt; ++ struct ubifs_ino_node *node; ++ struct rb_root root; ++}; ++ ++static int dbg_find_orphan(struct ubifs_info *c, ino_t inum) ++{ ++ struct ubifs_orphan *o; ++ struct rb_node *p; ++ ++ spin_lock(&c->orphan_lock); ++ p = c->orph_tree.rb_node; ++ while (p) { ++ o = rb_entry(p, struct ubifs_orphan, rb); ++ if (inum < o->inum) ++ p = p->rb_left; ++ else if (inum > o->inum) ++ p = p->rb_right; ++ else { ++ spin_unlock(&c->orphan_lock); ++ return 1; ++ } ++ } ++ spin_unlock(&c->orphan_lock); ++ return 0; ++} ++ ++static int dbg_ins_check_orphan(struct rb_root *root, ino_t inum) ++{ ++ struct check_orphan *orphan, *o; ++ struct rb_node **p, *parent = NULL; ++ ++ orphan = kzalloc(sizeof(struct check_orphan), GFP_NOFS); ++ if (!orphan) ++ return -ENOMEM; ++ orphan->inum = inum; ++ ++ p = &root->rb_node; ++ while (*p) { ++ parent = *p; ++ o = rb_entry(parent, struct check_orphan, rb); ++ if (inum < o->inum) ++ p = &(*p)->rb_left; ++ else if (inum > o->inum) ++ p = &(*p)->rb_right; ++ else { ++ kfree(orphan); ++ return 0; ++ } ++ } ++ rb_link_node(&orphan->rb, parent, p); ++ rb_insert_color(&orphan->rb, root); ++ return 0; ++} ++ ++static int dbg_find_check_orphan(struct rb_root *root, ino_t inum) ++{ ++ struct check_orphan *o; ++ struct rb_node *p; ++ ++ p = root->rb_node; ++ while (p) { ++ o = rb_entry(p, struct check_orphan, rb); ++ if (inum < o->inum) ++ p = p->rb_left; ++ else if (inum > o->inum) ++ p = p->rb_right; ++ else ++ return 1; ++ } ++ return 0; ++} ++ ++static void dbg_free_check_tree(struct rb_root *root) ++{ ++ struct rb_node *this = root->rb_node; ++ struct check_orphan *o; ++ ++ while (this) { ++ if (this->rb_left) { ++ this = this->rb_left; ++ continue; ++ } else if (this->rb_right) { ++ this = this->rb_right; ++ continue; ++ } ++ o = rb_entry(this, struct check_orphan, rb); ++ this = rb_parent(this); ++ if (this) { ++ if (this->rb_left == &o->rb) ++ this->rb_left = NULL; ++ else ++ this->rb_right = NULL; ++ } ++ kfree(o); ++ } ++} ++ ++static int dbg_orphan_check(struct ubifs_info *c, struct ubifs_zbranch *zbr, ++ void *priv) ++{ ++ struct check_info *ci = priv; ++ ino_t inum; ++ int err; ++ ++ inum = key_inum(c, &zbr->key); ++ if (inum != ci->last_ino) { ++ /* Lowest node type is the inode node, so it comes first */ ++ if (key_type(c, &zbr->key) != UBIFS_INO_KEY) ++ ubifs_err("found orphan node ino %lu, type %d", inum, ++ key_type(c, &zbr->key)); ++ ci->last_ino = inum; ++ ci->tot_inos += 1; ++ err = ubifs_tnc_read_node(c, zbr, ci->node); ++ if (err) { ++ ubifs_err("node read failed, error %d", err); ++ return err; ++ } ++ if (ci->node->nlink == 0) ++ /* Must be recorded as an orphan */ ++ if (!dbg_find_check_orphan(&ci->root, inum) && ++ !dbg_find_orphan(c, inum)) { ++ ubifs_err("missing orphan, ino %lu", inum); ++ ci->missing += 1; ++ } ++ } ++ ci->leaf_cnt += 1; ++ return 0; ++} ++ ++static int dbg_read_orphans(struct check_info *ci, struct ubifs_scan_leb *sleb) ++{ ++ struct ubifs_scan_node *snod; ++ struct ubifs_orph_node *orph; ++ ino_t inum; ++ int i, n, err; ++ ++ list_for_each_entry(snod, &sleb->nodes, list) { ++ cond_resched(); ++ if (snod->type != UBIFS_ORPH_NODE) ++ continue; ++ orph = snod->node; ++ n = (le32_to_cpu(orph->ch.len) - UBIFS_ORPH_NODE_SZ) >> 3; ++ for (i = 0; i < n; i++) { ++ inum = le64_to_cpu(orph->inos[i]); ++ err = dbg_ins_check_orphan(&ci->root, inum); ++ if (err) ++ return err; ++ } ++ } ++ return 0; ++} ++ ++static int dbg_scan_orphans(struct ubifs_info *c, struct check_info *ci) ++{ ++ int lnum, err = 0; ++ ++ /* Check no-orphans flag and skip this if no orphans */ ++ if (c->no_orphs) ++ return 0; ++ ++ for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) { ++ struct ubifs_scan_leb *sleb; ++ ++ sleb = ubifs_scan(c, lnum, 0, c->dbg_buf); ++ if (IS_ERR(sleb)) { ++ err = PTR_ERR(sleb); ++ break; ++ } ++ ++ err = dbg_read_orphans(ci, sleb); ++ ubifs_scan_destroy(sleb); ++ if (err) ++ break; ++ } ++ ++ return err; ++} ++ ++static int dbg_check_orphans(struct ubifs_info *c) ++{ ++ struct check_info ci; ++ int err; ++ ++ if (!(ubifs_chk_flags & UBIFS_CHK_ORPH)) ++ return 0; ++ ++ ci.last_ino = 0; ++ ci.tot_inos = 0; ++ ci.missing = 0; ++ ci.leaf_cnt = 0; ++ ci.root = RB_ROOT; ++ ci.node = kmalloc(UBIFS_MAX_INO_NODE_SZ, GFP_NOFS); ++ if (!ci.node) { ++ ubifs_err("out of memory"); ++ return -ENOMEM; ++ } ++ ++ err = dbg_scan_orphans(c, &ci); ++ if (err) ++ goto out; ++ ++ err = dbg_walk_index(c, &dbg_orphan_check, NULL, &ci); ++ if (err) { ++ ubifs_err("cannot scan TNC, error %d", err); ++ goto out; ++ } ++ ++ if (ci.missing) { ++ ubifs_err("%lu missing orphan(s)", ci.missing); ++ err = -EINVAL; ++ goto out; ++ } ++ ++ dbg_cmt("last inode number is %lu", ci.last_ino); ++ dbg_cmt("total number of inodes is %lu", ci.tot_inos); ++ dbg_cmt("total number of leaf nodes is %llu", ci.leaf_cnt); ++ ++out: ++ dbg_free_check_tree(&ci.root); ++ kfree(ci.node); ++ return err; ++} ++ ++#endif /* CONFIG_UBIFS_FS_DEBUG */ +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/recovery.c avr32-2.6/fs/ubifs/recovery.c +--- linux-2.6.25.6/fs/ubifs/recovery.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/recovery.c 2008-06-12 15:09:45.475816115 +0200 +@@ -0,0 +1,1537 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Adrian Hunter ++ * Artem Bityutskiy (Битюцкий Артём) ++ */ ++ ++/* ++ * This file implements functions needed to recover from unclean un-mounts. ++ * When UBIFS is mounted, it checks a flag on the master node to determine if ++ * an un-mount was completed sucessfully. If not, the process of mounting ++ * incorparates additional checking and fixing of on-flash data structures. ++ * UBIFS always cleans away all remnants of an unclean un-mount, so that ++ * errors do not accumulate. However UBIFS defers recovery if it is mounted ++ * read-only, and the flash is not modified in that case. ++ */ ++ ++#include <linux/crc32.h> ++#include "ubifs.h" ++ ++/** ++ * is_empty - determine whether a buffer is empty (contains all 0xff). ++ * @buf: buffer to clean ++ * @len: length of buffer ++ * ++ * This function returns %1 if the buffer is empty (contains all 0xff) otherwise ++ * %0 is returned. ++ */ ++static int is_empty(void *buf, int len) ++{ ++ uint8_t *p = buf; ++ int i; ++ ++ for (i = 0; i < len; i++) ++ if (*p++ != 0xff) ++ return 0; ++ return 1; ++} ++ ++/** ++ * get_master_node - get the last valid master node allowing for corruption. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number ++ * @pbuf: buffer containing the LEB read, is returned here ++ * @mst: master node, if found, is returned here ++ * @cor: corruption, if found, is returned here ++ * ++ * This function allocates a buffer, reads the LEB into it, and finds and ++ * returns the last valid master node allowing for one area of corruption. ++ * The corrupt area, if there is one, must be consistent with the assumption ++ * that it is the result of an unclean unmount while the master node was being ++ * written. Under those circumstances, it is valid to use the previously written ++ * master node. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int get_master_node(const struct ubifs_info *c, int lnum, void **pbuf, ++ struct ubifs_mst_node **mst, void **cor) ++{ ++ const int sz = c->mst_node_alsz; ++ int err, offs, len; ++ void *sbuf, *buf; ++ ++ sbuf = vmalloc(c->leb_size); ++ if (!sbuf) ++ return -ENOMEM; ++ ++ err = ubi_read(c->ubi, lnum, sbuf, 0, c->leb_size); ++ if (err && err != -EBADMSG) ++ goto out_free; ++ ++ /* Find the first position that is definitely not a node */ ++ offs = 0; ++ buf = sbuf; ++ len = c->leb_size; ++ while (offs + UBIFS_MST_NODE_SZ <= c->leb_size) { ++ struct ubifs_ch *ch = buf; ++ ++ if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC) ++ break; ++ offs += sz; ++ buf += sz; ++ len -= sz; ++ } ++ /* See if there was a valid master node before that */ ++ if (offs) { ++ int ret; ++ ++ offs -= sz; ++ buf -= sz; ++ len += sz; ++ ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1); ++ if (ret != SCANNED_A_NODE && offs) { ++ /* Could have been corruption so check one place back */ ++ offs -= sz; ++ buf -= sz; ++ len += sz; ++ ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1); ++ if (ret != SCANNED_A_NODE) ++ /* ++ * We accept only one area of corruption because ++ * we are assuming that it was caused while ++ * trying to write a master node. ++ */ ++ goto out_err; ++ } ++ if (ret == SCANNED_A_NODE) { ++ struct ubifs_ch *ch = buf; ++ ++ if (ch->node_type != UBIFS_MST_NODE) ++ goto out_err; ++ dbg_rcvry("found a master node at %d:%d", lnum, offs); ++ *mst = buf; ++ offs += sz; ++ buf += sz; ++ len -= sz; ++ } ++ } ++ /* Check for corruption */ ++ if (offs < c->leb_size) { ++ if (!is_empty(buf, min_t(int, len, sz))) { ++ *cor = buf; ++ dbg_rcvry("found corruption at %d:%d", lnum, offs); ++ } ++ offs += sz; ++ buf += sz; ++ len -= sz; ++ } ++ /* Check remaining empty space */ ++ if (offs < c->leb_size) ++ if (!is_empty(buf, len)) ++ goto out_err; ++ *pbuf = sbuf; ++ return 0; ++ ++out_err: ++ err = -EINVAL; ++out_free: ++ vfree(sbuf); ++ *mst = NULL; ++ *cor = NULL; ++ return err; ++} ++ ++/** ++ * write_rcvrd_mst_node - write recovered master node. ++ * @c: UBIFS file-system description object ++ * @mst: master node ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int write_rcvrd_mst_node(struct ubifs_info *c, ++ struct ubifs_mst_node *mst) ++{ ++ int err = 0, lnum = UBIFS_MST_LNUM, sz = c->mst_node_alsz; ++ uint32_t save_flags; ++ ++ dbg_rcvry("recovery"); ++ ++ save_flags = mst->flags; ++ mst->flags = cpu_to_le32(le32_to_cpu(mst->flags) | UBIFS_MST_RCVRY); ++ ++ ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1); ++ err = ubi_leb_change(c->ubi, lnum, mst, sz, UBI_SHORTTERM); ++ if (err) ++ goto out; ++ err = ubi_leb_change(c->ubi, lnum + 1, mst, sz, UBI_SHORTTERM); ++ if (err) ++ goto out; ++out: ++ mst->flags = save_flags; ++ return err; ++} ++ ++/** ++ * ubifs_recover_master_node - recover the master node. ++ * @c: UBIFS file-system description object ++ * ++ * This function recovers the master node from corruption that may occur due to ++ * an unclean unmount. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++int ubifs_recover_master_node(struct ubifs_info *c) ++{ ++ void *buf1 = NULL, *buf2 = NULL, *cor1 = NULL, *cor2 = NULL; ++ struct ubifs_mst_node *mst1 = NULL, *mst2 = NULL, *mst; ++ const int sz = c->mst_node_alsz; ++ int err, offs1, offs2; ++ ++ dbg_rcvry("recovery"); ++ ++ err = get_master_node(c, UBIFS_MST_LNUM, &buf1, &mst1, &cor1); ++ if (err) ++ goto out_free; ++ ++ err = get_master_node(c, UBIFS_MST_LNUM + 1, &buf2, &mst2, &cor2); ++ if (err) ++ goto out_free; ++ ++ if (mst1) { ++ offs1 = (void *)mst1 - buf1; ++ if ((le32_to_cpu(mst1->flags) & UBIFS_MST_RCVRY) && ++ (offs1 == 0 && !cor1)) { ++ /* ++ * mst1 was written by recovery at offset 0 with no ++ * corruption. ++ */ ++ dbg_rcvry("recovery recovery"); ++ mst = mst1; ++ } else if (mst2) { ++ offs2 = (void *)mst2 - buf2; ++ if (offs1 == offs2) { ++ /* Same offset, so must be the same */ ++ if (memcmp((void *)mst1 + UBIFS_CH_SZ, ++ (void *)mst2 + UBIFS_CH_SZ, ++ UBIFS_MST_NODE_SZ - UBIFS_CH_SZ)) ++ goto out_err; ++ mst = mst1; ++ } else if (offs2 + sz == offs1) { ++ /* 1st LEB was written, 2nd was not */ ++ if (cor1) ++ goto out_err; ++ mst = mst1; ++ } else if (offs1 == 0 && offs2 + sz >= c->leb_size) { ++ /* 1st LEB was unmapped and written, 2nd not */ ++ if (cor1) ++ goto out_err; ++ mst = mst1; ++ } else ++ goto out_err; ++ } else { ++ /* ++ * 2nd LEB was unmapped and about to be written, so ++ * there must be only one master node in the first LEB ++ * and no corruption. ++ */ ++ if (offs1 != 0 || cor1) ++ goto out_err; ++ mst = mst1; ++ } ++ } else { ++ if (!mst2) ++ goto out_err; ++ /* ++ * 1st LEB was unmapped and about to be written, so there must ++ * be no room left in 2nd LEB. ++ */ ++ offs2 = (void *)mst2 - buf2; ++ if (offs2 + sz + sz <= c->leb_size) ++ goto out_err; ++ mst = mst2; ++ } ++ ++ dbg_rcvry("recovered master node from LEB %d", ++ (mst == mst1 ? UBIFS_MST_LNUM : UBIFS_MST_LNUM + 1)); ++ ++ memcpy(c->mst_node, mst, UBIFS_MST_NODE_SZ); ++ ++ if ((c->vfs_sb->s_flags & MS_RDONLY)) { ++ /* Read-only mode. Keep a copy for switching to rw mode */ ++ c->rcvrd_mst_node = kmalloc(sz, GFP_KERNEL); ++ if (!c->rcvrd_mst_node) { ++ err = -ENOMEM; ++ goto out_free; ++ } ++ memcpy(c->rcvrd_mst_node, c->mst_node, UBIFS_MST_NODE_SZ); ++ } else { ++ /* Write the recovered master node */ ++ c->max_sqnum = le64_to_cpu(mst->ch.sqnum) - 1; ++ err = write_rcvrd_mst_node(c, c->mst_node); ++ if (err) ++ goto out_free; ++ } ++ ++ vfree(buf2); ++ vfree(buf1); ++ ++ return 0; ++ ++out_err: ++ err = -EINVAL; ++out_free: ++ ubifs_err("failed to recover master node"); ++ if (mst1) { ++ dbg_err("dumping first master node"); ++ dbg_dump_node(c, mst1); ++ } ++ if (mst2) { ++ dbg_err("dumping second master node"); ++ dbg_dump_node(c, mst2); ++ } ++ vfree(buf2); ++ vfree(buf1); ++ return err; ++} ++ ++/** ++ * ubifs_write_rcvrd_mst_node - write the recovered master node. ++ * @c: UBIFS file-system description object ++ * ++ * This function writes the master node that was recovered during mounting in ++ * read-only mode and must now be written because we are remounting rw. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++int ubifs_write_rcvrd_mst_node(struct ubifs_info *c) ++{ ++ int err; ++ ++ if (!c->rcvrd_mst_node) ++ return 0; ++ c->rcvrd_mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY); ++ c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY); ++ err = write_rcvrd_mst_node(c, c->rcvrd_mst_node); ++ if (err) ++ return err; ++ kfree(c->rcvrd_mst_node); ++ c->rcvrd_mst_node = NULL; ++ return 0; ++} ++ ++/** ++ * is_last_write - determine if an offset was in the last write to a LEB. ++ * @c: UBIFS file-system description object ++ * @buf: buffer to check ++ * @offs: offset to check ++ * ++ * This function returns %1 if @offs was in the last write to the LEB whose data ++ * is in @buf, otherwise %0 is returned. The determination is made by checking ++ * for subsequent empty space starting from the next min_io_size boundary (or a ++ * bit less than the common header size if min_io_size is one). ++ */ ++static int is_last_write(const struct ubifs_info *c, void *buf, int offs) ++{ ++ int empty_offs; ++ int check_len; ++ uint8_t *p; ++ ++ if (c->min_io_size == 1) { ++ check_len = c->leb_size - offs; ++ p = buf + check_len; ++ for (; check_len > 0; check_len--) ++ if (*--p != 0xff) ++ break; ++ /* ++ * 'check_len' is the size of the corruption which cannot be ++ * more than the size of 1 node if it was caused by an unclean ++ * unmount. ++ */ ++ if (check_len > UBIFS_MAX_NODE_SZ) ++ return 0; ++ return 1; ++ } ++ ++ /* ++ * Round up to the next c->min_io_size boundary i.e. 'offs' is in the ++ * last wbuf written. After that should be empty space. ++ */ ++ empty_offs = ALIGN(offs + 1, c->min_io_size); ++ check_len = c->leb_size - empty_offs; ++ p = buf + empty_offs - offs; ++ ++ for (; check_len > 0; check_len--) ++ if (*p++ != 0xff) ++ return 0; ++ return 1; ++} ++ ++/** ++ * clean_buf - clean the data from an LEB sitting in a buffer. ++ * @c: UBIFS file-system description object ++ * @buf: buffer to clean ++ * @lnum: LEB number to clean ++ * @offs: offset from which to clean ++ * @len: length of buffer ++ * ++ * This function pads up to the next min_io_size boundary (if there is one) and ++ * sets empty space to all 0xff. @buf, @offs and @len are updated to the next ++ * min_io_size boundary (if there is one). ++ */ ++static void clean_buf(const struct ubifs_info *c, void **buf, int lnum, ++ int *offs, int *len) ++{ ++ int empty_offs, pad_len; ++ ++ lnum = lnum; ++ dbg_rcvry("cleaning corruption at %d:%d", lnum, *offs); ++ ++ if (c->min_io_size == 1) { ++ memset(*buf, 0xff, c->leb_size - *offs); ++ return; ++ } ++ ++ ubifs_assert(!(*offs & 7)); ++ empty_offs = ALIGN(*offs, c->min_io_size); ++ pad_len = empty_offs - *offs; ++ ubifs_pad(c, *buf, pad_len); ++ *offs += pad_len; ++ *buf += pad_len; ++ *len -= pad_len; ++ memset(*buf, 0xff, c->leb_size - empty_offs); ++} ++ ++/** ++ * no_more_nodes - determine if there are no more nodes in a buffer. ++ * @c: UBIFS file-system description object ++ * @buf: buffer to check ++ * @len: length of buffer ++ * @lnum: LEB number of the LEB from which @buf was read ++ * @offs: offset from which @buf was read ++ * ++ * This function scans @buf for more nodes and returns %0 is a node is found and ++ * %1 if no more nodes are found. ++ */ ++static int no_more_nodes(const struct ubifs_info *c, void *buf, int len, ++ int lnum, int offs) ++{ ++ int skip, next_offs = 0; ++ ++ if (len > UBIFS_DATA_NODE_SZ) { ++ struct ubifs_ch *ch = buf; ++ int dlen = le32_to_cpu(ch->len); ++ ++ if (ch->node_type == UBIFS_DATA_NODE && dlen >= UBIFS_CH_SZ && ++ dlen <= UBIFS_MAX_DATA_NODE_SZ) ++ /* The corrupt node looks like a data node */ ++ next_offs = ALIGN(offs + dlen, 8); ++ } ++ ++ if (c->min_io_size == 1) ++ skip = 8; ++ else ++ skip = ALIGN(offs + 1, c->min_io_size) - offs; ++ ++ offs += skip; ++ buf += skip; ++ len -= skip; ++ while (len > 8) { ++ struct ubifs_ch *ch = buf; ++ uint32_t magic = le32_to_cpu(ch->magic); ++ int ret; ++ ++ if (magic == UBIFS_NODE_MAGIC) { ++ ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1); ++ if (ret == SCANNED_A_NODE || ret > 0) { ++ /* ++ * There is a small chance this is just data in ++ * a data node, so check that possibility. e.g. ++ * this is part of a file that itself contains ++ * a UBIFS image. ++ */ ++ if (next_offs && offs + le32_to_cpu(ch->len) <= ++ next_offs) ++ continue; ++ dbg_rcvry("unexpected node at %d:%d", lnum, ++ offs); ++ return 0; ++ } ++ } ++ offs += 8; ++ buf += 8; ++ len -= 8; ++ } ++ return 1; ++} ++ ++/** ++ * fix_unclean_leb - fix an unclean LEB. ++ * @c: UBIFS file-system description object ++ * @sleb: scanned LEB information ++ * @start: offset where scan started ++ */ ++static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb, ++ int start) ++{ ++ int lnum = sleb->lnum, endpt = start; ++ ++ /* Get the end offset of the last node we are keeping */ ++ if (!list_empty(&sleb->nodes)) { ++ struct ubifs_scan_node *snod; ++ ++ snod = list_entry(sleb->nodes.prev, ++ struct ubifs_scan_node, list); ++ endpt = snod->offs + snod->len; ++ } ++ ++ if ((c->vfs_sb->s_flags & MS_RDONLY) && !c->remounting_rw) { ++ /* Add to recovery list */ ++ struct ubifs_unclean_leb *ucleb; ++ ++ dbg_rcvry("need to fix LEB %d start %d endpt %d", ++ lnum, start, sleb->endpt); ++ ucleb = kzalloc(sizeof(struct ubifs_unclean_leb), GFP_NOFS); ++ if (!ucleb) ++ return -ENOMEM; ++ ucleb->lnum = lnum; ++ ucleb->endpt = endpt; ++ list_add_tail(&ucleb->list, &c->unclean_leb_list); ++ } else { ++ /* Write the fixed LEB back to flash */ ++ int err; ++ ++ dbg_rcvry("fixing LEB %d start %d endpt %d", ++ lnum, start, sleb->endpt); ++ if (endpt == 0) { ++ err = ubifs_leb_unmap(c, lnum); ++ if (err) ++ return err; ++ } else { ++ int len = ALIGN(endpt, c->min_io_size); ++ ++ if (start) { ++ err = ubi_read(c->ubi, lnum, sleb->buf, 0, ++ start); ++ if (err) ++ return err; ++ } ++ /* Pad to min_io_size */ ++ if (len > endpt) { ++ int pad_len = len - ALIGN(endpt, 8); ++ ++ if (pad_len > 0) { ++ void *buf = sleb->buf + len - pad_len; ++ ++ ubifs_pad(c, buf, pad_len); ++ } ++ } ++ err = ubi_leb_change(c->ubi, lnum, sleb->buf, len, ++ UBI_UNKNOWN); ++ if (err) ++ return err; ++ } ++ } ++ return 0; ++} ++ ++/** ++ * drop_incomplete_group - drop nodes from an incomplete group. ++ * @sleb: scanned LEB information ++ * @offs: offset of dropped nodes is returned here ++ * ++ * This function returns %1 if nodes are dropped and %0 otherwise. ++ */ ++static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs) ++{ ++ int dropped = 0; ++ ++ while (!list_empty(&sleb->nodes)) { ++ struct ubifs_scan_node *snod; ++ struct ubifs_ch *ch; ++ ++ snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node, ++ list); ++ ch = snod->node; ++ if (ch->group_type != UBIFS_IN_NODE_GROUP) ++ return dropped; ++ dbg_rcvry("dropping node at %d:%d", sleb->lnum, snod->offs); ++ *offs = snod->offs; ++ list_del(&snod->list); ++ kfree(snod); ++ sleb->nodes_cnt -= 1; ++ dropped = 1; ++ } ++ return dropped; ++} ++ ++/** ++ * ubifs_recover_leb - scan and recover a LEB. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number ++ * @offs: offset ++ * @sbuf: LEB-sized buffer to use ++ * @grouped: nodes may be grouped for recovery ++ * ++ * This function does a scan of a LEB, but caters for errors that might have ++ * been caused by the unclean unmount from which we are attempting to recover. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum, ++ int offs, void *sbuf, int grouped) ++{ ++ int err, len = c->leb_size - offs, need_clean = 0, quiet = 1; ++ int empty_chkd = 0, start = offs; ++ struct ubifs_scan_leb *sleb; ++ void *buf = sbuf + offs; ++ ++ dbg_rcvry("%d:%d", lnum, offs); ++ ++ sleb = ubifs_start_scan(c, lnum, offs, sbuf); ++ if (IS_ERR(sleb)) ++ return sleb; ++ ++ if (sleb->ecc) ++ need_clean = 1; ++ ++ while (len >= 8) { ++ int ret; ++ ++ dbg_scan("look at LEB %d:%d (%d bytes left)", ++ lnum, offs, len); ++ ++ cond_resched(); ++ ++ /* ++ * Scan quietly until there is an error from which we cannot ++ * recover ++ */ ++ ret = ubifs_scan_a_node(c, buf, len, lnum, offs, quiet); ++ ++ if (ret == SCANNED_A_NODE) { ++ /* A valid node, and not a padding node */ ++ struct ubifs_ch *ch = buf; ++ int node_len; ++ ++ err = ubifs_add_snod(c, sleb, buf, offs); ++ if (err) ++ goto error; ++ node_len = ALIGN(le32_to_cpu(ch->len), 8); ++ offs += node_len; ++ buf += node_len; ++ len -= node_len; ++ continue; ++ } ++ ++ if (ret > 0) { ++ /* Padding bytes or a valid padding node */ ++ offs += ret; ++ buf += ret; ++ len -= ret; ++ continue; ++ } ++ ++ if (ret == SCANNED_EMPTY_SPACE) { ++ if (!is_empty(buf, len)) { ++ if (!is_last_write(c, buf, offs)) ++ break; ++ clean_buf(c, &buf, lnum, &offs, &len); ++ need_clean = 1; ++ } ++ empty_chkd = 1; ++ break; ++ } ++ ++ if (ret == SCANNED_GARBAGE || ret == SCANNED_A_BAD_PAD_NODE) ++ if (is_last_write(c, buf, offs)) { ++ clean_buf(c, &buf, lnum, &offs, &len); ++ need_clean = 1; ++ empty_chkd = 1; ++ break; ++ } ++ ++ if (ret == SCANNED_A_CORRUPT_NODE) ++ if (no_more_nodes(c, buf, len, lnum, offs)) { ++ clean_buf(c, &buf, lnum, &offs, &len); ++ need_clean = 1; ++ empty_chkd = 1; ++ break; ++ } ++ ++ if (quiet) { ++ /* Redo the last scan but noisily */ ++ quiet = 0; ++ continue; ++ } ++ ++ switch (ret) { ++ case SCANNED_GARBAGE: ++ dbg_err("garbage"); ++ goto corrupted; ++ case SCANNED_A_CORRUPT_NODE: ++ case SCANNED_A_BAD_PAD_NODE: ++ dbg_err("bad node"); ++ goto corrupted; ++ default: ++ dbg_err("unknown"); ++ goto corrupted; ++ } ++ } ++ ++ if (!empty_chkd && !is_empty(buf, len)) { ++ if (is_last_write(c, buf, offs)) { ++ clean_buf(c, &buf, lnum, &offs, &len); ++ need_clean = 1; ++ } else { ++ ubifs_err("corrupt empty space at LEB %d:%d", ++ lnum, offs); ++ goto corrupted; ++ } ++ } ++ ++ /* Drop nodes from incomplete group */ ++ if (grouped && drop_incomplete_group(sleb, &offs)) { ++ buf = sbuf + offs; ++ len = c->leb_size - offs; ++ clean_buf(c, &buf, lnum, &offs, &len); ++ need_clean = 1; ++ } ++ ++ if (offs % c->min_io_size) { ++ clean_buf(c, &buf, lnum, &offs, &len); ++ need_clean = 1; ++ } ++ ++ ubifs_end_scan(c, sleb, lnum, offs); ++ ++ if (need_clean) { ++ err = fix_unclean_leb(c, sleb, start); ++ if (err) ++ goto error; ++ } ++ ++ return sleb; ++ ++corrupted: ++ ubifs_scanned_corruption(c, lnum, offs, buf); ++ err = -EUCLEAN; ++error: ++ ubifs_err("LEB %d scanning failed", lnum); ++ ubifs_scan_destroy(sleb); ++ return ERR_PTR(err); ++} ++ ++/** ++ * get_cs_sqnum - get commit start sequence number. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number of commit start node ++ * @offs: offset of commit start node ++ * @cs_sqnum: commit start sequence number is returned here ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int get_cs_sqnum(struct ubifs_info *c, int lnum, int offs, ++ unsigned long long *cs_sqnum) ++{ ++ struct ubifs_cs_node *cs_node = NULL; ++ int err, ret; ++ ++ dbg_rcvry("at %d:%d", lnum, offs); ++ cs_node = kmalloc(UBIFS_CS_NODE_SZ, GFP_KERNEL); ++ if (!cs_node) ++ return -ENOMEM; ++ if (c->leb_size - offs < UBIFS_CS_NODE_SZ) ++ goto out_err; ++ err = ubi_read(c->ubi, lnum, (void *)cs_node, offs, UBIFS_CS_NODE_SZ); ++ if (err && err != -EBADMSG) ++ goto out_free; ++ ret = ubifs_scan_a_node(c, cs_node, UBIFS_CS_NODE_SZ, lnum, offs, 0); ++ if (ret != SCANNED_A_NODE) { ++ dbg_err("Not a valid node"); ++ goto out_err; ++ } ++ if (cs_node->ch.node_type != UBIFS_CS_NODE) { ++ dbg_err("Node a CS node, type is %d", cs_node->ch.node_type); ++ goto out_err; ++ } ++ if (le64_to_cpu(cs_node->cmt_no) != c->cmt_no) { ++ dbg_err("CS node cmt_no %llu != current cmt_no %llu", ++ (unsigned long long)le64_to_cpu(cs_node->cmt_no), ++ c->cmt_no); ++ goto out_err; ++ } ++ *cs_sqnum = le64_to_cpu(cs_node->ch.sqnum); ++ dbg_rcvry("commit start sqnum %llu", *cs_sqnum); ++ kfree(cs_node); ++ return 0; ++ ++out_err: ++ err = -EINVAL; ++out_free: ++ ubifs_err("failed to get CS sqnum"); ++ kfree(cs_node); ++ return err; ++} ++ ++/** ++ * ubifs_recover_log_leb - scan and recover a log LEB. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number ++ * @offs: offset ++ * @sbuf: LEB-sized buffer to use ++ * ++ * This function does a scan of a LEB, but caters for errors that might have ++ * been caused by the unclean unmount from which we are attempting to recover. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum, ++ int offs, void *sbuf) ++{ ++ struct ubifs_scan_leb *sleb; ++ int next_lnum; ++ ++ dbg_rcvry("LEB %d", lnum); ++ next_lnum = lnum + 1; ++ if (next_lnum >= UBIFS_LOG_LNUM + c->log_lebs) ++ next_lnum = UBIFS_LOG_LNUM; ++ if (next_lnum != c->ltail_lnum) { ++ /* ++ * We can only recover at the end of the log, so check that the ++ * next log LEB is empty or out of date. ++ */ ++ sleb = ubifs_scan(c, next_lnum, 0, sbuf); ++ if (IS_ERR(sleb)) ++ return sleb; ++ if (sleb->nodes_cnt) { ++ struct ubifs_scan_node *snod; ++ unsigned long long cs_sqnum = c->cs_sqnum; ++ ++ snod = list_entry(sleb->nodes.next, ++ struct ubifs_scan_node, list); ++ if (cs_sqnum == 0) { ++ int err; ++ ++ err = get_cs_sqnum(c, lnum, offs, &cs_sqnum); ++ if (err) { ++ ubifs_scan_destroy(sleb); ++ return ERR_PTR(err); ++ } ++ } ++ if (snod->sqnum > cs_sqnum) { ++ ubifs_err("unrecoverable log corruption " ++ "in LEB %d", lnum); ++ ubifs_scan_destroy(sleb); ++ return ERR_PTR(-EUCLEAN); ++ } ++ } ++ ubifs_scan_destroy(sleb); ++ } ++ return ubifs_recover_leb(c, lnum, offs, sbuf, 0); ++} ++ ++/** ++ * recover_head - recover a head. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number of head to recover ++ * @offs: offset of head to recover ++ * @sbuf: LEB-sized buffer to use ++ * ++ * This function ensures that there is no data on the flash at a head location. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int recover_head(const struct ubifs_info *c, int lnum, int offs, ++ void *sbuf) ++{ ++ int len, err, need_clean = 0; ++ ++ if (c->min_io_size > 1) ++ len = c->min_io_size; ++ else ++ len = 512; ++ if (offs + len > c->leb_size) ++ len = c->leb_size - offs; ++ ++ if (!len) ++ return 0; ++ ++ /* Read at the head location and check it is empty flash */ ++ err = ubi_read(c->ubi, lnum, sbuf, offs, len); ++ if (err) ++ need_clean = 1; ++ else { ++ uint8_t *p = sbuf; ++ ++ while (len--) ++ if (*p++ != 0xff) { ++ need_clean = 1; ++ break; ++ } ++ } ++ ++ if (need_clean) { ++ dbg_rcvry("cleaning head at %d:%d", lnum, offs); ++ if (offs == 0) ++ return ubifs_leb_unmap(c, lnum); ++ err = ubi_read(c->ubi, lnum, sbuf, 0, offs); ++ if (err) ++ return err; ++ return ubi_leb_change(c->ubi, lnum, sbuf, offs, UBI_UNKNOWN); ++ } ++ ++ return 0; ++} ++ ++/** ++ * ubifs_recover_inl_heads - recover index and LPT heads. ++ * @c: UBIFS file-system description object ++ * @sbuf: LEB-sized buffer to use ++ * ++ * This function ensures that there is no data on the flash at the index and ++ * LPT head locations. ++ * ++ * This deals with the recovery of a half-completed journal commit. UBIFS is ++ * careful never to overwrite the last version of the index or the LPT. Because ++ * the index and LPT are wandering trees, data from a half-completed commit will ++ * not be referenced anywhere in UBIFS. The data will be either in LEBs that are ++ * assumed to be empty and will be unmapped anyway before use, or in the index ++ * and LPT heads. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf) ++{ ++ int err; ++ ++ ubifs_assert(!(c->vfs_sb->s_flags & MS_RDONLY) || c->remounting_rw); ++ ++ dbg_rcvry("checking index head at %d:%d", c->ihead_lnum, c->ihead_offs); ++ err = recover_head(c, c->ihead_lnum, c->ihead_offs, sbuf); ++ if (err) ++ return err; ++ ++ dbg_rcvry("checking LPT head at %d:%d", c->nhead_lnum, c->nhead_offs); ++ err = recover_head(c, c->nhead_lnum, c->nhead_offs, sbuf); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++/** ++ * clean_an_unclean_leb - read and write a LEB to remove corruption. ++ * @c: UBIFS file-system description object ++ * @ucleb: unclean LEB information ++ * @sbuf: LEB-sized buffer to use ++ * ++ * This function reads a LEB up to a point pre-determined by the mount recovery, ++ * checks the nodes, and writes the result back to the flash, thereby cleaning ++ * off any following corruption, or non-fatal ECC errors. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int clean_an_unclean_leb(const struct ubifs_info *c, ++ struct ubifs_unclean_leb *ucleb, void *sbuf) ++{ ++ int err, lnum = ucleb->lnum, offs = 0, len = ucleb->endpt, quiet = 1; ++ void *buf = sbuf; ++ ++ dbg_rcvry("LEB %d len %d", lnum, len); ++ ++ if (len == 0) { ++ /* Nothing to read, just unmap it */ ++ err = ubifs_leb_unmap(c, lnum); ++ if (err) ++ return err; ++ return 0; ++ } ++ ++ err = ubi_read(c->ubi, lnum, buf, offs, len); ++ if (err && err != -EBADMSG) ++ return err; ++ ++ while (len >= 8) { ++ int ret; ++ ++ cond_resched(); ++ ++ /* Scan quietly until there is an error */ ++ ret = ubifs_scan_a_node(c, buf, len, lnum, offs, quiet); ++ ++ if (ret == SCANNED_A_NODE) { ++ /* A valid node, and not a padding node */ ++ struct ubifs_ch *ch = buf; ++ int node_len; ++ ++ node_len = ALIGN(le32_to_cpu(ch->len), 8); ++ offs += node_len; ++ buf += node_len; ++ len -= node_len; ++ continue; ++ } ++ ++ if (ret > 0) { ++ /* Padding bytes or a valid padding node */ ++ offs += ret; ++ buf += ret; ++ len -= ret; ++ continue; ++ } ++ ++ if (ret == SCANNED_EMPTY_SPACE) { ++ ubifs_err("unexpected empty space at %d:%d", ++ lnum, offs); ++ return -EUCLEAN; ++ } ++ ++ if (quiet) { ++ /* Redo the last scan but noisily */ ++ quiet = 0; ++ continue; ++ } ++ ++ ubifs_scanned_corruption(c, lnum, offs, buf); ++ return -EUCLEAN; ++ } ++ ++ /* Pad to min_io_size */ ++ len = ALIGN(ucleb->endpt, c->min_io_size); ++ if (len > ucleb->endpt) { ++ int pad_len = len - ALIGN(ucleb->endpt, 8); ++ ++ if (pad_len > 0) { ++ buf = c->sbuf + len - pad_len; ++ ubifs_pad(c, buf, pad_len); ++ } ++ } ++ ++ /* Write back the LEB atomically */ ++ err = ubi_leb_change(c->ubi, lnum, sbuf, len, UBI_UNKNOWN); ++ if (err) ++ return err; ++ ++ dbg_rcvry("cleaned LEB %d", lnum); ++ ++ return 0; ++} ++ ++/** ++ * ubifs_clean_lebs - clean LEBs recovered during read-only mount. ++ * @c: UBIFS file-system description object ++ * @sbuf: LEB-sized buffer to use ++ * ++ * This function cleans a LEB identified during recovery that needs to be ++ * written but was not because UBIFS was mounted read-only. This happens when ++ * remounting to read-write mode. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf) ++{ ++ dbg_rcvry("recovery"); ++ while (!list_empty(&c->unclean_leb_list)) { ++ struct ubifs_unclean_leb *ucleb; ++ int err; ++ ++ ucleb = list_entry(c->unclean_leb_list.next, ++ struct ubifs_unclean_leb, list); ++ err = clean_an_unclean_leb(c, ucleb, sbuf); ++ if (err) ++ return err; ++ list_del(&ucleb->list); ++ kfree(ucleb); ++ } ++ return 0; ++} ++ ++/** ++ * ubifs_rcvry_gc_commit - recover the GC LEB number and run the commit. ++ * @c: UBIFS file-system description object ++ * ++ * Out-of-place garbage collection requires always one empty LEB with which to ++ * start garbage collection. The LEB number is recorded in c->gc_lnum and is ++ * written to the master node on unmounting. In the case of an unclean unmount ++ * the value of gc_lnum recorded in the master node is out of date and cannot ++ * be used. Instead, recovery must allocate an empty LEB for this purpose. ++ * However, there may not be enough empty space, in which case it must be ++ * possible to GC the dirtiest LEB into the GC head LEB. ++ * ++ * This function also runs the commit which causes the TNC updates from ++ * size-recovery and orphans to be written to the flash. That is important to ++ * ensure correct replay order for subsequent mounts. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++int ubifs_rcvry_gc_commit(struct ubifs_info *c) ++{ ++ struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf; ++ struct ubifs_lprops lp; ++ int lnum, err; ++ ++ c->gc_lnum = -1; ++ if (wbuf->lnum == -1) { ++ dbg_rcvry("no GC head LEB"); ++ goto find_free; ++ } ++ /* ++ * See whether the used space in the dirtiest LEB fits in the GC head ++ * LEB. ++ */ ++ if (wbuf->offs == c->leb_size) { ++ dbg_rcvry("no room in GC head LEB"); ++ goto find_free; ++ } ++ err = ubifs_find_dirty_leb(c, &lp, wbuf->offs, 2); ++ if (err) { ++ if (err == -ENOSPC) ++ dbg_err("could not find a dirty LEB"); ++ return err; ++ } ++ ubifs_assert(!(lp.flags & LPROPS_INDEX)); ++ lnum = lp.lnum; ++ if (lp.free + lp.dirty == c->leb_size) { ++ /* An empty LEB was returned */ ++ if (lp.free != c->leb_size) { ++ err = ubifs_change_one_lp(c, lnum, c->leb_size, ++ 0, 0, 0, 0); ++ if (err) ++ return err; ++ } ++ err = ubifs_leb_unmap(c, lnum); ++ if (err) ++ return err; ++ c->gc_lnum = lnum; ++ dbg_rcvry("allocated LEB %d for GC", lnum); ++ /* Run the commit */ ++ dbg_rcvry("committing"); ++ return ubifs_run_commit(c); ++ } ++ /* ++ * There was no empty LEB so the used space in the dirtiest LEB must fit ++ * in the GC head LEB. ++ */ ++ if (lp.free + lp.dirty < wbuf->offs) { ++ dbg_rcvry("LEB %d doesn't fit in GC head LEB %d:%d", ++ lnum, wbuf->lnum, wbuf->offs); ++ err = ubifs_return_leb(c, lnum); ++ if (err) ++ return err; ++ goto find_free; ++ } ++ /* ++ * We run the commit before garbage collection otherwise subsequent ++ * mounts will see the GC and orphan deletion in a different order. ++ */ ++ dbg_rcvry("committing"); ++ err = ubifs_run_commit(c); ++ if (err) ++ return err; ++ /* ++ * The data in the dirtiest LEB fits in the GC head LEB, so do the GC ++ * - use locking to keep 'ubifs_assert()' happy. ++ */ ++ dbg_rcvry("GC'ing LEB %d", lnum); ++ mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); ++ err = ubifs_garbage_collect_leb(c, &lp); ++ if (err >= 0) { ++ int err2 = ubifs_wbuf_sync_nolock(wbuf); ++ ++ if (err2) ++ err = err2; ++ } ++ mutex_unlock(&wbuf->io_mutex); ++ if (err < 0) { ++ dbg_err("GC failed, error %d", err); ++ if (err == -EAGAIN) ++ err = -EINVAL; ++ return err; ++ } ++ if (err != LEB_RETAINED) { ++ dbg_err("GC returned %d", err); ++ return -EINVAL; ++ } ++ err = ubifs_leb_unmap(c, c->gc_lnum); ++ if (err) ++ return err; ++ dbg_rcvry("allocated LEB %d for GC", lnum); ++ return 0; ++ ++find_free: ++ /* ++ * There is no GC head LEB or the free space in the GC head LEB is too ++ * small. Allocate gc_lnum by calling 'ubifs_find_free_leb_for_idx()' so ++ * GC is not run. ++ */ ++ lnum = ubifs_find_free_leb_for_idx(c); ++ if (lnum < 0) { ++ dbg_err("could not find an empty LEB"); ++ return lnum; ++ } ++ /* And reset the index flag */ ++ err = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0, ++ LPROPS_INDEX, 0); ++ if (err) ++ return err; ++ c->gc_lnum = lnum; ++ dbg_rcvry("allocated LEB %d for GC", lnum); ++ /* Run the commit */ ++ dbg_rcvry("committing"); ++ return ubifs_run_commit(c); ++} ++ ++/** ++ * struct size_entry - inode size information for recovery. ++ * @rb: link in the RB-tree of sizes ++ * @inum: inode number ++ * @i_size: size on inode ++ * @d_size: maximum size based on data nodes ++ * @exists: indicates whether the inode exists ++ * @inode: inode if pinned in memory awaiting rw mode to fix it ++ */ ++struct size_entry { ++ struct rb_node rb; ++ ino_t inum; ++ loff_t i_size; ++ loff_t d_size; ++ int exists; ++ struct inode *inode; ++}; ++ ++/** ++ * add_ino - add an entry to the size tree. ++ * @c: UBIFS file-system description object ++ * @inum: inode number ++ * @i_size: size on inode ++ * @d_size: maximum size based on data nodes ++ * @exists: indicates whether the inode exists ++ */ ++static int add_ino(struct ubifs_info *c, ino_t inum, loff_t i_size, ++ loff_t d_size, int exists) ++{ ++ struct rb_node **p = &c->size_tree.rb_node, *parent = NULL; ++ struct size_entry *e; ++ ++ while (*p) { ++ parent = *p; ++ e = rb_entry(parent, struct size_entry, rb); ++ if (inum < e->inum) ++ p = &(*p)->rb_left; ++ else ++ p = &(*p)->rb_right; ++ } ++ ++ e = kzalloc(sizeof(struct size_entry), GFP_KERNEL); ++ if (!e) ++ return -ENOMEM; ++ ++ e->inum = inum; ++ e->i_size = i_size; ++ e->d_size = d_size; ++ e->exists = exists; ++ ++ rb_link_node(&e->rb, parent, p); ++ rb_insert_color(&e->rb, &c->size_tree); ++ ++ return 0; ++} ++ ++/** ++ * find_ino - find an entry on the size tree. ++ * @c: UBIFS file-system description object ++ * @inum: inode number ++ */ ++static struct size_entry *find_ino(struct ubifs_info *c, ino_t inum) ++{ ++ struct rb_node *p = c->size_tree.rb_node; ++ struct size_entry *e; ++ ++ while (p) { ++ e = rb_entry(p, struct size_entry, rb); ++ if (inum < e->inum) ++ p = p->rb_left; ++ else if (inum > e->inum) ++ p = p->rb_right; ++ else ++ return e; ++ } ++ return NULL; ++} ++ ++/** ++ * remove_ino - remove an entry from the size tree. ++ * @c: UBIFS file-system description object ++ * @inum: inode number ++ */ ++static void remove_ino(struct ubifs_info *c, ino_t inum) ++{ ++ struct size_entry *e = find_ino(c, inum); ++ ++ if (!e) ++ return; ++ rb_erase(&e->rb, &c->size_tree); ++ kfree(e); ++} ++ ++/** ++ * ubifs_destroy_size_tree - free resources related to the size tree. ++ * @c: UBIFS file-system description object ++ */ ++void ubifs_destroy_size_tree(struct ubifs_info *c) ++{ ++ struct rb_node *this = c->size_tree.rb_node; ++ struct size_entry *e; ++ ++ while (this) { ++ if (this->rb_left) { ++ this = this->rb_left; ++ continue; ++ } else if (this->rb_right) { ++ this = this->rb_right; ++ continue; ++ } ++ e = rb_entry(this, struct size_entry, rb); ++ if (e->inode) ++ iput(e->inode); ++ this = rb_parent(this); ++ if (this) { ++ if (this->rb_left == &e->rb) ++ this->rb_left = NULL; ++ else ++ this->rb_right = NULL; ++ } ++ kfree(e); ++ } ++ c->size_tree = RB_ROOT; ++} ++ ++/** ++ * ubifs_recover_size_accum - accumulate inode sizes for recovery. ++ * @c: UBIFS file-system description object ++ * @key: node key ++ * @deletion: node is for a deletion ++ * @new_size: inode size ++ * ++ * This function has two purposes: ++ * 1) to ensure there are no data nodes that fall outside the inode size ++ * 2) to ensure there are no data nodes for inodes that do not exist ++ * To accomplish those purposes, a rb-tree is constructed containing an entry ++ * for each inode number in the journal that has not been deleted, and recording ++ * the size from the inode node, the maximum size of any data node (also altered ++ * by truncations) and a flag indicating a inode number for which no inode node ++ * was present in the journal. ++ * ++ * Note that there is still the possibility that there are data nodes that have ++ * been committed that are beyond the inode size, however the only way to find ++ * them would be to scan the entire index. Alternatively, some provision could ++ * be made to record the size of inodes at the start of commit, which would seem ++ * very cumbersome for a scenario that is quite unlikely and the only negative ++ * consequence of which is wasted space. ++ * ++ * This functions returns %0 on success and a negative error code on failure. ++ */ ++int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key, ++ int deletion, loff_t new_size) ++{ ++ ino_t inum = key_inum(c, key); ++ struct size_entry *e; ++ int err; ++ ++ switch (key_type(c, key)) { ++ case UBIFS_INO_KEY: ++ if (deletion) ++ remove_ino(c, inum); ++ else { ++ e = find_ino(c, inum); ++ if (e) { ++ e->i_size = new_size; ++ e->exists = 1; ++ } else { ++ err = add_ino(c, inum, new_size, 0, 1); ++ if (err) ++ return err; ++ } ++ } ++ break; ++ case UBIFS_DATA_KEY: ++ e = find_ino(c, inum); ++ if (e) { ++ if (new_size > e->d_size) ++ e->d_size = new_size; ++ } else { ++ err = add_ino(c, inum, 0, new_size, 0); ++ if (err) ++ return err; ++ } ++ break; ++ case UBIFS_TRUN_KEY: ++ e = find_ino(c, inum); ++ if (e) ++ e->d_size = new_size; ++ break; ++ } ++ return 0; ++} ++ ++/** ++ * fix_size_in_place - fix inode size in place on flash. ++ * @c: UBIFS file-system description object ++ * @e: inode size information for recovery ++ */ ++static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e) ++{ ++ struct ubifs_ino_node *ino = c->sbuf; ++ unsigned char *p; ++ union ubifs_key key; ++ int err, lnum, offs, len; ++ loff_t i_size; ++ uint32_t crc; ++ ++ /* Locate the inode node LEB number and offset */ ++ ino_key_init(c, &key, e->inum); ++ err = ubifs_tnc_locate(c, &key, ino, &lnum, &offs); ++ if (err) ++ goto out; ++ /* ++ * If the size recorded on the inode node is greater than the size that ++ * was calculated from nodes in the journal then don't change the inode. ++ */ ++ i_size = le64_to_cpu(ino->size); ++ if (i_size >= e->d_size) ++ return 0; ++ /* Read the LEB */ ++ err = ubi_read(c->ubi, lnum, c->sbuf, 0, c->leb_size); ++ if (err) ++ goto out; ++ /* Change the size field and recalculate the CRC */ ++ ino = c->sbuf + offs; ++ ino->size = cpu_to_le64(e->d_size); ++ len = le32_to_cpu(ino->ch.len); ++ crc = crc32(UBIFS_CRC32_INIT, (void *)ino + 8, len - 8); ++ ino->ch.crc = cpu_to_le32(crc); ++ /* Work out where data in the LEB ends and free space begins */ ++ p = c->sbuf; ++ len = c->leb_size - 1; ++ while (p[len] == 0xff) ++ len -= 1; ++ len = ALIGN(len + 1, c->min_io_size); ++ /* Atomically write the fixed LEB back again */ ++ err = ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN); ++ if (err) ++ goto out; ++ dbg_rcvry("inode %lu at %d:%d size %lld -> %lld ", e->inum, lnum, offs, ++ i_size, e->d_size); ++ return 0; ++ ++out: ++ ubifs_warn("inode %lu failed to fix size %lld -> %lld error %d", ++ e->inum, e->i_size, e->d_size, err); ++ return err; ++} ++ ++/** ++ * ubifs_recover_size - recover inode size. ++ * @c: UBIFS file-system description object ++ * ++ * This function attempts to fix inode size discrepancies identified by the ++ * 'ubifs_recover_size_accum()' function. ++ * ++ * This functions returns %0 on success and a negative error code on failure. ++ */ ++int ubifs_recover_size(struct ubifs_info *c) ++{ ++ struct rb_node *this = rb_first(&c->size_tree); ++ ++ while (this) { ++ struct size_entry *e; ++ int err; ++ ++ e = rb_entry(this, struct size_entry, rb); ++ if (!e->exists) { ++ union ubifs_key key; ++ ++ ino_key_init(c, &key, e->inum); ++ err = ubifs_tnc_lookup(c, &key, c->sbuf); ++ if (err && err != -ENOENT) ++ return err; ++ if (err == -ENOENT) { ++ /* Remove data nodes that have no inode */ ++ dbg_rcvry("removing ino %lu", e->inum); ++ err = ubifs_tnc_remove_ino(c, e->inum); ++ if (err) ++ return err; ++ } else { ++ struct ubifs_ino_node *ino = c->sbuf; ++ ++ e->exists = 1; ++ e->i_size = le64_to_cpu(ino->size); ++ } ++ } ++ if (e->exists && e->i_size < e->d_size) { ++ if (!e->inode && (c->vfs_sb->s_flags & MS_RDONLY)) { ++ /* Fix the inode size and pin it in memory */ ++ struct inode *inode; ++ ++ inode = ubifs_iget(c->vfs_sb, e->inum); ++ if (IS_ERR(inode)) ++ return PTR_ERR(inode); ++ if (inode->i_size < e->d_size) { ++ dbg_rcvry("ino %lu size %lld -> %lld", ++ e->inum, e->d_size, ++ inode->i_size); ++ inode->i_size = e->d_size; ++ e->inode = inode; ++ this = rb_next(this); ++ continue; ++ } ++ iput(inode); ++ } else { ++ /* Fix the size in place */ ++ err = fix_size_in_place(c, e); ++ if (err) { ++ if (e->inode) ++ /* ++ * We have changed the inode ++ * size in memory but failed to ++ * fix it on flash. Mark it ++ * dirty without budgeting, and ++ * hope we don't run out of ++ * space. ++ */ ++ mark_inode_dirty_sync(e->inode); ++ /* ++ * We consider that failing to recover ++ * the size is not fatal, because it ++ * only affects files that were being ++ * written without synchronization and ++ * the only down side is that some space ++ * may be wasted. ++ */ ++ err = 0; ++ } ++ if (e->inode) ++ iput(e->inode); ++ } ++ } ++ this = rb_next(this); ++ rb_erase(&e->rb, &c->size_tree); ++ kfree(e); ++ } ++ return 0; ++} +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/replay.c avr32-2.6/fs/ubifs/replay.c +--- linux-2.6.25.6/fs/ubifs/replay.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/replay.c 2008-06-12 15:09:45.515816461 +0200 +@@ -0,0 +1,1075 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Adrian Hunter ++ * Artem Bityutskiy (Битюцкий Артём) ++ */ ++ ++/* ++ * This file contains journal replay code. It runs when the file-system is being ++ * mounted and requires no locking. ++ * ++ * The larger is the journal, the longer it takes to scan it, so the longer it ++ * takes to mount UBIFS. This is why the journal has limited size which may be ++ * changed depending on the system requirements. But a larger journal gives ++ * faster I/O speed because it writes the index less frequently. So this is a ++ * trade-off. Also, the journal is indexed by the in-memory index (TNC), so the ++ * larger is the journal, the more memory its index may consume. ++ */ ++ ++#include "ubifs.h" ++ ++/* ++ * Replay flags. ++ * ++ * REPLAY_DELETION: node was deleted ++ * REPLAY_REF: node is a reference node ++ */ ++enum { ++ REPLAY_DELETION = 1, ++ REPLAY_REF = 2, ++}; ++ ++/** ++ * struct replay_entry - replay tree entry. ++ * @lnum: logical eraseblock number of the node ++ * @offs: node offset ++ * @len: node length ++ * @sqnum: node sequence number ++ * @flags: replay flags ++ * @rb: links the replay tree ++ * @key: node key ++ * @nm: directory entry name ++ * @old_size: truncation old size ++ * @new_size: truncation new size ++ * @free: amount of free space in a bud ++ * @dirty: amount of dirty space in a bud from padding and deletion nodes ++ * ++ * UBIFS journal replay must compare node sequence numbers, which means it must ++ * build a tree of node information to insert into the TNC. ++ */ ++struct replay_entry { ++ int lnum; ++ int offs; ++ int len; ++ unsigned long long sqnum; ++ int flags; ++ struct rb_node rb; ++ union ubifs_key key; ++ union { ++ struct qstr nm; ++ struct { ++ loff_t old_size; ++ loff_t new_size; ++ }; ++ struct { ++ int free; ++ int dirty; ++ }; ++ }; ++}; ++ ++/** ++ * struct bud_entry - entry in the list of buds to replay. ++ * @list: next bud in the list ++ * @bud: bud description object ++ * @free: free bytes in the bud ++ * @sqnum: reference node sequence number ++ */ ++struct bud_entry { ++ struct list_head list; ++ struct ubifs_bud *bud; ++ int free; ++ unsigned long long sqnum; ++}; ++ ++/** ++ * set_bud_lprops - set free and dirty space used by a bud. ++ * @c: UBIFS file-system description object ++ * @r: replay entry of bud ++ */ ++static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r) ++{ ++ const struct ubifs_lprops *lp; ++ int err = 0, dirty; ++ ++ ubifs_get_lprops(c); ++ ++ lp = ubifs_lpt_lookup_dirty(c, r->lnum); ++ if (IS_ERR(lp)) { ++ err = PTR_ERR(lp); ++ goto out; ++ } ++ ++ dirty = lp->dirty; ++ if (r->offs == 0 && (lp->free != c->leb_size || lp->dirty != 0)) { ++ /* ++ * The LEB was added to the journal with a starting offset of ++ * zero which means the LEB must have been empty. The LEB ++ * property values should be lp->free == c->leb_size and ++ * lp->dirty == 0, but that is not the case. The reason is that ++ * the LEB was garbage collected. The garbage collector resets ++ * the free and dirty space without recording it anywhere except ++ * lprops, so if there is not a commit then lprops does not have ++ * that information next time the file system is mounted. ++ * ++ * We do not need to adjust free space because the scan has told ++ * us the exact value which is recorded in the replay entry as ++ * r->free. ++ * ++ * However we do need to subtract from the dirty space the ++ * amount of space that the garbage collector reclaimed, which ++ * is the whole LEB minus the amount of space that was free. ++ */ ++ dbg_mnt("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum, ++ lp->free, lp->dirty); ++ dbg_gc("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum, ++ lp->free, lp->dirty); ++ dirty -= c->leb_size - lp->free; ++ /* ++ * If the replay order was perfect the dirty space would now be ++ * zero. The order is not perfect because the the journal heads ++ * race with eachother. This is not a problem but is does mean ++ * that the dirty space may temporarily exceed c->leb_size ++ * during the replay. ++ */ ++ if (dirty != 0) ++ dbg_msg("LEB %d lp: %d free %d dirty " ++ "replay: %d free %d dirty", r->lnum, lp->free, ++ lp->dirty, r->free, r->dirty); ++ } ++ lp = ubifs_change_lp(c, lp, r->free, dirty + r->dirty, ++ lp->flags | LPROPS_TAKEN, 0); ++ if (IS_ERR(lp)) { ++ err = PTR_ERR(lp); ++ goto out; ++ } ++out: ++ ubifs_release_lprops(c); ++ return err; ++} ++ ++/** ++ * trun_remove_range - apply a replay entry for a truncation to the TNC. ++ * @c: UBIFS file-system description object ++ * @r: replay entry of truncation ++ */ ++static int trun_remove_range(struct ubifs_info *c, struct replay_entry *r) ++{ ++ unsigned min_blk, max_blk; ++ union ubifs_key min_key, max_key; ++ ino_t ino; ++ ++ min_blk = r->new_size / UBIFS_BLOCK_SIZE; ++ if (r->new_size & (UBIFS_BLOCK_SIZE - 1)) ++ min_blk += 1; ++ ++ max_blk = r->old_size / UBIFS_BLOCK_SIZE; ++ if ((r->old_size & (UBIFS_BLOCK_SIZE - 1)) == 0) ++ max_blk -= 1; ++ ++ ino = key_inum(c, &r->key); ++ ++ data_key_init(c, &min_key, ino, min_blk); ++ data_key_init(c, &max_key, ino, max_blk); ++ ++ return ubifs_tnc_remove_range(c, &min_key, &max_key); ++} ++ ++/** ++ * apply_replay_entry - apply a replay entry to the TNC. ++ * @c: UBIFS file-system description object ++ * @r: replay entry to apply ++ * ++ * Apply a replay entry to the TNC. ++ */ ++static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r) ++{ ++ int err, deletion = ((r->flags & REPLAY_DELETION) != 0); ++ ++ dbg_mnt("LEB %d:%d len %d flgs %d sqnum %llu %s", r->lnum, ++ r->offs, r->len, r->flags, r->sqnum, DBGKEY(&r->key)); ++ ++ /* Set c->replay_sqnum to help deal with dangling branches. */ ++ c->replay_sqnum = r->sqnum; ++ ++ if (r->flags & REPLAY_REF) ++ err = set_bud_lprops(c, r); ++ else if (is_hash_key(c, &r->key)) { ++ if (deletion) ++ err = ubifs_tnc_remove_nm(c, &r->key, &r->nm); ++ else ++ err = ubifs_tnc_add_nm(c, &r->key, r->lnum, r->offs, ++ r->len, &r->nm); ++ } else { ++ if (deletion) ++ switch (key_type(c, &r->key)) { ++ case UBIFS_INO_KEY: ++ { ++ ino_t inum = key_inum(c, &r->key); ++ ++ err = ubifs_tnc_remove_ino(c, inum); ++ break; ++ } ++ case UBIFS_TRUN_KEY: ++ err = trun_remove_range(c, r); ++ break; ++ default: ++ err = ubifs_tnc_remove(c, &r->key); ++ break; ++ } ++ else ++ err = ubifs_tnc_add(c, &r->key, r->lnum, r->offs, ++ r->len); ++ if (err) ++ return err; ++ ++ if (c->need_recovery) ++ err = ubifs_recover_size_accum(c, &r->key, deletion, ++ r->new_size); ++ } ++ ++ return err; ++} ++ ++/** ++ * destroy_replay_tree - destroy the replay. ++ * @c: UBIFS file-system description object ++ * ++ * Destroy the replay tree. ++ */ ++static void destroy_replay_tree(struct ubifs_info *c) ++{ ++ struct rb_node *this = c->replay_tree.rb_node; ++ struct replay_entry *r; ++ ++ while (this) { ++ if (this->rb_left) { ++ this = this->rb_left; ++ continue; ++ } else if (this->rb_right) { ++ this = this->rb_right; ++ continue; ++ } ++ r = rb_entry(this, struct replay_entry, rb); ++ this = rb_parent(this); ++ if (this) { ++ if (this->rb_left == &r->rb) ++ this->rb_left = NULL; ++ else ++ this->rb_right = NULL; ++ } ++ if (is_hash_key(c, &r->key)) ++ kfree(r->nm.name); ++ kfree(r); ++ } ++ c->replay_tree = RB_ROOT; ++} ++ ++/** ++ * apply_replay_tree - apply the replay tree to the TNC. ++ * @c: UBIFS file-system description object ++ * ++ * Apply the replay tree. ++ * Returns zero in case of success and a negative error code in case of ++ * failure. ++ */ ++static int apply_replay_tree(struct ubifs_info *c) ++{ ++ struct rb_node *this = rb_first(&c->replay_tree); ++ ++ while (this) { ++ struct replay_entry *r; ++ int err; ++ ++ cond_resched(); ++ ++ r = rb_entry(this, struct replay_entry, rb); ++ err = apply_replay_entry(c, r); ++ if (err) ++ return err; ++ this = rb_next(this); ++ } ++ return 0; ++} ++ ++/** ++ * insert_node - insert a node to the replay tree. ++ * @c: UBIFS file-system description object ++ * @lnum: node logical eraseblock number ++ * @offs: node offset ++ * @len: node length ++ * @key: node key ++ * @sqnum: sequence number ++ * @deletion: non-zero if this is a deletion ++ * @used: number of bytes in use in a LEB ++ * @old_size: truncation old size ++ * @new_size: truncation new size ++ * ++ * This function inserts a scanned non-direntry node to the replay tree. The ++ * replay tree is an RB-tree containing @struct replay_entry elements which are ++ * indexed by the sequence number. The replay tree is applied at the very end ++ * of the replay process. Since the tree is sorted in sequence number order, ++ * the older modifications are applied first. This function returns zero in ++ * case of success and a negative error code in case of failure. ++ */ ++static int insert_node(struct ubifs_info *c, int lnum, int offs, int len, ++ union ubifs_key *key, unsigned long long sqnum, ++ int deletion, int *used, loff_t old_size, ++ loff_t new_size) ++{ ++ struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL; ++ struct replay_entry *r; ++ ++ if (key_inum(c, key) >= c->highest_inum) ++ c->highest_inum = key_inum(c, key); ++ ++ dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key)); ++ while (*p) { ++ parent = *p; ++ r = rb_entry(parent, struct replay_entry, rb); ++ if (sqnum < r->sqnum) { ++ p = &(*p)->rb_left; ++ continue; ++ } else if (sqnum > r->sqnum) { ++ p = &(*p)->rb_right; ++ continue; ++ } ++ ubifs_err("duplicate sqnum in replay"); ++ return -EINVAL; ++ } ++ ++ r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL); ++ if (!r) ++ return -ENOMEM; ++ ++ if (!deletion) ++ *used += ALIGN(len, 8); ++ r->lnum = lnum; ++ r->offs = offs; ++ r->len = len; ++ r->sqnum = sqnum; ++ r->flags = (deletion ? REPLAY_DELETION : 0); ++ r->old_size = old_size; ++ r->new_size = new_size; ++ key_copy(c, key, &r->key); ++ ++ rb_link_node(&r->rb, parent, p); ++ rb_insert_color(&r->rb, &c->replay_tree); ++ return 0; ++} ++ ++/** ++ * insert_dent - insert a directory entry node into the replay tree. ++ * @c: UBIFS file-system description object ++ * @lnum: node logical eraseblock number ++ * @offs: node offset ++ * @len: node length ++ * @key: node key ++ * @name: directory entry name ++ * @nlen: directory entry name length ++ * @sqnum: sequence number ++ * @deletion: non-zero if this is a deletion ++ * @used: number of bytes in use in a LEB ++ * ++ * This function inserts a scanned directory entry node to the replay tree. ++ * Returns zero in case of success and a negative error code in case of ++ * failure. ++ * ++ * This function is also used for extended attribute entries because they are ++ * implemented as directory entry nodes. ++ */ ++static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len, ++ union ubifs_key *key, const char *name, int nlen, ++ unsigned long long sqnum, int deletion, int *used) ++{ ++ struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL; ++ struct replay_entry *r; ++ char *nbuf; ++ ++ if (key_inum(c, key) >= c->highest_inum) ++ c->highest_inum = key_inum(c, key); ++ ++ dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key)); ++ while (*p) { ++ parent = *p; ++ r = rb_entry(parent, struct replay_entry, rb); ++ if (sqnum < r->sqnum) { ++ p = &(*p)->rb_left; ++ continue; ++ } ++ if (sqnum > r->sqnum) { ++ p = &(*p)->rb_right; ++ continue; ++ } ++ ubifs_err("duplicate sqnum in replay"); ++ return -EINVAL; ++ } ++ ++ r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL); ++ if (!r) ++ return -ENOMEM; ++ nbuf = kmalloc(nlen + 1, GFP_KERNEL); ++ if (!nbuf) { ++ kfree(r); ++ return -ENOMEM; ++ } ++ ++ if (!deletion) ++ *used += ALIGN(len, 8); ++ r->lnum = lnum; ++ r->offs = offs; ++ r->len = len; ++ r->sqnum = sqnum; ++ r->nm.len = nlen; ++ memcpy(nbuf, name, nlen); ++ nbuf[nlen] = '\0'; ++ r->nm.name = nbuf; ++ r->flags = (deletion ? REPLAY_DELETION : 0); ++ key_copy(c, key, &r->key); ++ ++ ubifs_assert(!*p); ++ rb_link_node(&r->rb, parent, p); ++ rb_insert_color(&r->rb, &c->replay_tree); ++ return 0; ++} ++ ++/** ++ * ubifs_validate_entry - validate directory or extended attribute entry node. ++ * @c: UBIFS file-system description object ++ * @dent: the node to validate ++ * ++ * This function validates directory or extended attribute entry node @dent. ++ * Returns zero if the node is all right and a %-EINVAL if not. ++ */ ++int ubifs_validate_entry(struct ubifs_info *c, ++ const struct ubifs_dent_node *dent) ++{ ++ int key_type = key_type_flash(c, dent->key); ++ int nlen = le16_to_cpu(dent->nlen); ++ ++ if (le32_to_cpu(dent->ch.len) != nlen + UBIFS_DENT_NODE_SZ + 1 || ++ dent->type >= UBIFS_ITYPES_CNT || ++ nlen > UBIFS_MAX_NLEN || dent->name[nlen] != 0 || ++ strnlen(dent->name, nlen) != nlen || ++ le64_to_cpu(dent->inum) > MAX_INUM) { ++ ubifs_err("bad %s node", key_type == UBIFS_DENT_KEY ? ++ "directory entry" : "extended attribute entry"); ++ return -EINVAL; ++ } ++ ++ if (key_type != UBIFS_DENT_KEY && key_type != UBIFS_XENT_KEY) { ++ ubifs_err("bad key type %d", key_type); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/** ++ * replay_bud - replay a bud logical eraseblock. ++ * @c: UBIFS file-system description object ++ * @lnum: bud logical eraseblock number to replay ++ * @offs: bud start offset ++ * @jhead: journal head to which this bud belongs ++ * @free: amount of free space in the bud is returned here ++ * @dirty: amount of dirty space from padding and deletion nodes is returned ++ * here ++ * ++ * This function returns zero in case of success and a negative error code in ++ * case of failure. ++ */ ++static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead, ++ int *free, int *dirty) ++{ ++ int err = 0, used = 0; ++ struct ubifs_scan_leb *sleb; ++ struct ubifs_scan_node *snod; ++ struct ubifs_bud *bud; ++ ++ dbg_mnt("replay bud LEB %d, head %d", lnum, jhead); ++ if (c->need_recovery) ++ sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, jhead != GCHD); ++ else ++ sleb = ubifs_scan(c, lnum, offs, c->sbuf); ++ if (IS_ERR(sleb)) ++ return PTR_ERR(sleb); ++ ++ /* ++ * The bud does not have to start from offset zero - the beginning of ++ * the 'lnum' LEB may contain previously committed data. One of the ++ * things we have to do in replay is to correctly update lprops with ++ * newer information about this LEB. ++ * ++ * At this point lprops thinks that this LEB has 'c->leb_size - offs' ++ * bytes of free space because it only contain information about ++ * committed data. ++ * ++ * But we know that real amount of free space is 'c->leb_size - ++ * sleb->endpt', and the space in the 'lnum' LEB between 'offs' and ++ * 'sleb->endpt' is used by bud data. We have to correctly calculate ++ * how much of these data are dirty and update lprops with this ++ * information. ++ * ++ * The dirt in that LEB region is comprised of padding nodes, deletion ++ * nodes, truncation nodes and nodes which are obsoleted by subsequent ++ * nodes in this LEB. So instead of calculating clean space, we ++ * calculate used space ('used' variable). ++ */ ++ ++ list_for_each_entry(snod, &sleb->nodes, list) { ++ int deletion = 0; ++ ++ cond_resched(); ++ ++ if (snod->sqnum >= SQNUM_WATERMARK) { ++ ubifs_err("file system's life ended"); ++ goto out_dump; ++ } ++ ++ if (snod->sqnum > c->max_sqnum) ++ c->max_sqnum = snod->sqnum; ++ ++ switch (snod->type) { ++ case UBIFS_INO_NODE: ++ { ++ struct ubifs_ino_node *ino = snod->node; ++ loff_t new_size = le64_to_cpu(ino->size); ++ ++ if (le32_to_cpu(ino->nlink) == 0) ++ deletion = 1; ++ err = insert_node(c, lnum, snod->offs, snod->len, ++ &snod->key, snod->sqnum, deletion, ++ &used, 0, new_size); ++ break; ++ } ++ case UBIFS_DATA_NODE: ++ { ++ struct ubifs_data_node *dn = snod->node; ++ loff_t new_size = le32_to_cpu(dn->size) + ++ key_block(c, &snod->key) * ++ UBIFS_BLOCK_SIZE; ++ ++ err = insert_node(c, lnum, snod->offs, snod->len, ++ &snod->key, snod->sqnum, deletion, ++ &used, 0, new_size); ++ break; ++ } ++ case UBIFS_DENT_NODE: ++ case UBIFS_XENT_NODE: ++ { ++ struct ubifs_dent_node *dent = snod->node; ++ ++ err = ubifs_validate_entry(c, dent); ++ if (err) ++ goto out_dump; ++ ++ err = insert_dent(c, lnum, snod->offs, snod->len, ++ &snod->key, dent->name, ++ le16_to_cpu(dent->nlen), snod->sqnum, ++ !le64_to_cpu(dent->inum), &used); ++ break; ++ } ++ case UBIFS_TRUN_NODE: ++ { ++ struct ubifs_trun_node *trun = snod->node; ++ loff_t old_size = le64_to_cpu(trun->old_size); ++ loff_t new_size = le64_to_cpu(trun->new_size); ++ union ubifs_key key; ++ ++ /* Validate truncation node */ ++ if (old_size < 0 || old_size > c->max_inode_sz || ++ new_size < 0 || new_size > c->max_inode_sz || ++ old_size <= new_size) { ++ ubifs_err("bad truncation node"); ++ goto out_dump; ++ } ++ ++ /* ++ * Create a fake truncation key just to use the same ++ * functions which expect nodes to have keys. ++ */ ++ trun_key_init(c, &key, le32_to_cpu(trun->inum)); ++ err = insert_node(c, lnum, snod->offs, snod->len, ++ &key, snod->sqnum, 1, &used, ++ old_size, new_size); ++ break; ++ } ++ default: ++ ubifs_err("unexpected node type %d in bud LEB %d:%d", ++ snod->type, lnum, snod->offs); ++ err = -EINVAL; ++ goto out_dump; ++ } ++ if (err) ++ goto out; ++ } ++ ++ bud = ubifs_search_bud(c, lnum); ++ if (!bud) ++ BUG(); ++ ++ ubifs_assert(sleb->endpt - offs >= used); ++ ubifs_assert(sleb->endpt % c->min_io_size == 0); ++ ++ if (sleb->endpt + c->min_io_size <= c->leb_size && ++ !(c->vfs_sb->s_flags & MS_RDONLY)) ++ err = ubifs_wbuf_seek_nolock(&c->jheads[jhead].wbuf, lnum, ++ sleb->endpt, UBI_SHORTTERM); ++ ++ *dirty = sleb->endpt - offs - used; ++ *free = c->leb_size - sleb->endpt; ++ ++out: ++ ubifs_scan_destroy(sleb); ++ return err; ++ ++out_dump: ++ ubifs_err("bad node is at LEB %d:%d", lnum, snod->offs); ++ dbg_dump_node(c, snod->node); ++ ubifs_scan_destroy(sleb); ++ return -EINVAL; ++} ++ ++/** ++ * insert_ref_node - insert a reference node to the replay tree. ++ * @c: UBIFS file-system description object ++ * @lnum: node logical eraseblock number ++ * @offs: node offset ++ * @sqnum: sequence number ++ * @free: amount of free space in bud ++ * @dirty: amount of dirty space from padding and deletion nodes ++ * ++ * This function inserts a reference node to the replay tree and returns zero ++ * in case of success ort a negative error code in case of failure. ++ */ ++static int insert_ref_node(struct ubifs_info *c, int lnum, int offs, ++ unsigned long long sqnum, int free, int dirty) ++{ ++ struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL; ++ struct replay_entry *r; ++ ++ dbg_mnt("add ref LEB %d:%d", lnum, offs); ++ while (*p) { ++ parent = *p; ++ r = rb_entry(parent, struct replay_entry, rb); ++ if (sqnum < r->sqnum) { ++ p = &(*p)->rb_left; ++ continue; ++ } else if (sqnum > r->sqnum) { ++ p = &(*p)->rb_right; ++ continue; ++ } ++ ubifs_err("duplicate sqnum in replay tree"); ++ return -EINVAL; ++ } ++ ++ r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL); ++ if (!r) ++ return -ENOMEM; ++ ++ r->lnum = lnum; ++ r->offs = offs; ++ r->sqnum = sqnum; ++ r->flags = REPLAY_REF; ++ r->free = free; ++ r->dirty = dirty; ++ ++ rb_link_node(&r->rb, parent, p); ++ rb_insert_color(&r->rb, &c->replay_tree); ++ return 0; ++} ++ ++/** ++ * replay_buds - replay all buds. ++ * @c: UBIFS file-system description object ++ * ++ * This function returns zero in case of success and a negative error code in ++ * case of failure. ++ */ ++static int replay_buds(struct ubifs_info *c) ++{ ++ struct bud_entry *b; ++ int err, uninitialized_var(free), uninitialized_var(dirty); ++ ++ list_for_each_entry(b, &c->replay_buds, list) { ++ err = replay_bud(c, b->bud->lnum, b->bud->start, b->bud->jhead, ++ &free, &dirty); ++ if (err) ++ return err; ++ err = insert_ref_node(c, b->bud->lnum, b->bud->start, b->sqnum, ++ free, dirty); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} ++ ++/** ++ * destroy_bud_list - destroy the list of buds to replay. ++ * @c: UBIFS file-system description object ++ */ ++static void destroy_bud_list(struct ubifs_info *c) ++{ ++ struct bud_entry *b; ++ ++ while (!list_empty(&c->replay_buds)) { ++ b = list_entry(c->replay_buds.next, struct bud_entry, list); ++ list_del(&b->list); ++ kfree(b); ++ } ++} ++ ++/** ++ * add_replay_bud - add a bud to the list of buds to replay. ++ * @c: UBIFS file-system description object ++ * @lnum: bud logical eraseblock number to replay ++ * @offs: bud start offset ++ * @jhead: journal head to which this bud belongs ++ * @sqnum: reference node sequence number ++ * ++ * This function returns zero in case of success and a negative error code in ++ * case of failure. ++ */ ++static int add_replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead, ++ unsigned long long sqnum) ++{ ++ struct ubifs_bud *bud; ++ struct bud_entry *b; ++ ++ dbg_mnt("add replay bud LEB %d:%d, head %d", lnum, offs, jhead); ++ ++ bud = kmalloc(sizeof(struct ubifs_bud), GFP_KERNEL); ++ if (!bud) ++ return -ENOMEM; ++ ++ b = kmalloc(sizeof(struct bud_entry), GFP_KERNEL); ++ if (!b) { ++ kfree(bud); ++ return -ENOMEM; ++ } ++ ++ bud->lnum = lnum; ++ bud->start = offs; ++ bud->jhead = jhead; ++ ubifs_add_bud(c, bud); ++ ++ b->bud = bud; ++ b->sqnum = sqnum; ++ list_add_tail(&b->list, &c->replay_buds); ++ ++ return 0; ++} ++ ++/** ++ * validate_ref - validate a reference node. ++ * @c: UBIFS file-system description object ++ * @ref: the reference node to validate ++ * @ref_lnum: LEB number of the reference node ++ * @ref_offs: reference node offset ++ * ++ * This function returns %1 if a bud reference already exists for the LEB. %0 is ++ * returned if the reference node is new, otherwise %-EINVAL is returned if ++ * validation failed. ++ */ ++static int validate_ref(struct ubifs_info *c, const struct ubifs_ref_node *ref) ++{ ++ struct ubifs_bud *bud; ++ int lnum = le32_to_cpu(ref->lnum); ++ unsigned int offs = le32_to_cpu(ref->offs); ++ unsigned int jhead = le32_to_cpu(ref->jhead); ++ ++ /* ++ * ref->offs may point to the end of LEB when the journal head points ++ * to the end of LEB and we write reference node for it during commit. ++ * So this is why we require 'offs > c->leb_size'. ++ */ ++ if (jhead >= c->jhead_cnt || lnum >= c->leb_cnt || ++ lnum < c->main_first || offs > c->leb_size || ++ offs & (c->min_io_size - 1)) ++ return -EINVAL; ++ ++ /* Make sure we have not already looked at this bud */ ++ bud = ubifs_search_bud(c, lnum); ++ if (bud) { ++ if (bud->jhead == jhead && bud->start <= offs) ++ return 1; ++ ubifs_err("bud at LEB %d:%d was already referred", lnum, offs); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/** ++ * replay_log_leb - replay a log logical eraseblock. ++ * @c: UBIFS file-system description object ++ * @lnum: log logical eraseblock to replay ++ * @offs: offset to start replaying from ++ * @sbuf: scan buffer ++ * ++ * This function replays a log LEB and returns zero in case of success, %1 if ++ * this is the last LEB in the log, and a negative error code in case of ++ * failure. ++ */ ++static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf) ++{ ++ int err; ++ struct ubifs_scan_leb *sleb; ++ struct ubifs_scan_node *snod; ++ const struct ubifs_cs_node *node; ++ ++ dbg_mnt("replay log LEB %d:%d", lnum, offs); ++ sleb = ubifs_scan(c, lnum, offs, sbuf); ++ if (IS_ERR(sleb)) { ++ if (c->need_recovery) ++ sleb = ubifs_recover_log_leb(c, lnum, offs, sbuf); ++ if (IS_ERR(sleb)) ++ return PTR_ERR(sleb); ++ } ++ ++ if (sleb->nodes_cnt == 0) { ++ err = 1; ++ goto out; ++ } ++ ++ node = sleb->buf; ++ ++ snod = list_entry(sleb->nodes.next, struct ubifs_scan_node, list); ++ if (c->cs_sqnum == 0) { ++ /* ++ * This is the first log LEB we are looking at, make sure that ++ * the first node is a commit start node. Also record its ++ * sequence number so that UBIFS can determine where the log ++ * ends, because all nodes which were have higher sequence ++ * numbers. ++ */ ++ if (snod->type != UBIFS_CS_NODE) { ++ dbg_err("first log node at LEB %d:%d is not CS node", ++ lnum, offs); ++ goto out_dump; ++ } ++ if (le64_to_cpu(node->cmt_no) != c->cmt_no) { ++ dbg_err("first CS node at LEB %d:%d has wrong " ++ "commit number %llu expected %llu", ++ lnum, offs, ++ (unsigned long long)le64_to_cpu(node->cmt_no), ++ c->cmt_no); ++ goto out_dump; ++ } ++ ++ c->cs_sqnum = le64_to_cpu(node->ch.sqnum); ++ dbg_mnt("commit start sqnum %llu", c->cs_sqnum); ++ } ++ ++ if (snod->sqnum < c->cs_sqnum) { ++ /* ++ * This means that we reached end of log and now ++ * look to the older log data, which was already ++ * committed but the eraseblock was not erased (UBIFS ++ * only unmaps it). So this basically means we have to ++ * exit with "end of log" code. ++ */ ++ err = 1; ++ goto out; ++ } ++ ++ /* Make sure the first node sits at offset zero of the LEB */ ++ if (snod->offs != 0) { ++ dbg_err("first node is not at zero offset"); ++ goto out_dump; ++ } ++ ++ list_for_each_entry(snod, &sleb->nodes, list) { ++ ++ cond_resched(); ++ ++ if (snod->sqnum >= SQNUM_WATERMARK) { ++ ubifs_err("file system's life ended"); ++ goto out_dump; ++ } ++ ++ if (snod->sqnum < c->cs_sqnum) { ++ dbg_err("bad sqnum %llu, commit sqnum %llu", ++ snod->sqnum, c->cs_sqnum); ++ goto out_dump; ++ } ++ ++ if (snod->sqnum > c->max_sqnum) ++ c->max_sqnum = snod->sqnum; ++ ++ switch (snod->type) { ++ case UBIFS_REF_NODE: { ++ const struct ubifs_ref_node *ref = snod->node; ++ ++ err = validate_ref(c, ref); ++ if (err == 1) ++ break; /* Already have this bud */ ++ if (err) ++ goto out_dump; ++ ++ err = add_replay_bud(c, le32_to_cpu(ref->lnum), ++ le32_to_cpu(ref->offs), ++ le32_to_cpu(ref->jhead), ++ snod->sqnum); ++ if (err) ++ goto out; ++ ++ break; ++ } ++ case UBIFS_CS_NODE: ++ /* Make sure it sits at the beginning of LEB */ ++ if (snod->offs != 0) { ++ ubifs_err("unexpected node in log"); ++ goto out_dump; ++ } ++ break; ++ default: ++ ubifs_err("unexpected node in log"); ++ goto out_dump; ++ } ++ } ++ ++ if (sleb->endpt || c->lhead_offs >= c->leb_size) { ++ c->lhead_lnum = lnum; ++ c->lhead_offs = sleb->endpt; ++ } ++ ++ err = !sleb->endpt; ++out: ++ ubifs_scan_destroy(sleb); ++ return err; ++ ++out_dump: ++ ubifs_err("log error detected while replying the log at LEB %d:%d", ++ lnum, offs + snod->offs); ++ dbg_dump_node(c, snod->node); ++ ubifs_scan_destroy(sleb); ++ return -EINVAL; ++} ++ ++/** ++ * take_ihead - update the status of the index head in lprops to 'taken'. ++ * @c: UBIFS file-system description object ++ * ++ * This function returns the amount of free space in the index head LEB or a ++ * negative error code. ++ */ ++static int take_ihead(struct ubifs_info *c) ++{ ++ const struct ubifs_lprops *lp; ++ int err, free; ++ ++ ubifs_get_lprops(c); ++ ++ lp = ubifs_lpt_lookup_dirty(c, c->ihead_lnum); ++ if (IS_ERR(lp)) { ++ err = PTR_ERR(lp); ++ goto out; ++ } ++ ++ free = lp->free; ++ ++ lp = ubifs_change_lp(c, lp, LPROPS_NC, LPROPS_NC, ++ lp->flags | LPROPS_TAKEN, 0); ++ if (IS_ERR(lp)) { ++ err = PTR_ERR(lp); ++ goto out; ++ } ++ ++ err = free; ++out: ++ ubifs_release_lprops(c); ++ return err; ++} ++ ++/** ++ * ubifs_replay_journal - replay journal. ++ * @c: UBIFS file-system description object ++ * ++ * This function scans the journal, replays and cleans it up. It makes sure all ++ * memory data structures related to uncommitted journal are built (dirty TNC ++ * tree, tree of buds, modified lprops, etc). ++ */ ++int ubifs_replay_journal(struct ubifs_info *c) ++{ ++ int err, i, lnum, offs, free; ++ void *sbuf = NULL; ++ ++ BUILD_BUG_ON(UBIFS_TRUN_KEY > 5); ++ ++ /* Update the status of the index head in lprops to 'taken' */ ++ free = take_ihead(c); ++ if (free < 0) ++ return free; /* Error code */ ++ ++ if (c->ihead_offs != c->leb_size - free) { ++ ubifs_err("bad index head LEB %d:%d", c->ihead_lnum, ++ c->ihead_offs); ++ return -EINVAL; ++ } ++ ++ sbuf = vmalloc(c->leb_size); ++ if (!sbuf) ++ return -ENOMEM; ++ ++ dbg_mnt("start replaying the journal"); ++ ++ c->replaying = 1; ++ ++ lnum = c->ltail_lnum = c->lhead_lnum; ++ offs = c->lhead_offs; ++ ++ for (i = 0; i < c->log_lebs; i++, lnum++) { ++ if (lnum >= UBIFS_LOG_LNUM + c->log_lebs) { ++ /* ++ * The log is logically circular, we reached the last ++ * LEB, switch to the first one. ++ */ ++ lnum = UBIFS_LOG_LNUM; ++ offs = 0; ++ } ++ err = replay_log_leb(c, lnum, offs, sbuf); ++ if (err == 1) ++ /* We hit the end of the log */ ++ break; ++ if (err) ++ goto out; ++ offs = 0; ++ } ++ ++ err = replay_buds(c); ++ if (err) ++ goto out; ++ ++ err = apply_replay_tree(c); ++ if (err) ++ goto out; ++ ++ ubifs_assert(c->bud_bytes <= c->max_bud_bytes || c->need_recovery); ++ dbg_mnt("finished, log head LEB %d:%d, max_sqnum %llu, " ++ "highest_inum %lu", c->lhead_lnum, c->lhead_offs, c->max_sqnum, ++ c->highest_inum); ++out: ++ destroy_replay_tree(c); ++ destroy_bud_list(c); ++ vfree(sbuf); ++ c->replaying = 0; ++ return err; ++} +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/sb.c avr32-2.6/fs/ubifs/sb.c +--- linux-2.6.25.6/fs/ubifs/sb.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/sb.c 2008-06-12 15:09:45.515816461 +0200 +@@ -0,0 +1,618 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Artem Bityutskiy (Битюцкий Артём) ++ * Adrian Hunter ++ */ ++ ++/* ++ * This file implements UBIFS superblock. The superblock is stored at the first ++ * LEB of the volume and is never changed by UBIFS. Only user-space tools may ++ * change it. The superblock node mostly contains geometry information. ++ */ ++ ++#include "ubifs.h" ++#include <linux/random.h> ++ ++/* ++ * Default journal size in logical eraseblocks as a percent of total ++ * flash size. ++ */ ++#define DEFAULT_JNL_PERCENT 5 ++ ++/* Default maximum journal size in bytes */ ++#define DEFAULT_MAX_JNL (32*1024*1024) ++ ++/* Default indexing tree fanout */ ++#define DEFAULT_FANOUT 8 ++ ++/* Default number of LEBs for orphan information */ ++#ifdef CONFIG_UBIFS_FS_DEBUG ++#define DEFAULT_ORPHAN_LEBS 2 /* 2 is better for testing */ ++#else ++#define DEFAULT_ORPHAN_LEBS 1 ++#endif ++ ++/* Default number of journal heads */ ++#define DEFAULT_JHEADS_CNT 1 ++ ++/* Default positions of different LEBs in the main area */ ++#define DEFAULT_IDX_LEB 0 ++#define DEFAULT_DATA_LEB 1 ++#define DEFAULT_GC_LEB 2 ++ ++/* Default number of LEB numbers in LPT's save table */ ++#define DEFAULT_LSAVE_CNT 256 ++ ++/* Default reserved pool size as a percent of maximum free space */ ++#define DEFAULT_RP_PERCENT 5 ++ ++/* The default maximum size of reserved pool in bytes */ ++#define DEFAULT_MAX_RP_SIZE (5*1024*1024) ++ ++/* Default UBIFS compressor */ ++#define DEFAULT_COMPRESSOR UBIFS_COMPR_LZO ++ ++/* Default time granularity in nanoseconds */ ++#define DEFAULT_TIME_GRAN 1000000000 ++ ++/** ++ * create_default_filesystem - format empty UBI volume. ++ * @c: UBIFS file-system description object ++ * ++ * This function creates default empty file-system. Returns zero in case of ++ * success and a negative error code in case of failure. ++ */ ++static int create_default_filesystem(struct ubifs_info *c) ++{ ++ struct ubifs_sb_node *sup; ++ struct ubifs_mst_node *mst; ++ struct ubifs_idx_node *idx; ++ struct ubifs_branch *br; ++ struct ubifs_ino_node *ino; ++ struct ubifs_cs_node *cs; ++ union ubifs_key key; ++ int err, tmp, jnl_lebs, log_lebs, max_buds, main_lebs, main_first; ++ int lpt_lebs, lpt_first, orph_lebs, big_lpt, ino_waste, sup_flags = 0; ++ uint64_t tmp64, main_bytes; ++ ++ /* Some functions called from here depend on the @c->key_len filed */ ++ c->key_len = UBIFS_SK_LEN; ++ ++ /* ++ * First of all, we have to calculate default file-system geometry - ++ * log size, journal size, etc. ++ */ ++ c->max_leb_cnt = c->leb_cnt; ++ if (c->leb_cnt < 0x7FFFFFFF / DEFAULT_JNL_PERCENT) ++ /* We can first multiply then divide and have no overflow */ ++ jnl_lebs = c->leb_cnt * DEFAULT_JNL_PERCENT / 100; ++ else ++ jnl_lebs = (c->leb_cnt / 100) * DEFAULT_JNL_PERCENT; ++ ++ if (jnl_lebs < UBIFS_MIN_JNL_LEBS) ++ jnl_lebs = UBIFS_MIN_JNL_LEBS; ++ if (jnl_lebs * c->leb_size > DEFAULT_MAX_JNL) ++ jnl_lebs = DEFAULT_MAX_JNL / c->leb_size; ++ ++ /* ++ * The log should be large enough to fit reference nodes for all bud ++ * LEBs. Because buds do not have to start from the beginning of LEBs ++ * (half of the LEB may contain committed data), the log should ++ * generally be larger, make it twice as large. ++ */ ++ tmp = 2 * (c->ref_node_alsz * jnl_lebs) + c->leb_size - 1; ++ log_lebs = tmp / c->leb_size; ++ /* Plus one LEB reserved for commit */ ++ log_lebs += 1; ++ /* And some extra space to allow writes while committing */ ++ log_lebs += 1; ++ ++ max_buds = jnl_lebs - log_lebs; ++ if (max_buds < UBIFS_MIN_BUD_LEBS) ++ max_buds = UBIFS_MIN_BUD_LEBS; ++ ++ /* ++ * Orphan nodes are stored in a separate area. One node can store a lot ++ * of orphan inode numbers, but when new orphan comes we just add a new ++ * orphan node. At some point the nodes are consolidated into one ++ * orphan node. ++ */ ++ orph_lebs = DEFAULT_ORPHAN_LEBS; ++ ++ main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS - log_lebs; ++ main_lebs -= orph_lebs; ++ ++ lpt_first = UBIFS_LOG_LNUM + log_lebs; ++ c->lsave_cnt = DEFAULT_LSAVE_CNT; ++ err = ubifs_create_dflt_lpt(c, &main_lebs, lpt_first, &lpt_lebs, ++ &big_lpt); ++ if (err) ++ return err; ++ ++ dbg_gen("LEB Properties Tree created (LEBs %d-%d)", lpt_first, ++ lpt_first + lpt_lebs - 1); ++ ++ main_first = c->leb_cnt - main_lebs; ++ ++ /* Create default superblock */ ++ tmp = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size); ++ sup = kzalloc(tmp, GFP_KERNEL); ++ if (!sup) ++ return -ENOMEM; ++ ++ tmp64 = (uint64_t)max_buds * c->leb_size; ++ if (big_lpt) ++ sup_flags |= UBIFS_FLG_BIGLPT; ++ ++ sup->ch.node_type = UBIFS_SB_NODE; ++ sup->key_hash = UBIFS_KEY_HASH_R5; ++ sup->flags = cpu_to_le32(sup_flags); ++ sup->min_io_size = cpu_to_le32(c->min_io_size); ++ sup->leb_size = cpu_to_le32(c->leb_size); ++ sup->leb_cnt = cpu_to_le32(c->leb_cnt); ++ sup->max_leb_cnt = cpu_to_le32(c->max_leb_cnt); ++ sup->max_bud_bytes = cpu_to_le64(tmp64); ++ sup->log_lebs = cpu_to_le32(log_lebs); ++ sup->lpt_lebs = cpu_to_le32(lpt_lebs); ++ sup->orph_lebs = cpu_to_le32(orph_lebs); ++ sup->jhead_cnt = cpu_to_le32(DEFAULT_JHEADS_CNT); ++ sup->fanout = cpu_to_le32(DEFAULT_FANOUT); ++ sup->lsave_cnt = cpu_to_le32(c->lsave_cnt); ++ sup->fmt_version = cpu_to_le32(UBIFS_FORMAT_VERSION); ++ sup->default_compr = cpu_to_le16(DEFAULT_COMPRESSOR); ++ sup->time_gran = cpu_to_le32(DEFAULT_TIME_GRAN); ++ ++ generate_random_uuid(sup->uuid); ++ ++ main_bytes = (uint64_t)main_lebs * c->leb_size; ++ tmp64 = main_bytes * DEFAULT_RP_PERCENT; ++ do_div(tmp64, 100); ++ if (tmp64 > DEFAULT_MAX_RP_SIZE) ++ tmp64 = DEFAULT_MAX_RP_SIZE; ++ sup->rp_size = cpu_to_le64(tmp64); ++ ++ err = ubifs_write_node(c, sup, UBIFS_SB_NODE_SZ, 0, 0, UBI_LONGTERM); ++ kfree(sup); ++ if (err) ++ return err; ++ ++ dbg_gen("default superblock created at LEB 0:0"); ++ ++ /* Create default master node */ ++ mst = kzalloc(c->mst_node_alsz, GFP_KERNEL); ++ if (!mst) ++ return -ENOMEM; ++ ++ mst->ch.node_type = UBIFS_MST_NODE; ++ mst->log_lnum = cpu_to_le32(UBIFS_LOG_LNUM); ++ mst->highest_inum = cpu_to_le64(UBIFS_FIRST_INO); ++ mst->cmt_no = 0; ++ mst->root_lnum = cpu_to_le32(main_first + DEFAULT_IDX_LEB); ++ mst->root_offs = 0; ++ tmp = ubifs_idx_node_sz(c, 1); ++ mst->root_len = cpu_to_le32(tmp); ++ mst->gc_lnum = cpu_to_le32(main_first + DEFAULT_GC_LEB); ++ mst->ihead_lnum = cpu_to_le32(main_first + DEFAULT_IDX_LEB); ++ mst->ihead_offs = cpu_to_le32(ALIGN(tmp, c->min_io_size)); ++ mst->index_size = cpu_to_le64(ALIGN(tmp, 8)); ++ mst->lpt_lnum = cpu_to_le32(c->lpt_lnum); ++ mst->lpt_offs = cpu_to_le32(c->lpt_offs); ++ mst->nhead_lnum = cpu_to_le32(c->nhead_lnum); ++ mst->nhead_offs = cpu_to_le32(c->nhead_offs); ++ mst->ltab_lnum = cpu_to_le32(c->ltab_lnum); ++ mst->ltab_offs = cpu_to_le32(c->ltab_offs); ++ mst->lsave_lnum = cpu_to_le32(c->lsave_lnum); ++ mst->lsave_offs = cpu_to_le32(c->lsave_offs); ++ mst->lscan_lnum = cpu_to_le32(main_first); ++ mst->empty_lebs = cpu_to_le32(main_lebs - 2); ++ mst->idx_lebs = cpu_to_le32(1); ++ mst->leb_cnt = cpu_to_le32(c->leb_cnt); ++ ++ /* Calculate lprops statistics */ ++ tmp64 = main_bytes; ++ tmp64 -= ALIGN(ubifs_idx_node_sz(c, 1), c->min_io_size); ++ tmp64 -= ALIGN(UBIFS_INO_NODE_SZ, c->min_io_size); ++ mst->total_free = cpu_to_le64(tmp64); ++ ++ tmp64 = ALIGN(ubifs_idx_node_sz(c, 1), c->min_io_size); ++ ino_waste = ALIGN(UBIFS_INO_NODE_SZ, c->min_io_size) - ++ UBIFS_INO_NODE_SZ; ++ tmp64 += ino_waste; ++ tmp64 -= ALIGN(ubifs_idx_node_sz(c, 1), 8); ++ mst->total_dirty = cpu_to_le64(tmp64); ++ ++ /* The indexing LEB does not contribute to dark space */ ++ tmp64 = (c->main_lebs - 1) * c->dark_wm; ++ mst->total_dark = cpu_to_le64(tmp64); ++ ++ mst->total_used = cpu_to_le64(UBIFS_INO_NODE_SZ); ++ ++ err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM, 0, ++ UBI_UNKNOWN); ++ if (err) { ++ kfree(mst); ++ return err; ++ } ++ err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM + 1, 0, ++ UBI_UNKNOWN); ++ kfree(mst); ++ if (err) ++ return err; ++ ++ dbg_gen("default master node created at LEB %d:0", UBIFS_MST_LNUM); ++ ++ /* Create the root indexing node */ ++ tmp = ubifs_idx_node_sz(c, 1); ++ idx = kzalloc(ALIGN(tmp, c->min_io_size), GFP_KERNEL); ++ if (!idx) ++ return -ENOMEM; ++ ++ c->key_fmt = UBIFS_SIMPLE_KEY_FMT; ++ c->key_hash = key_r5_hash; ++ ++ idx->ch.node_type = UBIFS_IDX_NODE; ++ idx->child_cnt = cpu_to_le16(1); ++ ino_key_init(c, &key, UBIFS_ROOT_INO); ++ br = ubifs_idx_branch(c, idx, 0); ++ key_write_idx(c, &key, &br->key); ++ br->lnum = cpu_to_le32(main_first + DEFAULT_DATA_LEB); ++ br->len = cpu_to_le32(UBIFS_INO_NODE_SZ); ++ err = ubifs_write_node(c, idx, tmp, main_first + DEFAULT_IDX_LEB, 0, ++ UBI_UNKNOWN); ++ kfree(idx); ++ if (err) ++ return err; ++ ++ dbg_gen("default root indexing node created LEB %d:0", ++ main_first + DEFAULT_IDX_LEB); ++ ++ /* Create default root inode */ ++ tmp = ALIGN(UBIFS_INO_NODE_SZ, c->min_io_size); ++ ino = kzalloc(tmp, GFP_KERNEL); ++ if (!ino) ++ return -ENOMEM; ++ ++ ino_key_init_flash(c, &ino->key, UBIFS_ROOT_INO); ++ ino->ch.node_type = UBIFS_INO_NODE; ++ ino->creat_sqnum = cpu_to_le64(++c->max_sqnum); ++ ino->nlink = cpu_to_le32(2); ++ tmp = cpu_to_le64(CURRENT_TIME_SEC.tv_sec); ++ ino->atime_sec = tmp; ++ ino->ctime_sec = tmp; ++ ino->mtime_sec = tmp; ++ ino->atime_nsec = 0; ++ ino->ctime_nsec = 0; ++ ino->mtime_nsec = 0; ++ ino->mode = cpu_to_le32(S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO); ++ ino->size = cpu_to_le64(UBIFS_INO_NODE_SZ); ++ ++ /* Set compression enabled by default */ ++ ino->flags = cpu_to_le32(UBIFS_COMPR_FL); ++ ++ err = ubifs_write_node(c, ino, UBIFS_INO_NODE_SZ, ++ main_first + DEFAULT_DATA_LEB, 0, ++ UBI_UNKNOWN); ++ kfree(ino); ++ if (err) ++ return err; ++ ++ dbg_gen("root inode created at LEB %d:0", ++ main_first + DEFAULT_DATA_LEB); ++ ++ /* ++ * The first node in the log has to be the commit start node. This is ++ * always the case during normal file-system operation. Write a fake ++ * commit start node to the log. ++ */ ++ tmp = ALIGN(UBIFS_CS_NODE_SZ, c->min_io_size); ++ cs = kzalloc(tmp, GFP_KERNEL); ++ if (!cs) ++ return -ENOMEM; ++ ++ cs->ch.node_type = UBIFS_CS_NODE; ++ err = ubifs_write_node(c, cs, UBIFS_CS_NODE_SZ, UBIFS_LOG_LNUM, ++ 0, UBI_UNKNOWN); ++ kfree(cs); ++ ++ ubifs_msg("default file-system created"); ++ return 0; ++} ++ ++/** ++ * validate_sb - validate superblock node. ++ * @c: UBIFS file-system description object ++ * @sup: superblock node ++ * ++ * This function validates superblock node @sup. Since most of data was read ++ * from the superblock and stored in @c, the function validates fields in @c ++ * instead. Returns zero in case of success and %-EINVAL in case of validation ++ * failure. ++ */ ++static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup) ++{ ++ long long max_bytes; ++ int err = 1; ++ ++ if (!c->key_hash) { ++ err = 2; ++ goto failed; ++ } ++ ++ if (sup->key_fmt != UBIFS_SIMPLE_KEY_FMT) { ++ err = 3; ++ goto failed; ++ } ++ ++ if (le32_to_cpu(sup->min_io_size) != c->min_io_size) { ++ ubifs_err("min. I/O unit mismatch: %d in superblock, %d real", ++ le32_to_cpu(sup->min_io_size), c->min_io_size); ++ goto failed; ++ } ++ ++ if (le32_to_cpu(sup->leb_size) != c->leb_size) { ++ ubifs_err("LEB size mismatch: %d in superblock, %d real", ++ le32_to_cpu(sup->leb_size), c->leb_size); ++ goto failed; ++ } ++ ++ if (c->leb_cnt < UBIFS_MIN_LEB_CNT || c->leb_cnt > c->vi.size) { ++ ubifs_err("bad LEB count: %d in superblock, %d on UBI volume, " ++ "%d minimum required", c->leb_cnt, c->vi.size, ++ UBIFS_MIN_LEB_CNT); ++ goto failed; ++ } ++ ++ if (c->max_leb_cnt < c->leb_cnt) { ++ ubifs_err("max. LEB count %d less than LEB count %d", ++ c->max_leb_cnt, c->leb_cnt); ++ goto failed; ++ } ++ ++ if (c->log_lebs < UBIFS_MIN_LOG_LEBS || ++ c->lpt_lebs < UBIFS_MIN_LPT_LEBS || ++ c->orph_lebs < UBIFS_MIN_ORPH_LEBS || ++ c->main_lebs < UBIFS_MIN_MAIN_LEBS) { ++ err = 6; ++ goto failed; ++ } ++ ++ if (c->main_lebs < UBIFS_MIN_MAIN_LEBS) { ++ err = 7; ++ goto failed; ++ } ++ ++ if (c->max_bud_bytes < (long long)c->leb_size * UBIFS_MIN_BUD_LEBS || ++ c->max_bud_bytes > (long long)c->leb_size * c->main_lebs) { ++ err = 8; ++ goto failed; ++ } ++ ++ if (c->jhead_cnt < NONDATA_JHEADS_CNT + 1 || ++ c->jhead_cnt > NONDATA_JHEADS_CNT + UBIFS_MAX_JHEADS) { ++ err = 9; ++ goto failed; ++ } ++ ++ if (c->fanout < UBIFS_MIN_FANOUT || ++ ubifs_idx_node_sz(c, c->fanout) > c->leb_size) { ++ err = 10; ++ goto failed; ++ } ++ ++ if (c->lsave_cnt < 0 || (c->lsave_cnt > DEFAULT_LSAVE_CNT && ++ c->lsave_cnt > c->max_leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS - ++ c->log_lebs - c->lpt_lebs - c->orph_lebs)) { ++ err = 11; ++ goto failed; ++ } ++ ++ if (UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs + c->lpt_lebs + ++ c->orph_lebs + c->main_lebs != c->leb_cnt) { ++ err = 12; ++ goto failed; ++ } ++ ++ if (c->default_compr < 0 || c->default_compr >= UBIFS_COMPR_TYPES_CNT) { ++ err = 13; ++ goto failed; ++ } ++ ++ max_bytes = c->main_lebs * (long long)c->leb_size; ++ if (c->rp_size < 0 || max_bytes < c->rp_size) { ++ err = 14; ++ goto failed; ++ } ++ ++ if (le32_to_cpu(sup->time_gran) > 1000000000 || ++ le32_to_cpu(sup->time_gran) < 1) { ++ err = 15; ++ goto failed; ++ } ++ ++ return 0; ++ ++failed: ++ ubifs_err("bad superblock, error %d", err); ++ dbg_dump_node(c, sup); ++ return -EINVAL; ++} ++ ++/** ++ * ubifs_read_sb_node - read superblock node. ++ * @c: UBIFS file-system description object ++ * ++ * This function returns a pointer to the superblock node or a negative error ++ * code. ++ */ ++struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c) ++{ ++ struct ubifs_sb_node *sup; ++ int err; ++ ++ sup = kmalloc(ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size), GFP_NOFS); ++ if (!sup) ++ return ERR_PTR(-ENOMEM); ++ ++ err = ubifs_read_node(c, sup, UBIFS_SB_NODE, UBIFS_SB_NODE_SZ, ++ UBIFS_SB_LNUM, 0); ++ if (err) { ++ kfree(sup); ++ return ERR_PTR(err); ++ } ++ ++ return sup; ++} ++ ++/** ++ * ubifs_write_sb_node - write superblock node. ++ * @c: UBIFS file-system description object ++ * @sup: superblock node read with 'ubifs_read_sb_node()' ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup) ++{ ++ int len = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size); ++ ++ ubifs_prepare_node(c, sup, UBIFS_SB_NODE_SZ, 1); ++ return ubi_leb_change(c->ubi, UBIFS_SB_LNUM, sup, len, UBI_LONGTERM); ++} ++ ++/** ++ * ubifs_read_superblock - read superblock. ++ * @c: UBIFS file-system description object ++ * ++ * This function finds, reads and checks the superblock. If an empty UBI volume ++ * is being mounted, this function creates default superblock. Returns zero in ++ * case of success, and a negative error code in case of failure. ++ */ ++int ubifs_read_superblock(struct ubifs_info *c) ++{ ++ int err, sup_flags; ++ struct ubifs_sb_node *sup; ++ ++ if (c->empty) { ++ err = create_default_filesystem(c); ++ if (err) ++ return err; ++ } ++ ++ sup = ubifs_read_sb_node(c); ++ if (IS_ERR(sup)) ++ return PTR_ERR(sup); ++ ++ /* ++ * The software supports all previous versions but not future versions, ++ * due to the unavailability of time-travelling equipment. ++ */ ++ c->fmt_version = le32_to_cpu(sup->fmt_version); ++ if (c->fmt_version > UBIFS_FORMAT_VERSION) { ++ ubifs_err("on-flash format version is %d, but software only " ++ "supports up to version %d", c->fmt_version, ++ UBIFS_FORMAT_VERSION); ++ err = -EINVAL; ++ goto out; ++ } ++ ++ if (c->fmt_version < 3) { ++ ubifs_err("on-flash format version %d is not supported", ++ c->fmt_version); ++ err = -EINVAL; ++ goto out; ++ } ++ ++ switch (sup->key_hash) { ++ case UBIFS_KEY_HASH_R5: ++ c->key_hash = key_r5_hash; ++ c->key_hash_type = UBIFS_KEY_HASH_R5; ++ break; ++ ++ case UBIFS_KEY_HASH_TEST: ++ c->key_hash = key_test_hash; ++ c->key_hash_type = UBIFS_KEY_HASH_TEST; ++ break; ++ }; ++ ++ c->key_fmt = sup->key_fmt; ++ ++ switch (c->key_fmt) { ++ case UBIFS_SIMPLE_KEY_FMT: ++ c->key_len = UBIFS_SK_LEN; ++ break; ++ default: ++ ubifs_err("unsupported key format"); ++ err = -EINVAL; ++ goto out; ++ } ++ ++ c->leb_cnt = le32_to_cpu(sup->leb_cnt); ++ c->max_leb_cnt = le32_to_cpu(sup->max_leb_cnt); ++ c->max_bud_bytes = le64_to_cpu(sup->max_bud_bytes); ++ c->log_lebs = le32_to_cpu(sup->log_lebs); ++ c->lpt_lebs = le32_to_cpu(sup->lpt_lebs); ++ c->orph_lebs = le32_to_cpu(sup->orph_lebs); ++ c->jhead_cnt = le32_to_cpu(sup->jhead_cnt) + NONDATA_JHEADS_CNT; ++ c->fanout = le32_to_cpu(sup->fanout); ++ c->lsave_cnt = le32_to_cpu(sup->lsave_cnt); ++ c->default_compr = le16_to_cpu(sup->default_compr); ++ c->rp_size = le64_to_cpu(sup->rp_size); ++ c->rp_uid = le32_to_cpu(sup->rp_uid); ++ c->rp_gid = le32_to_cpu(sup->rp_gid); ++ sup_flags = le32_to_cpu(sup->flags); ++ ++ c->vfs_sb->s_time_gran = le32_to_cpu(sup->time_gran); ++ ++ memcpy(&c->uuid, &sup->uuid, 16); ++ ++ c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT); ++ ++ /* Automatically increase file system size to the maximum size */ ++ c->old_leb_cnt = c->leb_cnt; ++ if (c->leb_cnt < c->vi.size && c->leb_cnt < c->max_leb_cnt) { ++ c->leb_cnt = min_t(int, c->max_leb_cnt, c->vi.size); ++ if (c->vfs_sb->s_flags & MS_RDONLY) ++ dbg_mnt("Auto resizing (ro) from %d LEBs to %d LEBs", ++ c->old_leb_cnt, c->leb_cnt); ++ else { ++ dbg_mnt("Auto resizing (sb) from %d LEBs to %d LEBs", ++ c->old_leb_cnt, c->leb_cnt); ++ sup->leb_cnt = cpu_to_le32(c->leb_cnt); ++ err = ubifs_write_sb_node(c, sup); ++ if (err) ++ goto out; ++ c->old_leb_cnt = c->leb_cnt; ++ } ++ } ++ ++ c->log_bytes = (long long)c->log_lebs * c->leb_size; ++ c->log_last = UBIFS_LOG_LNUM + c->log_lebs - 1; ++ c->lpt_first = UBIFS_LOG_LNUM + c->log_lebs; ++ c->lpt_last = c->lpt_first + c->lpt_lebs - 1; ++ c->orph_first = c->lpt_last + 1; ++ c->orph_last = c->orph_first + c->orph_lebs - 1; ++ c->main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS; ++ c->main_lebs -= c->log_lebs + c->lpt_lebs + c->orph_lebs; ++ c->main_first = c->leb_cnt - c->main_lebs; ++ c->report_rp_size = ubifs_reported_space(c, c->rp_size); ++ ++ err = validate_sb(c, sup); ++out: ++ kfree(sup); ++ return err; ++} +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/scan.c avr32-2.6/fs/ubifs/scan.c +--- linux-2.6.25.6/fs/ubifs/scan.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/scan.c 2008-06-12 15:09:45.515816461 +0200 +@@ -0,0 +1,362 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Adrian Hunter ++ * Artem Bityutskiy (Битюцкий Артём) ++ */ ++ ++/* ++ * This file implements the scan which is a general-purpose function for ++ * determining what nodes are in an eraseblock. The scan is used to replay the ++ * journal, to do garbage collection. for the TNC in-the-gaps method, and by ++ * debugging functions. ++ */ ++ ++#include "ubifs.h" ++ ++/** ++ * scan_padding_bytes - scan for padding bytes. ++ * @buf: buffer to scan ++ * @len: length of buffer ++ * ++ * This function returns the number of padding bytes on success and ++ * %SCANNED_GARBAGE on failure. ++ */ ++static int scan_padding_bytes(void *buf, int len) ++{ ++ int pad_len = 0, max_pad_len = min_t(int, UBIFS_PAD_NODE_SZ, len); ++ uint8_t *p = buf; ++ ++ dbg_scan("not a node"); ++ ++ while (pad_len < max_pad_len && *p++ == UBIFS_PADDING_BYTE) ++ pad_len += 1; ++ ++ if (!pad_len || (pad_len & 7)) ++ return SCANNED_GARBAGE; ++ ++ dbg_scan("%d padding bytes", pad_len); ++ ++ return pad_len; ++} ++ ++/** ++ * ubifs_scan_a_node - scan for a node or padding. ++ * @c: UBIFS file-system description object ++ * @buf: buffer to scan ++ * @len: length of buffer ++ * @lnum: logical eraseblock number ++ * @offs: offset within the logical eraseblock ++ * @quiet: print no messages ++ * ++ * This function returns a scanning code to indicate what was scanned. ++ */ ++int ubifs_scan_a_node(const struct ubifs_info *c, void *buf, int len, int lnum, ++ int offs, int quiet) ++{ ++ struct ubifs_ch *ch = buf; ++ uint32_t magic; ++ ++ magic = le32_to_cpu(ch->magic); ++ ++ if (magic == 0xFFFFFFFF) { ++ dbg_scan("hit empty space"); ++ return SCANNED_EMPTY_SPACE; ++ } ++ ++ if (magic != UBIFS_NODE_MAGIC) ++ return scan_padding_bytes(buf, len); ++ ++ if (len < UBIFS_CH_SZ) ++ return SCANNED_GARBAGE; ++ ++ dbg_scan("scanning %s", dbg_ntype(ch->node_type)); ++ ++ if (ubifs_check_node(c, buf, lnum, offs, quiet)) ++ return SCANNED_A_CORRUPT_NODE; ++ ++ if (ch->node_type == UBIFS_PAD_NODE) { ++ struct ubifs_pad_node *pad = buf; ++ int pad_len = le32_to_cpu(pad->pad_len); ++ int node_len = le32_to_cpu(ch->len); ++ ++ /* Validate the padding node */ ++ if (pad_len < 0 || ++ offs + node_len + pad_len > c->leb_size) { ++ if (!quiet) { ++ ubifs_err("bad pad node at LEB %d:%d", ++ lnum, offs); ++ dbg_dump_node(c, pad); ++ } ++ return SCANNED_A_BAD_PAD_NODE; ++ } ++ ++ /* Make the node pads to 8-byte boundary */ ++ if ((node_len + pad_len) & 7) { ++ if (!quiet) { ++ dbg_err("bad padding length %d - %d", ++ offs, offs + node_len + pad_len); ++ } ++ return SCANNED_A_BAD_PAD_NODE; ++ } ++ ++ dbg_scan("%d bytes padded, offset now %d", ++ pad_len, ALIGN(offs + node_len + pad_len, 8)); ++ ++ return node_len + pad_len; ++ } ++ ++ return SCANNED_A_NODE; ++} ++ ++/** ++ * ubifs_start_scan - create LEB scanning information at start of scan. ++ * @c: UBIFS file-system description object ++ * @lnum: logical eraseblock number ++ * @offs: offset to start at (usually zero) ++ * @sbuf: scan buffer (must be c->leb_size) ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum, ++ int offs, void *sbuf) ++{ ++ struct ubifs_scan_leb *sleb; ++ int err; ++ ++ dbg_scan("scan LEB %d:%d", lnum, offs); ++ ++ sleb = kzalloc(sizeof(struct ubifs_scan_leb), GFP_NOFS); ++ if (!sleb) ++ return ERR_PTR(-ENOMEM); ++ ++ sleb->lnum = lnum; ++ INIT_LIST_HEAD(&sleb->nodes); ++ sleb->buf = sbuf; ++ ++ err = ubi_read(c->ubi, lnum, sbuf + offs, offs, c->leb_size - offs); ++ if (err && err != -EBADMSG) { ++ ubifs_err("cannot read %d bytes from LEB %d:%d," ++ " error %d", c->leb_size - offs, lnum, offs, err); ++ kfree(sleb); ++ return ERR_PTR(err); ++ } ++ ++ if (err == -EBADMSG) ++ sleb->ecc = 1; ++ ++ return sleb; ++} ++ ++/** ++ * ubifs_end_scan - update LEB scanning information at end of scan. ++ * @c: UBIFS file-system description object ++ * @sleb: scanning information ++ * @lnum: logical eraseblock number ++ * @offs: offset to start at (usually zero) ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++void ubifs_end_scan(const struct ubifs_info *c, struct ubifs_scan_leb *sleb, ++ int lnum, int offs) ++{ ++ lnum = lnum; ++ dbg_scan("stop scanning LEB %d at offset %d", lnum, offs); ++ ubifs_assert(offs % c->min_io_size == 0); ++ ++ sleb->endpt = ALIGN(offs, c->min_io_size); ++} ++ ++/** ++ * ubifs_add_snod - add a scanned node to LEB scanning information. ++ * @c: UBIFS file-system description object ++ * @sleb: scanning information ++ * @buf: buffer containing node ++ * @offs: offset of node on flash ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb, ++ void *buf, int offs) ++{ ++ struct ubifs_ch *ch = buf; ++ struct ubifs_ino_node *ino = buf; ++ struct ubifs_scan_node *snod; ++ ++ snod = kzalloc(sizeof(struct ubifs_scan_node), GFP_NOFS); ++ if (!snod) ++ return -ENOMEM; ++ ++ snod->sqnum = le64_to_cpu(ch->sqnum); ++ snod->type = ch->node_type; ++ snod->offs = offs; ++ snod->len = le32_to_cpu(ch->len); ++ snod->node = buf; ++ ++ switch (ch->node_type) { ++ case UBIFS_INO_NODE: ++ case UBIFS_DENT_NODE: ++ case UBIFS_XENT_NODE: ++ case UBIFS_DATA_NODE: ++ case UBIFS_TRUN_NODE: ++ /* ++ * The key is in the same place in all keyed ++ * nodes. ++ */ ++ key_read(c, &ino->key, &snod->key); ++ break; ++ } ++ list_add_tail(&snod->list, &sleb->nodes); ++ sleb->nodes_cnt += 1; ++ return 0; ++} ++ ++/** ++ * ubifs_scanned_corruption - print information after UBIFS scanned corruption. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number of corruption ++ * @offs: offset of corruption ++ * @buf: buffer containing corruption ++ */ ++void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs, ++ void *buf) ++{ ++ int len; ++ ++ ubifs_err("corrupted data at LEB %d:%d", lnum, offs); ++ if (dbg_failure_mode) ++ return; ++ len = c->leb_size - offs; ++ if (len > 4096) ++ len = 4096; ++ dbg_err("first %d bytes from LEB %d:%d", len, lnum, offs); ++ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 4, buf, len, 1); ++} ++ ++/** ++ * ubifs_scan - scan a logical eraseblock. ++ * @c: UBIFS file-system description object ++ * @lnum: logical eraseblock number ++ * @offs: offset to start at (usually zero) ++ * @sbuf: scan buffer (must be c->leb_size) ++ * ++ * This function scans LEB number @lnum and returns complete information about ++ * its contents. Returns an error code in case of failure. ++ */ ++struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum, ++ int offs, void *sbuf) ++{ ++ void *buf = sbuf + offs; ++ int err, len = c->leb_size - offs; ++ struct ubifs_scan_leb *sleb; ++ ++ sleb = ubifs_start_scan(c, lnum, offs, sbuf); ++ if (IS_ERR(sleb)) ++ return sleb; ++ ++ while (len >= 8) { ++ struct ubifs_ch *ch = buf; ++ int node_len, ret; ++ ++ dbg_scan("look at LEB %d:%d (%d bytes left)", ++ lnum, offs, len); ++ ++ cond_resched(); ++ ++ ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 0); ++ ++ if (ret > 0) { ++ /* Padding bytes or a valid padding node */ ++ offs += ret; ++ buf += ret; ++ len -= ret; ++ continue; ++ } ++ ++ if (ret == SCANNED_EMPTY_SPACE) ++ /* Empty space is checked later */ ++ break; ++ ++ switch (ret) { ++ case SCANNED_GARBAGE: ++ dbg_err("garbage"); ++ goto corrupted; ++ case SCANNED_A_NODE: ++ break; ++ case SCANNED_A_CORRUPT_NODE: ++ case SCANNED_A_BAD_PAD_NODE: ++ dbg_err("bad node"); ++ goto corrupted; ++ default: ++ dbg_err("unknown"); ++ goto corrupted; ++ } ++ ++ err = ubifs_add_snod(c, sleb, buf, offs); ++ if (err) ++ goto error; ++ ++ node_len = ALIGN(le32_to_cpu(ch->len), 8); ++ offs += node_len; ++ buf += node_len; ++ len -= node_len; ++ } ++ ++ if (offs % c->min_io_size) ++ goto corrupted; ++ ++ ubifs_end_scan(c, sleb, lnum, offs); ++ ++ for (; len > 4; offs += 4, buf = buf + 4, len -= 4) ++ if (*(uint32_t *)buf != 0xffffffff) ++ break; ++ for (; len; offs++, buf++, len--) ++ if (*(uint8_t *)buf != 0xff) { ++ ubifs_err("corrupt empty space at LEB %d:%d", ++ lnum, offs); ++ goto corrupted; ++ } ++ ++ return sleb; ++ ++corrupted: ++ ubifs_scanned_corruption(c, lnum, offs, buf); ++ err = -EUCLEAN; ++error: ++ ubifs_err("LEB %d scanning failed", lnum); ++ ubifs_scan_destroy(sleb); ++ return ERR_PTR(err); ++} ++ ++/** ++ * ubifs_scan_destroy - destroy LEB scanning information. ++ * @sleb: scanning information to free ++ */ ++void ubifs_scan_destroy(struct ubifs_scan_leb *sleb) ++{ ++ struct ubifs_scan_node *node; ++ struct list_head *head; ++ ++ head = &sleb->nodes; ++ while (!list_empty(head)) { ++ node = list_entry(head->next, struct ubifs_scan_node, list); ++ list_del(&node->list); ++ kfree(node); ++ } ++ kfree(sleb); ++} +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/shrinker.c avr32-2.6/fs/ubifs/shrinker.c +--- linux-2.6.25.6/fs/ubifs/shrinker.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/shrinker.c 2008-06-12 15:09:45.515816461 +0200 +@@ -0,0 +1,322 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Artem Bityutskiy (Битюцкий Артём) ++ * Adrian Hunter ++ */ ++ ++/* ++ * This file implements UBIFS shrinker which evicts clean znodes from the TNC ++ * tree when Linux VM needs more RAM. ++ * ++ * We do not implement any LRU lists to find oldest znodes to free because it ++ * would add additional overhead to the file system fast paths. So the shrinker ++ * just walks the TNC tree when searching for znodes to free. ++ * ++ * If the root of a TNC sub-tree is clean and old enough, then the children are ++ * also clean and old enough. So the shrinker walks the TNC in level order and ++ * dumps entire sub-trees. ++ * ++ * The age of znodes is just the time-stamp when they were last looked at. ++ * The current shrinker first tries to evict old znodes, then young ones. ++ * ++ * Since the shrinker is global, it has to protect against races with FS ++ * un-mounts, which is done by the 'ubifs_infos_lock' and 'c->umount_mutex'. ++ */ ++ ++#include "ubifs.h" ++ ++/* List of all UBIFS file-system instances */ ++LIST_HEAD(ubifs_infos); ++ ++/* ++ * We number each shrinker run and record the number on the ubifs_info structure ++ * so that we can easily work out which ubifs_info structures have already been ++ * done by the current run. ++ */ ++static unsigned int shrinker_run_no; ++ ++/* Protects 'ubifs_infos' list */ ++DEFINE_SPINLOCK(ubifs_infos_lock); ++ ++/* Global clean znode counter (for all mounted UBIFS instances) */ ++atomic_long_t ubifs_clean_zn_cnt; ++ ++/** ++ * shrink_tnc - shrink TNC tree. ++ * @c: UBIFS file-system description object ++ * @nr: number of znodes to free ++ * @age: the age of znodes to free ++ * @contention: if any contention, this is set to %1 ++ * ++ * This function traverses TNC tree and frees clean znodes. It does not free ++ * clean znodes which younger then @age. Returns number of freed znodes. ++ */ ++static int shrink_tnc(struct ubifs_info *c, int nr, int age, int *contention) ++{ ++ int total_freed = 0; ++ struct ubifs_znode *znode, *zprev; ++ int time = get_seconds(); ++ ++ ubifs_assert(mutex_is_locked(&c->umount_mutex)); ++ ubifs_assert(mutex_is_locked(&c->tnc_mutex)); ++ ++ if (!c->zroot.znode || atomic_long_read(&c->clean_zn_cnt) == 0) ++ return 0; ++ ++ /* ++ * Traverse the TNC tree in levelorder manner, so that it is possible ++ * to destroy large sub-trees. Indeed, if a znode is old, then all its ++ * children are older or of the same age. ++ * ++ * Note, we are holding 'c->tnc_mutex', so we do not have to lock the ++ * 'c->space_lock' when _reading_ 'c->clean_zn_cnt', because it is ++ * changed only when the 'c->tnc_mutex' is held. ++ */ ++ zprev = NULL; ++ znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL); ++ while (znode && total_freed < nr && ++ atomic_long_read(&c->clean_zn_cnt) > 0) { ++ int freed; ++ ++ /* ++ * If the znode is clean, but it is in the 'c->cnext' list, this ++ * means that this znode has just been written to flash as a ++ * part of commit and was marked clean. They will be removed ++ * from the list at end commit. We cannot change the list, ++ * because it is not protected by any mutex (design decision to ++ * make commit really independent and parallel to main I/O). So ++ * we just skip these znodes. ++ * ++ * Note, the 'clean_zn_cnt' counters are not updated until ++ * after the commit, so the UBIFS shrinker does not report ++ * the znodes which are in the 'c->cnext' list as freeable. ++ * ++ * Also note, if the root of a sub-tree is not in 'c->cnext', ++ * then the whole sub-tree is not in 'c->cnext' as well, so it ++ * is safe to dump whole sub-tree. ++ */ ++ ++ if (znode->cnext) { ++ /* ++ * Very soon these znodes will be removed from the list ++ * and become freeable. ++ */ ++ *contention = 1; ++ } else if (!ubifs_zn_dirty(znode) && ++ abs(time - znode->time) >= age) { ++ if (znode->parent) ++ znode->parent->zbranch[znode->iip].znode = NULL; ++ else ++ c->zroot.znode = NULL; ++ ++ freed = ubifs_destroy_tnc_subtree(znode); ++ atomic_long_sub(freed, &ubifs_clean_zn_cnt); ++ atomic_long_sub(freed, &c->clean_zn_cnt); ++ ubifs_assert(atomic_long_read(&c->clean_zn_cnt) >= 0); ++ total_freed += freed; ++ znode = zprev; ++ } ++ ++ if (unlikely(!c->zroot.znode)) ++ break; ++ ++ zprev = znode; ++ znode = ubifs_tnc_levelorder_next(c->zroot.znode, znode); ++ cond_resched(); ++ } ++ ++ return total_freed; ++} ++ ++/** ++ * shrink_tnc_trees - shrink UBIFS TNC trees. ++ * @nr: number of znodes to free ++ * @age: the age of znodes to free ++ * @contention: if any contention, this is set to %1 ++ * ++ * This function walks the list of mounted UBIFS file-systems and frees clean ++ * znodes which are older then @age, until at least @nr znodes are freed. ++ * Returns the number of freed znodes. ++ */ ++static int shrink_tnc_trees(int nr, int age, int *contention) ++{ ++ struct ubifs_info *c; ++ struct list_head *p; ++ unsigned int run_no; ++ int freed = 0; ++ ++ spin_lock(&ubifs_infos_lock); ++ do ++ run_no = ++shrinker_run_no; ++ while (run_no == 0); ++ /* Iterate over all mounted UBIFS file-systems and try to shrink them */ ++ p = ubifs_infos.next; ++ while (p != &ubifs_infos) { ++ c = list_entry(p, struct ubifs_info, infos_list); ++ /* ++ * We move the ones we do to the end of the list, so we stop ++ * when we see one we have already done. ++ */ ++ if (c->shrinker_run_no == run_no) ++ break; ++ if (!mutex_trylock(&c->umount_mutex)) { ++ /* Some un-mount is in progress, try next FS */ ++ *contention = 1; ++ p = p->next; ++ continue; ++ } ++ /* ++ * We're holding 'c->umount_mutex', so the file-system won't go ++ * away. ++ */ ++ if (!mutex_trylock(&c->tnc_mutex)) { ++ mutex_unlock(&c->umount_mutex); ++ *contention = 1; ++ p = p->next; ++ continue; ++ } ++ spin_unlock(&ubifs_infos_lock); ++ /* ++ * OK, now we have TNC locked, the file-system cannot go away - ++ * it is safe to reap the cache. ++ */ ++ c->shrinker_run_no = run_no; ++ freed += shrink_tnc(c, nr, age, contention); ++ mutex_unlock(&c->tnc_mutex); ++ spin_lock(&ubifs_infos_lock); ++ /* Get the next list element before we move this one */ ++ p = p->next; ++ /* ++ * Move this one to the end of the list to provide some ++ * fairness. ++ */ ++ list_del(&c->infos_list); ++ list_add_tail(&c->infos_list, &ubifs_infos); ++ mutex_unlock(&c->umount_mutex); ++ if (freed >= nr) ++ break; ++ } ++ spin_unlock(&ubifs_infos_lock); ++ return freed; ++} ++ ++/** ++ * kick_a_thread - kick a background thread to start commit. ++ * ++ * This function kicks a background thread to start background commit. Returns ++ * %-1 if a thread was kicked or there is another reason to assume the memory ++ * will soon be freed or become freeable. If there are no dirty znodes, returns ++ * %0. ++ */ ++static int kick_a_thread(void) ++{ ++ int i; ++ struct ubifs_info *c; ++ ++ /* ++ * Iterate over all mounted UBIFS file-systems and find out if there is ++ * already an ongoing commit operation there. If no, then iterate for ++ * the second time and initiate background commit. ++ */ ++ spin_lock(&ubifs_infos_lock); ++ for (i = 0; i < 2; i++) { ++ list_for_each_entry(c, &ubifs_infos, infos_list) { ++ long dirty_zn_cnt; ++ ++ if (!mutex_trylock(&c->umount_mutex)) { ++ /* ++ * Some un-mount is in progress, it will ++ * certainly free memory, so just return. ++ */ ++ spin_unlock(&ubifs_infos_lock); ++ return -1; ++ } ++ ++ dirty_zn_cnt = atomic_long_read(&c->dirty_zn_cnt); ++ ++ if (!dirty_zn_cnt || c->cmt_state == COMMIT_BROKEN || ++ c->ro_media) { ++ mutex_unlock(&c->umount_mutex); ++ continue; ++ } ++ ++ if (c->cmt_state != COMMIT_RESTING) { ++ spin_unlock(&ubifs_infos_lock); ++ mutex_unlock(&c->umount_mutex); ++ return -1; ++ } ++ ++ if (i == 1) { ++ list_del(&c->infos_list); ++ list_add_tail(&c->infos_list, &ubifs_infos); ++ spin_unlock(&ubifs_infos_lock); ++ ++ ubifs_request_bg_commit(c); ++ mutex_unlock(&c->umount_mutex); ++ return -1; ++ } ++ mutex_unlock(&c->umount_mutex); ++ } ++ } ++ spin_unlock(&ubifs_infos_lock); ++ ++ return 0; ++} ++ ++int ubifs_shrinker(int nr, gfp_t gfp_mask) ++{ ++ int freed, contention = 0; ++ long clean_zn_cnt = atomic_long_read(&ubifs_clean_zn_cnt); ++ ++ if (nr == 0) ++ return clean_zn_cnt; ++ ++ if (!clean_zn_cnt) { ++ /* ++ * No clean znodes, nothing to reap. All we can do in this case ++ * is to kick background threads to start commit, which will ++ * probably make clean znodes which, in turn, will be freeable. ++ * And we return -1 which means will make VM call us again ++ * later. ++ */ ++ dbg_tnc("no clean znodes, kick a thread"); ++ return kick_a_thread(); ++ } ++ ++ freed = shrink_tnc_trees(nr, OLD_ZNODE_AGE, &contention); ++ if (freed >= nr) ++ goto out; ++ ++ dbg_tnc("not enough old znodes, try to free young ones"); ++ freed += shrink_tnc_trees(nr - freed, YOUNG_ZNODE_AGE, &contention); ++ if (freed >= nr) ++ goto out; ++ ++ dbg_tnc("not enough young znodes, free all"); ++ freed += shrink_tnc_trees(nr - freed, 0, &contention); ++ ++ if (!freed && contention) { ++ dbg_tnc("freed nothing, but contention"); ++ return -1; ++ } ++ ++out: ++ dbg_tnc("%d znodes were freed, requested %d", freed, nr); ++ return freed; ++} +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/super.c avr32-2.6/fs/ubifs/super.c +--- linux-2.6.25.6/fs/ubifs/super.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/super.c 2008-06-12 15:09:45.600758286 +0200 +@@ -0,0 +1,1969 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Artem Bityutskiy (Битюцкий Артём) ++ * Adrian Hunter ++ */ ++ ++/* ++ * This file implements UBIFS initialization and VFS superblock operations. Some ++ * initialization stuff which is rather large and complex is placed at ++ * corresponding subsystems, but most of it is here. ++ */ ++ ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/module.h> ++#include <linux/ctype.h> ++#include <linux/random.h> ++#include <linux/kthread.h> ++#include <linux/parser.h> ++#include <linux/seq_file.h> ++#include <linux/mount.h> ++#include "ubifs.h" ++ ++/* Slab cache for UBIFS inodes */ ++struct kmem_cache *ubifs_inode_slab; ++ ++/* UBIFS TNC shrinker description */ ++static struct shrinker ubifs_shrinker_info = { ++ .shrink = ubifs_shrinker, ++ .seeks = DEFAULT_SEEKS, ++}; ++ ++/** ++ * validate_inode - validate inode. ++ * @c: UBIFS file-system description object ++ * @inode: the inode to validate ++ * ++ * This is a helper function for 'ubifs_iget()' which validates various fields ++ * of a newly built inode to make sure they contain sane values and prevent ++ * possible vulnerabilities. Returns zero if the inode is all right and ++ * a non-zero error code if not. ++ */ ++static int validate_inode(struct ubifs_info *c, const struct inode *inode) ++{ ++ int err; ++ const struct ubifs_inode *ui = ubifs_inode(inode); ++ ++ if (inode->i_size > c->max_inode_sz) { ++ ubifs_err("inode is too large (%lld)", ++ (long long)inode->i_size); ++ return 1; ++ } ++ ++ if (ui->compr_type < 0 || ui->compr_type >= UBIFS_COMPR_TYPES_CNT) { ++ ubifs_err("unknown compression type %d", ui->compr_type); ++ return 2; ++ } ++ ++ if (ui->xattr_cnt < 0) ++ return 3; ++ ++ if (ui->xattr_size < 0) ++ return 4; ++ ++ if (ui->xattr_names < 0 || ++ ui->xattr_names + ui->xattr_cnt > XATTR_LIST_MAX) ++ return 5; ++ ++ if (ui->data_len < 0 || ui->data_len > UBIFS_MAX_INO_DATA) ++ return 6; ++ ++ if (!ubifs_compr_present(ui->compr_type)) { ++ ubifs_warn("inode %lu uses '%s' compression, but it was not " ++ "compiled in", inode->i_ino, ++ ubifs_compr_name(ui->compr_type)); ++ } ++ ++ err = dbg_check_dir_size(c, inode); ++ return err; ++} ++ ++struct inode *ubifs_iget(struct super_block *sb, unsigned long inum) ++{ ++ int err; ++ union ubifs_key key; ++ struct ubifs_ino_node *ino; ++ struct ubifs_info *c = sb->s_fs_info; ++ struct inode *inode; ++ struct ubifs_inode *ui; ++ ++ dbg_gen("inode %lu", inum); ++ ++ inode = iget_locked(sb, inum); ++ if (!inode) ++ return ERR_PTR(-ENOMEM); ++ if (!(inode->i_state & I_NEW)) ++ return inode; ++ ui = ubifs_inode(inode); ++ ++ ino = kmalloc(UBIFS_MAX_INO_NODE_SZ, GFP_NOFS); ++ if (!ino) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ ino_key_init(c, &key, inode->i_ino); ++ ++ err = ubifs_tnc_lookup(c, &key, ino); ++ if (err) ++ goto out_ino; ++ ++ inode->i_flags |= (S_NOCMTIME | S_NOATIME); ++ inode->i_nlink = le32_to_cpu(ino->nlink); ++ inode->i_uid = le32_to_cpu(ino->uid); ++ inode->i_gid = le32_to_cpu(ino->gid); ++ inode->i_atime.tv_sec = (int64_t)le64_to_cpu(ino->atime_sec); ++ inode->i_atime.tv_nsec = le32_to_cpu(ino->atime_nsec); ++ inode->i_mtime.tv_sec = (int64_t)le64_to_cpu(ino->mtime_sec); ++ inode->i_mtime.tv_nsec = le32_to_cpu(ino->mtime_nsec); ++ inode->i_ctime.tv_sec = (int64_t)le64_to_cpu(ino->ctime_sec); ++ inode->i_ctime.tv_nsec = le32_to_cpu(ino->ctime_nsec); ++ inode->i_mode = le32_to_cpu(ino->mode); ++ inode->i_size = le64_to_cpu(ino->size); ++ ++ ui->data_len = le32_to_cpu(ino->data_len); ++ ui->flags = le32_to_cpu(ino->flags); ++ ui->compr_type = le16_to_cpu(ino->compr_type); ++ ui->creat_sqnum = le64_to_cpu(ino->creat_sqnum); ++ ui->xattr_cnt = le32_to_cpu(ino->xattr_cnt); ++ ui->xattr_size = le64_to_cpu(ino->xattr_size); ++ ui->xattr_names = le32_to_cpu(ino->xattr_names); ++ ++ err = validate_inode(c, inode); ++ if (err) ++ goto out_invalid; ++ ++ /* Disable readahead */ ++ inode->i_mapping->backing_dev_info = &ubifs_backing_dev_info; ++ ++ switch (inode->i_mode & S_IFMT) { ++ case S_IFREG: ++ inode->i_mapping->a_ops = &ubifs_file_address_operations; ++ inode->i_op = &ubifs_file_inode_operations; ++ inode->i_fop = &ubifs_file_operations; ++ if (ui->data_len != 0) { ++ err = 10; ++ goto out_invalid; ++ } ++ break; ++ case S_IFDIR: ++ inode->i_op = &ubifs_dir_inode_operations; ++ inode->i_fop = &ubifs_dir_operations; ++ if (ui->data_len != 0) { ++ err = 11; ++ goto out_invalid; ++ } ++ break; ++ case S_IFLNK: ++ inode->i_op = &ubifs_symlink_inode_operations; ++ if (ui->data_len <= 0 || ui->data_len > UBIFS_MAX_INO_DATA) { ++ err = 12; ++ goto out_invalid; ++ } ++ ui->data = kmalloc(ui->data_len + 1, GFP_NOFS); ++ if (!ui->data) { ++ err = -ENOMEM; ++ goto out_ino; ++ } ++ memcpy(ui->data, ino->data, ui->data_len); ++ ((char *)ui->data)[ui->data_len] = '\0'; ++ break; ++ case S_IFBLK: ++ case S_IFCHR: ++ { ++ dev_t rdev; ++ union ubifs_dev_desc *dev; ++ ++ ui->data = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); ++ if (!ui->data) { ++ err = -ENOMEM; ++ goto out_ino; ++ } ++ ++ dev = (union ubifs_dev_desc *)ino->data; ++ if (ui->data_len == sizeof(dev->new)) ++ rdev = new_decode_dev(le32_to_cpu(dev->new)); ++ else if (ui->data_len == sizeof(dev->huge)) ++ rdev = huge_decode_dev(le64_to_cpu(dev->huge)); ++ else { ++ err = 13; ++ goto out_invalid; ++ } ++ memcpy(ui->data, ino->data, ui->data_len); ++ inode->i_op = &ubifs_file_inode_operations; ++ init_special_inode(inode, inode->i_mode, rdev); ++ break; ++ } ++ case S_IFSOCK: ++ case S_IFIFO: ++ inode->i_op = &ubifs_file_inode_operations; ++ init_special_inode(inode, inode->i_mode, 0); ++ if (ui->data_len != 0) { ++ err = 14; ++ goto out_invalid; ++ } ++ break; ++ default: ++ err = 15; ++ goto out_invalid; ++ } ++ ++ kfree(ino); ++ ubifs_set_inode_flags(inode); ++ unlock_new_inode(inode); ++ return inode; ++ ++out_invalid: ++ ubifs_err("inode %lu validation failed, error %d", inode->i_ino, err); ++ dbg_dump_node(c, ino); ++ dbg_dump_inode(c, inode); ++ err = -EINVAL; ++out_ino: ++ kfree(ino); ++out: ++ ubifs_err("failed to read inode %lu, error %d", inode->i_ino, err); ++ iget_failed(inode); ++ return ERR_PTR(err); ++} ++ ++static struct inode *ubifs_alloc_inode(struct super_block *sb) ++{ ++ struct ubifs_inode *ui; ++ ++ ui = kmem_cache_alloc(ubifs_inode_slab, GFP_NOFS); ++ if (!ui) ++ return NULL; ++ ++ memset((void *)ui + sizeof(struct inode), 0, ++ sizeof(struct ubifs_inode) - sizeof(struct inode)); ++ mutex_init(&ui->budg_mutex); ++ return &ui->vfs_inode; ++}; ++ ++static void ubifs_destroy_inode(struct inode *inode) ++{ ++ struct ubifs_inode *ui = ubifs_inode(inode); ++ ++ kfree(ui->data); ++ kmem_cache_free(ubifs_inode_slab, inode); ++} ++ ++/* ++ * Note, Linux write-back code calls this without 'i_mutex'. ++ */ ++static int ubifs_write_inode(struct inode *inode, int wait) ++{ ++ int err; ++ struct ubifs_info *c = inode->i_sb->s_fs_info; ++ struct ubifs_inode *ui = ubifs_inode(inode); ++ struct ubifs_budget_req req = {.dd_growth = c->inode_budget, ++ .dirtied_ino_d = ui->data_len}; ++ ++ ubifs_assert(!ui->xattr); ++ if (is_bad_inode(inode)) ++ return 0; ++ ++ mutex_lock(&ui->budg_mutex); ++ ++ /* ++ * Due to races between write-back forced by budgeting ++ * (see 'sync_some_inodes()') and pdflush write-back, the inode may ++ * have already been synchronized, do not do this again. ++ * ++ * This might also happen if it was synchronized in e.g. ubifs_link()', ++ * etc. ++ */ ++ if (!ui->dirty) { ++ mutex_unlock(&ui->budg_mutex); ++ return 0; ++ } ++ ++ ubifs_assert(ui->budgeted); ++ dbg_gen("inode %lu", inode->i_ino); ++ ++ err = ubifs_jnl_write_inode(c, inode, 0, IS_SYNC(inode)); ++ if (err) ++ ubifs_err("can't write inode %lu, error %d", inode->i_ino, err); ++ ++ ui->dirty = 0; ++ UBIFS_DBG(ui->budgeted = 0); ++ atomic_long_dec(&c->dirty_ino_cnt); ++ ++ ubifs_release_budget(c, &req); ++ mutex_unlock(&ui->budg_mutex); ++ ++ return err; ++} ++ ++static void ubifs_delete_inode(struct inode *inode) ++{ ++ struct ubifs_info *c = inode->i_sb->s_fs_info; ++ struct ubifs_inode *ui = ubifs_inode(inode); ++ struct ubifs_budget_req req = {.dd_growth = c->inode_budget, ++ .dirtied_ino_d = ui->data_len}; ++ int err; ++ ++ if (ui->xattr) { ++ /* ++ * Extended attribute inode deletions are fully handled in ++ * 'ubifs_removexattr()'. These inodes are special and have ++ * limited usage, so there is nothing to do here. ++ */ ++ ubifs_assert(!ui->dirty); ++ goto out; ++ } ++ ++ dbg_gen("inode %lu", inode->i_ino); ++ ubifs_assert(!atomic_read(&inode->i_count)); ++ ubifs_assert(inode->i_nlink == 0); ++ ++ truncate_inode_pages(&inode->i_data, 0); ++ if (is_bad_inode(inode)) ++ goto out; ++ ++ mutex_lock(&ui->budg_mutex); ++ ++ inode->i_size = 0; ++ ++ err = ubifs_jnl_write_inode(c, inode, 1, IS_SYNC(inode)); ++ if (err) ++ /* ++ * Worst case we have a lost orphan inode wasting space, so a ++ * simple error message is ok here. ++ */ ++ ubifs_err("can't write inode %lu, error %d", inode->i_ino, err); ++ ++ if (ui->dirty) { ++ ubifs_assert(ui->budgeted); ++ atomic_long_dec(&c->dirty_ino_cnt); ++ ui->dirty = 0; ++ UBIFS_DBG(ui->budgeted = 0); ++ ubifs_release_budget(c, &req); ++ } ++ ++ mutex_unlock(&ui->budg_mutex); ++out: ++ clear_inode(inode); ++} ++ ++static void ubifs_dirty_inode(struct inode *inode) ++{ ++ struct ubifs_inode *ui = ubifs_inode(inode); ++ ++ ubifs_assert(mutex_is_locked(&ui->budg_mutex)); ++ if (!ui->dirty) { ++ struct ubifs_info *c = inode->i_sb->s_fs_info; ++ ++ ui->dirty = 1; ++ atomic_long_inc(&c->dirty_ino_cnt); ++ dbg_gen("inode %lu", inode->i_ino); ++ } ++} ++ ++static int ubifs_statfs(struct dentry *dentry, struct kstatfs *buf) ++{ ++ struct ubifs_info *c = dentry->d_sb->s_fs_info; ++ unsigned long long free; ++ ++ free = ubifs_budg_get_free_space(c); ++ dbg_gen("free space %lld bytes (%lld blocks)", ++ free, free >> UBIFS_BLOCK_SHIFT); ++ ++ buf->f_type = UBIFS_SUPER_MAGIC; ++ buf->f_bsize = UBIFS_BLOCK_SIZE; ++ buf->f_blocks = c->block_cnt; ++ buf->f_bfree = free >> UBIFS_BLOCK_SHIFT; ++ if (free > c->report_rp_size) ++ buf->f_bavail = (free - c->report_rp_size) >> UBIFS_BLOCK_SHIFT; ++ else ++ buf->f_bavail = 0; ++ buf->f_files = 0; ++ buf->f_ffree = 0; ++ buf->f_namelen = UBIFS_MAX_NLEN; ++ ++ return 0; ++} ++ ++static int ubifs_show_options(struct seq_file *s, struct vfsmount *mnt) ++{ ++ struct ubifs_info *c = mnt->mnt_sb->s_fs_info; ++ ++ if (c->mount_opts.unmount_mode == 2) ++ seq_printf(s, ",fast_unmount"); ++ else if (c->mount_opts.unmount_mode == 1) ++ seq_printf(s, ",norm_unmount"); ++ ++ return 0; ++} ++ ++static int ubifs_sync_fs(struct super_block *sb, int wait) ++{ ++ struct ubifs_info *c = sb->s_fs_info; ++ int i, ret = 0, err; ++ ++ if (c->jheads) ++ for (i = 0; i < c->jhead_cnt; i++) { ++ err = ubifs_wbuf_sync(&c->jheads[i].wbuf); ++ if (err && !ret) ++ ret = err; ++ } ++ /* ++ * We ought to call sync for c->ubi but it does not have one. If it had ++ * it would in turn call mtd->sync, however mtd operations are ++ * synchronous anyway, so we don't lose any sleep here. ++ */ ++ return ret; ++} ++ ++/** ++ * init_constants_early - initialize UBIFS constants. ++ * @c: UBIFS file-system description object ++ * ++ * This function initialize UBIFS constants which do not need the superblock to ++ * be read. It also checks that the UBI volume satisfies basic UBIFS ++ * requirements. Returns zero in case of success and a negative error code in ++ * case of failure. ++ */ ++static int init_constants_early(struct ubifs_info *c) ++{ ++ if (c->vi.corrupted) { ++ ubifs_warn("UBI volume is corrupted - read-only mode"); ++ c->ro_media = 1; ++ } ++ ++ if (c->di.ro_mode) { ++ ubifs_msg("read-only UBI device"); ++ c->ro_media = 1; ++ } ++ ++ if (c->vi.vol_type == UBI_STATIC_VOLUME) { ++ ubifs_msg("static UBI volume - read-only mode"); ++ c->ro_media = 1; ++ } ++ ++ c->leb_cnt = c->vi.size; ++ c->leb_size = c->vi.usable_leb_size; ++ c->half_leb_size = c->leb_size / 2; ++ c->min_io_size = c->di.min_io_size; ++ c->min_io_shift = fls(c->min_io_size) - 1; ++ ++ if (c->leb_size < UBIFS_MIN_LEB_SZ) { ++ ubifs_err("too small LEBs (%d bytes), min. is %d bytes", ++ c->leb_size, UBIFS_MIN_LEB_SZ); ++ return -EINVAL; ++ } ++ ++ if (c->leb_cnt < UBIFS_MIN_LEB_CNT) { ++ ubifs_err("too few LEBs (%d), min. is %d", ++ c->leb_cnt, UBIFS_MIN_LEB_CNT); ++ return -EINVAL; ++ } ++ ++ if (!is_power_of_2(c->min_io_size)) { ++ ubifs_err("bad min. I/O size %d", c->min_io_size); ++ return -EINVAL; ++ } ++ ++ /* ++ * UBIFS aligns all node to 8-byte boundary, so to make function in ++ * io.c simpler, assume minimum I/O unit size to be 8 bytes if it is ++ * less than 8. ++ */ ++ if (c->min_io_size < 8) { ++ c->min_io_size = 8; ++ c->min_io_shift = 3; ++ } ++ ++ c->ref_node_alsz = ALIGN(UBIFS_REF_NODE_SZ, c->min_io_size); ++ c->mst_node_alsz = ALIGN(UBIFS_MST_NODE_SZ, c->min_io_size); ++ ++ /* ++ * Initialize node length ranges which are mostly needed for node ++ * length validation. ++ */ ++ c->ranges[UBIFS_PAD_NODE].len = UBIFS_PAD_NODE_SZ; ++ c->ranges[UBIFS_SB_NODE].len = UBIFS_SB_NODE_SZ; ++ c->ranges[UBIFS_MST_NODE].len = UBIFS_MST_NODE_SZ; ++ c->ranges[UBIFS_REF_NODE].len = UBIFS_REF_NODE_SZ; ++ c->ranges[UBIFS_TRUN_NODE].len = UBIFS_TRUN_NODE_SZ; ++ c->ranges[UBIFS_CS_NODE].len = UBIFS_CS_NODE_SZ; ++ ++ c->ranges[UBIFS_INO_NODE].min_len = UBIFS_INO_NODE_SZ; ++ c->ranges[UBIFS_INO_NODE].max_len = UBIFS_MAX_INO_NODE_SZ; ++ c->ranges[UBIFS_ORPH_NODE].min_len = ++ UBIFS_ORPH_NODE_SZ + sizeof(__le64); ++ c->ranges[UBIFS_ORPH_NODE].max_len = c->leb_size; ++ c->ranges[UBIFS_DENT_NODE].min_len = UBIFS_DENT_NODE_SZ; ++ c->ranges[UBIFS_DENT_NODE].max_len = UBIFS_MAX_DENT_NODE_SZ; ++ c->ranges[UBIFS_XENT_NODE].min_len = UBIFS_XENT_NODE_SZ; ++ c->ranges[UBIFS_XENT_NODE].max_len = UBIFS_MAX_XENT_NODE_SZ; ++ c->ranges[UBIFS_DATA_NODE].min_len = UBIFS_DATA_NODE_SZ; ++ c->ranges[UBIFS_DATA_NODE].max_len = UBIFS_MAX_DATA_NODE_SZ; ++ /* ++ * Minimum indexing node size is amended later when superblock is ++ * read and the key length is known. ++ */ ++ c->ranges[UBIFS_IDX_NODE].min_len = UBIFS_IDX_NODE_SZ + UBIFS_BRANCH_SZ; ++ /* ++ * Maximum indexing node size is amended later when superblock is ++ * read and the fanout is known. ++ */ ++ c->ranges[UBIFS_IDX_NODE].max_len = INT_MAX; ++ ++ /* ++ * Initialize dead and dark LEB space watermarks. ++ * ++ * Dead space is the space which cannot be used. Its watermark is ++ * equivalent to min. I/O unit or minimum node size if it is greater ++ * then min. I/O unit. ++ * ++ * Dark space is the space which might be used, or might not, depending ++ * on which node should be written to the LEB. Its watermark is ++ * equivalent to maximum UBIFS node size. ++ */ ++ c->dead_wm = ALIGN(MIN_WRITE_SZ, c->min_io_size); ++ c->dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, c->min_io_size); ++ ++ return 0; ++} ++ ++/** ++ * bud_wbuf_callback - bud LEB write-buffer synchronization call-back. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB the write-buffer was synchronized to ++ * @free: how many free bytes left in this LEB ++ * @pad: how many bytes were padded ++ * ++ * This is a callback function which is called by the I/O unit when the ++ * write-buffer is synchronized. We need this to correctly maintain space ++ * accounting in bud logical eraseblocks. This function returns zero in case of ++ * success and a negative error code in case of failure. ++ * ++ * This function actually belongs to the journal, but we keep it here because ++ * we want to keep it static. ++ */ ++static int bud_wbuf_callback(struct ubifs_info *c, int lnum, int free, int pad) ++{ ++ return ubifs_update_one_lp(c, lnum, free, pad, 0, 0); ++} ++ ++/* ++ * init_constants_late - initialize UBIFS constants. ++ * @c: UBIFS file-system description object ++ * ++ * This is a helper function which initializes various UBIFS constants after ++ * the superblock has been read. It also checks various UBIFS parameters and ++ * makes sure they are all right. Returns zero in case of success and a ++ * negative error code in case of failure. ++ */ ++static int init_constants_late(struct ubifs_info *c) ++{ ++ int tmp, err; ++ uint64_t tmp64; ++ ++ c->main_bytes = c->main_lebs * c->leb_size; ++ ++ c->max_znode_sz = sizeof(struct ubifs_znode) + ++ c->fanout * sizeof(struct ubifs_zbranch); ++ ++ tmp = ubifs_idx_node_sz(c, 1); ++ c->ranges[UBIFS_IDX_NODE].min_len = tmp; ++ c->min_idx_node_sz = ALIGN(tmp, 8); ++ ++ tmp = ubifs_idx_node_sz(c, c->fanout); ++ c->ranges[UBIFS_IDX_NODE].max_len = tmp; ++ c->max_idx_node_sz = ALIGN(tmp, 8); ++ ++ /* Make sure LEB size is large enough to fit full commit */ ++ tmp = UBIFS_CS_NODE_SZ + UBIFS_REF_NODE_SZ * c->jhead_cnt; ++ tmp = ALIGN(tmp, c->min_io_size); ++ if (tmp > c->leb_size) { ++ dbg_err("too small LEB size %d, at least %d needed", ++ c->leb_size, tmp); ++ return -EINVAL; ++ } ++ ++ /* ++ * Make sure that the log is large enough to fit reference nodes for ++ * all buds plus one reserved LEB. ++ */ ++ tmp64 = c->max_bud_bytes; ++ tmp = do_div(tmp64, c->leb_size); ++ c->max_bud_cnt = tmp64 + !!tmp; ++ tmp = (c->ref_node_alsz * c->max_bud_cnt + c->leb_size - 1); ++ tmp /= c->leb_size; ++ tmp += 1; ++ if (c->log_lebs < tmp) { ++ dbg_err("too small log %d LEBs, required min. %d LEBs", ++ c->log_lebs, tmp); ++ return -EINVAL; ++ } ++ ++ /* ++ * When budgeting we assume worst-case scenarios when the pages are not ++ * be compressed and direntries are of the maximum size. ++ * ++ * Note, data, which may be stored in inodes is budgeted separately, so ++ * it is not included into 'c->inode_budget'. ++ */ ++ c->page_budget = UBIFS_MAX_DATA_NODE_SZ * UBIFS_BLOCKS_PER_PAGE; ++ c->inode_budget = UBIFS_INO_NODE_SZ; ++ c->dent_budget = UBIFS_MAX_DENT_NODE_SZ; ++ ++ /* ++ * When the amount of flash space used by buds becomes ++ * 'c->max_bud_bytes', UBIFS just blocks all writers and starts commit. ++ * The writers are unblocked when the commit is finished. To avoid ++ * writers to be blocked UBIFS initiates background commit in advance, ++ * when number of bud bytes becomes above the limit defined below. ++ */ ++ c->bg_bud_bytes = (c->max_bud_bytes * 13) >> 4; ++ ++ /* ++ * Ensure minimum journal size. All the bytes in the journal heads are ++ * considered to be used, when calculating the current journal usage. ++ * Consequently, if the journal is too small, UBIFS will treat it as ++ * always full. ++ */ ++ tmp64 = (uint64_t)(c->jhead_cnt + 1) * c->leb_size + 1; ++ if (c->bg_bud_bytes < tmp64) ++ c->bg_bud_bytes = tmp64; ++ if (c->max_bud_bytes < tmp64 + c->leb_size) ++ c->max_bud_bytes = tmp64 + c->leb_size; ++ ++ err = ubifs_calc_lpt_geom(c); ++ if (err) ++ return err; ++ ++ c->min_idx_lebs = ubifs_calc_min_idx_lebs(c); ++ ++ /* ++ * Calculate total amount of FS blocks. This number is not used ++ * internally because it does not make much sense for UBIFS, but it is ++ * necessary to report something for the 'statfs()' call. ++ * ++ * Subtract the LEB reserved for GC and the LEB which is reserved for ++ * deletions. ++ * ++ * Review 'ubifs_calc_available()' if changing this calculation. ++ */ ++ tmp64 = c->main_lebs - 2; ++ tmp64 *= c->leb_size - c->dark_wm; ++ tmp64 = ubifs_reported_space(c, tmp64); ++ c->block_cnt = tmp64 >> UBIFS_BLOCK_SHIFT; ++ ++ return 0; ++} ++ ++/** ++ * take_gc_lnum - reserve GC LEB. ++ * @c: UBIFS file-system description object ++ * ++ * This function ensures that the LEB reserved for garbage collection is ++ * unmapped and is marked as "taken" in lprops. We also have to set free space ++ * to LEB size and dirty space to zero, because lprops may contain out-of-date ++ * information if the file-system was un-mounted before it has been committed. ++ * This function returns zero in case of success and a negative error code in ++ * case of failure. ++ */ ++static int take_gc_lnum(struct ubifs_info *c) ++{ ++ int err; ++ ++ if (c->gc_lnum == -1) { ++ ubifs_err("no LEB for GC"); ++ return -EINVAL; ++ } ++ ++ err = ubifs_leb_unmap(c, c->gc_lnum); ++ if (err) ++ return err; ++ ++ /* And we have to tell lprops that this LEB is taken */ ++ err = ubifs_change_one_lp(c, c->gc_lnum, c->leb_size, 0, ++ LPROPS_TAKEN, 0, 0); ++ return err; ++} ++ ++/** ++ * alloc_wbufs - allocate write-buffers. ++ * @c: UBIFS file-system description object ++ * ++ * This helper function allocates and initializes UBIFS write-buffers. Returns ++ * zero in case of success and %-ENOMEM in case of failure. ++ */ ++static int alloc_wbufs(struct ubifs_info *c) ++{ ++ int i, err; ++ ++ c->jheads = kzalloc(c->jhead_cnt * sizeof(struct ubifs_jhead), ++ GFP_KERNEL); ++ if (!c->jheads) ++ return -ENOMEM; ++ ++ /* Initialize journal heads */ ++ for (i = 0; i < c->jhead_cnt; i++) { ++ INIT_LIST_HEAD(&c->jheads[i].buds_list); ++ err = ubifs_wbuf_init(c, &c->jheads[i].wbuf); ++ if (err) ++ return err; ++ ++ c->jheads[i].wbuf.sync_callback = &bud_wbuf_callback; ++ c->jheads[i].wbuf.jhead = i; ++ } ++ ++ c->jheads[BASEHD].wbuf.dtype = UBI_SHORTTERM; ++ /* ++ * Garbage Collector head likely contains long-term data and ++ * does not need to be synchronized by timer. ++ */ ++ c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM; ++ c->jheads[GCHD].wbuf.timeout = 0; ++ ++ return 0; ++} ++ ++/** ++ * free_wbufs - free write-buffers. ++ * @c: UBIFS file-system description object ++ */ ++static void free_wbufs(struct ubifs_info *c) ++{ ++ int i; ++ ++ if (c->jheads) { ++ for (i = 0; i < c->jhead_cnt; i++) { ++ kfree(c->jheads[i].wbuf.buf); ++ kfree(c->jheads[i].wbuf.inodes); ++ } ++ kfree(c->jheads); ++ c->jheads = NULL; ++ } ++} ++ ++/** ++ * free_orphans - free orphans. ++ * @c: UBIFS file-system description object ++ */ ++static void free_orphans(struct ubifs_info *c) ++{ ++ struct ubifs_orphan *orph; ++ ++ while (c->orph_dnext) { ++ orph = c->orph_dnext; ++ c->orph_dnext = orph->dnext; ++ list_del(&orph->list); ++ kfree(orph); ++ } ++ ++ while (!list_empty(&c->orph_list)) { ++ orph = list_entry(c->orph_list.next, struct ubifs_orphan, list); ++ list_del(&orph->list); ++ kfree(orph); ++ dbg_err("orphan list not empty at unmount"); ++ } ++ ++ vfree(c->orph_buf); ++ c->orph_buf = NULL; ++} ++ ++/** ++ * free_buds - free per-bud objects. ++ * @c: UBIFS file-system description object ++ */ ++static void free_buds(struct ubifs_info *c) ++{ ++ struct rb_node *this = c->buds.rb_node; ++ struct ubifs_bud *bud; ++ ++ while (this) { ++ if (this->rb_left) ++ this = this->rb_left; ++ else if (this->rb_right) ++ this = this->rb_right; ++ else { ++ bud = rb_entry(this, struct ubifs_bud, rb); ++ this = rb_parent(this); ++ if (this) { ++ if (this->rb_left == &bud->rb) ++ this->rb_left = NULL; ++ else ++ this->rb_right = NULL; ++ } ++ kfree(bud); ++ } ++ } ++} ++ ++/** ++ * check_volume_empty - check if the UBI volume is empty. ++ * @c: UBIFS file-system description object ++ * ++ * This function checks if the UBIFS volume is empty by looking if its LEBs are ++ * mapped or not. The result of checking is stored in the @c->empty variable. ++ * Returns zero in case of success and a negative error code in case of ++ * failure. ++ */ ++static int check_volume_empty(struct ubifs_info *c) ++{ ++ int lnum, err; ++ ++ c->empty = 1; ++ for (lnum = 0; lnum < c->leb_cnt; lnum++) { ++ err = ubi_is_mapped(c->ubi, lnum); ++ if (unlikely(err < 0)) ++ return err; ++ if (err == 1) { ++ c->empty = 0; ++ break; ++ } ++ ++ cond_resched(); ++ } ++ ++ return 0; ++} ++ ++/* ++ * UBIFS mount options. ++ * ++ * Opt_fast_unmount: do not run a journal commit before un-mounting ++ * Opt_norm_unmount: run a journal commit before un-mounting ++ * Opt_err: just end of array marker ++ */ ++enum { ++ Opt_fast_unmount, ++ Opt_norm_unmount, ++ Opt_err, ++}; ++ ++static match_table_t tokens = { ++ {Opt_fast_unmount, "fast_unmount"}, ++ {Opt_norm_unmount, "norm_unmount"}, ++ {Opt_err, NULL}, ++}; ++ ++/** ++ * ubifs_parse_options - parse mount parameters. ++ * @c: UBIFS file-system description object ++ * @options: parameters to parse ++ * @is_remount: non-zero if this is FS re-mount ++ * ++ * This function parses UBIFS mount options and returns zero in case success ++ * and a negative error code in case of failure. ++ */ ++static int ubifs_parse_options(struct ubifs_info *c, char *options, ++ int is_remount) ++{ ++ char *p; ++ substring_t args[MAX_OPT_ARGS]; ++ ++ if (!options) ++ return 0; ++ ++ while ((p = strsep(&options, ","))) { ++ int token; ++ ++ if (!*p) ++ continue; ++ ++ token = match_token(p, tokens, args); ++ switch (token) { ++ case Opt_fast_unmount: ++ c->mount_opts.unmount_mode = 2; ++ c->fast_unmount = 1; ++ break; ++ case Opt_norm_unmount: ++ c->mount_opts.unmount_mode = 1; ++ c->fast_unmount = 0; ++ break; ++ default: ++ ubifs_err("unrecognized mount option \"%s\" " ++ "or missing value", p); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++/** ++ * destroy_journal - destroy journal data structures. ++ * @c: UBIFS file-system description object ++ * ++ * This function destroys journal data structures including those that may have ++ * been created by recovery functions. ++ */ ++static void destroy_journal(struct ubifs_info *c) ++{ ++ while (!list_empty(&c->unclean_leb_list)) { ++ struct ubifs_unclean_leb *ucleb; ++ ++ ucleb = list_entry(c->unclean_leb_list.next, ++ struct ubifs_unclean_leb, list); ++ list_del(&ucleb->list); ++ kfree(ucleb); ++ } ++ while (!list_empty(&c->old_buds)) { ++ struct ubifs_bud *bud; ++ ++ bud = list_entry(c->old_buds.next, struct ubifs_bud, list); ++ list_del(&bud->list); ++ kfree(bud); ++ } ++ ubifs_destroy_idx_gc(c); ++ ubifs_destroy_size_tree(c); ++ ubifs_tnc_close(c); ++ free_buds(c); ++} ++ ++/** ++ * mount_ubifs - mount UBIFS file-system. ++ * @c: UBIFS file-system description object ++ * ++ * This function mounts UBIFS file system. Returns zero in case of success and ++ * a negative error code in case of failure. ++ * ++ * Note, the function does not de-allocate resources it it fails half way ++ * through, and the caller has to do this instead. ++ */ ++static int mount_ubifs(struct ubifs_info *c) ++{ ++ struct super_block *sb = c->vfs_sb; ++ int err, mounted_read_only = (sb->s_flags & MS_RDONLY); ++ unsigned long long x; ++ size_t sz; ++ ++ err = init_constants_early(c); ++ if (err) ++ return err; ++ ++#ifdef CONFIG_UBIFS_FS_DEBUG ++ c->dbg_buf = vmalloc(c->leb_size); ++ if (!c->dbg_buf) ++ return -ENOMEM; ++#endif ++ ++ err = check_volume_empty(c); ++ if (err) ++ goto out_free; ++ ++ if (c->empty && (mounted_read_only || c->ro_media)) { ++ /* ++ * This UBI volume is empty, and read-only, or the file system ++ * is mounted read-only - we cannot format it. ++ */ ++ ubifs_err("can't format empty UBI volume: read-only %s", ++ c->ro_media ? "UBI volume" : "mount"); ++ err = -EROFS; ++ goto out_free; ++ } ++ ++ if (c->ro_media && !mounted_read_only) { ++ ubifs_err("cannot mount read-write - read-only media"); ++ err = -EROFS; ++ goto out_free; ++ } ++ ++ /* ++ * The requirement for the buffer is that it should fit indexing B-tree ++ * height amount of integers. We assume the height if the TNC tree will ++ * never exceed 64. ++ */ ++ err = -ENOMEM; ++ c->bottom_up_buf = kmalloc(BOTTOM_UP_HEIGHT * sizeof(int), GFP_KERNEL); ++ if (!c->bottom_up_buf) ++ goto out_free; ++ ++ c->sbuf = vmalloc(c->leb_size); ++ if (!c->sbuf) ++ goto out_free; ++ ++ if (!mounted_read_only) { ++ c->ileb_buf = vmalloc(c->leb_size); ++ if (!c->ileb_buf) ++ goto out_free; ++ } ++ ++ err = ubifs_read_superblock(c); ++ if (err) ++ goto out_free; ++ ++ /* ++ * Make sure the compressor which is set as the default on in the ++ * superblock was actually compiled in. ++ */ ++ if (!ubifs_compr_present(c->default_compr)) { ++ ubifs_warn("'%s' compressor is set by superblock, but not " ++ "compiled in", ubifs_compr_name(c->default_compr)); ++ c->default_compr = UBIFS_COMPR_NONE; ++ } ++ ++ dbg_failure_mode_registration(c); ++ ++ err = init_constants_late(c); ++ if (err) ++ goto out_dereg; ++ ++ sz = ALIGN(c->max_idx_node_sz, c->min_io_size); ++ sz = ALIGN(sz + c->max_idx_node_sz, c->min_io_size); ++ c->cbuf = kmalloc(sz, GFP_NOFS); ++ if (!c->cbuf) { ++ err = -ENOMEM; ++ goto out_dereg; ++ } ++ ++ if (!mounted_read_only) { ++ err = alloc_wbufs(c); ++ if (err) ++ goto out_cbuf; ++ ++ /* Create background thread */ ++ sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, ++ c->vi.vol_id); ++ c->bgt = kthread_create(ubifs_bg_thread, c, c->bgt_name); ++ if (!c->bgt) ++ c->bgt = ERR_PTR(-EINVAL); ++ if (IS_ERR(c->bgt)) { ++ err = PTR_ERR(c->bgt); ++ c->bgt = NULL; ++ ubifs_err("cannot spawn \"%s\", error %d", ++ c->bgt_name, err); ++ goto out_wbufs; ++ } ++ wake_up_process(c->bgt); ++ } ++ ++ err = ubifs_read_master(c); ++ if (err) ++ goto out_stop; ++ ++ if ((c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY)) != 0) { ++ ubifs_msg("recovery needed"); ++ c->need_recovery = 1; ++ if (!mounted_read_only) { ++ err = ubifs_recover_inl_heads(c, c->sbuf); ++ if (err) ++ goto out_master; ++ } ++ } else if (!mounted_read_only) { ++ /* ++ * Set the "dirty" flag so that if we reboot uncleanly we ++ * will notice this immediately on the next mount. ++ */ ++ c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY); ++ err = ubifs_write_master(c); ++ if (err) ++ goto out_master; ++ } ++ ++ err = ubifs_lpt_init(c, 1, !mounted_read_only); ++ if (err) ++ goto out_lpt; ++ ++ err = dbg_check_idx_size(c, c->old_idx_sz); ++ if (err) ++ goto out_lpt; ++ ++ err = ubifs_replay_journal(c); ++ if (err) ++ goto out_journal; ++ ++ err = ubifs_mount_orphans(c, c->need_recovery, mounted_read_only); ++ if (err) ++ goto out_orphans; ++ ++ if (!mounted_read_only) { ++ int lnum; ++ ++ /* Check for enough free space */ ++ if (ubifs_calc_available(c) <= 0) { ++ ubifs_err("insufficient available space"); ++ err = -EINVAL; ++ goto out_orphans; ++ } ++ ++ /* Check for enough log space */ ++ lnum = c->lhead_lnum + 1; ++ if (lnum >= UBIFS_LOG_LNUM + c->log_lebs) ++ lnum = UBIFS_LOG_LNUM; ++ if (lnum == c->ltail_lnum) { ++ err = ubifs_consolidate_log(c); ++ if (err) ++ goto out_orphans; ++ } ++ ++ if (c->need_recovery) { ++ err = ubifs_recover_size(c); ++ if (err) ++ goto out_orphans; ++ err = ubifs_rcvry_gc_commit(c); ++ } else ++ err = take_gc_lnum(c); ++ if (err) ++ goto out_orphans; ++ ++ err = dbg_check_lprops(c); ++ if (err) ++ goto out_orphans; ++ } else if (c->need_recovery) { ++ err = ubifs_recover_size(c); ++ if (err) ++ goto out_orphans; ++ } ++ ++ spin_lock(&ubifs_infos_lock); ++ list_add_tail(&c->infos_list, &ubifs_infos); ++ spin_unlock(&ubifs_infos_lock); ++ ++ if (c->need_recovery) { ++ if (mounted_read_only) ++ ubifs_msg("recovery deferred"); ++ else { ++ c->need_recovery = 0; ++ ubifs_msg("recovery completed"); ++ } ++ } ++ ++ err = dbg_check_filesystem(c); ++ if (err) ++ goto out_infos; ++ ++ ubifs_msg("mounted UBI device %d, volume %d", c->vi.ubi_num, ++ c->vi.vol_id); ++ if (mounted_read_only) ++ ubifs_msg("mounted read-only"); ++ ubifs_msg("minimal I/O unit size: %d bytes", c->min_io_size); ++ ubifs_msg("logical eraseblock size: %d bytes (%d KiB)", ++ c->leb_size, c->leb_size / 1024); ++ x = (unsigned long long)c->main_lebs * c->leb_size; ++ ubifs_msg("file system size: %lld bytes (%lld KiB, %lld MiB, " ++ "%d LEBs)", x, x >> 10, x >> 20, c->main_lebs); ++ x = (unsigned long long)c->log_lebs * c->leb_size + c->max_bud_bytes; ++ ubifs_msg("journal size: %lld bytes (%lld KiB, %lld MiB, " ++ "%d LEBs)", x, x >> 10, x >> 20, ++ c->log_lebs + c->max_bud_cnt); ++ ubifs_msg("data journal heads: %d", ++ c->jhead_cnt - NONDATA_JHEADS_CNT); ++ ubifs_msg("default compressor: %s", ++ ubifs_compr_name(c->default_compr)); ++ ubifs_msg("media format %d, latest format %d", ++ c->fmt_version, UBIFS_FORMAT_VERSION); ++ ++ dbg_msg("compiled on: " __DATE__ " at " __TIME__); ++ dbg_msg("UUID: %02X%02X%02X%02X-%02X%02X" ++ "-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", ++ c->uuid[0], c->uuid[1], c->uuid[2], c->uuid[3], ++ c->uuid[4], c->uuid[5], c->uuid[6], c->uuid[7], ++ c->uuid[8], c->uuid[9], c->uuid[10], c->uuid[11], ++ c->uuid[12], c->uuid[13], c->uuid[14], c->uuid[15]); ++ dbg_msg("fast unmount: %d", c->fast_unmount); ++ dbg_msg("big_lpt %d", c->big_lpt); ++ dbg_msg("log LEBs: %d (%d - %d)", ++ c->log_lebs, UBIFS_LOG_LNUM, c->log_last); ++ dbg_msg("LPT area LEBs: %d (%d - %d)", ++ c->lpt_lebs, c->lpt_first, c->lpt_last); ++ dbg_msg("orphan area LEBs: %d (%d - %d)", ++ c->orph_lebs, c->orph_first, c->orph_last); ++ dbg_msg("main area LEBs: %d (%d - %d)", ++ c->main_lebs, c->main_first, c->leb_cnt - 1); ++ dbg_msg("index LEBs: %d", c->lst.idx_lebs); ++ dbg_msg("total index bytes: %lld (%lld KiB, %lld MiB)", ++ c->old_idx_sz, c->old_idx_sz >> 10, c->old_idx_sz >> 20); ++ dbg_msg("key hash type: %d", c->key_hash_type); ++ dbg_msg("tree fanout: %d", c->fanout); ++ dbg_msg("reserved GC LEB: %d", c->gc_lnum); ++ dbg_msg("first main LEB: %d", c->main_first); ++ dbg_msg("dead watermark: %d", c->dead_wm); ++ dbg_msg("dark watermark: %d", c->dark_wm); ++ x = c->main_lebs * c->dark_wm; ++ dbg_msg("max. dark space: %lld (%lld KiB, %lld MiB)", ++ x, x >> 10, x >> 20); ++ dbg_msg("maximum bud bytes: %lld (%lld KiB, %lld MiB)", ++ c->max_bud_bytes, c->max_bud_bytes >> 10, ++ c->max_bud_bytes >> 20); ++ dbg_msg("BG commit bud bytes: %lld (%lld KiB, %lld MiB)", ++ c->bg_bud_bytes, c->bg_bud_bytes >> 10, ++ c->bg_bud_bytes >> 20); ++ dbg_msg("current bud bytes %lld (%lld KiB, %lld MiB)", ++ c->bud_bytes, c->bud_bytes >> 10, c->bud_bytes >> 20); ++ dbg_msg("max. seq. number: %llu", c->max_sqnum); ++ dbg_msg("commit number: %llu", c->cmt_no); ++ ++ return 0; ++ ++out_infos: ++ spin_lock(&ubifs_infos_lock); ++ list_del(&c->infos_list); ++ spin_unlock(&ubifs_infos_lock); ++out_orphans: ++ free_orphans(c); ++out_journal: ++ destroy_journal(c); ++out_lpt: ++ ubifs_lpt_free(c, 0); ++out_master: ++ kfree(c->mst_node); ++ kfree(c->rcvrd_mst_node); ++out_stop: ++ if (c->bgt) ++ kthread_stop(c->bgt); ++out_wbufs: ++ free_wbufs(c); ++out_cbuf: ++ kfree(c->cbuf); ++out_dereg: ++ dbg_failure_mode_deregistration(c); ++out_free: ++ vfree(c->ileb_buf); ++ vfree(c->sbuf); ++ kfree(c->bottom_up_buf); ++ UBIFS_DBG(vfree(c->dbg_buf)); ++ return err; ++} ++ ++/** ++ * ubifs_umount - un-mount UBIFS file-system. ++ * @c: UBIFS file-system description object ++ * ++ * Note, this function is called to free allocated resourced when un-mounting, ++ * as well as free resources when an error occurred while we were half way ++ * through mounting (error path cleanup function). So it has to make sure the ++ * resource was actually allocated before freeing it. ++ */ ++static void ubifs_umount(struct ubifs_info *c) ++{ ++ dbg_gen("un-mounting UBI device %d, volume %d", c->vi.ubi_num, ++ c->vi.vol_id); ++ ++ spin_lock(&ubifs_infos_lock); ++ list_del(&c->infos_list); ++ spin_unlock(&ubifs_infos_lock); ++ ++ if (c->bgt) ++ kthread_stop(c->bgt); ++ ++ destroy_journal(c); ++ free_wbufs(c); ++ free_orphans(c); ++ ubifs_lpt_free(c, 0); ++ ++ kfree(c->cbuf); ++ kfree(c->rcvrd_mst_node); ++ kfree(c->mst_node); ++ vfree(c->sbuf); ++ kfree(c->bottom_up_buf); ++ UBIFS_DBG(vfree(c->dbg_buf)); ++ vfree(c->ileb_buf); ++ dbg_failure_mode_deregistration(c); ++} ++ ++/** ++ * ubifs_remount_rw - re-mount in read-write mode. ++ * @c: UBIFS file-system description object ++ * ++ * UBIFS avoids allocating many unnecessary resources when mounted in read-only ++ * mode. This function allocates the needed resources and re-mounts UBIFS in ++ * read-write mode. ++ */ ++static int ubifs_remount_rw(struct ubifs_info *c) ++{ ++ int err, lnum; ++ ++ if (c->ro_media) ++ return -EINVAL; ++ ++ mutex_lock(&c->umount_mutex); ++ c->remounting_rw = 1; ++ ++ /* Check for enough free space */ ++ if (ubifs_calc_available(c) <= 0) { ++ ubifs_err("insufficient available space"); ++ err = -EINVAL; ++ goto out; ++ } ++ ++ if (c->old_leb_cnt != c->leb_cnt) { ++ struct ubifs_sb_node *sup; ++ ++ sup = ubifs_read_sb_node(c); ++ if (IS_ERR(sup)) { ++ err = PTR_ERR(sup); ++ goto out; ++ } ++ sup->leb_cnt = cpu_to_le32(c->leb_cnt); ++ err = ubifs_write_sb_node(c, sup); ++ if (err) ++ goto out; ++ } ++ ++ if (c->need_recovery) { ++ ubifs_msg("completing deferred recovery"); ++ err = ubifs_write_rcvrd_mst_node(c); ++ if (err) ++ goto out; ++ err = ubifs_recover_size(c); ++ if (err) ++ goto out; ++ err = ubifs_clean_lebs(c, c->sbuf); ++ if (err) ++ goto out; ++ err = ubifs_recover_inl_heads(c, c->sbuf); ++ if (err) ++ goto out; ++ } ++ ++ if (!(c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY))) { ++ c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY); ++ err = ubifs_write_master(c); ++ if (err) ++ goto out; ++ } ++ ++ c->ileb_buf = vmalloc(c->leb_size); ++ if (!c->ileb_buf) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ err = ubifs_lpt_init(c, 0, 1); ++ if (err) ++ goto out; ++ ++ err = alloc_wbufs(c); ++ if (err) ++ goto out; ++ ++ ubifs_create_buds_lists(c); ++ ++ /* Create background thread */ ++ c->bgt = kthread_create(ubifs_bg_thread, c, c->bgt_name); ++ if (!c->bgt) ++ c->bgt = ERR_PTR(-EINVAL); ++ if (IS_ERR(c->bgt)) { ++ err = PTR_ERR(c->bgt); ++ c->bgt = NULL; ++ ubifs_err("cannot spawn \"%s\", error %d", ++ c->bgt_name, err); ++ return err; ++ } ++ wake_up_process(c->bgt); ++ ++ c->orph_buf = vmalloc(c->leb_size); ++ if (!c->orph_buf) ++ return -ENOMEM; ++ ++ /* Check for enough log space */ ++ lnum = c->lhead_lnum + 1; ++ if (lnum >= UBIFS_LOG_LNUM + c->log_lebs) ++ lnum = UBIFS_LOG_LNUM; ++ if (lnum == c->ltail_lnum) { ++ err = ubifs_consolidate_log(c); ++ if (err) ++ goto out; ++ } ++ ++ if (c->need_recovery) ++ err = ubifs_rcvry_gc_commit(c); ++ else ++ err = take_gc_lnum(c); ++ if (err) ++ goto out; ++ ++ if (c->need_recovery) { ++ c->need_recovery = 0; ++ ubifs_msg("deferred recovery completed"); ++ } ++ ++ dbg_gen("re-mounted read-write"); ++ c->vfs_sb->s_flags &= ~MS_RDONLY; ++ c->remounting_rw = 0; ++ mutex_unlock(&c->umount_mutex); ++ return 0; ++ ++out: ++ vfree(c->orph_buf); ++ c->orph_buf = NULL; ++ if (c->bgt) { ++ kthread_stop(c->bgt); ++ c->bgt = NULL; ++ } ++ free_wbufs(c); ++ vfree(c->ileb_buf); ++ c->ileb_buf = NULL; ++ ubifs_lpt_free(c, 1); ++ c->remounting_rw = 0; ++ mutex_unlock(&c->umount_mutex); ++ return err; ++} ++ ++/** ++ * commit_on_unmount - commit the journal when un-mounting. ++ * @c: UBIFS file-system description object ++ * ++ * This function is called during un-mounting and it commits the journal unless ++ * the "fast unmount" mode is enabled. It also avoids committing the journal if ++ * it contains too few data. ++ * ++ * Sometimes recovery requires the journal to be committed at least once, and ++ * this function takes care about this. ++ */ ++static void commit_on_unmount(struct ubifs_info *c) ++{ ++ if (!c->fast_unmount) { ++ long long bud_bytes; ++ ++ spin_lock(&c->buds_lock); ++ bud_bytes = c->bud_bytes; ++ spin_unlock(&c->buds_lock); ++ if (bud_bytes > c->leb_size) ++ ubifs_run_commit(c); ++ } ++} ++ ++/** ++ * ubifs_remount_ro - re-mount in read-only mode. ++ * @c: UBIFS file-system description object ++ * ++ * We rely on VFS to have stopped writing. Possibly the background thread could ++ * be running a commit, however kthread_stop will wait in that case. ++ */ ++static void ubifs_remount_ro(struct ubifs_info *c) ++{ ++ int i, err; ++ ++ ubifs_assert(!c->need_recovery); ++ commit_on_unmount(c); ++ ++ mutex_lock(&c->umount_mutex); ++ if (c->bgt) { ++ kthread_stop(c->bgt); ++ c->bgt = NULL; ++ } ++ ++ for (i = 0; i < c->jhead_cnt; i++) { ++ ubifs_wbuf_sync(&c->jheads[i].wbuf); ++ del_timer_sync(&c->jheads[i].wbuf.timer); ++ } ++ ++ if (!c->ro_media) { ++ c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY); ++ c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS); ++ c->mst_node->gc_lnum = cpu_to_le32(c->gc_lnum); ++ err = ubifs_write_master(c); ++ if (err) ++ ubifs_ro_mode(c, err); ++ } ++ ++ ubifs_destroy_idx_gc(c); ++ free_wbufs(c); ++ vfree(c->orph_buf); ++ c->orph_buf = NULL; ++ vfree(c->ileb_buf); ++ c->ileb_buf = NULL; ++ ubifs_lpt_free(c, 1); ++ mutex_unlock(&c->umount_mutex); ++} ++ ++static void ubifs_put_super(struct super_block *sb) ++{ ++ int i; ++ struct ubifs_info *c = sb->s_fs_info; ++ ++ ubifs_msg("un-mount UBI device %d, volume %d", c->vi.ubi_num, ++ c->vi.vol_id); ++ /* ++ * The following asserts are only valid if there has not been a failure ++ * of the media. For example, there will be dirty inodes if we failed ++ * to write them back because of I/O errors. ++ */ ++ ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0); ++ ubifs_assert(atomic_long_read(&c->dirty_ino_cnt) == 0); ++ ubifs_assert(c->budg_idx_growth == 0); ++ ubifs_assert(c->budg_data_growth == 0); ++ ++ /* ++ * The 'c->umount_lock' prevents races between UBIFS memory shrinker ++ * and file system un-mount. Namely, it prevents the shrinker from ++ * picking this superblock for shrinking - it will be just skipped if ++ * the mutex is locked. ++ */ ++ mutex_lock(&c->umount_mutex); ++ if (!(c->vfs_sb->s_flags & MS_RDONLY)) { ++ /* ++ * First of all kill the background thread to make sure it does ++ * not interfere with un-mounting and freeing resources. ++ */ ++ if (c->bgt) { ++ kthread_stop(c->bgt); ++ c->bgt = NULL; ++ } ++ ++ /* Synchronize write-buffers */ ++ if (c->jheads) ++ for (i = 0; i < c->jhead_cnt; i++) { ++ ubifs_wbuf_sync(&c->jheads[i].wbuf); ++ del_timer_sync(&c->jheads[i].wbuf.timer); ++ } ++ ++ /* ++ * On fatal errors c->ro_media is set to 1, in which case we do ++ * not write the master node. ++ */ ++ if (!c->ro_media) { ++ /* ++ * We are being cleanly unmounted which means the ++ * orphans were killed - indicate this in the master ++ * node. Also save the reserved GC LEB number. ++ */ ++ int err; ++ ++ c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY); ++ c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS); ++ c->mst_node->gc_lnum = cpu_to_le32(c->gc_lnum); ++ err = ubifs_write_master(c); ++ if (err) ++ /* ++ * Recovery will attempt to fix the master area ++ * next mount, so we just print a message and ++ * continue to unmount normally. ++ */ ++ ubifs_err("failed to write master node, " ++ "error %d", err); ++ } ++ } ++ ++ ubifs_umount(c); ++ ubi_close_volume(c->ubi); ++ mutex_unlock(&c->umount_mutex); ++ kfree(c); ++} ++ ++static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data) ++{ ++ int err; ++ struct ubifs_info *c = sb->s_fs_info; ++ ++ dbg_gen("old flags %#lx, new flags %#x", sb->s_flags, *flags); ++ ++ err = ubifs_parse_options(c, data, 1); ++ if (err) { ++ ubifs_err("invalid or unknown remount parameter"); ++ return err; ++ } ++ if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) { ++ err = ubifs_remount_rw(c); ++ if (err) ++ return err; ++ } else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) ++ ubifs_remount_ro(c); ++ ++ return 0; ++} ++ ++struct super_operations ubifs_super_operations = { ++ .alloc_inode = ubifs_alloc_inode, ++ .destroy_inode = ubifs_destroy_inode, ++ .put_super = ubifs_put_super, ++ .write_inode = ubifs_write_inode, ++ .delete_inode = ubifs_delete_inode, ++ .statfs = ubifs_statfs, ++ .dirty_inode = ubifs_dirty_inode, ++ .remount_fs = ubifs_remount_fs, ++ .show_options = ubifs_show_options, ++ .sync_fs = ubifs_sync_fs, ++}; ++ ++/** ++ * open_ubi - parse UBI device name string and open the UBI device. ++ * @name: UBI volume name ++ * @mode: UBI volume open mode ++ * ++ * There are several ways to specify UBI volumes when mounting UBIFS: ++ * o ubiX_Y - UBI device number X, volume Y; ++ * o ubiY - UBI device number 0, volume Y; ++ * o ubiX:NAME - mount UBI device X, volume with name NAME; ++ * o ubi:NAME - mount UBI device 0, volume with name NAME. ++ * ++ * Alternative '!' separator may be used instead of ':' (because some shells ++ * like busybox may interpret ':' as an NFS host name separator). This function ++ * returns ubi volume object in case of success and a negative error code in ++ * case of failure. ++ */ ++static struct ubi_volume_desc *open_ubi(const char *name, int mode) ++{ ++ int dev, vol; ++ char *endptr; ++ ++ if (name[0] != 'u' || name[1] != 'b' || name[2] != 'i') ++ return ERR_PTR(-EINVAL); ++ ++ /* ubi:NAME method */ ++ if ((name[3] == ':' || name[3] == '!') && name[4] != '\0') ++ return ubi_open_volume_nm(0, name + 4, mode); ++ ++ if (!isdigit(name[3])) ++ return ERR_PTR(-EINVAL); ++ ++ dev = simple_strtoul(name + 3, &endptr, 0); ++ ++ /* ubiY method */ ++ if (*endptr == '\0') ++ return ubi_open_volume(0, dev, mode); ++ ++ /* ubiX_Y method */ ++ if (*endptr == '_' && isdigit(endptr[1])) { ++ vol = simple_strtoul(endptr + 1, &endptr, 0); ++ if (*endptr != '\0') ++ return ERR_PTR(-EINVAL); ++ return ubi_open_volume(dev, vol, mode); ++ } ++ ++ /* ubiX:NAME method */ ++ if ((*endptr == ':' || *endptr == '!') && endptr[1] != '\0') ++ return ubi_open_volume_nm(dev, ++endptr, mode); ++ ++ return ERR_PTR(-EINVAL); ++} ++ ++static int ubifs_fill_super(struct super_block *sb, void *data, int silent) ++{ ++ struct ubi_volume_desc *ubi = sb->s_fs_info; ++ struct ubifs_info *c; ++ struct inode *root; ++ int err; ++ ++ c = kzalloc(sizeof(struct ubifs_info), GFP_KERNEL); ++ if (!c) ++ return -ENOMEM; ++ ++ spin_lock_init(&c->cnt_lock); ++ spin_lock_init(&c->cs_lock); ++ spin_lock_init(&c->buds_lock); ++ spin_lock_init(&c->space_lock); ++ spin_lock_init(&c->orphan_lock); ++ init_rwsem(&c->commit_sem); ++ mutex_init(&c->lp_mutex); ++ mutex_init(&c->tnc_mutex); ++ mutex_init(&c->log_mutex); ++ mutex_init(&c->mst_mutex); ++ mutex_init(&c->umount_mutex); ++ init_waitqueue_head(&c->cmt_wq); ++ c->buds = RB_ROOT; ++ c->old_idx = RB_ROOT; ++ c->size_tree = RB_ROOT; ++ c->orph_tree = RB_ROOT; ++ INIT_LIST_HEAD(&c->infos_list); ++ INIT_LIST_HEAD(&c->idx_gc); ++ INIT_LIST_HEAD(&c->replay_list); ++ INIT_LIST_HEAD(&c->replay_buds); ++ INIT_LIST_HEAD(&c->uncat_list); ++ INIT_LIST_HEAD(&c->empty_list); ++ INIT_LIST_HEAD(&c->freeable_list); ++ INIT_LIST_HEAD(&c->frdi_idx_list); ++ INIT_LIST_HEAD(&c->unclean_leb_list); ++ INIT_LIST_HEAD(&c->old_buds); ++ INIT_LIST_HEAD(&c->orph_list); ++ INIT_LIST_HEAD(&c->orph_new); ++ ++ c->highest_inum = UBIFS_FIRST_INO; ++ get_random_bytes(&c->vfs_gen, sizeof(int)); ++ c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM; ++ ++ ubi_get_volume_info(ubi, &c->vi); ++ ubi_get_device_info(c->vi.ubi_num, &c->di); ++ ++ /* Re-open the UBI device in read-write mode */ ++ c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READWRITE); ++ if (IS_ERR(c->ubi)) { ++ err = PTR_ERR(c->ubi); ++ goto out_free; ++ } ++ ++ err = ubifs_parse_options(c, data, 0); ++ if (err) ++ goto out_close; ++ ++ c->vfs_sb = sb; ++ ++ sb->s_fs_info = c; ++ sb->s_magic = UBIFS_SUPER_MAGIC; ++ sb->s_blocksize = UBIFS_BLOCK_SIZE; ++ sb->s_blocksize_bits = UBIFS_BLOCK_SHIFT; ++ sb->s_dev = c->vi.cdev; ++ sb->s_maxbytes = c->max_inode_sz = key_max_inode_size(c); ++ if (c->max_inode_sz > MAX_LFS_FILESIZE) ++ sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE; ++ sb->s_op = &ubifs_super_operations; ++ ++ mutex_lock(&c->umount_mutex); ++ err = mount_ubifs(c); ++ if (err) { ++ ubifs_assert(err < 0); ++ goto out_unlock; ++ } ++ ++ /* Read the root inode */ ++ root = ubifs_iget(sb, UBIFS_ROOT_INO); ++ if (IS_ERR(root)) { ++ err = PTR_ERR(root); ++ goto out_umount; ++ } ++ ++ sb->s_root = d_alloc_root(root); ++ if (!sb->s_root) ++ goto out_iput; ++ ++ mutex_unlock(&c->umount_mutex); ++ ++ return 0; ++ ++out_iput: ++ iput(root); ++out_umount: ++ ubifs_umount(c); ++out_unlock: ++ mutex_unlock(&c->umount_mutex); ++out_close: ++ ubi_close_volume(c->ubi); ++out_free: ++ kfree(c); ++ return err; ++} ++ ++static int sb_test(struct super_block *sb, void *data) ++{ ++ dev_t *dev = data; ++ ++ return sb->s_dev == *dev; ++} ++ ++static int sb_set(struct super_block *sb, void *data) ++{ ++ dev_t *dev = data; ++ ++ sb->s_dev = *dev; ++ return 0; ++} ++ ++static int ubifs_get_sb(struct file_system_type *fs_type, int flags, ++ const char *name, void *data, struct vfsmount *mnt) ++{ ++ struct ubi_volume_desc *ubi; ++ struct ubi_volume_info vi; ++ struct super_block *sb; ++ int err; ++ ++ dbg_gen("name %s, flags %#x", name, flags); ++ ++ /* ++ * Get UBI device number and volume ID. Mount it read-only so far ++ * because this might be a new mount point, and UBI allows only one ++ * read-write user at a time. ++ */ ++ ubi = open_ubi(name, UBI_READONLY); ++ if (IS_ERR(ubi)) { ++ ubifs_err("cannot open \"%s\", error %d", ++ name, (int)PTR_ERR(ubi)); ++ return PTR_ERR(ubi); ++ } ++ ubi_get_volume_info(ubi, &vi); ++ ++ dbg_gen("opened ubi%d_%d", vi.ubi_num, vi.vol_id); ++ ++ sb = sget(fs_type, &sb_test, &sb_set, &vi.cdev); ++ if (IS_ERR(sb)) { ++ err = PTR_ERR(sb); ++ goto out_close; ++ } ++ ++ if (sb->s_root) { ++ /* A new mount point for already mounted UBIFS */ ++ dbg_gen("this ubi volume is already mounted"); ++ if ((flags ^ sb->s_flags) & MS_RDONLY) { ++ err = -EBUSY; ++ goto out_deact; ++ } ++ } else { ++ sb->s_flags = flags; ++ /* ++ * Pass 'ubi' to 'fill_super()' in sb->s_fs_info where it is ++ * replaced by 'c'. ++ */ ++ sb->s_fs_info = ubi; ++ err = ubifs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0); ++ if (err) ++ goto out_deact; ++ /* We do not support atime */ ++ sb->s_flags |= MS_ACTIVE | MS_NOATIME; ++ } ++ ++ /* 'fill_super()' opens ubi again so we must close it here */ ++ ubi_close_volume(ubi); ++ ++ return simple_set_mnt(mnt, sb); ++ ++out_deact: ++ up_write(&sb->s_umount); ++ deactivate_super(sb); ++out_close: ++ ubi_close_volume(ubi); ++ return err; ++} ++ ++static void ubifs_kill_sb(struct super_block *sb) ++{ ++ struct ubifs_info *c = sb->s_fs_info; ++ ++ /* ++ * We do 'commit_on_unmount()' here instead of 'ubifs_put_super()' ++ * in order to be outside BKL. ++ */ ++ if (sb->s_root && !(sb->s_flags & MS_RDONLY)) ++ commit_on_unmount(c); ++ /* The un-mount routine is actually done in put_super() */ ++ generic_shutdown_super(sb); ++} ++ ++static struct file_system_type ubifs_fs_type = { ++ .name = "ubifs", ++ .owner = THIS_MODULE, ++ .get_sb = ubifs_get_sb, ++ .kill_sb = ubifs_kill_sb ++}; ++ ++/* ++ * Inode slab cache constructor. ++ */ ++static void inode_slab_ctor(struct kmem_cache *cachep, void *obj) ++{ ++ struct ubifs_inode *inode = obj; ++ inode_init_once(&inode->vfs_inode); ++} ++ ++static int __init ubifs_init(void) ++{ ++ int err; ++ ++ BUILD_BUG_ON(sizeof(struct ubifs_ch) != 24); ++ ++ /* Make sure node sizes are 8-byte aligned */ ++ BUILD_BUG_ON(UBIFS_CH_SZ & 7); ++ BUILD_BUG_ON(UBIFS_INO_NODE_SZ & 7); ++ BUILD_BUG_ON(UBIFS_DENT_NODE_SZ & 7); ++ BUILD_BUG_ON(UBIFS_XENT_NODE_SZ & 7); ++ BUILD_BUG_ON(UBIFS_DATA_NODE_SZ & 7); ++ BUILD_BUG_ON(UBIFS_TRUN_NODE_SZ & 7); ++ BUILD_BUG_ON(UBIFS_SB_NODE_SZ & 7); ++ BUILD_BUG_ON(UBIFS_MST_NODE_SZ & 7); ++ BUILD_BUG_ON(UBIFS_REF_NODE_SZ & 7); ++ BUILD_BUG_ON(UBIFS_CS_NODE_SZ & 7); ++ BUILD_BUG_ON(UBIFS_ORPH_NODE_SZ & 7); ++ ++ BUILD_BUG_ON(UBIFS_MAX_DENT_NODE_SZ & 7); ++ BUILD_BUG_ON(UBIFS_MAX_XENT_NODE_SZ & 7); ++ BUILD_BUG_ON(UBIFS_MAX_DATA_NODE_SZ & 7); ++ BUILD_BUG_ON(UBIFS_MAX_INO_NODE_SZ & 7); ++ BUILD_BUG_ON(UBIFS_MAX_NODE_SZ & 7); ++ BUILD_BUG_ON(MIN_WRITE_SZ & 7); ++ ++ /* Check min. node size */ ++ BUILD_BUG_ON(UBIFS_INO_NODE_SZ < MIN_WRITE_SZ); ++ BUILD_BUG_ON(UBIFS_DENT_NODE_SZ < MIN_WRITE_SZ); ++ BUILD_BUG_ON(UBIFS_XENT_NODE_SZ < MIN_WRITE_SZ); ++ BUILD_BUG_ON(UBIFS_TRUN_NODE_SZ < MIN_WRITE_SZ); ++ ++ BUILD_BUG_ON(UBIFS_MAX_DENT_NODE_SZ > UBIFS_MAX_NODE_SZ); ++ BUILD_BUG_ON(UBIFS_MAX_XENT_NODE_SZ > UBIFS_MAX_NODE_SZ); ++ BUILD_BUG_ON(UBIFS_MAX_DATA_NODE_SZ > UBIFS_MAX_NODE_SZ); ++ BUILD_BUG_ON(UBIFS_MAX_INO_NODE_SZ > UBIFS_MAX_NODE_SZ); ++ ++ /* Defined node sizes */ ++ BUILD_BUG_ON(UBIFS_SB_NODE_SZ != 4096); ++ BUILD_BUG_ON(UBIFS_MST_NODE_SZ != 512); ++ BUILD_BUG_ON(UBIFS_INO_NODE_SZ != 160); ++ BUILD_BUG_ON(UBIFS_REF_NODE_SZ != 64); ++ ++ /* ++ * We require that PAGE_CACHE_SIZE is greater-than-or-equal-to ++ * UBIFS_BLOCK_SIZE. It is assumed that both are powers of 2. ++ */ ++ if (PAGE_CACHE_SIZE < UBIFS_BLOCK_SIZE) { ++ ubifs_err("VFS page cache size is %u bytes, but UBIFS requires" ++ " at least 4096 bytes", ++ (unsigned int)PAGE_CACHE_SIZE); ++ return -EINVAL; ++ } ++ ++ err = bdi_init(&ubifs_backing_dev_info); ++ if (err) ++ return err; ++ ++ err = register_filesystem(&ubifs_fs_type); ++ if (err) { ++ ubifs_err("cannot register file system, error %d", err); ++ goto out; ++ } ++ ++ err = -ENOMEM; ++ ubifs_inode_slab = kmem_cache_create("ubifs_inode_slab", ++ sizeof(struct ubifs_inode), 0, ++ SLAB_MEM_SPREAD | SLAB_RECLAIM_ACCOUNT, ++ &inode_slab_ctor); ++ if (!ubifs_inode_slab) ++ goto out_reg; ++ ++ register_shrinker(&ubifs_shrinker_info); ++ ++ err = ubifs_compressors_init(); ++ if (err) ++ goto out_compr; ++ ++ return 0; ++ ++out_compr: ++ unregister_shrinker(&ubifs_shrinker_info); ++ kmem_cache_destroy(ubifs_inode_slab); ++out_reg: ++ unregister_filesystem(&ubifs_fs_type); ++out: ++ bdi_destroy(&ubifs_backing_dev_info); ++ return err; ++} ++/* late_initcall to let compressors initialize first */ ++late_initcall(ubifs_init); ++ ++static void __exit ubifs_exit(void) ++{ ++ ubifs_assert(list_empty(&ubifs_infos)); ++ ubifs_assert(atomic_long_read(&ubifs_clean_zn_cnt) == 0); ++ ++ ubifs_compressors_exit(); ++ unregister_shrinker(&ubifs_shrinker_info); ++ kmem_cache_destroy(ubifs_inode_slab); ++ unregister_filesystem(&ubifs_fs_type); ++ bdi_destroy(&ubifs_backing_dev_info); ++} ++module_exit(ubifs_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(__stringify(UBIFS_VERSION)); ++MODULE_AUTHOR("Artem Bityutskiy, Adrian Hunter"); ++MODULE_DESCRIPTION("UBIFS - UBI File System"); +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/tnc.c avr32-2.6/fs/ubifs/tnc.c +--- linux-2.6.25.6/fs/ubifs/tnc.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/tnc.c 2008-06-12 15:09:45.600758286 +0200 +@@ -0,0 +1,2961 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Adrian Hunter ++ * Artem Bityutskiy (Битюцкий Артём) ++ */ ++ ++/* ++ * This file implements TNC (Tree Node Cache) which caches indexing nodes of ++ * the UBIFS B-tree. ++ * ++ * At the moment the locking rules of the TNC tree are quite simple and ++ * straightforward. We just have a mutex and lock it when we traverse the ++ * tree. If a znode is not in memory, we read it from flash while still having ++ * the mutex locked. ++ */ ++ ++#include <linux/crc32.h> ++#include "ubifs.h" ++ ++/* ++ * Returned codes of 'matches_name()' and 'fallible_matches_name()' functions. ++ * @NAME_LESS: name corresponding to the first argument is less than second ++ * @NAME_MATCHES: names match ++ * @NAME_GREATER: name corresponding to the second argument is greater than ++ * first ++ * @NOT_ON_MEDIA: node referred by zbranch does not exist on the media ++ * ++ * These constants were introduce to improve readability. ++ */ ++enum { ++ NAME_LESS = 0, ++ NAME_MATCHES = 1, ++ NAME_GREATER = 2, ++ NOT_ON_MEDIA = 3, ++}; ++ ++/** ++ * insert_old_idx - record an index node obsoleted since the last commit start. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number of obsoleted index node ++ * @offs: offset of obsoleted index node ++ * ++ * Returns %0 on success, and a negative error code on failure. ++ * ++ * For recovery, there must always be a complete intact version of the index on ++ * flash at all times. That is called the "old index". It is the index as at the ++ * time of the last successful commit. Many of the index nodes in the old index ++ * may be dirty, but they must not be erased until the next successful commit ++ * (at which point that index becomes the old index). ++ * ++ * That means that the garbage collection and the in-the-gaps method of ++ * committing must be able to determine if an index node is in the old index. ++ * Most of the old index nodes can be found by looking up the TNC using the ++ * 'lookup_znode()' function. However, some of the old index nodes may have ++ * been deleted from the current index or may have been changed so much that ++ * they cannot be easily found. In those cases, an entry is added to an RB-tree. ++ * That is what this function does. The RB-tree is ordered by LEB number and ++ * offset because they uniquely identify the old index node. ++ */ ++static int insert_old_idx(struct ubifs_info *c, int lnum, int offs) ++{ ++ struct ubifs_old_idx *old_idx, *o; ++ struct rb_node **p, *parent = NULL; ++ ++ old_idx = kmalloc(sizeof(struct ubifs_old_idx), GFP_NOFS); ++ if (unlikely(!old_idx)) ++ return -ENOMEM; ++ old_idx->lnum = lnum; ++ old_idx->offs = offs; ++ ++ p = &c->old_idx.rb_node; ++ while (*p) { ++ parent = *p; ++ o = rb_entry(parent, struct ubifs_old_idx, rb); ++ if (lnum < o->lnum) ++ p = &(*p)->rb_left; ++ else if (lnum > o->lnum) ++ p = &(*p)->rb_right; ++ else if (offs < o->offs) ++ p = &(*p)->rb_left; ++ else if (offs > o->offs) ++ p = &(*p)->rb_right; ++ else { ++ ubifs_err("old idx added twice!"); ++ kfree(old_idx); ++ return 0; ++ } ++ } ++ rb_link_node(&old_idx->rb, parent, p); ++ rb_insert_color(&old_idx->rb, &c->old_idx); ++ return 0; ++} ++ ++/** ++ * insert_old_idx_znode - record a znode obsoleted since last commit start. ++ * @c: UBIFS file-system description object ++ * @znode: znode of obsoleted index node ++ * ++ * Returns %0 on success, and a negative error code on failure. ++ */ ++int insert_old_idx_znode(struct ubifs_info *c, struct ubifs_znode *znode) ++{ ++ if (znode->parent) { ++ struct ubifs_zbranch *zbr; ++ ++ zbr = &znode->parent->zbranch[znode->iip]; ++ if (zbr->len) ++ return insert_old_idx(c, zbr->lnum, zbr->offs); ++ } else ++ if (c->zroot.len) ++ return insert_old_idx(c, c->zroot.lnum, ++ c->zroot.offs); ++ return 0; ++} ++ ++/** ++ * ins_clr_old_idx_znode - record a znode obsoleted since last commit start. ++ * @c: UBIFS file-system description object ++ * @znode: znode of obsoleted index node ++ * ++ * Returns %0 on success, and a negative error code on failure. ++ */ ++static int ins_clr_old_idx_znode(struct ubifs_info *c, ++ struct ubifs_znode *znode) ++{ ++ int err; ++ ++ if (znode->parent) { ++ struct ubifs_zbranch *zbr; ++ ++ zbr = &znode->parent->zbranch[znode->iip]; ++ if (zbr->len) { ++ err = insert_old_idx(c, zbr->lnum, zbr->offs); ++ if (err) ++ return err; ++ zbr->lnum = 0; ++ zbr->offs = 0; ++ zbr->len = 0; ++ } ++ } else ++ if (c->zroot.len) { ++ err = insert_old_idx(c, c->zroot.lnum, c->zroot.offs); ++ if (err) ++ return err; ++ c->zroot.lnum = 0; ++ c->zroot.offs = 0; ++ c->zroot.len = 0; ++ } ++ return 0; ++} ++ ++/** ++ * destroy_old_idx - destroy the old_idx RB-tree. ++ * @c: UBIFS file-system description object ++ * ++ * During start commit, the old_idx RB-tree is used to avoid overwriting index ++ * nodes that were in the index last commit but have since been deleted. This ++ * is necessary for recovery i.e. the old index must be kept intact until the ++ * new index is successfully written. The old-idx RB-tree is used for the ++ * in-the-gaps method of writing index nodes and is destroyed every commit. ++ */ ++void destroy_old_idx(struct ubifs_info *c) ++{ ++ struct rb_node *this = c->old_idx.rb_node; ++ struct ubifs_old_idx *old_idx; ++ ++ while (this) { ++ if (this->rb_left) { ++ this = this->rb_left; ++ continue; ++ } else if (this->rb_right) { ++ this = this->rb_right; ++ continue; ++ } ++ old_idx = rb_entry(this, struct ubifs_old_idx, rb); ++ this = rb_parent(this); ++ if (this) { ++ if (this->rb_left == &old_idx->rb) ++ this->rb_left = NULL; ++ else ++ this->rb_right = NULL; ++ } ++ kfree(old_idx); ++ } ++ c->old_idx = RB_ROOT; ++} ++ ++/** ++ * copy_znode - copy a dirty znode. ++ * @c: UBIFS file-system description object ++ * @znode: znode to copy ++ * ++ * A dirty znode being committed may not be changed, so it is copied. ++ */ ++static struct ubifs_znode *copy_znode(struct ubifs_info *c, ++ struct ubifs_znode *znode) ++{ ++ struct ubifs_znode *zn; ++ ++ zn = kmalloc(c->max_znode_sz, GFP_NOFS); ++ if (unlikely(!zn)) ++ return ERR_PTR(-ENOMEM); ++ ++ memcpy(zn, znode, c->max_znode_sz); ++ zn->cnext = NULL; ++ __set_bit(DIRTY_ZNODE, &zn->flags); ++ __clear_bit(COW_ZNODE, &zn->flags); ++ ++ ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags)); ++ __set_bit(OBSOLETE_ZNODE, &znode->flags); ++ ++ if (znode->level != 0) { ++ int i; ++ const int n = zn->child_cnt; ++ ++ /* The children now have new parent */ ++ for (i = 0; i < n; i++) { ++ struct ubifs_zbranch *zbr = &zn->zbranch[i]; ++ ++ if (zbr->znode) ++ zbr->znode->parent = zn; ++ } ++ } ++ ++ atomic_long_inc(&c->dirty_zn_cnt); ++ return zn; ++} ++ ++/** ++ * add_idx_dirt - add dirt due to a dirty znode. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number of index node ++ * @dirt: size of index node ++ * ++ * This function updates lprops dirty space and the new size of the index. ++ */ ++static int add_idx_dirt(struct ubifs_info *c, int lnum, int dirt) ++{ ++ c->calc_idx_sz -= ALIGN(dirt, 8); ++ return ubifs_add_dirt(c, lnum, dirt); ++} ++ ++/** ++ * dirty_cow_znode - ensure a znode is not being committed. ++ * @c: UBIFS file-system description object ++ * @zbr: branch of znode to check ++ * ++ * Returns dirtied znode on success or negative error code on failure. ++ */ ++static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c, ++ struct ubifs_zbranch *zbr) ++{ ++ struct ubifs_znode *znode = zbr->znode; ++ struct ubifs_znode *zn; ++ int err; ++ ++ if (!test_bit(COW_ZNODE, &znode->flags)) { ++ /* znode is not being committed */ ++ if (!test_and_set_bit(DIRTY_ZNODE, &znode->flags)) { ++ atomic_long_inc(&c->dirty_zn_cnt); ++ atomic_long_dec(&c->clean_zn_cnt); ++ atomic_long_dec(&ubifs_clean_zn_cnt); ++ err = add_idx_dirt(c, zbr->lnum, zbr->len); ++ if (unlikely(err)) ++ return ERR_PTR(err); ++ } ++ return znode; ++ } ++ ++ zn = copy_znode(c, znode); ++ if (unlikely(IS_ERR(zn))) ++ return zn; ++ ++ if (zbr->len) { ++ err = insert_old_idx(c, zbr->lnum, zbr->offs); ++ if (unlikely(err)) ++ return ERR_PTR(err); ++ err = add_idx_dirt(c, zbr->lnum, zbr->len); ++ } else ++ err = 0; ++ ++ zbr->znode = zn; ++ zbr->lnum = 0; ++ zbr->offs = 0; ++ zbr->len = 0; ++ ++ if (unlikely(err)) ++ return ERR_PTR(err); ++ return zn; ++} ++ ++/** ++ * lnc_add - add a leaf node to the leaf node cache. ++ * @c: UBIFS file-system description object ++ * @zbr: zbranch of leaf node ++ * @node: leaf node ++ * ++ * Leaf nodes are non-index nodes directory entry nodes or data nodes. The ++ * purpose of the leaf node cache is to save re-reading the same leaf node over ++ * and over again. Most things are cached by VFS, however the file system must ++ * cache directory entries for readdir and for resolving hash collisions. The ++ * present implementation of the leaf node cache is extremely simple, and ++ * allows for error returns that are not used but that may be needed if a more ++ * complex implementation is created. ++ * ++ * Note, this function does not add the @node object to LNC directly, but ++ * allocates a copy of the object and adds the copy to LNC. The reason for this ++ * is that @node has been allocated outside of the TNC subsystem and will be ++ * used with @c->tnc_mutex unlock upon return from the TNC subsystem. But LNC ++ * may be changed at any time, e.g. freed by the shrinker. ++ */ ++static int lnc_add(struct ubifs_info *c, struct ubifs_zbranch *zbr, ++ const void *node) ++{ ++ int err; ++ void *lnc_node; ++ const struct ubifs_dent_node *dent = node; ++ ++ ubifs_assert(!zbr->leaf); ++ ubifs_assert(zbr->len != 0); ++ ubifs_assert(is_hash_key(c, &zbr->key)); ++ ++ err = ubifs_validate_entry(c, dent); ++ if (err) { ++ dbg_dump_stack(); ++ dbg_dump_node(c, dent); ++ return err; ++ } ++ ++ lnc_node = kmalloc(zbr->len, GFP_NOFS); ++ if (!lnc_node) ++ /* We don't have to have the cache, so no error */ ++ return 0; ++ ++ memcpy(lnc_node, node, zbr->len); ++ zbr->leaf = lnc_node; ++ return 0; ++} ++ ++ /** ++ * lnc_add_directly - add a leaf node to the leaf-node-cache. ++ * @c: UBIFS file-system description object ++ * @zbr: zbranch of leaf node ++ * @node: leaf node ++ * ++ * This function is similar to 'lnc_add()', but it does not create a copy of ++ * @node but inserts @node to TNC directly. ++ */ ++static int lnc_add_directly(struct ubifs_info *c, struct ubifs_zbranch *zbr, ++ void *node) ++{ ++ int err; ++ ++ ubifs_assert(!zbr->leaf); ++ ubifs_assert(zbr->len != 0); ++ ++ err = ubifs_validate_entry(c, node); ++ if (err) { ++ dbg_dump_stack(); ++ dbg_dump_node(c, node); ++ return err; ++ } ++ ++ zbr->leaf = node; ++ return 0; ++} ++ ++/** ++ * lnc_free - remove a leaf node from the leaf node cache. ++ * @zbr: zbranch of leaf node ++ * @node: leaf node ++ */ ++static void lnc_free(struct ubifs_zbranch *zbr) ++{ ++ if (!zbr->leaf) ++ return; ++ kfree(zbr->leaf); ++ zbr->leaf = NULL; ++} ++ ++/** ++ * tnc_read_node_nm - read a "hashed" leaf node. ++ * @c: UBIFS file-system description object ++ * @zbr: key and position of the node ++ * @node: node is returned here ++ * ++ * This function reads a "hashed" node defined by @zbr from the leaf node cache ++ * (in it is there) or from the hash media, in which case the node is also ++ * added to LNC. Returns zero in case of success or a negative negative error ++ * code in case of failure. ++ */ ++static int tnc_read_node_nm(struct ubifs_info *c, struct ubifs_zbranch *zbr, ++ void *node) ++{ ++ int err; ++ ++ ubifs_assert(is_hash_key(c, &zbr->key)); ++ ++ if (zbr->leaf) { ++ /* Read from the leaf node cache */ ++ ubifs_assert(zbr->len != 0); ++ memcpy(node, zbr->leaf, zbr->len); ++ return 0; ++ } ++ ++ err = ubifs_tnc_read_node(c, zbr, node); ++ if (err) ++ return err; ++ ++ /* Add the node to the leaf node cache */ ++ err = lnc_add(c, zbr, node); ++ return err; ++} ++ ++/** ++ * try_read_node - read a node if it is a node. ++ * @c: UBIFS file-system description object ++ * @buf: buffer to read to ++ * @type: node type ++ * @len: node length (not aligned) ++ * @lnum: LEB number of node to read ++ * @offs: offset of node to read ++ * ++ * This function tries to read a node of known type and length, checks it and ++ * stores it in @buf. This function returns %1 if a node is present and %0 if ++ * a node is not present. A negative error code is returned for I/O errors. ++ * This function performs that same function as ubifs_read_node except that ++ * it does not require that there is actually a node present and instead ++ * the return code indicates if a node was read. ++ */ ++static int try_read_node(const struct ubifs_info *c, void *buf, int type, ++ int len, int lnum, int offs) ++{ ++ int err, node_len; ++ struct ubifs_ch *ch = buf; ++ uint32_t crc, node_crc; ++ ++ dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len); ++ ++ err = ubi_read(c->ubi, lnum, buf, offs, len); ++ if (err) { ++ ubifs_err("cannot read node type %d from LEB %d:%d, error %d", ++ type, lnum, offs, err); ++ return err; ++ } ++ ++ if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC) ++ return 0; ++ ++ if (ch->node_type != type) ++ return 0; ++ ++ node_len = le32_to_cpu(ch->len); ++ if (node_len != len) ++ return 0; ++ ++ crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8); ++ node_crc = le32_to_cpu(ch->crc); ++ if (crc != node_crc) ++ return 0; ++ ++ return 1; ++} ++ ++/** ++ * fallible_read_node - try to read a leaf node. ++ * @c: UBIFS file-system description object ++ * @key: key of node to read ++ * @zbr: position of node ++ * @node: node returned ++ * ++ * This function tries to read a node and returns %1 if the node is read, %0 ++ * if the node is not present, and a negative error code in the case of error. ++ */ ++static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key, ++ struct ubifs_zbranch *zbr, void *node) ++{ ++ int ret; ++ ++ dbg_tnc("LEB %d:%d, key %s", zbr->lnum, zbr->offs, DBGKEY(key)); ++ ++ ret = try_read_node(c, node, key_type(c, key), zbr->len, zbr->lnum, ++ zbr->offs); ++ if (ret == 1) { ++ union ubifs_key node_key; ++ struct ubifs_dent_node *dent = node; ++ ++ /* All nodes have key in the same place */ ++ key_read(c, &dent->key, &node_key); ++ if (keys_cmp(c, key, &node_key) != 0) ++ ret = 0; ++ } ++ if (ret == 0) ++ dbg_mnt("dangling branch LEB %d:%d len %d, key %s", ++ zbr->lnum, zbr->offs, zbr->len, DBGKEY(key)); ++ return ret; ++} ++ ++/** ++ * matches_name - determine if a directory or extended attribute entry matches ++ * a given name. ++ * @c: UBIFS file-system description object ++ * @zbr: zbranch of dent ++ * @nm: name to match ++ * ++ * This function checks if xentry/direntry referred by zbranch @zbr matches name ++ * @nm. Returns %NAME_MATCHES if it does, %NAME_LESS if the name referred by ++ * @zbr is less than @nm, and %NAME_GREATER if it is greater than @nm. In case ++ * of failure, a negative error code is returned. ++ */ ++static int matches_name(struct ubifs_info *c, struct ubifs_zbranch *zbr, ++ const struct qstr *nm) ++{ ++ struct ubifs_dent_node *dent; ++ int nlen, err; ++ ++ /* If possible, match against the dent in the leaf node cache */ ++ if (!zbr->leaf) { ++ dent = kmalloc(zbr->len, GFP_NOFS); ++ if (!dent) ++ return -ENOMEM; ++ ++ err = ubifs_tnc_read_node(c, zbr, dent); ++ if (err) ++ goto out_free; ++ ++ /* Add the node to the leaf node cache */ ++ err = lnc_add_directly(c, zbr, dent); ++ if (err) ++ goto out_free; ++ } else ++ dent = zbr->leaf; ++ ++ nlen = le16_to_cpu(dent->nlen); ++ err = memcmp(dent->name, nm->name, min_t(int, nlen, nm->len)); ++ if (err == 0) { ++ if (nlen == nm->len) ++ return NAME_MATCHES; ++ else if (nlen < nm->len) ++ return NAME_LESS; ++ else ++ return NAME_GREATER; ++ } else if (err < 0) ++ return NAME_LESS; ++ else ++ return NAME_GREATER; ++ ++out_free: ++ kfree(dent); ++ return err; ++} ++ ++/** ++ * get_znode - get a TNC znode that may not be loaded yet. ++ * @c: UBIFS file-system description object ++ * @znode: parent znode ++ * @n: znode branch slot number ++ * ++ * This function returns the znode or a negative error code. ++ */ ++static struct ubifs_znode *get_znode(struct ubifs_info *c, ++ struct ubifs_znode *znode, int n) ++{ ++ struct ubifs_zbranch *zbr; ++ ++ zbr = &znode->zbranch[n]; ++ if (zbr->znode) ++ znode = zbr->znode; ++ else ++ znode = ubifs_load_znode(c, zbr, znode, n); ++ return znode; ++} ++ ++/** ++ * tnc_next - find next TNC entry. ++ * @c: UBIFS file-system description object ++ * @zn: znode is passed and returned here ++ * @n: znode branch slot number is passed and returned here ++ * ++ * This function returns %0 if the next TNC entry is found, %-ENOENT if there is ++ * no next entry, or a negative error code otherwise. ++ */ ++static int tnc_next(struct ubifs_info *c, struct ubifs_znode **zn, int *n) ++{ ++ struct ubifs_znode *znode = *zn; ++ int nn = *n; ++ ++ nn += 1; ++ if (nn < znode->child_cnt) { ++ *n = nn; ++ return 0; ++ } ++ while (1) { ++ struct ubifs_znode *zp; ++ ++ zp = znode->parent; ++ if (!zp) ++ return -ENOENT; ++ nn = znode->iip + 1; ++ znode = zp; ++ if (nn < znode->child_cnt) { ++ znode = get_znode(c, znode, nn); ++ if (IS_ERR(znode)) ++ return PTR_ERR(znode); ++ while (znode->level != 0) { ++ znode = get_znode(c, znode, 0); ++ if (IS_ERR(znode)) ++ return PTR_ERR(znode); ++ } ++ nn = 0; ++ break; ++ } ++ } ++ *zn = znode; ++ *n = nn; ++ return 0; ++} ++ ++/** ++ * tnc_prev - find previous TNC entry. ++ * @c: UBIFS file-system description object ++ * @zn: znode is returned here ++ * @n: znode branch slot number is passed and returned here ++ * ++ * This function returns %0 if the previous TNC entry is found, %-ENOENT if ++ * there is no next entry, or a negative error code otherwise. ++ */ ++static int tnc_prev(struct ubifs_info *c, struct ubifs_znode **zn, int *n) ++{ ++ struct ubifs_znode *znode = *zn; ++ int nn = *n; ++ ++ if (nn > 0) { ++ *n = nn - 1; ++ return 0; ++ } ++ while (1) { ++ struct ubifs_znode *zp; ++ ++ zp = znode->parent; ++ if (!zp) ++ return -ENOENT; ++ nn = znode->iip - 1; ++ znode = zp; ++ if (nn >= 0) { ++ znode = get_znode(c, znode, nn); ++ if (IS_ERR(znode)) ++ return PTR_ERR(znode); ++ while (znode->level != 0) { ++ nn = znode->child_cnt - 1; ++ znode = get_znode(c, znode, nn); ++ if (IS_ERR(znode)) ++ return PTR_ERR(znode); ++ } ++ nn = znode->child_cnt - 1; ++ break; ++ } ++ } ++ *zn = znode; ++ *n = nn; ++ return 0; ++} ++ ++/** ++ * resolve_collision - resolve a collision. ++ * @c: UBIFS file-system description object ++ * @key: key of a directory or extended attribute entry ++ * @zn: znode is returned here ++ * @n: zbranch number is passed and returned here ++ * @nm: name of the entry ++ * ++ * This function is called for "hashed" keys to make sure that the found key ++ * really corresponds to the looked up node (directory or extended attribute ++ * entry). It returns %1 and sets @zn and @n if the collision is resolved. ++ * %0 is returned if @nm is not found and @zn and @n are set to the previous ++ * entry, i.e. to the entry after which @nm could follow if it were in TNC. ++ * This means that @n may be set to %-1 if the leftmost key in @zn is the ++ * previous one. A negative error code is returned on failures. ++ */ ++static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key, ++ struct ubifs_znode **zn, int *n, ++ const struct qstr *nm) ++{ ++ int err; ++ ++ err = matches_name(c, &(*zn)->zbranch[*n], nm); ++ if (unlikely(err < 0)) ++ return err; ++ if (err == NAME_MATCHES) ++ return 1; ++ ++ if (err == NAME_GREATER) { ++ /* Look left */ ++ while (1) { ++ err = tnc_prev(c, zn, n); ++ if (err == -ENOENT) { ++ ubifs_assert(*n == 0); ++ *n = -1; ++ return 0; ++ } ++ if (err < 0) ++ return err; ++ if (keys_cmp(c, &(*zn)->zbranch[*n].key, key)) { ++ /* ++ * We have found the branch after which we would ++ * like to insert, but inserting in this znode ++ * may still be wrong. Consider the following 3 ++ * znodes, in the case where we are resolving a ++ * collision with Key2. ++ * ++ * znode zp ++ * ---------------------- ++ * level 1 | Key0 | Key1 | ++ * ----------------------- ++ * | | ++ * znode za | | znode zb ++ * ------------ ------------ ++ * level 0 | Key0 | | Key2 | ++ * ------------ ------------ ++ * ++ * The lookup finds Key2 in znode zb. Lets say ++ * there is no match and the name is greater so ++ * we look left. When we find Key0, we end up ++ * here. If we return now, we will insert into ++ * znode za at slot n = 1. But that is invalid ++ * according to the parent's keys. Key2 must ++ * be inserted into znode zb. ++ * ++ * Note, this problem is not relevant for the ++ * case when we go right, because ++ * 'tnc_insert()' would correct the parent key. ++ */ ++ if (*n == (*zn)->child_cnt - 1) { ++ err = tnc_next(c, zn, n); ++ if (err) { ++ /* Should be impossible */ ++ ubifs_assert(0); ++ if (err == -ENOENT) ++ err = -EINVAL; ++ return err; ++ } ++ ubifs_assert(*n == 0); ++ *n = -1; ++ } ++ return 0; ++ } ++ err = matches_name(c, &(*zn)->zbranch[*n], nm); ++ if (err < 0) ++ return err; ++ if (err == NAME_LESS) ++ return 0; ++ if (err == NAME_MATCHES) ++ return 1; ++ ubifs_assert(err == NAME_GREATER); ++ } ++ } else { ++ int nn = *n; ++ struct ubifs_znode *znode = *zn; ++ ++ /* Look right */ ++ while (1) { ++ err = tnc_next(c, &znode, &nn); ++ if (err == -ENOENT) ++ return 0; ++ if (err < 0) ++ return err; ++ if (keys_cmp(c, &znode->zbranch[nn].key, key)) ++ return 0; ++ err = matches_name(c, &znode->zbranch[nn], nm); ++ if (err < 0) ++ return err; ++ if (err == NAME_GREATER) ++ return 0; ++ *zn = znode; ++ *n = nn; ++ if (err == NAME_MATCHES) ++ return 1; ++ ubifs_assert(err == NAME_LESS); ++ } ++ } ++} ++ ++/** ++ * fallible_matches_name - determine if a dent matches a given name. ++ * @c: UBIFS file-system description object ++ * @zbr: zbranch of dent ++ * @nm: name to match ++ * ++ * This is a "fallible" version of 'matches_name()' function which does not ++ * panic if the direntry/xentry referred by @zbr does not exist on the media. ++ * ++ * This function checks if xentry/direntry referred by zbranch @zbr matches name ++ * @nm. Returns %NAME_MATCHES it does, %NAME_LESS if the name referred by @zbr ++ * is less than @nm, %NAME_GREATER if it is greater than @nm, and @NOT_ON_MEDIA ++ * if xentry/direntry referred by @zbr does not exist on the media. A negative ++ * error code is returned in case of failure. ++ */ ++static int fallible_matches_name(struct ubifs_info *c, ++ struct ubifs_zbranch *zbr, ++ const struct qstr *nm) ++{ ++ struct ubifs_dent_node *dent; ++ int nlen, err; ++ ++ /* If possible, match against the dent in the leaf node cache */ ++ if (!zbr->leaf) { ++ dent = kmalloc(zbr->len, GFP_NOFS); ++ if (!dent) ++ return -ENOMEM; ++ ++ err = fallible_read_node(c, &zbr->key, zbr, dent); ++ if (err < 0) ++ goto out_free; ++ if (err == 0) { ++ /* The node was not present */ ++ err = NOT_ON_MEDIA; ++ goto out_free; ++ } ++ ubifs_assert(err == 1); ++ ++ err = lnc_add_directly(c, zbr, dent); ++ if (err) ++ goto out_free; ++ } else ++ dent = zbr->leaf; ++ ++ nlen = le16_to_cpu(dent->nlen); ++ err = memcmp(dent->name, nm->name, min_t(int, nlen, nm->len)); ++ if (err == 0) { ++ if (nlen == nm->len) ++ return NAME_MATCHES; ++ else if (nlen < nm->len) ++ return NAME_LESS; ++ else ++ return NAME_GREATER; ++ } else if (err < 0) ++ return NAME_LESS; ++ else ++ return NAME_GREATER; ++ ++out_free: ++ kfree(dent); ++ return err; ++} ++ ++/** ++ * fallible_resolve_collision - resolve a collision even if nodes are missing. ++ * @c: UBIFS file-system description object ++ * @key: key ++ * @zn: znode is returned here ++ * @n: branch number is passed and returned here ++ * @nm: name of directory entry ++ * @adding: indicates caller is adding a key to the TNC ++ * ++ * This is a "fallible" version of the 'resolve_collision()' function which ++ * does not panic if one of the nodes referred to by TNC does not exist on the ++ * media. This may happen when replaying the journal if a deleted node was ++ * Garbage-collected and the commit was not done. A branch that refers to a node ++ * that is not present is called a dangling branch. The following are the return ++ * codes for this function: ++ * o if @nm was found, %1 is returned and @zn and @n are set to the found ++ * branch; ++ * o if we are @adding and @nm was not found, %0 is returned; ++ * o if we are not @adding and @nm was not found, but a dangling branch was ++ * found, then %1 is returned and @zn and @n are set to the dangling branch; ++ * o a negative error code is returned in case of failure. ++ */ ++static int fallible_resolve_collision(struct ubifs_info *c, ++ const union ubifs_key *key, ++ struct ubifs_znode **zn, int *n, ++ const struct qstr *nm, int adding) ++{ ++ struct ubifs_znode *o_znode = NULL, *znode = *zn; ++ int uninitialized_var(o_n), err, cmp, unsure = 0, nn = *n; ++ ++ cmp = fallible_matches_name(c, &znode->zbranch[nn], nm); ++ if (unlikely(cmp < 0)) ++ return cmp; ++ if (cmp == NAME_MATCHES) ++ return 1; ++ if (cmp == NOT_ON_MEDIA) { ++ o_znode = znode; ++ o_n = nn; ++ /* ++ * We are unlucky and hit a dangling branch straight away. ++ * Now we do not really know where to go to find the needed ++ * branch - to the left or to the right. Well, let's try left. ++ */ ++ unsure = 1; ++ } else if (!adding) ++ unsure = 1; /* Remove a dangling branch wherever it is */ ++ ++ if (cmp == NAME_GREATER || unsure) { ++ /* Look left */ ++ while (1) { ++ err = tnc_prev(c, zn, n); ++ if (err == -ENOENT) { ++ ubifs_assert(*n == 0); ++ *n = -1; ++ break; ++ } ++ if (err < 0) ++ return err; ++ if (keys_cmp(c, &(*zn)->zbranch[*n].key, key)) { ++ /* See comments in 'resolve_collision()' */ ++ if (*n == (*zn)->child_cnt - 1) { ++ err = tnc_next(c, zn, n); ++ if (err) { ++ /* Should be impossible */ ++ ubifs_assert(0); ++ if (err == -ENOENT) ++ err = -EINVAL; ++ return err; ++ } ++ ubifs_assert(*n == 0); ++ *n = -1; ++ } ++ break; ++ } ++ err = fallible_matches_name(c, &(*zn)->zbranch[*n], nm); ++ if (err < 0) ++ return err; ++ if (err == NAME_MATCHES) ++ return 1; ++ if (err == NOT_ON_MEDIA) { ++ o_znode = *zn; ++ o_n = *n; ++ continue; ++ } ++ if (!adding) ++ continue; ++ if (err == NAME_LESS) ++ break; ++ else ++ unsure = 0; ++ } ++ } ++ ++ if (cmp == NAME_LESS || unsure) { ++ /* Look right */ ++ *zn = znode; ++ *n = nn; ++ while (1) { ++ err = tnc_next(c, &znode, &nn); ++ if (err == -ENOENT) ++ break; ++ if (err < 0) ++ return err; ++ if (keys_cmp(c, &znode->zbranch[nn].key, key)) ++ break; ++ err = fallible_matches_name(c, &znode->zbranch[nn], nm); ++ if (err < 0) ++ return err; ++ if (err == NAME_GREATER) ++ break; ++ *zn = znode; ++ *n = nn; ++ if (err == NAME_MATCHES) ++ return 1; ++ if (err == NOT_ON_MEDIA) { ++ o_znode = znode; ++ o_n = nn; ++ } ++ } ++ } ++ ++ /* Never match a dangling branch when adding */ ++ if (adding || !o_znode) ++ return 0; ++ ++ dbg_mnt("dangling match LEB %d:%d len %d %s", ++ o_znode->zbranch[o_n].lnum, o_znode->zbranch[o_n].offs, ++ o_znode->zbranch[o_n].len, DBGKEY(key)); ++ *zn = o_znode; ++ *n = o_n; ++ return 1; ++} ++ ++/** ++ * matches_position - determine if a zbranch matches a given position. ++ * @zbr: zbranch of dent ++ * @lnum: LEB number of dent to match ++ * @offs: offset of dent to match ++ * ++ * This function returns %1 if @lnum:@offs matches, and %0 otherwise. ++ */ ++static int matches_position(struct ubifs_zbranch *zbr, int lnum, int offs) ++{ ++ if (zbr->lnum == lnum && zbr->offs == offs) ++ return 1; ++ else ++ return 0; ++} ++ ++/** ++ * resolve_collision_directly - resolve a collision directly. ++ * @c: UBIFS file-system description object ++ * @key: key of directory entry ++ * @zn: znode is passed and returned here ++ * @n: zbranch number is passed and returned here ++ * @lnum: LEB number of dent node to match ++ * @offs: offset of dent node to match ++ * ++ * This function is used for "hashed" keys to make sure the found directory or ++ * extended attribute entry node is what was looked for. It is used when the ++ * flash address of the right node is known (@lnum:@offs) which makes it much ++ * easier to resolve collisions (no need to read entries and match full ++ * names). This function returns %1 and sets @zn and @n if the collision is ++ * resolved, %0 if @lnum:@offs is not found and @zn and @n are set to the ++ * previous directory entry. Otherwise a negative error code is returned. ++ */ ++static int resolve_collision_directly(struct ubifs_info *c, ++ const union ubifs_key *key, ++ struct ubifs_znode **zn, int *n, ++ int lnum, int offs) ++{ ++ struct ubifs_znode *znode; ++ int nn, err; ++ ++ znode = *zn; ++ nn = *n; ++ if (matches_position(&znode->zbranch[nn], lnum, offs)) ++ return 1; ++ ++ /* Look left */ ++ while (1) { ++ err = tnc_prev(c, &znode, &nn); ++ if (err == -ENOENT) ++ break; ++ if (err < 0) ++ return err; ++ if (keys_cmp(c, &znode->zbranch[nn].key, key)) ++ break; ++ if (matches_position(&znode->zbranch[nn], lnum, offs)) { ++ *zn = znode; ++ *n = nn; ++ return 1; ++ } ++ } ++ ++ /* Look right */ ++ znode = *zn; ++ nn = *n; ++ while (1) { ++ err = tnc_next(c, &znode, &nn); ++ if (err == -ENOENT) ++ return 0; ++ if (err < 0) ++ return err; ++ if (keys_cmp(c, &znode->zbranch[nn].key, key)) ++ return 0; ++ *zn = znode; ++ *n = nn; ++ if (matches_position(&znode->zbranch[nn], lnum, offs)) ++ return 1; ++ } ++} ++ ++/** ++ * dirty_cow_bottom_up - dirty a znode and its ancestors. ++ * @c: UBIFS file-system description object ++ * @znode: znode to dirty ++ * ++ * If we do not have a unique key that resides in a znode, then we cannot ++ * dirty that znode from the top down (i.e. by using lookup_level0_dirty) ++ * This function records the path back to the last dirty ancestor, and then ++ * dirties the znodes on that path. ++ */ ++static struct ubifs_znode *dirty_cow_bottom_up(struct ubifs_info *c, ++ struct ubifs_znode *znode) ++{ ++ struct ubifs_znode *zp; ++ int *path = c->bottom_up_buf, p = 0; ++ ++ ubifs_assert(c->zroot.znode); ++ ubifs_assert(znode); ++ if (c->zroot.znode->level > BOTTOM_UP_HEIGHT) { ++ kfree(c->bottom_up_buf); ++ c->bottom_up_buf = kmalloc(c->zroot.znode->level * sizeof(int), ++ GFP_NOFS); ++ if (!c->bottom_up_buf) ++ return ERR_PTR(-ENOMEM); ++ path = c->bottom_up_buf; ++ } ++ if (c->zroot.znode->level) { ++ /* Go up until parent is dirty */ ++ while (1) { ++ int n; ++ ++ zp = znode->parent; ++ if (!zp) ++ break; ++ n = znode->iip; ++ ubifs_assert(p < c->zroot.znode->level); ++ path[p++] = n; ++ if (!zp->cnext && ubifs_zn_dirty(znode)) ++ break; ++ znode = zp; ++ } ++ } ++ ++ /* Come back down, dirtying as we go */ ++ while (1) { ++ struct ubifs_zbranch *zbr; ++ ++ zp = znode->parent; ++ if (zp) { ++ ubifs_assert(path[p - 1] >= 0); ++ ubifs_assert(path[p - 1] < zp->child_cnt); ++ zbr = &zp->zbranch[path[--p]]; ++ znode = dirty_cow_znode(c, zbr); ++ } else { ++ ubifs_assert(znode == c->zroot.znode); ++ znode = dirty_cow_znode(c, &c->zroot); ++ } ++ if (unlikely(IS_ERR(znode)) || !p) ++ break; ++ ubifs_assert(path[p - 1] >= 0); ++ ubifs_assert(path[p - 1] < znode->child_cnt); ++ znode = znode->zbranch[path[p - 1]].znode; ++ } ++ ++ return znode; ++} ++ ++/** ++ * ubifs_lookup_level0 - search for zero-level znode. ++ * @c: UBIFS file-system description object ++ * @key: key to lookup ++ * @zn: znode is returned here ++ * @n: znode branch slot number is returned here ++ * ++ * This function looks up the TNC tree and search for zero-level znode which ++ * refers key @key. The found zero-level znode is returned in @zn. There are 3 ++ * cases: ++ * o exact match, i.e. the found zero-level znode contains key @key, then %1 ++ * is returned and slot number of the matched branch is stored in @n; ++ * o not exact match, which means that zero-level znode does not contain ++ * @key, then %0 is returned and slot number of the closed branch is stored ++ * in @n; ++ * o @key is so small that it is even less than the lowest key of the ++ * leftmost zero-level node, then %0 is returned and %0 is stored in @n. ++ * ++ * Note, when the TNC tree is traversed, some znodes may be absent, then this ++ * function reads corresponding indexing nodes and inserts them to TNC. In ++ * case of failure, a negative error code is returned. ++ */ ++int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key, ++ struct ubifs_znode **zn, int *n) ++{ ++ int err, exact; ++ struct ubifs_znode *znode; ++ unsigned long time = get_seconds(); ++ ++ dbg_tnc("search key %s", DBGKEY(key)); ++ ++ znode = c->zroot.znode; ++ if (unlikely(!znode)) { ++ znode = ubifs_load_znode(c, &c->zroot, NULL, 0); ++ if (IS_ERR(znode)) ++ return PTR_ERR(znode); ++ } ++ ++ znode->time = time; ++ ++ while (1) { ++ struct ubifs_zbranch *zbr; ++ ++ exact = ubifs_search_zbranch(c, znode, key, n); ++ ++ if (znode->level == 0) ++ break; ++ ++ if (*n < 0) ++ *n = 0; ++ zbr = &znode->zbranch[*n]; ++ ++ if (zbr->znode) { ++ znode->time = time; ++ znode = zbr->znode; ++ continue; ++ } ++ ++ /* znode is not in TNC cache, load it from the media */ ++ znode = ubifs_load_znode(c, zbr, znode, *n); ++ if (IS_ERR(znode)) ++ return PTR_ERR(znode); ++ } ++ ++ *zn = znode; ++ if (exact || !is_hash_key(c, key) || *n != -1) { ++ dbg_tnc("found %d, lvl %d, n %d", exact, znode->level, *n); ++ return exact; ++ } ++ ++ /* ++ * Here is a tricky place. We have not found the key and this is a ++ * "hashed" key, which may collide. The rest of the code deals with ++ * situations like this: ++ * ++ * | 3 | 5 | ++ * / \ ++ * | 3 | 5 | | 6 | 7 | (x) ++ * ++ * Or more a complex example: ++ * ++ * | 1 | 5 | ++ * / \ ++ * | 1 | 3 | | 5 | 8 | ++ * \ / ++ * | 5 | 5 | | 6 | 7 | (x) ++ * ++ * In the examples, if we are looking for key "5", we may reach nodes ++ * marked with "(x)". In this case what we have do is to look at the ++ * left and see if there is "5" key there. If there is, we have to ++ * return it. ++ * ++ * Note, this whole situation is possible because we allow to have ++ * elements which are equivalent to the next key in the parent in the ++ * children of current znode. For example, this happens if we split a ++ * znode like this: | 3 | 5 | 5 | 6 | 7 |, which results in something ++ * like this: ++ * | 3 | 5 | ++ * / \ ++ * | 3 | 5 | | 5 | 6 | 7 | ++ * ^ ++ * And this becomes what is at the first "picture" after key "5" marked ++ * with "^" is removed. What could be done is we could prohibit ++ * splitting in the middle of the colliding sequence. Also, when ++ * removing the leftmost key, we would have to correct the key of the ++ * parent node, which would introduce additional complications. Namely, ++ * if we changed the the leftmost key of the parent znode, the garbage ++ * collector would be unable to find it (GC is doing this when GC'ing ++ * indexing LEBs). Although we already have an additional RB-tree where ++ * we save such changed znodes (see 'ins_clr_old_idx_znode()') until ++ * after the commit. But anyway, this does not look easy to implement ++ * so we did not try this. ++ */ ++ err = tnc_prev(c, &znode, n); ++ if (err == -ENOENT) { ++ dbg_tnc("found 0, lvl %d, n -1", znode->level); ++ *n = -1; ++ return 0; ++ } ++ if (unlikely(err < 0)) ++ return err; ++ if (keys_cmp(c, key, &znode->zbranch[*n].key)) { ++ dbg_tnc("found 0, lvl %d, n -1", znode->level); ++ *n = -1; ++ return 0; ++ } ++ ++ dbg_tnc("found 1, lvl %d, n %d", znode->level, *n); ++ *zn = znode; ++ return 1; ++} ++ ++/** ++ * lookup_level0_dirty - search for zero-level znode dirtying. ++ * @c: UBIFS file-system description object ++ * @key: key to lookup ++ * @zn: znode is returned here ++ * @n: znode branch slot number is returned here ++ * ++ * This function looks up the TNC tree and search for zero-level znode which ++ * refers key @key. The found zero-level znode is returned in @zn. There are 3 ++ * cases: ++ * o exact match, i.e. the found zero-level znode contains key @key, then %1 ++ * is returned and slot number of the matched branch is stored in @n; ++ * o not exact match, which means that zero-level znode does not contain @key ++ * then %0 is returned and slot number of the closed branch is stored in ++ * @n; ++ * o @key is so small that it is even less than the lowest key of the ++ * leftmost zero-level node, then %0 is returned and %-1 is stored in @n. ++ * ++ * Additionally all znodes in the path from the root to the located zero-level ++ * znode are marked as dirty. ++ * ++ * Note, when the TNC tree is traversed, some znodes may be absent, then this ++ * function reads corresponding indexing nodes and inserts them to TNC. In ++ * case of failure, a negative error code is returned. ++ */ ++static int lookup_level0_dirty(struct ubifs_info *c, const union ubifs_key *key, ++ struct ubifs_znode **zn, int *n) ++{ ++ int err, exact; ++ struct ubifs_znode *znode; ++ unsigned long time = get_seconds(); ++ ++ dbg_tnc("search and dirty key %s", DBGKEY(key)); ++ ++ znode = c->zroot.znode; ++ if (unlikely(!znode)) { ++ znode = ubifs_load_znode(c, &c->zroot, NULL, 0); ++ if (IS_ERR(znode)) ++ return PTR_ERR(znode); ++ } ++ ++ znode = dirty_cow_znode(c, &c->zroot); ++ if (IS_ERR(znode)) ++ return PTR_ERR(znode); ++ ++ znode->time = time; ++ ++ while (1) { ++ struct ubifs_zbranch *zbr; ++ ++ exact = ubifs_search_zbranch(c, znode, key, n); ++ ++ if (znode->level == 0) ++ break; ++ ++ if (*n < 0) ++ *n = 0; ++ zbr = &znode->zbranch[*n]; ++ ++ if (zbr->znode) { ++ znode->time = time; ++ znode = dirty_cow_znode(c, zbr); ++ if (IS_ERR(znode)) ++ return PTR_ERR(znode); ++ continue; ++ } ++ ++ /* znode is not in TNC cache, load it from the media */ ++ znode = ubifs_load_znode(c, zbr, znode, *n); ++ if (IS_ERR(znode)) ++ return PTR_ERR(znode); ++ znode = dirty_cow_znode(c, zbr); ++ if (IS_ERR(znode)) ++ return PTR_ERR(znode); ++ } ++ ++ *zn = znode; ++ if (exact || !is_hash_key(c, key) || *n != -1) { ++ dbg_tnc("found %d, lvl %d, n %d", exact, znode->level, *n); ++ return exact; ++ } ++ ++ /* ++ * See huge comment at 'lookup_level0_dirty()' what is the rest of the ++ * code. ++ */ ++ err = tnc_prev(c, &znode, n); ++ if (err == -ENOENT) { ++ *n = -1; ++ dbg_tnc("found 0, lvl %d, n -1", znode->level); ++ return 0; ++ } ++ if (unlikely(err < 0)) ++ return err; ++ if (keys_cmp(c, key, &znode->zbranch[*n].key)) { ++ *n = -1; ++ dbg_tnc("found 0, lvl %d, n -1", znode->level); ++ return 0; ++ } ++ ++ if (znode->cnext || !ubifs_zn_dirty(znode)) { ++ znode = dirty_cow_bottom_up(c, znode); ++ if (IS_ERR(znode)) ++ return PTR_ERR(znode); ++ } ++ ++ dbg_tnc("found 1, lvl %d, n %d", znode->level, *n); ++ *zn = znode; ++ return 1; ++} ++ ++/** ++ * ubifs_tnc_lookup - look up a file-system node. ++ * @c: UBIFS file-system description object ++ * @key: node key to lookup ++ * @node: the node is returned here ++ * ++ * This function look up and reads node with key @key. The caller has to make ++ * sure the @node buffer is large enough to fit the node. Returns zero in case ++ * of success, %-ENOENT if the node was not found, and a negative error code in ++ * case of failure. ++ */ ++int ubifs_tnc_lookup(struct ubifs_info *c, const union ubifs_key *key, ++ void *node) ++{ ++ int found, n, err; ++ struct ubifs_znode *znode; ++ struct ubifs_zbranch zbr, *zt; ++ ++ mutex_lock(&c->tnc_mutex); ++ found = ubifs_lookup_level0(c, key, &znode, &n); ++ if (!found) { ++ err = -ENOENT; ++ goto out; ++ } else if (found < 0) { ++ err = found; ++ goto out; ++ } ++ zt = &znode->zbranch[n]; ++ if (is_hash_key(c, key)) { ++ /* ++ * In this case the leaf node cache gets used, so we pass the ++ * address of the zbranch and keep the mutex locked ++ */ ++ err = tnc_read_node_nm(c, zt, node); ++ goto out; ++ } ++ zbr = znode->zbranch[n]; ++ mutex_unlock(&c->tnc_mutex); ++ ++ err = ubifs_tnc_read_node(c, &zbr, node); ++ return err; ++ ++out: ++ mutex_unlock(&c->tnc_mutex); ++ return err; ++} ++ ++/** ++ * ubifs_tnc_locate - look up a file-system node and return it and its location. ++ * @c: UBIFS file-system description object ++ * @key: node key to lookup ++ * @node: the node is returned here ++ * @lnum: LEB number is returned here ++ * @offs: offset is returned here ++ * ++ * This function is the same as 'ubifs_tnc_lookup()' but it returns the node ++ * location also. See 'ubifs_tnc_lookup()'. ++ */ ++int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key, ++ void *node, int *lnum, int *offs) ++{ ++ int found, n, err; ++ struct ubifs_znode *znode; ++ struct ubifs_zbranch zbr, *zt; ++ ++ mutex_lock(&c->tnc_mutex); ++ found = ubifs_lookup_level0(c, key, &znode, &n); ++ if (!found) { ++ err = -ENOENT; ++ goto out; ++ } else if (found < 0) { ++ err = found; ++ goto out; ++ } ++ zt = &znode->zbranch[n]; ++ if (is_hash_key(c, key)) { ++ /* ++ * In this case the leaf node cache gets used, so we pass the ++ * address of the zbranch and keep the mutex locked ++ */ ++ *lnum = zt->lnum; ++ *offs = zt->offs; ++ err = tnc_read_node_nm(c, zt, node); ++ goto out; ++ } ++ zbr = znode->zbranch[n]; ++ mutex_unlock(&c->tnc_mutex); ++ ++ *lnum = zbr.lnum; ++ *offs = zbr.offs; ++ ++ err = ubifs_tnc_read_node(c, &zbr, node); ++ return err; ++ ++out: ++ mutex_unlock(&c->tnc_mutex); ++ return err; ++} ++ ++/** ++ * do_lookup_nm- look up a "hashed" node. ++ * directory entry file-system node. ++ * @c: UBIFS file-system description object ++ * @key: node key to lookup ++ * @node: the node is returned here ++ * @nm: node name ++ * ++ * This function look up and reads a node which contains name hash in the key. ++ * Since the hash may have collisions, there may be many nodes with the same ++ * key, so we have to sequentially look to all of them until the needed one is ++ * found. This function returns zero in case of success, %-ENOENT if the node ++ * was not found, and a negative error code in case of failure. ++ */ ++static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, ++ void *node, const struct qstr *nm) ++{ ++ int found, n, err; ++ struct ubifs_znode *znode; ++ struct ubifs_zbranch zbr; ++ ++ dbg_tnc("name '%.*s' key %s", nm->len, nm->name, DBGKEY(key)); ++ mutex_lock(&c->tnc_mutex); ++ found = ubifs_lookup_level0(c, key, &znode, &n); ++ if (!found) { ++ err = -ENOENT; ++ goto out_unlock; ++ } else if (found < 0) { ++ err = found; ++ goto out_unlock; ++ } ++ ++ ubifs_assert(n >= 0); ++ ++ err = resolve_collision(c, key, &znode, &n, nm); ++ dbg_tnc("rc returned %d, znode %p, n %d", err, znode, n); ++ if (unlikely(err < 0)) ++ goto out_unlock; ++ if (err == 0) { ++ err = -ENOENT; ++ goto out_unlock; ++ } ++ ++ zbr = znode->zbranch[n]; ++ mutex_unlock(&c->tnc_mutex); ++ ++ err = tnc_read_node_nm(c, &zbr, node); ++ return err; ++ ++out_unlock: ++ mutex_unlock(&c->tnc_mutex); ++ return err; ++} ++ ++/** ++ * ubifs_tnc_lookup_nm- look up a "hashed" node. ++ * directory entry file-system node. ++ * @c: UBIFS file-system description object ++ * @key: node key to lookup ++ * @node: the node is returned here ++ * @nm: node name ++ * ++ * This function look up and reads a node which contains name hash in the key. ++ * Since the hash may have collisions, there may be many nodes with the same ++ * key, so we have to sequentially look to all of them until the needed one is ++ * found. This function returns zero in case of success, %-ENOENT if the node ++ * was not found, and a negative error code in case of failure. ++ */ ++int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, ++ void *node, const struct qstr *nm) ++{ ++ int err, len; ++ const struct ubifs_dent_node *dent = node; ++ ++ /* ++ * We assume that in most of the cases there are no name collisions and ++ * 'ubifs_tnc_lookup()' returns us the right direntry. ++ */ ++ err = ubifs_tnc_lookup(c, key, node); ++ if (err) ++ return err; ++ ++ len = le16_to_cpu(dent->nlen); ++ if (nm->len == len && !memcmp(dent->name, nm->name, len)) ++ return 0; ++ ++ /* ++ * Unluckily, there are hash collisions and we have to iterate over ++ * them look at each direntry with colliding name hash sequentially. ++ */ ++ return do_lookup_nm(c, key, node, nm); ++} ++ ++/** ++ * correct_parent_keys - correct parent znodes' keys. ++ * @c: UBIFS file-system description object ++ * @znode: znode to correct parent znodes for ++ * ++ * This is a helper function for 'tnc_insert()'. When the key of the leftmost ++ * zbranch changes, keys of parent znodes have to be corrected. This helper ++ * function is called in such situations and corrects the keys if needed. ++ */ ++static void correct_parent_keys(const struct ubifs_info *c, ++ struct ubifs_znode *znode) ++{ ++ union ubifs_key *key, *key1; ++ ++ ubifs_assert(znode->parent); ++ ubifs_assert(znode->iip == 0); ++ ++ key = &znode->zbranch[0].key; ++ key1 = &znode->parent->zbranch[0].key; ++ ++ while (keys_cmp(c, key, key1) < 0) { ++ key_copy(c, key, key1); ++ znode = znode->parent; ++ if (!znode->parent || znode->iip) ++ break; ++ key1 = &znode->parent->zbranch[0].key; ++ } ++} ++ ++/** ++ * insert_zbranch - insert a zbranch into a znode. ++ * @znode: znode into which to insert ++ * @zbr: zbranch to insert ++ * @n: slot number to insert to ++ * ++ * This is a helper function for 'tnc_insert()'. UBIFS does not allow "gaps" in ++ * znode's array of zbranches and keeps zbranches consolidated, so when a new ++ * zbranch has to be inserted to the @znode->zbranches[]' array at the @n-th ++ * slot, zbranches starting from @n have to be moved right. ++ */ ++static void insert_zbranch(struct ubifs_znode *znode, ++ const struct ubifs_zbranch *zbr, int n) ++{ ++ int i; ++ ++ ubifs_assert(ubifs_zn_dirty(znode)); ++ ++ if (znode->level) { ++ for (i = znode->child_cnt; i > n; i--) { ++ znode->zbranch[i] = znode->zbranch[i - 1]; ++ if (znode->zbranch[i].znode) ++ znode->zbranch[i].znode->iip = i; ++ } ++ if (zbr->znode) ++ zbr->znode->iip = n; ++ } else ++ for (i = znode->child_cnt; i > n; i--) ++ znode->zbranch[i] = znode->zbranch[i - 1]; ++ ++ znode->zbranch[n] = *zbr; ++ znode->child_cnt += 1; ++ ++ /* ++ * After inserting at slot zero, the lower bound of the key range of ++ * this znode may have changed. If this znode is subsequently split ++ * then the upper bound of the key range may change, and furthermore ++ * it could change to be lower than the original lower bound. If that ++ * happens, then it will no longer be possible to find this znode in the ++ * TNC using the key from the index node on flash. That is bad because ++ * if it is not found, we will assume it is obsolete and may overwrite ++ * it. Then if there is an unclean unmount, we will start using the ++ * old index which will be broken. ++ * ++ * So we first mark znodes that have insertions at slot zero, and then ++ * if they are split we add their lnum/offs to the old_idx tree. ++ */ ++ if (n == 0) ++ znode->alt = 1; ++} ++ ++/** ++ * tnc_insert - insert a node into TNC. ++ * @c: UBIFS file-system description object ++ * @znode: znode to insert into ++ * @zbr: branch to insert ++ * @n: slot number to insert new zbranch to ++ * ++ * This function inserts a new node described by @zbr into znode @znode. If ++ * znode does not have a free slot for new zbranch, it is split. Parent znodes ++ * are splat as well if needed. Returns zero in case of success or a negative ++ * error code in case of failure. ++ */ ++static int tnc_insert(struct ubifs_info *c, struct ubifs_znode *znode, ++ struct ubifs_zbranch *zbr, int n) ++{ ++ struct ubifs_znode *zn, *zi, *zp; ++ int i, keep, move, appending = 0; ++ union ubifs_key *key = &zbr->key; ++ ++ ubifs_assert(n >= 0 && n <= c->fanout); ++ ++ /* Implement naive insert for now */ ++again: ++ zp = znode->parent; ++ if (znode->child_cnt < c->fanout) { ++ ubifs_assert(n != c->fanout); ++ dbg_tnc("inserted at %d level %d, key %s", n, znode->level, ++ DBGKEY(key)); ++ ++ insert_zbranch(znode, zbr, n); ++ ++ /* Ensure parent's key is correct */ ++ if (n == 0 && zp && znode->iip == 0) ++ correct_parent_keys(c, znode); ++ ++ return 0; ++ } ++ ++ /* ++ * Unfortunately, @znode does not have more empty slots and we have to ++ * split it. ++ */ ++ dbg_tnc("splitting level %d, key %s", znode->level, DBGKEY(key)); ++ ++ if (znode->alt) ++ /* ++ * We can no longer be sure of finding this znode by key, so we ++ * record it in the old_idx tree. ++ */ ++ ins_clr_old_idx_znode(c, znode); ++ ++ zn = kzalloc(c->max_znode_sz, GFP_NOFS); ++ if (!zn) ++ return -ENOMEM; ++ zn->parent = zp; ++ zn->level = znode->level; ++ ++ /* Decide where to split */ ++ if (znode->level == 0 && n == c->fanout && ++ key_type(c, key) == UBIFS_DATA_KEY) { ++ union ubifs_key *key1; ++ ++ /* ++ * If this is an inode which is being appended - do not split ++ * it because no other zbranches can be inserted between ++ * zbranches of consecutive data nodes anyway. ++ */ ++ key1 = &znode->zbranch[n - 1].key; ++ if (key_inum(c, key1) == key_inum(c, key) && ++ key_type(c, key1) == UBIFS_DATA_KEY && ++ key_block(c, key1) == key_block(c, key) - 1) ++ appending = 1; ++ } ++ ++ if (appending) { ++ keep = c->fanout; ++ move = 0; ++ } else { ++ keep = (c->fanout + 1) / 2; ++ move = c->fanout - keep; ++ } ++ ++ /* ++ * Although we don't at present, we could look at the neighbors and see ++ * if we can move some zbranches there. ++ */ ++ ++ if (n < keep) { ++ /* Insert into existing znode */ ++ zi = znode; ++ move += 1; ++ keep -= 1; ++ } else { ++ /* Insert into new znode */ ++ zi = zn; ++ n -= keep; ++ /* Re-parent */ ++ if (zn->level != 0) ++ zbr->znode->parent = zn; ++ } ++ ++ __set_bit(DIRTY_ZNODE, &zn->flags); ++ atomic_long_inc(&c->dirty_zn_cnt); ++ ++ zn->child_cnt = move; ++ znode->child_cnt = keep; ++ ++ dbg_tnc("moving %d, keeping %d", move, keep); ++ ++ /* Move zbranch */ ++ for (i = 0; i < move; i++) { ++ zn->zbranch[i] = znode->zbranch[keep + i]; ++ /* Re-parent */ ++ if (zn->level != 0) ++ if (zn->zbranch[i].znode) { ++ zn->zbranch[i].znode->parent = zn; ++ zn->zbranch[i].znode->iip = i; ++ } ++ } ++ ++ /* Insert new key and branch */ ++ dbg_tnc("inserting at %d level %d, key %s", n, zn->level, DBGKEY(key)); ++ ++ insert_zbranch(zi, zbr, n); ++ ++ /* Insert new znode (produced by spitting) into the parent */ ++ if (zp) { ++ i = n; ++ /* Locate insertion point */ ++ n = znode->iip + 1; ++ if (appending && n != c->fanout) ++ appending = 0; ++ ++ if (i == 0 && zi == znode && znode->iip == 0) ++ correct_parent_keys(c, znode); ++ ++ /* Tail recursion */ ++ zbr->key = zn->zbranch[0].key; ++ zbr->znode = zn; ++ zbr->lnum = 0; ++ zbr->offs = 0; ++ zbr->len = 0; ++ znode = zp; ++ ++ goto again; ++ } ++ ++ /* We have to split root znode */ ++ dbg_tnc("creating new zroot at level %d", znode->level + 1); ++ ++ zi = kzalloc(c->max_znode_sz, GFP_NOFS); ++ if (!zi) ++ return -ENOMEM; ++ ++ zi->child_cnt = 2; ++ zi->level = znode->level + 1; ++ ++ __set_bit(DIRTY_ZNODE, &zi->flags); ++ atomic_long_inc(&c->dirty_zn_cnt); ++ ++ zi->zbranch[0].key = znode->zbranch[0].key; ++ zi->zbranch[0].znode = znode; ++ zi->zbranch[0].lnum = c->zroot.lnum; ++ zi->zbranch[0].offs = c->zroot.offs; ++ zi->zbranch[0].len = c->zroot.len; ++ zi->zbranch[1].key = zn->zbranch[0].key; ++ zi->zbranch[1].znode = zn; ++ ++ c->zroot.lnum = 0; ++ c->zroot.offs = 0; ++ c->zroot.len = 0; ++ c->zroot.znode = zi; ++ ++ zn->parent = zi; ++ zn->iip = 1; ++ znode->parent = zi; ++ znode->iip = 0; ++ ++ return 0; ++} ++ ++/** ++ * ubifs_tnc_add - add a node to TNC. ++ * @c: UBIFS file-system description object ++ * @key: key to add ++ * @lnum: LEB number of node ++ * @offs: node offset ++ * @len: node length ++ * ++ * This function adds a node with key @key to TNC. The node may be new or it may ++ * obsolete some existing one. Returns %0 on success or negative error code on ++ * failure. ++ */ ++int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum, ++ int offs, int len) ++{ ++ int found, n, err = 0; ++ struct ubifs_znode *znode; ++ ++ mutex_lock(&c->tnc_mutex); ++ dbg_tnc("%d:%d, len %d, key %s", lnum, offs, len, DBGKEY(key)); ++ found = lookup_level0_dirty(c, key, &znode, &n); ++ if (!found) { ++ struct ubifs_zbranch zbr; ++ ++ zbr.znode = NULL; ++ zbr.lnum = lnum; ++ zbr.offs = offs; ++ zbr.len = len; ++ key_copy(c, key, &zbr.key); ++ err = tnc_insert(c, znode, &zbr, n + 1); ++ } else if (found == 1) { ++ struct ubifs_zbranch *zbr = &znode->zbranch[n]; ++ ++ lnc_free(zbr); ++ err = ubifs_add_dirt(c, zbr->lnum, zbr->len); ++ zbr->lnum = lnum; ++ zbr->offs = offs; ++ zbr->len = len; ++ } else ++ err = found; ++ if (!err) ++ err = dbg_check_tnc(c, 0); ++ mutex_unlock(&c->tnc_mutex); ++ ++ return err; ++} ++ ++/** ++ * ubifs_tnc_replace - replace a node in the TNC only if the old node is found. ++ * @c: UBIFS file-system description object ++ * @key: key to add ++ * @old_lnum: LEB number of old node ++ * @old_offs: old node offset ++ * @lnum: LEB number of node ++ * @offs: node offset ++ * @len: node length ++ * ++ * This function replaces a node with key @key in the TNC only if the old node ++ * is found. This function is called by garbage collection when node are moved. ++ * Returns %0 on success or negative error code on failure. ++ */ ++int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key, ++ int old_lnum, int old_offs, int lnum, int offs, int len) ++{ ++ int found, n, err = 0; ++ struct ubifs_znode *znode; ++ ++ mutex_lock(&c->tnc_mutex); ++ dbg_tnc("old LEB %d:%d, new LEB %d:%d, len %d, key %s", old_lnum, ++ old_offs, lnum, offs, len, DBGKEY(key)); ++ found = lookup_level0_dirty(c, key, &znode, &n); ++ if (found < 0) { ++ err = found; ++ goto out_unlock; ++ } ++ ++ if (found == 1) { ++ struct ubifs_zbranch *zbr = &znode->zbranch[n]; ++ ++ found = 0; ++ if (zbr->lnum == old_lnum && zbr->offs == old_offs) { ++ lnc_free(zbr); ++ err = ubifs_add_dirt(c, zbr->lnum, zbr->len); ++ if (err) ++ goto out_unlock; ++ zbr->lnum = lnum; ++ zbr->offs = offs; ++ zbr->len = len; ++ found = 1; ++ } else if (is_hash_key(c, key)) { ++ found = resolve_collision_directly(c, key, &znode, &n, ++ old_lnum, old_offs); ++ dbg_tnc("rc returned %d, znode %p, n %d, LEB %d:%d", ++ found, znode, n, old_lnum, old_offs); ++ if (found < 0) { ++ err = found; ++ goto out_unlock; ++ } ++ ++ if (found) { ++ /* Ensure the znode is dirtied */ ++ if (znode->cnext || !ubifs_zn_dirty(znode)) { ++ znode = dirty_cow_bottom_up(c, ++ znode); ++ if (IS_ERR(znode)) { ++ err = PTR_ERR(znode); ++ goto out_unlock; ++ } ++ } ++ zbr = &znode->zbranch[n]; ++ lnc_free(zbr); ++ err = ubifs_add_dirt(c, zbr->lnum, ++ zbr->len); ++ if (err) ++ goto out_unlock; ++ zbr->lnum = lnum; ++ zbr->offs = offs; ++ zbr->len = len; ++ } ++ } ++ } ++ ++ if (!found) ++ err = ubifs_add_dirt(c, lnum, len); ++ ++ if (!err) ++ err = dbg_check_tnc(c, 0); ++ ++out_unlock: ++ mutex_unlock(&c->tnc_mutex); ++ return err; ++} ++ ++/** ++ * ubifs_tnc_add_nm - add a "hashed" node to TNC. ++ * @c: UBIFS file-system description object ++ * @key: key to add ++ * @lnum: LEB number of node ++ * @offs: node offset ++ * @len: node length ++ * @nm: node name ++ * ++ * This is the same as 'ubifs_tnc_add()' but it should be used with keys which ++ * may have collisions, like directory entry keys. ++ */ ++int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key, ++ int lnum, int offs, int len, const struct qstr *nm) ++{ ++ int found, n, err = 0; ++ struct ubifs_znode *znode; ++ ++ mutex_lock(&c->tnc_mutex); ++ dbg_tnc("LEB %d:%d, name '%.*s', key %s", lnum, offs, nm->len, nm->name, ++ DBGKEY(key)); ++ found = lookup_level0_dirty(c, key, &znode, &n); ++ if (found < 0) { ++ err = found; ++ goto out_unlock; ++ } ++ ++ if (found == 1) { ++ if (c->replaying) ++ found = fallible_resolve_collision(c, key, &znode, &n, ++ nm, 1); ++ else ++ found = resolve_collision(c, key, &znode, &n, nm); ++ dbg_tnc("rc returned %d, znode %p, n %d", found, znode, n); ++ if (found < 0) { ++ err = found; ++ goto out_unlock; ++ } ++ ++ /* Ensure the znode is dirtied */ ++ if (znode->cnext || !ubifs_zn_dirty(znode)) { ++ znode = dirty_cow_bottom_up(c, znode); ++ if (IS_ERR(znode)) { ++ err = PTR_ERR(znode); ++ goto out_unlock; ++ } ++ } ++ ++ if (found == 1) { ++ struct ubifs_zbranch *zbr = &znode->zbranch[n]; ++ ++ lnc_free(zbr); ++ err = ubifs_add_dirt(c, zbr->lnum, zbr->len); ++ zbr->lnum = lnum; ++ zbr->offs = offs; ++ zbr->len = len; ++ goto out_unlock; ++ } ++ } ++ ++ if (!found) { ++ struct ubifs_zbranch zbr; ++ ++ zbr.znode = NULL; ++ zbr.lnum = lnum; ++ zbr.offs = offs; ++ zbr.len = len; ++ key_copy(c, key, &zbr.key); ++ err = tnc_insert(c, znode, &zbr, n + 1); ++ if (err) ++ goto out_unlock; ++ if (c->replaying && c->replay_sqnum < c->cs_sqnum) { ++ /* ++ * This node was moved by garbage collection. We can ++ * tell because it is in the journal but it has a ++ * sequence number earlier than the last commit-start. ++ * We did not find it in the index so there may be a ++ * dangling branch still in the index. So we remove it ++ * by passing 'ubifs_tnc_remove_nm()' the same key but ++ * an unmatchable name. ++ */ ++ struct qstr noname = { .len = 0, .name = "" }; ++ ++ err = dbg_check_tnc(c, 0); ++ mutex_unlock(&c->tnc_mutex); ++ if (err) ++ return err; ++ return ubifs_tnc_remove_nm(c, key, &noname); ++ } ++ } ++ ++out_unlock: ++ if (!err) ++ err = dbg_check_tnc(c, 0); ++ mutex_unlock(&c->tnc_mutex); ++ return err; ++} ++ ++/** ++ * tnc_delete - delete a znode form TNC. ++ * @c: UBIFS file-system description object ++ * @znode: znode to delete from ++ * @n: zbranch slot number to delete ++ * ++ * This function deletes a leaf node from @n-th slot of @znode. Returns zero in ++ * case of success and a negative error code in case of failure. ++ */ ++static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n) ++{ ++ struct ubifs_zbranch *zbr; ++ struct ubifs_znode *zp; ++ int i, err; ++ ++ /* Delete without merge for now */ ++ ubifs_assert(znode->level == 0); ++ ubifs_assert(n >= 0 && n < c->fanout); ++ dbg_tnc("deleting %s", DBGKEY(&znode->zbranch[n].key)); ++ ++ zbr = &znode->zbranch[n]; ++ lnc_free(zbr); ++ ++ err = ubifs_add_dirt(c, zbr->lnum, zbr->len); ++ if (err) { ++ dbg_dump_znode(c, znode); ++ return err; ++ } ++ ++ /* We do not "gap" zbranch slots */ ++ for (i = n; i < znode->child_cnt - 1; i++) ++ znode->zbranch[i] = znode->zbranch[i + 1]; ++ znode->child_cnt -= 1; ++ ++ if (znode->child_cnt > 0) ++ return 0; ++ ++ /* ++ * This was the last zbranch, we have to delete this znode from the ++ * parent. ++ */ ++ ++ do { ++ ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags)); ++ ubifs_assert(ubifs_zn_dirty(znode)); ++ ++ zp = znode->parent; ++ n = znode->iip; ++ ++ atomic_long_dec(&c->dirty_zn_cnt); ++ ++ err = insert_old_idx_znode(c, znode); ++ if (err) ++ return err; ++ ++ if (znode->cnext) { ++ __set_bit(OBSOLETE_ZNODE, &znode->flags); ++ atomic_long_inc(&c->clean_zn_cnt); ++ atomic_long_inc(&ubifs_clean_zn_cnt); ++ } else ++ kfree(znode); ++ znode = zp; ++ } while (znode->child_cnt == 1); /* while removing last child */ ++ ++ /* Remove from znode, entry n - 1 */ ++ znode->child_cnt -= 1; ++ ubifs_assert(znode->level != 0); ++ for (i = n; i < znode->child_cnt; i++) { ++ znode->zbranch[i] = znode->zbranch[i + 1]; ++ if (znode->zbranch[i].znode) ++ znode->zbranch[i].znode->iip = i; ++ } ++ ++ /* ++ * If this is the root and it has only 1 child then ++ * collapse the tree. ++ */ ++ if (!znode->parent) { ++ while (znode->child_cnt == 1 && znode->level != 0) { ++ zp = znode; ++ zbr = &znode->zbranch[0]; ++ znode = get_znode(c, znode, 0); ++ if (IS_ERR(znode)) ++ return PTR_ERR(znode); ++ znode = dirty_cow_znode(c, zbr); ++ if (IS_ERR(znode)) ++ return PTR_ERR(znode); ++ znode->parent = NULL; ++ znode->iip = 0; ++ if (c->zroot.len) { ++ err = insert_old_idx(c, c->zroot.lnum, ++ c->zroot.offs); ++ if (err) ++ return err; ++ } ++ c->zroot.lnum = zbr->lnum; ++ c->zroot.offs = zbr->offs; ++ c->zroot.len = zbr->len; ++ c->zroot.znode = znode; ++ ubifs_assert(!test_bit(OBSOLETE_ZNODE, ++ &zp->flags)); ++ ubifs_assert(test_bit(DIRTY_ZNODE, &zp->flags)); ++ atomic_long_dec(&c->dirty_zn_cnt); ++ ++ if (zp->cnext) { ++ __set_bit(OBSOLETE_ZNODE, &zp->flags); ++ atomic_long_inc(&c->clean_zn_cnt); ++ atomic_long_inc(&ubifs_clean_zn_cnt); ++ } else ++ kfree(zp); ++ } ++ } ++ ++ return 0; ++} ++ ++/** ++ * ubifs_tnc_remove - remove an index entry of a node. ++ * @c: UBIFS file-system description object ++ * @key: key of node ++ * ++ * Returns %0 on success or negative error code on failure. ++ */ ++int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key) ++{ ++ int found, n, err = 0; ++ struct ubifs_znode *znode; ++ ++ mutex_lock(&c->tnc_mutex); ++ dbg_tnc("key %s", DBGKEY(key)); ++ found = lookup_level0_dirty(c, key, &znode, &n); ++ if (found < 0) { ++ err = found; ++ goto out_unlock; ++ } ++ if (found == 1) ++ err = tnc_delete(c, znode, n); ++ if (!err) ++ err = dbg_check_tnc(c, 0); ++ ++out_unlock: ++ mutex_unlock(&c->tnc_mutex); ++ return err; ++} ++ ++/** ++ * ubifs_tnc_remove_nm - remove an index entry for a "hashed" node. ++ * @c: UBIFS file-system description object ++ * @key: key of node ++ * @nm: directory entry name ++ * ++ * Returns %0 on success or negative error code on failure. ++ */ ++int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key, ++ const struct qstr *nm) ++{ ++ int n, err; ++ struct ubifs_znode *znode; ++ ++ mutex_lock(&c->tnc_mutex); ++ dbg_tnc("%.*s, key %s", nm->len, nm->name, DBGKEY(key)); ++ err = lookup_level0_dirty(c, key, &znode, &n); ++ if (err < 0) ++ goto out_unlock; ++ ++ if (err) { ++ if (c->replaying) ++ err = fallible_resolve_collision(c, key, &znode, &n, ++ nm, 0); ++ else ++ err = resolve_collision(c, key, &znode, &n, nm); ++ dbg_tnc("rc returned %d, znode %p, n %d", err, znode, n); ++ if (err < 0) ++ goto out_unlock; ++ if (err) { ++ /* Ensure the znode is dirtied */ ++ if (znode->cnext || !ubifs_zn_dirty(znode)) { ++ znode = dirty_cow_bottom_up(c, znode); ++ if (IS_ERR(znode)) { ++ err = PTR_ERR(znode); ++ goto out_unlock; ++ } ++ } ++ err = tnc_delete(c, znode, n); ++ } ++ } ++ ++out_unlock: ++ if (!err) ++ err = dbg_check_tnc(c, 0); ++ mutex_unlock(&c->tnc_mutex); ++ return err; ++} ++ ++/** ++ * key_in_range - determine if a key falls within a range of keys. ++ * @c: UBIFS file-system description object ++ * @key: key to check ++ * @from_key: lowest key in range ++ * @to_key: highest key in range ++ * ++ * This function returns %1 if the key is in range and %0 otherwise. ++ */ ++static int key_in_range(struct ubifs_info *c, union ubifs_key *key, ++ union ubifs_key *from_key, union ubifs_key *to_key) ++{ ++ if (keys_cmp(c, key, from_key) < 0) ++ return 0; ++ if (keys_cmp(c, key, to_key) > 0) ++ return 0; ++ return 1; ++} ++ ++/** ++ * ubifs_tnc_remove_range - remove index entries in range. ++ * @c: UBIFS file-system description object ++ * @from_key: lowest key to remove ++ * @to_key: highest key to remove ++ * ++ * This function removes index entries starting at @from_key and ending at ++ * @to_key. This function returns zero in case of success and a negative error ++ * code in case of failure. ++ */ ++int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key, ++ union ubifs_key *to_key) ++{ ++ int i, n, k, err = 0; ++ struct ubifs_znode *znode; ++ union ubifs_key *key; ++ ++ mutex_lock(&c->tnc_mutex); ++ while (1) { ++ /* Find first level 0 znode that contains keys to remove */ ++ err = ubifs_lookup_level0(c, from_key, &znode, &n); ++ if (err < 0) ++ goto out_unlock; ++ ++ if (err) ++ key = from_key; ++ else { ++ err = tnc_next(c, &znode, &n); ++ if (err == -ENOENT) { ++ err = 0; ++ goto out_unlock; ++ } ++ if (err < 0) ++ goto out_unlock; ++ key = &znode->zbranch[n].key; ++ if (!key_in_range(c, key, from_key, to_key)) { ++ err = 0; ++ goto out_unlock; ++ } ++ } ++ ++ /* Ensure the znode is dirtied */ ++ if (znode->cnext || !ubifs_zn_dirty(znode)) { ++ znode = dirty_cow_bottom_up(c, znode); ++ if (IS_ERR(znode)) { ++ err = PTR_ERR(znode); ++ goto out_unlock; ++ } ++ } ++ ++ /* Remove all keys in range except the first */ ++ for (i = n + 1, k = 0; i < znode->child_cnt; i++, k++) { ++ key = &znode->zbranch[i].key; ++ if (!key_in_range(c, key, from_key, to_key)) ++ break; ++ lnc_free(&znode->zbranch[i]); ++ err = ubifs_add_dirt(c, znode->zbranch[i].lnum, ++ znode->zbranch[i].len); ++ if (err) { ++ dbg_dump_znode(c, znode); ++ goto out_unlock; ++ } ++ dbg_tnc("removing %s", DBGKEY(key)); ++ } ++ if (k) { ++ for (i = n + 1 + k; i < znode->child_cnt; i++) ++ znode->zbranch[i - k] = znode->zbranch[i]; ++ znode->child_cnt -= k; ++ } ++ ++ /* Now delete the first */ ++ err = tnc_delete(c, znode, n); ++ if (err) ++ goto out_unlock; ++ } ++ ++out_unlock: ++ if (!err) ++ err = dbg_check_tnc(c, 0); ++ mutex_unlock(&c->tnc_mutex); ++ return err; ++} ++ ++/** ++ * ubifs_tnc_remove_ino - remove an inode from TNC. ++ * @c: UBIFS file-system description object ++ * @inum: inode number to remove ++ * ++ * This function remove inode @inum and all the extended attributes associated ++ * with the anode from TNC and returns zero in case of success or a negative ++ * error code in case of failure. ++ */ ++int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum) ++{ ++ union ubifs_key key1, key2; ++ struct ubifs_dent_node *xent, *pxent = NULL; ++ struct qstr nm = { .name = NULL }; ++ ++ dbg_tnc("ino %lu", inum); ++ ++ /* ++ * Walk all extended attribute entries and remove them together with ++ * corresponding extended attribute inodes. ++ */ ++ lowest_xent_key(c, &key1, inum); ++ while (1) { ++ ino_t xattr_inum; ++ int err; ++ ++ xent = ubifs_tnc_next_ent(c, &key1, &nm); ++ if (IS_ERR(xent)) { ++ err = PTR_ERR(xent); ++ if (err == -ENOENT) ++ break; ++ return err; ++ } ++ ++ xattr_inum = le64_to_cpu(xent->inum); ++ dbg_tnc("xent '%s', ino %lu", xent->name, xattr_inum); ++ ++ nm.name = xent->name; ++ nm.len = le16_to_cpu(xent->nlen); ++ err = ubifs_tnc_remove_nm(c, &key1, &nm); ++ if (err) { ++ kfree(xent); ++ return err; ++ } ++ ++ lowest_ino_key(c, &key1, xattr_inum); ++ highest_ino_key(c, &key2, xattr_inum); ++ err = ubifs_tnc_remove_range(c, &key1, &key2); ++ if (err) { ++ kfree(xent); ++ return err; ++ } ++ ++ kfree(pxent); ++ pxent = xent; ++ key_read(c, &xent->key, &key1); ++ } ++ ++ kfree(pxent); ++ lowest_ino_key(c, &key1, inum); ++ highest_ino_key(c, &key2, inum); ++ ++ return ubifs_tnc_remove_range(c, &key1, &key2); ++} ++ ++/** ++ * ubifs_tnc_next_ent - walk directory or extended attribute entries. ++ * @c: UBIFS file-system description object ++ * @key: key of last entry ++ * @nm: name of last entry found or %NULL ++ * ++ * This function finds and reads the next directory or extended attribute entry ++ * after the given key (@key) if there is one. @nm is used to resolve ++ * collisions. ++ * ++ * If the name of the current entry is not known and only the key is known, ++ * @nm->name has to be %NULL. In this case the semantics of this function is a ++ * little bit different and it returns the entry corresponding to this key, not ++ * the next one. If the key was not found, the closest "right" entry is ++ * returned. ++ * ++ * If the fist entry has to be found, @key has to contain the lowest possible ++ * key value for this inode and @name has to be %NULL. ++ * ++ * This function returns the found directory or extended attribute entry node ++ * in case of success, %-ENOENT is returned if no entry was found, and a ++ * negative error code is returned in case of failure. ++ */ ++struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c, ++ union ubifs_key *key, ++ const struct qstr *nm) ++{ ++ int n, err, type = key_type(c, key); ++ struct ubifs_znode *znode; ++ struct ubifs_dent_node *dent; ++ struct ubifs_zbranch *zbr; ++ union ubifs_key *dkey; ++ ++ dbg_tnc("%s %s", nm->name ? (char *)nm->name : "(lowest)", DBGKEY(key)); ++ ubifs_assert(is_hash_key(c, key)); ++ ++ mutex_lock(&c->tnc_mutex); ++ err = ubifs_lookup_level0(c, key, &znode, &n); ++ if (unlikely(err < 0)) ++ goto out_unlock; ++ ++ if (nm->name) { ++ if (err) { ++ /* Handle collisions */ ++ err = resolve_collision(c, key, &znode, &n, nm); ++ dbg_tnc("rc returned %d, znode %p, n %d", ++ err, znode, n); ++ if (unlikely(err < 0)) ++ goto out_unlock; ++ } ++ ++ /* Now find next entry */ ++ err = tnc_next(c, &znode, &n); ++ if (unlikely(err)) ++ goto out_unlock; ++ } else { ++ /* ++ * The full name of the entry was not given, in which case the ++ * behavior of this function is a little different and it ++ * returns current entry, not the next one. ++ */ ++ if (!err) { ++ /* ++ * However, the given key does not exist in the TNC ++ * tree and @znode/@n variables contain the closest ++ * "preceding" element. Switch to the next one. ++ */ ++ err = tnc_next(c, &znode, &n); ++ if (err) ++ goto out_unlock; ++ } ++ } ++ ++ zbr = &znode->zbranch[n]; ++ dent = kmalloc(zbr->len, GFP_NOFS); ++ if (unlikely(!dent)) { ++ err = -ENOMEM; ++ goto out_unlock; ++ } ++ ++ /* ++ * The above 'tnc_next()' call could lead us to the next inode, check ++ * this. ++ */ ++ dkey = &zbr->key; ++ if (key_inum(c, dkey) != key_inum(c, key) || ++ key_type(c, dkey) != type) { ++ err = -ENOENT; ++ goto out_free; ++ } ++ ++ err = tnc_read_node_nm(c, zbr, dent); ++ if (unlikely(err)) ++ goto out_free; ++ ++ mutex_unlock(&c->tnc_mutex); ++ return dent; ++ ++out_free: ++ kfree(dent); ++out_unlock: ++ mutex_unlock(&c->tnc_mutex); ++ return ERR_PTR(err); ++} ++ ++/** ++ * tnc_destroy_cnext - destroy left-over obsolete znodes from a failed commit. ++ * @c: UBIFS file-system description object ++ * ++ * Destroy left-over obsolete znodes from a failed commit. ++ */ ++static void tnc_destroy_cnext(struct ubifs_info *c) ++{ ++ struct ubifs_znode *cnext; ++ ++ if (!c->cnext) ++ return; ++ ubifs_assert(c->cmt_state == COMMIT_BROKEN); ++ cnext = c->cnext; ++ do { ++ struct ubifs_znode *znode = cnext; ++ ++ cnext = cnext->cnext; ++ if (test_bit(OBSOLETE_ZNODE, &znode->flags)) ++ kfree(znode); ++ } while (cnext && cnext != c->cnext); ++} ++ ++/** ++ * ubifs_tnc_close - close TNC subsystem and free all related resources. ++ * @c: UBIFS file-system description object ++ */ ++void ubifs_tnc_close(struct ubifs_info *c) ++{ ++ long clean_freed; ++ ++ tnc_destroy_cnext(c); ++ if (c->zroot.znode) { ++ clean_freed = ubifs_destroy_tnc_subtree(c->zroot.znode); ++ atomic_long_sub(clean_freed, &ubifs_clean_zn_cnt); ++ } ++ kfree(c->gap_lebs); ++ kfree(c->ilebs); ++ destroy_old_idx(c); ++} ++ ++/** ++ * left_znode - get the znode to the left. ++ * @c: UBIFS file-system description object ++ * @znode: znode ++ * ++ * This function returns a pointer to the znode to the left of @znode or NULL if ++ * there is not one. A negative error code is returned on failure. ++ */ ++static struct ubifs_znode *left_znode(struct ubifs_info *c, ++ struct ubifs_znode *znode) ++{ ++ int level = znode->level; ++ ++ while (1) { ++ int n = znode->iip - 1; ++ ++ /* Go up until we can go left */ ++ znode = znode->parent; ++ if (!znode) ++ return NULL; ++ if (n >= 0) { ++ /* Now go down the rightmost branch to 'level' */ ++ znode = get_znode(c, znode, n); ++ if (IS_ERR(znode)) ++ return znode; ++ while (znode->level != level) { ++ n = znode->child_cnt - 1; ++ znode = get_znode(c, znode, n); ++ if (IS_ERR(znode)) ++ return znode; ++ } ++ break; ++ } ++ } ++ return znode; ++} ++ ++/** ++ * right_znode - get the znode to the right. ++ * @c: UBIFS file-system description object ++ * @znode: znode ++ * ++ * This function returns a pointer to the znode to the right of @znode or NULL ++ * if there is not one. A negative error code is returned on failure. ++ */ ++static struct ubifs_znode *right_znode(struct ubifs_info *c, ++ struct ubifs_znode *znode) ++{ ++ int level = znode->level; ++ ++ while (1) { ++ int n = znode->iip + 1; ++ ++ /* Go up until we can go right */ ++ znode = znode->parent; ++ if (!znode) ++ return NULL; ++ if (n < znode->child_cnt) { ++ /* Now go down the leftmost branch to 'level' */ ++ znode = get_znode(c, znode, n); ++ if (IS_ERR(znode)) ++ return znode; ++ while (znode->level != level) { ++ znode = get_znode(c, znode, 0); ++ if (IS_ERR(znode)) ++ return znode; ++ } ++ break; ++ } ++ } ++ return znode; ++} ++ ++/** ++ * lookup_znode - find a particular indexing node from TNC. ++ * @c: UBIFS file-system description object ++ * @key: index node key to lookup ++ * @level: index node level ++ * @lnum: index node LEB number ++ * @offs: index node offset ++ * ++ * This function searches an indexing node by its first key @key and its ++ * address @lnum:@offs. It looks up the indexing tree by pulling all indexing ++ * nodes it traverses to TNC. This function is called fro indexing nodes which ++ * were found on the media by scanning, for example when garbage-collecting or ++ * when doing in-the-gaps commit. This means that the indexing node which is ++ * looked for does not have to have exactly the same leftmost key @key, because ++ * the leftmost key may have been changed, in which case TNC will contain a ++ * dirty znode which still refers the same @lnum:@offs. This function is clever ++ * enough to recognize such indexing nodes. ++ * ++ * Note, if a znode was deleted or changed too much, then this function will ++ * not find it. For situations like this UBIFS has the old index RB-tree ++ * (indexed by @lnum:@offs). ++ * ++ * This function returns a pointer to the znode found or %NULL if it is not ++ * found. A negative error code is returned on failure. ++ */ ++static struct ubifs_znode *lookup_znode(struct ubifs_info *c, ++ union ubifs_key *key, int level, ++ int lnum, int offs) ++{ ++ struct ubifs_znode *znode, *zn; ++ int n, nn; ++ ++ /* ++ * The arguments have probably been read off flash, so don't assume ++ * they are valid. ++ */ ++ if (level < 0) ++ return ERR_PTR(-EINVAL); ++ ++ /* Get the root znode */ ++ znode = c->zroot.znode; ++ if (!znode) { ++ znode = ubifs_load_znode(c, &c->zroot, NULL, 0); ++ if (IS_ERR(znode)) ++ return znode; ++ } ++ /* Check if it is the one we are looking for */ ++ if (c->zroot.lnum == lnum && c->zroot.offs == offs) ++ return znode; ++ /* Descend to the parent level i.e. (level + 1) */ ++ if (level >= znode->level) ++ return NULL; ++ while (1) { ++ ubifs_search_zbranch(c, znode, key, &n); ++ if (n < 0) { ++ /* ++ * We reached a znode where the leftmost key is greater ++ * than the key we are searching for. This is the same ++ * situation as the one described in a huge comment at ++ * the end of the 'ubifs_lookup_level0()' function. And ++ * for exactly the same reasons we have to try to look ++ * left before giving up. ++ */ ++ znode = left_znode(c, znode); ++ if (!znode) ++ return NULL; ++ if (IS_ERR(znode)) ++ return znode; ++ ubifs_search_zbranch(c, znode, key, &n); ++ ubifs_assert(n >= 0); ++ } ++ if (znode->level == level + 1) ++ break; ++ znode = get_znode(c, znode, n); ++ if (IS_ERR(znode)) ++ return znode; ++ } ++ /* Check if the child is the one we are looking for */ ++ if (znode->zbranch[n].lnum == lnum && znode->zbranch[n].offs == offs) ++ return get_znode(c, znode, n); ++ /* If the key is unique, there is nowhere else to look */ ++ if (!is_hash_key(c, key)) ++ return NULL; ++ /* ++ * The key is not unique and so may be also in the znodes to either ++ * side. ++ */ ++ zn = znode; ++ nn = n; ++ /* Look left */ ++ while (1) { ++ /* Move one branch to the left */ ++ if (n) ++ n -= 1; ++ else { ++ znode = left_znode(c, znode); ++ if (!znode) ++ break; ++ if (IS_ERR(znode)) ++ return znode; ++ n = znode->child_cnt - 1; ++ } ++ /* Check it */ ++ if (znode->zbranch[n].lnum == lnum && ++ znode->zbranch[n].offs == offs) ++ return get_znode(c, znode, n); ++ /* Stop if the key is less than the one we are looking for */ ++ if (keys_cmp(c, &znode->zbranch[n].key, key) < 0) ++ break; ++ } ++ /* Back to the middle */ ++ znode = zn; ++ n = nn; ++ /* Look right */ ++ while (1) { ++ /* Move one branch to the right */ ++ if (++n >= znode->child_cnt) { ++ znode = right_znode(c, znode); ++ if (!znode) ++ break; ++ if (IS_ERR(znode)) ++ return znode; ++ n = 0; ++ } ++ /* Check it */ ++ if (znode->zbranch[n].lnum == lnum && ++ znode->zbranch[n].offs == offs) ++ return get_znode(c, znode, n); ++ /* Stop if the key is greater than the one we are looking for */ ++ if (keys_cmp(c, &znode->zbranch[n].key, key) > 0) ++ break; ++ } ++ return NULL; ++} ++ ++/** ++ * is_idx_node_in_tnc - determine if an index node is in the TNC. ++ * @c: UBIFS file-system description object ++ * @key: key of index node ++ * @level: index node level ++ * @lnum: LEB number of index node ++ * @offs: offset of index node ++ * ++ * This function returns %0 if the index node is not referred to in the TNC, %1 ++ * if the index node is referred to in the TNC and the corresponding znode is ++ * dirty, %2 if an index node is referred to in the TNC and the corresponding ++ * znode is clean, and a negative error code in case of failure. ++ * ++ * Note, the @key argument has to be the key of the first child. Also note, ++ * this function relies on the fact that 0:0 is never a valid LEB number and ++ * offset for a main-area node. ++ */ ++int is_idx_node_in_tnc(struct ubifs_info *c, union ubifs_key *key, int level, ++ int lnum, int offs) ++{ ++ struct ubifs_znode *znode; ++ ++ znode = lookup_znode(c, key, level, lnum, offs); ++ if (!znode) ++ return 0; ++ if (IS_ERR(znode)) ++ return PTR_ERR(znode); ++ ++ return ubifs_zn_dirty(znode) ? 1 : 2; ++} ++ ++/** ++ * is_leaf_node_in_tnc - determine if a non-indexing not is in the TNC. ++ * @c: UBIFS file-system description object ++ * @key: node key ++ * @lnum: node LEB number ++ * @offs: node offset ++ * ++ * This function returns %1 if the node is referred to in the TNC, %0 if it is ++ * not, and a negative error code in case of failure. ++ * ++ * Note, this function relies on the fact that 0:0 is never a valid LEB number ++ * and offset for a main-area node. ++ */ ++static int is_leaf_node_in_tnc(struct ubifs_info *c, union ubifs_key *key, ++ int lnum, int offs) ++{ ++ struct ubifs_zbranch *zbr; ++ struct ubifs_znode *znode, *zn; ++ int n, found, err, nn; ++ const int unique = !is_hash_key(c, key); ++ ++ found = ubifs_lookup_level0(c, key, &znode, &n); ++ if (found < 0) ++ return found; /* Error code */ ++ if (!found) ++ return 0; ++ zbr = &znode->zbranch[n]; ++ if (lnum == zbr->lnum && offs == zbr->offs) ++ return 1; /* Found it */ ++ if (unique) ++ return 0; ++ /* ++ * Because the key is not unique, we have to look left ++ * and right as well ++ */ ++ zn = znode; ++ nn = n; ++ /* Look left */ ++ while (1) { ++ err = tnc_prev(c, &znode, &n); ++ if (err == -ENOENT) ++ break; ++ if (err) ++ return err; ++ if (keys_cmp(c, key, &znode->zbranch[n].key)) ++ break; ++ zbr = &znode->zbranch[n]; ++ if (lnum == zbr->lnum && offs == zbr->offs) ++ return 1; /* Found it */ ++ } ++ /* Look right */ ++ znode = zn; ++ n = nn; ++ while (1) { ++ err = tnc_next(c, &znode, &n); ++ if (err) { ++ if (err == -ENOENT) ++ return 0; ++ return err; ++ } ++ if (keys_cmp(c, key, &znode->zbranch[n].key)) ++ break; ++ zbr = &znode->zbranch[n]; ++ if (lnum == zbr->lnum && offs == zbr->offs) ++ return 1; /* Found it */ ++ } ++ return 0; ++} ++ ++/** ++ * ubifs_tnc_has_node - determine whether a node is in the TNC. ++ * @c: UBIFS file-system description object ++ * @key: node key ++ * @level: index node level (if it is an index node) ++ * @lnum: node LEB number ++ * @offs: node offset ++ * @is_idx: non-zero if the node is an index node ++ * ++ * This function returns %1 if the node is in the TNC, %0 if it is not, and a ++ * negative error code in case of failure. For index nodes, @key has to be the ++ * key of the first child. An index node is considered to be in the TNC only if ++ * the corresponding znode is clean or has not been loaded. ++ */ ++int ubifs_tnc_has_node(struct ubifs_info *c, union ubifs_key *key, int level, ++ int lnum, int offs, int is_idx) ++{ ++ int err; ++ ++ mutex_lock(&c->tnc_mutex); ++ if (is_idx) { ++ err = is_idx_node_in_tnc(c, key, level, lnum, offs); ++ if (err < 0) ++ goto out_unlock; ++ if (err == 1) ++ /* The index node was found but it was dirty */ ++ err = 0; ++ else if (err == 2) ++ /* The index node was found and it was clean */ ++ err = 1; ++ else ++ BUG_ON(err != 0); ++ } else ++ err = is_leaf_node_in_tnc(c, key, lnum, offs); ++ ++out_unlock: ++ mutex_unlock(&c->tnc_mutex); ++ return err; ++} ++ ++/** ++ * ubifs_dirty_idx_node - dirty an index node. ++ * @c: UBIFS file-system description object ++ * @key: index node key ++ * @level: index node level ++ * @lnum: index node LEB number ++ * @offs: index node offset ++ * ++ * This function loads and dirties an index node so that it can be garbage ++ * collected. The @key argument has to be the key of the first child. This ++ * function relies on the fact that 0:0 is never a valid LEB number and offset ++ * for a main-area node. Returns %0 on success and a negative error code on ++ * failure. ++ */ ++int ubifs_dirty_idx_node(struct ubifs_info *c, union ubifs_key *key, int level, ++ int lnum, int offs) ++{ ++ struct ubifs_znode *znode; ++ int err = 0; ++ ++ mutex_lock(&c->tnc_mutex); ++ znode = lookup_znode(c, key, level, lnum, offs); ++ if (!znode) ++ goto out_unlock; ++ if (IS_ERR(znode)) { ++ err = PTR_ERR(znode); ++ goto out_unlock; ++ } ++ znode = dirty_cow_bottom_up(c, znode); ++ if (IS_ERR(znode)) { ++ err = PTR_ERR(znode); ++ goto out_unlock; ++ } ++ ++out_unlock: ++ mutex_unlock(&c->tnc_mutex); ++ return err; ++} +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/tnc_commit.c avr32-2.6/fs/ubifs/tnc_commit.c +--- linux-2.6.25.6/fs/ubifs/tnc_commit.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/tnc_commit.c 2008-06-12 15:09:45.603817614 +0200 +@@ -0,0 +1,1105 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Adrian Hunter ++ * Artem Bityutskiy (Битюцкий Артём) ++ */ ++ ++/* This file implements TNC functions for committing */ ++ ++#include "ubifs.h" ++ ++/** ++ * make_idx_node - make an index node for fill-the-gaps method of TNC commit. ++ * @c: UBIFS file-system description object ++ * @idx: buffer in which to place new index node ++ * @znode: znode from which to make new index node ++ * @lnum: LEB number where new index node will be written ++ * @offs: offset where new index node will be written ++ * @len: length of new index node ++ */ ++static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx, ++ struct ubifs_znode *znode, int lnum, int offs, int len) ++{ ++ struct ubifs_znode *zp; ++ int i, err; ++ ++ /* Make index node */ ++ idx->ch.node_type = UBIFS_IDX_NODE; ++ idx->child_cnt = cpu_to_le16(znode->child_cnt); ++ idx->level = cpu_to_le16(znode->level); ++ for (i = 0; i < znode->child_cnt; i++) { ++ struct ubifs_branch *br = ubifs_idx_branch(c, idx, i); ++ struct ubifs_zbranch *zbr = &znode->zbranch[i]; ++ ++ key_write_idx(c, &zbr->key, &br->key); ++ br->lnum = cpu_to_le32(zbr->lnum); ++ br->offs = cpu_to_le32(zbr->offs); ++ br->len = cpu_to_le32(zbr->len); ++ if (!zbr->lnum || !zbr->len) { ++ ubifs_err("bad ref in znode"); ++ dbg_dump_znode(c, znode); ++ if (zbr->znode) ++ dbg_dump_znode(c, zbr->znode); ++ } ++ } ++ ubifs_prepare_node(c, idx, len, 0); ++ ++#ifdef CONFIG_UBIFS_FS_DEBUG ++ znode->lnum = lnum; ++ znode->offs = offs; ++ znode->len = len; ++#endif ++ ++ err = insert_old_idx_znode(c, znode); ++ ++ /* Update the parent */ ++ zp = znode->parent; ++ if (zp) { ++ struct ubifs_zbranch *zbr; ++ ++ zbr = &zp->zbranch[znode->iip]; ++ zbr->lnum = lnum; ++ zbr->offs = offs; ++ zbr->len = len; ++ } else { ++ c->zroot.lnum = lnum; ++ c->zroot.offs = offs; ++ c->zroot.len = len; ++ } ++ c->calc_idx_sz += ALIGN(len, 8); ++ ++ atomic_long_dec(&c->dirty_zn_cnt); ++ ++ ubifs_assert(ubifs_zn_dirty(znode)); ++ ubifs_assert(test_bit(COW_ZNODE, &znode->flags)); ++ ++ __clear_bit(DIRTY_ZNODE, &znode->flags); ++ __clear_bit(COW_ZNODE, &znode->flags); ++ ++ return err; ++} ++ ++/** ++ * fill_gap - make index nodes in gaps in dirty index LEBs. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number that gap appears in ++ * @gap_start: offset of start of gap ++ * @gap_end: offset of end of gap ++ * @dirt: adds dirty space to this ++ * ++ * This function returns the number of index nodes written into the gap. ++ */ ++static int fill_gap(struct ubifs_info *c, int lnum, int gap_start, int gap_end, ++ int *dirt) ++{ ++ int len, gap_remains, gap_pos, written, pad_len; ++ ++ ubifs_assert((gap_start & 7) == 0); ++ ubifs_assert((gap_end & 7) == 0); ++ ubifs_assert(gap_end >= gap_start); ++ ++ gap_remains = gap_end - gap_start; ++ if (!gap_remains) ++ return 0; ++ gap_pos = gap_start; ++ written = 0; ++ while (c->enext) { ++ len = ubifs_idx_node_sz(c, c->enext->child_cnt); ++ if (len < gap_remains) { ++ struct ubifs_znode *znode = c->enext; ++ const int alen = ALIGN(len, 8); ++ int err; ++ ++ ubifs_assert(alen <= gap_remains); ++ err = make_idx_node(c, c->ileb_buf + gap_pos, znode, ++ lnum, gap_pos, len); ++ if (err) ++ return err; ++ gap_remains -= alen; ++ gap_pos += alen; ++ c->enext = znode->cnext; ++ if (c->enext == c->cnext) ++ c->enext = NULL; ++ written += 1; ++ } else ++ break; ++ } ++ if (gap_end == c->leb_size) { ++ c->ileb_len = ALIGN(gap_pos, c->min_io_size); ++ /* Pad to end of min_io_size */ ++ pad_len = c->ileb_len - gap_pos; ++ } else ++ /* Pad to end of gap */ ++ pad_len = gap_remains; ++ dbg_gc("LEB %d:%d to %d len %d nodes written %d wasted bytes %d", ++ lnum, gap_start, gap_end, gap_end - gap_start, written, pad_len); ++ ubifs_pad(c, c->ileb_buf + gap_pos, pad_len); ++ *dirt += pad_len; ++ return written; ++} ++ ++/** ++ * find_old_idx - find an index node obsoleted since the last commit start. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB number of obsoleted index node ++ * @offs: offset of obsoleted index node ++ * ++ * Returns %1 if found and %0 otherwise. ++ */ ++static int find_old_idx(struct ubifs_info *c, int lnum, int offs) ++{ ++ struct ubifs_old_idx *o; ++ struct rb_node *p; ++ ++ p = c->old_idx.rb_node; ++ while (p) { ++ o = rb_entry(p, struct ubifs_old_idx, rb); ++ if (lnum < o->lnum) ++ p = p->rb_left; ++ else if (lnum > o->lnum) ++ p = p->rb_right; ++ else if (offs < o->offs) ++ p = p->rb_left; ++ else if (offs > o->offs) ++ p = p->rb_right; ++ else ++ return 1; ++ } ++ return 0; ++} ++ ++/** ++ * is_idx_node_in_use - determine if an index node can be overwritten. ++ * @c: UBIFS file-system description object ++ * @key: key of index node ++ * @level: index node level ++ * @lnum: LEB number of index node ++ * @offs: offset of index node ++ * ++ * If @key / @lnum / @offs identify an index node that was not part of the old ++ * index, then this function returns %0 (obsolete). Else if the index node was ++ * part of the old index but is now dirty %1 is returned, else if it is clean %2 ++ * is returned. A negative error code is returned on failure. ++ */ ++static int is_idx_node_in_use(struct ubifs_info *c, union ubifs_key *key, ++ int level, int lnum, int offs) ++{ ++ int ret; ++ ++ ret = is_idx_node_in_tnc(c, key, level, lnum, offs); ++ if (ret < 0) ++ return ret; /* Error code */ ++ if (ret == 0) ++ if (find_old_idx(c, lnum, offs)) ++ return 1; ++ return ret; ++} ++ ++/** ++ * layout_leb_in_gaps - layout index nodes using in-the-gaps method. ++ * @c: UBIFS file-system description object ++ * @p: return LEB number here ++ * ++ * This function lays out new index nodes for dirty znodes using in-the-gaps ++ * method of TNC commit. ++ * This function merely puts the next znode into the next gap, making no attempt ++ * to try to maximise the number of znodes that fit. ++ * This function returns the number of index nodes written into the gaps, or a ++ * negative error code on failure. ++ */ ++static int layout_leb_in_gaps(struct ubifs_info *c, int *p) ++{ ++ struct ubifs_scan_leb *sleb; ++ struct ubifs_scan_node *snod; ++ int lnum, dirt = 0, gap_start, gap_end, err, written, tot_written; ++ ++ tot_written = 0; ++ /* Get an index LEB with lots of obsolete index nodes */ ++ lnum = ubifs_find_dirty_idx_leb(c); ++ if (lnum < 0) ++ /* ++ * There also may be dirt in the index head that could be ++ * filled, however we do not check there at present. ++ */ ++ return lnum; /* Error code */ ++ *p = lnum; ++ dbg_gc("LEB %d", lnum); ++ /* ++ * Scan the index LEB. We use the generic scan for this even though ++ * it is more comprehensive and less efficient than is needed for this ++ * purpose. ++ */ ++ sleb = ubifs_scan(c, lnum, 0, c->ileb_buf); ++ c->ileb_len = 0; ++ if (IS_ERR(sleb)) ++ return PTR_ERR(sleb); ++ gap_start = 0; ++ list_for_each_entry(snod, &sleb->nodes, list) { ++ struct ubifs_idx_node *idx; ++ int in_use, level; ++ ++ ubifs_assert(snod->type == UBIFS_IDX_NODE); ++ idx = snod->node; ++ key_read(c, ubifs_idx_key(c, idx), &snod->key); ++ level = le16_to_cpu(idx->level); ++ /* Determine if the index node is in use (not obsolete) */ ++ in_use = is_idx_node_in_use(c, &snod->key, level, lnum, ++ snod->offs); ++ if (in_use < 0) { ++ ubifs_scan_destroy(sleb); ++ return in_use; /* Error code */ ++ } ++ if (in_use) { ++ if (in_use == 1) ++ dirt += ALIGN(snod->len, 8); ++ /* ++ * The obsolete index nodes form gaps that can be ++ * overwritten. This gap has ended because we have ++ * found an index node that is still in use ++ * i.e. not obsolete ++ */ ++ gap_end = snod->offs; ++ /* Try to fill gap */ ++ written = fill_gap(c, lnum, gap_start, gap_end, &dirt); ++ if (written < 0) { ++ ubifs_scan_destroy(sleb); ++ return written; /* Error code */ ++ } ++ tot_written += written; ++ gap_start = ALIGN(snod->offs + snod->len, 8); ++ } ++ } ++ ubifs_scan_destroy(sleb); ++ c->ileb_len = c->leb_size; ++ gap_end = c->leb_size; ++ /* Try to fill gap */ ++ written = fill_gap(c, lnum, gap_start, gap_end, &dirt); ++ if (written < 0) ++ return written; /* Error code */ ++ tot_written += written; ++ if (tot_written == 0) { ++ struct ubifs_lprops lp; ++ ++ dbg_gc("LEB %d wrote %d index nodes", lnum, tot_written); ++ err = ubifs_read_one_lp(c, lnum, &lp); ++ if (err) ++ return err; ++ if (lp.free == c->leb_size) { ++ /* ++ * We must have snatched this LEB from the idx_gc list ++ * so we need to correct the free and dirty space. ++ */ ++ err = ubifs_change_one_lp(c, lnum, ++ c->leb_size - c->ileb_len, ++ dirt, 0, 0, 0); ++ if (err) ++ return err; ++ } ++ return 0; ++ } ++ err = ubifs_change_one_lp(c, lnum, c->leb_size - c->ileb_len, dirt, ++ 0, 0, 0); ++ if (err) ++ return err; ++ err = ubi_leb_change(c->ubi, lnum, c->ileb_buf, c->ileb_len, ++ UBI_SHORTTERM); ++ if (err) { ++ ubifs_err("ubi_leb_change failed, error %d", err); ++ return err; ++ } ++ dbg_gc("LEB %d wrote %d index nodes", lnum, tot_written); ++ return tot_written; ++} ++ ++/** ++ * get_leb_cnt - calculate the number of empty LEBs needed to commit. ++ * @c: UBIFS file-system description object ++ * @cnt: number of znodes to commit ++ * ++ * This function returns the number of empty LEBs needed to commit @cnt znodes ++ * to the current index head. The number is not exact and may be more than ++ * needed. ++ */ ++static int get_leb_cnt(struct ubifs_info *c, int cnt) ++{ ++ int d; ++ ++ /* Assume maximum index node size (i.e. overestimate space needed) */ ++ cnt -= (c->leb_size - c->ihead_offs) / c->max_idx_node_sz; ++ if (cnt < 0) ++ cnt = 0; ++ d = c->leb_size / c->max_idx_node_sz; ++ return DIV_ROUND_UP(cnt, d); ++} ++ ++/** ++ * layout_in_gaps - in-the-gaps method of committing TNC. ++ * @c: UBIFS file-system description object ++ * @cnt: number of dirty znodes to commit. ++ * ++ * This function lays out new index nodes for dirty znodes using in-the-gaps ++ * method of TNC commit. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int layout_in_gaps(struct ubifs_info *c, int cnt) ++{ ++ int err, leb_needed_cnt, written, *p; ++ ++ dbg_gc("%d znodes to write", cnt); ++ ++ c->gap_lebs = kmalloc(sizeof(int) * (c->lst.idx_lebs + 1), GFP_NOFS); ++ if (!c->gap_lebs) ++ return -ENOMEM; ++ ++ p = c->gap_lebs; ++ do { ++ ubifs_assert(p < c->gap_lebs + sizeof(int) * c->lst.idx_lebs); ++ written = layout_leb_in_gaps(c, p); ++ if (written < 0) { ++ err = written; ++ if (err == -ENOSPC) { ++ if (!dbg_force_in_the_gaps_enabled) { ++ /* ++ * Do not print scary warnings if the ++ * debugging option which forces ++ * in-the-gaps is enabled. ++ */ ++ ubifs_err("out of space"); ++ spin_lock(&c->space_lock); ++ dbg_dump_budg(c); ++ spin_unlock(&c->space_lock); ++ dbg_dump_lprops(c); ++ } ++ /* Try to commit anyway */ ++ err = 0; ++ break; ++ } ++ kfree(c->gap_lebs); ++ c->gap_lebs = NULL; ++ return err; ++ } ++ p++; ++ cnt -= written; ++ leb_needed_cnt = get_leb_cnt(c, cnt); ++ dbg_gc("%d znodes remaining, need %d LEBs, have %d", cnt, ++ leb_needed_cnt, c->ileb_cnt); ++ } while (leb_needed_cnt > c->ileb_cnt); ++ ++ *p = -1; ++ return 0; ++} ++ ++/** ++ * layout_in_empty_space - layout index nodes in empty space. ++ * @c: UBIFS file-system description object ++ * ++ * This function lays out new index nodes for dirty znodes using empty LEBs. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int layout_in_empty_space(struct ubifs_info *c) ++{ ++ struct ubifs_znode *znode, *cnext, *zp; ++ int lnum, offs, len, next_len, buf_len, buf_offs, used, avail; ++ int wlen, blen, err; ++ ++ cnext = c->enext; ++ if (!cnext) ++ return 0; ++ ++ lnum = c->ihead_lnum; ++ buf_offs = c->ihead_offs; ++ ++ buf_len = ubifs_idx_node_sz(c, c->fanout); ++ buf_len = ALIGN(buf_len, c->min_io_size); ++ used = 0; ++ avail = buf_len; ++ ++ /* Ensure there is enough room for first write */ ++ next_len = ubifs_idx_node_sz(c, cnext->child_cnt); ++ if (buf_offs + next_len > c->leb_size) ++ lnum = -1; ++ ++ while (1) { ++ znode = cnext; ++ ++ len = ubifs_idx_node_sz(c, znode->child_cnt); ++ ++ /* Determine the index node position */ ++ if (lnum == -1) { ++ if (c->ileb_nxt >= c->ileb_cnt) { ++ ubifs_err("out of space"); ++ return -ENOSPC; ++ } ++ lnum = c->ilebs[c->ileb_nxt++]; ++ buf_offs = 0; ++ used = 0; ++ avail = buf_len; ++ } ++ ++ offs = buf_offs + used; ++ ++#ifdef CONFIG_UBIFS_FS_DEBUG ++ znode->lnum = lnum; ++ znode->offs = offs; ++ znode->len = len; ++#endif ++ ++ /* Update the parent */ ++ zp = znode->parent; ++ if (zp) { ++ struct ubifs_zbranch *zbr; ++ int i; ++ ++ i = znode->iip; ++ zbr = &zp->zbranch[i]; ++ zbr->lnum = lnum; ++ zbr->offs = offs; ++ zbr->len = len; ++ } else { ++ c->zroot.lnum = lnum; ++ c->zroot.offs = offs; ++ c->zroot.len = len; ++ } ++ c->calc_idx_sz += ALIGN(len, 8); ++ ++ /* ++ * Once lprops is updated, we can decrease the dirty znode count ++ * but it is easier to just do it here. ++ */ ++ atomic_long_dec(&c->dirty_zn_cnt); ++ ++ /* ++ * Calculate the next index node length to see if there is ++ * enough room for it ++ */ ++ cnext = znode->cnext; ++ if (cnext == c->cnext) ++ next_len = 0; ++ else ++ next_len = ubifs_idx_node_sz(c, cnext->child_cnt); ++ ++ if (c->min_io_size == 1) { ++ buf_offs += ALIGN(len, 8); ++ if (next_len) { ++ if (buf_offs + next_len <= c->leb_size) ++ continue; ++ err = ubifs_update_one_lp(c, lnum, 0, ++ c->leb_size - buf_offs, 0, 0); ++ if (err) ++ return err; ++ lnum = -1; ++ continue; ++ } ++ err = ubifs_update_one_lp(c, lnum, ++ c->leb_size - buf_offs, 0, 0, 0); ++ if (err) ++ return err; ++ break; ++ } ++ ++ /* Update buffer positions */ ++ wlen = used + len; ++ used += ALIGN(len, 8); ++ avail -= ALIGN(len, 8); ++ ++ if (next_len != 0 && ++ buf_offs + used + next_len <= c->leb_size && ++ avail > 0) ++ continue; ++ ++ if (avail <= 0 && next_len && ++ buf_offs + used + next_len <= c->leb_size) ++ blen = buf_len; ++ else ++ blen = ALIGN(wlen, c->min_io_size); ++ ++ /* The buffer is full or there are no more znodes to do */ ++ buf_offs += blen; ++ if (next_len) { ++ if (buf_offs + next_len > c->leb_size) { ++ err = ubifs_update_one_lp(c, lnum, ++ c->leb_size - buf_offs, blen - used, ++ 0, 0); ++ if (err) ++ return err; ++ lnum = -1; ++ } ++ used -= blen; ++ if (used < 0) ++ used = 0; ++ avail = buf_len - used; ++ continue; ++ } ++ err = ubifs_update_one_lp(c, lnum, c->leb_size - buf_offs, ++ blen - used, 0, 0); ++ if (err) ++ return err; ++ break; ++ } ++ ++#ifdef CONFIG_UBIFS_FS_DEBUG ++ c->new_ihead_lnum = lnum; ++ c->new_ihead_offs = buf_offs; ++#endif ++ ++ return 0; ++} ++ ++/** ++ * layout_commit - determine positions of index nodes to commit. ++ * @c: UBIFS file-system description object ++ * @no_space: indicates that insufficient empty LEBs were allocated ++ * @cnt: number of znodes to commit ++ * ++ * Calculate and update the positions of index nodes to commit. If there were ++ * an insufficient number of empty LEBs allocated, then index nodes are placed ++ * into the gaps created by obsolete index nodes in non-empty index LEBs. For ++ * this purpose, an obsolete index node is one that was not in the index as at ++ * the end of the last commit. To write "in-the-gaps" requires that those index ++ * LEBs are updated atomically in-place. ++ */ ++static int layout_commit(struct ubifs_info *c, int no_space, int cnt) ++{ ++ int err; ++ ++ if (no_space) { ++ err = layout_in_gaps(c, cnt); ++ if (err) ++ return err; ++ } ++ err = layout_in_empty_space(c); ++ return err; ++} ++ ++/** ++ * find_first_dirty - find first dirty znode. ++ * @znode: znode to begin searching from ++ */ ++static struct ubifs_znode *find_first_dirty(struct ubifs_znode *znode) ++{ ++ int i, cont; ++ ++ if (!znode) ++ return NULL; ++ ++ while (1) { ++ if (znode->level == 0) { ++ if (ubifs_zn_dirty(znode)) ++ return znode; ++ return NULL; ++ } ++ cont = 0; ++ for (i = 0; i < znode->child_cnt; i++) { ++ struct ubifs_zbranch *zbr = &znode->zbranch[i]; ++ ++ if (zbr->znode && ubifs_zn_dirty(zbr->znode)) { ++ znode = zbr->znode; ++ cont = 1; ++ break; ++ } ++ } ++ if (!cont) { ++ if (ubifs_zn_dirty(znode)) ++ return znode; ++ return NULL; ++ } ++ } ++} ++ ++/** ++ * find_next_dirty - find next dirty znode. ++ * @znode: znode to begin searching from ++ */ ++static struct ubifs_znode *find_next_dirty(struct ubifs_znode *znode) ++{ ++ int n = znode->iip + 1; ++ ++ znode = znode->parent; ++ if (!znode) ++ return NULL; ++ for (; n < znode->child_cnt; n++) { ++ struct ubifs_zbranch *zbr = &znode->zbranch[n]; ++ ++ if (zbr->znode && ubifs_zn_dirty(zbr->znode)) ++ return find_first_dirty(zbr->znode); ++ } ++ return znode; ++} ++ ++/** ++ * get_znodes_to_commit - create list of dirty znodes to commit. ++ * @c: UBIFS file-system description object ++ * ++ * This function returns the number of znodes to commit. ++ */ ++static int get_znodes_to_commit(struct ubifs_info *c) ++{ ++ struct ubifs_znode *znode, *cnext; ++ int cnt = 0; ++ ++ c->cnext = find_first_dirty(c->zroot.znode); ++ znode = c->enext = c->cnext; ++ if (!znode) { ++ dbg_cmt("no znodes to commit"); ++ return 0; ++ } ++ cnt += 1; ++ while (1) { ++ ubifs_assert(!test_bit(COW_ZNODE, &znode->flags)); ++ __set_bit(COW_ZNODE, &znode->flags); ++ znode->alt = 0; ++ cnext = find_next_dirty(znode); ++ if (!cnext) { ++ znode->cnext = c->cnext; ++ break; ++ } ++ znode->cnext = cnext; ++ znode = cnext; ++ cnt += 1; ++ } ++ dbg_cmt("committing %d znodes", cnt); ++ ubifs_assert(cnt == atomic_long_read(&c->dirty_zn_cnt)); ++ return cnt; ++} ++ ++/** ++ * alloc_idx_lebs - allocate empty LEBs to be used to commit. ++ * @c: UBIFS file-system description object ++ * @cnt: number of znodes to commit ++ * ++ * This function returns %-ENOSPC if it cannot allocate a sufficient number of ++ * empty LEBs. %0 is returned on success, otherwise a negative error code ++ * is returned. ++ */ ++static int alloc_idx_lebs(struct ubifs_info *c, int cnt) ++{ ++ int i, leb_cnt, lnum; ++ ++ c->ileb_cnt = 0; ++ c->ileb_nxt = 0; ++ leb_cnt = get_leb_cnt(c, cnt); ++ dbg_cmt("need about %d empty LEBS for TNC commit", leb_cnt); ++ if (!leb_cnt) ++ return 0; ++ c->ilebs = kmalloc(leb_cnt * sizeof(int), GFP_NOFS); ++ if (!c->ilebs) ++ return -ENOMEM; ++ for (i = 0; i < leb_cnt; i++) { ++ lnum = ubifs_find_free_leb_for_idx(c); ++ if (lnum < 0) ++ return lnum; ++ c->ilebs[c->ileb_cnt++] = lnum; ++ dbg_cmt("LEB %d", lnum); ++ } ++ if (dbg_force_in_the_gaps()) ++ return -ENOSPC; ++ return 0; ++} ++ ++/** ++ * free_unused_idx_lebs - free unused LEBs that were allocated for the commit. ++ * @c: UBIFS file-system description object ++ * ++ * It is possible that we allocate more empty LEBs for the commit than we need. ++ * This functions frees the surplus. ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int free_unused_idx_lebs(struct ubifs_info *c) ++{ ++ int i, err = 0, lnum, er; ++ ++ for (i = c->ileb_nxt; i < c->ileb_cnt; i++) { ++ lnum = c->ilebs[i]; ++ dbg_cmt("LEB %d", lnum); ++ er = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0, ++ LPROPS_INDEX | LPROPS_TAKEN, 0); ++ if (!err) ++ err = er; ++ } ++ return err; ++} ++ ++/** ++ * free_idx_lebs - free unused LEBs after commit end. ++ * @c: UBIFS file-system description object ++ * ++ * This function returns %0 on success and a negative error code on failure. ++ */ ++static int free_idx_lebs(struct ubifs_info *c) ++{ ++ int err; ++ ++ err = free_unused_idx_lebs(c); ++ kfree(c->ilebs); ++ c->ilebs = NULL; ++ return err; ++} ++ ++/** ++ * ubifs_tnc_start_commit - start TNC commit. ++ * @c: UBIFS file-system description object ++ * @zroot: new index root position is returned here ++ * ++ * This function prepares the list of indexing nodes to commit and lays out ++ * their positions on flash. If there is not enough free space it uses the ++ * in-gap commit method. Returns zero in case of success and a negative error ++ * code in case of failure. ++ */ ++int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot) ++{ ++ int err = 0, cnt; ++ ++ mutex_lock(&c->tnc_mutex); ++ err = dbg_check_tnc(c, 1); ++ if (err) ++ goto out; ++ cnt = get_znodes_to_commit(c); ++ if (cnt != 0) { ++ int no_space = 0; ++ ++ err = alloc_idx_lebs(c, cnt); ++ if (err == -ENOSPC) ++ no_space = 1; ++ else if (err) ++ goto out_free; ++ err = layout_commit(c, no_space, cnt); ++ if (err) ++ goto out_free; ++ ubifs_assert(atomic_long_read(&c->dirty_zn_cnt) == 0); ++ err = free_unused_idx_lebs(c); ++ if (err) ++ goto out; ++ } ++ destroy_old_idx(c); ++ memcpy(zroot, &c->zroot, sizeof(struct ubifs_zbranch)); ++ ++ err = ubifs_save_dirty_idx_lnums(c); ++ if (err) ++ goto out; ++ ++ spin_lock(&c->space_lock); ++ /* ++ * Although we have not finished committing yet, update size of the ++ * committed index ('c->old_idx_sz') and zero out the index growth ++ * budget. It is OK to do this now, because we've reserved all the ++ * space which is needed to commit the index, and it is save for the ++ * budgeting subsystem to assume the index is already committed, ++ * even though it is not. ++ */ ++ c->old_idx_sz = c->calc_idx_sz; ++ c->budg_uncommitted_idx = 0; ++ spin_unlock(&c->space_lock); ++ mutex_unlock(&c->tnc_mutex); ++ ++ dbg_cmt("number of index LEBs %d", c->lst.idx_lebs); ++ dbg_cmt("size of index %llu", c->calc_idx_sz); ++ return err; ++ ++out_free: ++ free_idx_lebs(c); ++out: ++ mutex_unlock(&c->tnc_mutex); ++ return err; ++} ++ ++/** ++ * write_index - write index nodes. ++ * @c: UBIFS file-system description object ++ * ++ * This function writes the index nodes whose positions were laid out in the ++ * layout_in_empty_space function. ++ */ ++static int write_index(struct ubifs_info *c) ++{ ++ struct ubifs_idx_node *idx; ++ struct ubifs_znode *znode, *cnext; ++ int i, lnum, offs, len, next_len, buf_len, buf_offs, used; ++ int avail, wlen, err, lnum_pos = 0; ++ ++ cnext = c->enext; ++ if (!cnext) ++ return 0; ++ ++ /* ++ * Always write index nodes to the index head so that index nodes and ++ * other types of nodes are never mixed in the same erase block. ++ */ ++ lnum = c->ihead_lnum; ++ buf_offs = c->ihead_offs; ++ ++ /* Allocate commit buffer */ ++ buf_len = ALIGN(c->max_idx_node_sz, c->min_io_size); ++ used = 0; ++ avail = buf_len; ++ ++ /* Ensure there is enough room for first write */ ++ next_len = ubifs_idx_node_sz(c, cnext->child_cnt); ++ if (buf_offs + next_len > c->leb_size) { ++ err = ubifs_update_one_lp(c, lnum, LPROPS_NC, 0, 0, ++ LPROPS_TAKEN); ++ if (err) ++ return err; ++ lnum = -1; ++ } ++ ++ while (1) { ++ cond_resched(); ++ ++ znode = cnext; ++ idx = c->cbuf + used; ++ ++ /* Make index node */ ++ idx->ch.node_type = UBIFS_IDX_NODE; ++ idx->child_cnt = cpu_to_le16(znode->child_cnt); ++ idx->level = cpu_to_le16(znode->level); ++ for (i = 0; i < znode->child_cnt; i++) { ++ struct ubifs_branch *br = ubifs_idx_branch(c, idx, i); ++ struct ubifs_zbranch *zbr = &znode->zbranch[i]; ++ ++ key_write_idx(c, &zbr->key, &br->key); ++ br->lnum = cpu_to_le32(zbr->lnum); ++ br->offs = cpu_to_le32(zbr->offs); ++ br->len = cpu_to_le32(zbr->len); ++ if (!zbr->lnum || !zbr->len) { ++ ubifs_err("bad ref in znode"); ++ dbg_dump_znode(c, znode); ++ if (zbr->znode) ++ dbg_dump_znode(c, zbr->znode); ++ } ++ } ++ len = ubifs_idx_node_sz(c, znode->child_cnt); ++ ubifs_prepare_node(c, idx, len, 0); ++ ++ /* Determine the index node position */ ++ if (lnum == -1) { ++ lnum = c->ilebs[lnum_pos++]; ++ buf_offs = 0; ++ used = 0; ++ avail = buf_len; ++ } ++ offs = buf_offs + used; ++ ++#ifdef CONFIG_UBIFS_FS_DEBUG ++ if (lnum != znode->lnum || offs != znode->offs || ++ len != znode->len) { ++ ubifs_err("inconsistent znode posn"); ++ return -EINVAL; ++ } ++#endif ++ ++ /* Grab some stuff from znode while we still can */ ++ cnext = znode->cnext; ++ ++ ubifs_assert(ubifs_zn_dirty(znode)); ++ ubifs_assert(test_bit(COW_ZNODE, &znode->flags)); ++ ++ /* ++ * It is important that other threads should see %DIRTY_ZNODE ++ * flag cleared before %COW_ZNODE. Specifically, it matters in ++ * the 'dirty_cow_znode()' function. This is the reason for the ++ * first barrier. Also, we want the bit changes to be seen to ++ * other threads ASAP, to avoid unnecesarry copying, which is ++ * the reason for the second barrier. ++ */ ++ clear_bit(DIRTY_ZNODE, &znode->flags); ++ smp_mb__before_clear_bit(); ++ clear_bit(COW_ZNODE, &znode->flags); ++ smp_mb__after_clear_bit(); ++ ++ /* Do not access znode from this point on */ ++ ++ /* Update buffer positions */ ++ wlen = used + len; ++ used += ALIGN(len, 8); ++ avail -= ALIGN(len, 8); ++ ++ /* ++ * Calculate the next index node length to see if there is ++ * enough room for it ++ */ ++ if (cnext == c->cnext) ++ next_len = 0; ++ else ++ next_len = ubifs_idx_node_sz(c, cnext->child_cnt); ++ ++ if (c->min_io_size == 1) { ++ /* ++ * Write the prepared index node immediately if there is ++ * no minimum IO size ++ */ ++ err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs, ++ wlen, UBI_SHORTTERM); ++ if (err) ++ return err; ++ buf_offs += ALIGN(wlen, 8); ++ if (next_len) { ++ used = 0; ++ avail = buf_len; ++ if (buf_offs + next_len > c->leb_size) { ++ err = ubifs_update_one_lp(c, lnum, ++ LPROPS_NC, 0, 0, LPROPS_TAKEN); ++ if (err) ++ return err; ++ lnum = -1; ++ } ++ continue; ++ } ++ } else { ++ int blen, nxt_offs = buf_offs + used + next_len; ++ ++ if (next_len && nxt_offs <= c->leb_size) { ++ if (avail > 0) ++ continue; ++ else ++ blen = buf_len; ++ } else { ++ wlen = ALIGN(wlen, 8); ++ blen = ALIGN(wlen, c->min_io_size); ++ ubifs_pad(c, c->cbuf + wlen, blen - wlen); ++ } ++ /* ++ * The buffer is full or there are no more znodes ++ * to do ++ */ ++ err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs, ++ blen, UBI_SHORTTERM); ++ if (err) ++ return err; ++ buf_offs += blen; ++ if (next_len) { ++ if (nxt_offs > c->leb_size) { ++ err = ubifs_update_one_lp(c, lnum, ++ LPROPS_NC, 0, 0, LPROPS_TAKEN); ++ if (err) ++ return err; ++ lnum = -1; ++ } ++ used -= blen; ++ if (used < 0) ++ used = 0; ++ avail = buf_len - used; ++ memmove(c->cbuf, c->cbuf + blen, used); ++ continue; ++ } ++ } ++ break; ++ } ++ ++#ifdef CONFIG_UBIFS_FS_DEBUG ++ if (lnum != c->new_ihead_lnum || buf_offs != c->new_ihead_offs) { ++ ubifs_err("inconsistent ihead"); ++ return -EINVAL; ++ } ++#endif ++ ++ c->ihead_lnum = lnum; ++ c->ihead_offs = buf_offs; ++ ++ return 0; ++} ++ ++/** ++ * free_obsolete_znodes - free obsolete znodes. ++ * @c: UBIFS file-system description object ++ * ++ * At the end of commit end, obsolete znodes are freed. ++ */ ++static void free_obsolete_znodes(struct ubifs_info *c) ++{ ++ struct ubifs_znode *znode, *cnext; ++ ++ cnext = c->cnext; ++ do { ++ znode = cnext; ++ cnext = znode->cnext; ++ if (test_bit(OBSOLETE_ZNODE, &znode->flags)) ++ kfree(znode); ++ else { ++ znode->cnext = NULL; ++ atomic_long_inc(&c->clean_zn_cnt); ++ atomic_long_inc(&ubifs_clean_zn_cnt); ++ } ++ } while (cnext != c->cnext); ++} ++ ++/** ++ * return_gap_lebs - return LEBs used by the in-gap commit method. ++ * @c: UBIFS file-system description object ++ * ++ * This function clears the "taken" flag for the LEBs which were used by the ++ * "commit in-the-gaps" method. ++ */ ++static int return_gap_lebs(struct ubifs_info *c) ++{ ++ int *p, err; ++ ++ if (!c->gap_lebs) ++ return 0; ++ ++ dbg_cmt(""); ++ for (p = c->gap_lebs; *p != -1; p++) { ++ err = ubifs_change_one_lp(c, *p, LPROPS_NC, LPROPS_NC, 0, ++ LPROPS_TAKEN, 0); ++ if (err) ++ return err; ++ } ++ ++ kfree(c->gap_lebs); ++ c->gap_lebs = NULL; ++ return 0; ++} ++ ++/** ++ * ubifs_tnc_end_commit - update the TNC for commit end. ++ * @c: UBIFS file-system description object ++ * ++ * Write the dirty znodes. ++ */ ++int ubifs_tnc_end_commit(struct ubifs_info *c) ++{ ++ int err; ++ ++ if (!c->cnext) ++ return 0; ++ ++ err = return_gap_lebs(c); ++ if (err) ++ return err; ++ ++ err = write_index(c); ++ if (err) ++ return err; ++ ++ mutex_lock(&c->tnc_mutex); ++ ++ dbg_cmt("TNC height is %d", c->zroot.znode->level + 1); ++ ++ free_obsolete_znodes(c); ++ ++ c->cnext = NULL; ++ kfree(c->ilebs); ++ c->ilebs = NULL; ++ ++ mutex_unlock(&c->tnc_mutex); ++ ++ return 0; ++} +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/tnc_misc.c avr32-2.6/fs/ubifs/tnc_misc.c +--- linux-2.6.25.6/fs/ubifs/tnc_misc.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/tnc_misc.c 2008-06-12 15:09:45.603817614 +0200 +@@ -0,0 +1,496 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Adrian Hunter ++ * Artem Bityutskiy (Битюцкий Артём) ++ */ ++ ++/* ++ * This file contains miscelanious TNC-related functions shared betweend ++ * different files. This file does not form any logically separate TNC ++ * sub-system. The file was created because there is a lot of TNC code and ++ * putting it all in one file would make that file too big and unreadable. ++ */ ++ ++#include "ubifs.h" ++ ++/** ++ * ubifs_tnc_levelorder_next - next TNC tree element in levelorder traversal. ++ * @zr: root of the subtree to traverse ++ * @znode: previous znode ++ * ++ * This function implements levelorder TNC traversal. The LNC is ignored. ++ * Returns the next element or %NULL if @znode is already the last one. ++ */ ++struct ubifs_znode *ubifs_tnc_levelorder_next(struct ubifs_znode *zr, ++ struct ubifs_znode *znode) ++{ ++ int level, iip, level_search = 0; ++ struct ubifs_znode *zn; ++ ++ ubifs_assert(zr); ++ ++ if (unlikely(!znode)) ++ return zr; ++ ++ if (unlikely(znode == zr)) { ++ if (znode->level == 0) ++ return NULL; ++ return ubifs_tnc_find_child(zr, 0); ++ } ++ ++ level = znode->level; ++ ++ iip = znode->iip; ++ while (1) { ++ ubifs_assert(znode->level <= zr->level); ++ ++ /* ++ * First walk up until there is a znode with next branch to ++ * look at. ++ */ ++ while (znode->parent != zr && iip >= znode->parent->child_cnt) { ++ znode = znode->parent; ++ iip = znode->iip; ++ } ++ ++ if (unlikely(znode->parent == zr && ++ iip >= znode->parent->child_cnt)) { ++ /* This level is done, switch to the lower one */ ++ level -= 1; ++ if (level_search || level < 0) ++ /* ++ * We were already looking for znode at lower ++ * level ('level_search'). As we are here ++ * again, it just does not exist. Or all levels ++ * were finished ('level < 0'). ++ */ ++ return NULL; ++ ++ level_search = 1; ++ iip = -1; ++ znode = ubifs_tnc_find_child(zr, 0); ++ ubifs_assert(znode); ++ } ++ ++ /* Switch to the next index */ ++ zn = ubifs_tnc_find_child(znode->parent, iip + 1); ++ if (!zn) { ++ /* No more children to look at, we have walk up */ ++ iip = znode->parent->child_cnt; ++ continue; ++ } ++ ++ /* Walk back down to the level we came from ('level') */ ++ while (zn->level != level) { ++ znode = zn; ++ zn = ubifs_tnc_find_child(zn, 0); ++ if (!zn) { ++ /* ++ * This path is not too deep so it does not ++ * reach 'level'. Try next path. ++ */ ++ iip = znode->iip; ++ break; ++ } ++ } ++ ++ if (zn) { ++ ubifs_assert(zn->level >= 0); ++ return zn; ++ } ++ } ++} ++ ++/** ++ * ubifs_search_zbranch - search znode branch. ++ * @c: UBIFS file-system description object ++ * @znode: znode to search in ++ * @key: key to search for ++ * @n: znode branch slot number is returned here ++ * ++ * This is a helper function which search branch with key @key in @znode using ++ * binary search. The result of the search may be: ++ * o exact match, then %1 is returned, and the slot number of the branch is ++ * stored in @n; ++ * o no exact match, then %0 is returned and the slot number of the left ++ * closest branch is returned in @n; the slot if all keys in this znode are ++ * greater than @key, then %-1 is returned in @n. ++ */ ++int ubifs_search_zbranch(const struct ubifs_info *c, ++ const struct ubifs_znode *znode, ++ const union ubifs_key *key, int *n) ++{ ++ int beg = 0, end = znode->child_cnt, uninitialized_var(mid); ++ int uninitialized_var(cmp); ++ const struct ubifs_zbranch *zbr = &znode->zbranch[0]; ++ ++ ubifs_assert(end > beg); ++ ++ while (end > beg) { ++ mid = (beg + end) >> 1; ++ cmp = keys_cmp(c, key, &zbr[mid].key); ++ if (cmp > 0) ++ beg = mid + 1; ++ else if (cmp < 0) ++ end = mid; ++ else { ++ *n = mid; ++ return 1; ++ } ++ } ++ ++ *n = end - 1; ++ ++ /* The insert point is after *n */ ++ ubifs_assert(*n >= -1 && *n < znode->child_cnt); ++ if (*n == -1) ++ ubifs_assert(keys_cmp(c, key, &zbr[0].key) < 0); ++ else ++ ubifs_assert(keys_cmp(c, key, &zbr[*n].key) > 0); ++ if (*n + 1 < znode->child_cnt) ++ ubifs_assert(keys_cmp(c, key, &zbr[*n + 1].key) < 0); ++ ++ return 0; ++} ++ ++/** ++ * ubifs_tnc_postorder_first - find first znode to do postorder tree traversal. ++ * @znode: znode to start at (root of the sub-tree to traverse) ++ * ++ * Find the lowest leftmost znode in a subtree of the TNC tree. The LNC is ++ * ignored. ++ */ ++struct ubifs_znode *ubifs_tnc_postorder_first(struct ubifs_znode *znode) ++{ ++ if (unlikely(!znode)) ++ return NULL; ++ ++ while (znode->level > 0) { ++ struct ubifs_znode *child; ++ ++ child = ubifs_tnc_find_child(znode, 0); ++ if (!child) ++ return znode; ++ znode = child; ++ } ++ ++ return znode; ++} ++ ++/** ++ * ubifs_tnc_postorder_next - next TNC tree element in postorder traversal. ++ * @znode: previous znode ++ * ++ * This function implements postorder TNC traversal. The LNC is ignored. ++ * Returns the next element or %NULL if @znode is already the last one. ++ */ ++struct ubifs_znode *ubifs_tnc_postorder_next(struct ubifs_znode *znode) ++{ ++ struct ubifs_znode *zn; ++ ++ ubifs_assert(znode); ++ if (unlikely(!znode->parent)) ++ return NULL; ++ ++ /* Switch to the next index in the parent */ ++ zn = ubifs_tnc_find_child(znode->parent, znode->iip + 1); ++ if (!zn) ++ /* This is in fact the last child, return parent */ ++ return znode->parent; ++ ++ /* Go to the first znode in this new subtree */ ++ return ubifs_tnc_postorder_first(zn); ++} ++ ++/** ++ * ubifs_destroy_tnc_subtree - destroy all znodes connected to a subtree. ++ * @znode: znode defining subtree to destroy ++ * ++ * This function destroys subtree of the TNC tree. Returns number of clean ++ * znodes in the subtree. ++ */ ++long ubifs_destroy_tnc_subtree(struct ubifs_znode *znode) ++{ ++ struct ubifs_znode *zn = ubifs_tnc_postorder_first(znode); ++ long clean_freed = 0; ++ int n; ++ ++ ubifs_assert(zn); ++ while (1) { ++ for (n = 0; n < zn->child_cnt; n++) { ++ if (!zn->zbranch[n].znode) ++ continue; ++ ++ if (zn->level > 0 && ++ !ubifs_zn_dirty(zn->zbranch[n].znode)) ++ clean_freed += 1; ++ ++ cond_resched(); ++ kfree(zn->zbranch[n].znode); ++ } ++ ++ if (zn == znode) { ++ if (!ubifs_zn_dirty(zn)) ++ clean_freed += 1; ++ kfree(zn); ++ return clean_freed; ++ } ++ ++ zn = ubifs_tnc_postorder_next(zn); ++ } ++} ++ ++/** ++ * read_znode - read an indexing node from flash and fill znode. ++ * @c: UBIFS file-system description object ++ * @lnum: LEB of the indexing node to read ++ * @offs: node offset ++ * @len: node length ++ * @znode: znode to read to ++ * ++ * This function reads an indexing node from the flash media and fills znode ++ * with the read data. Returns zero in case of success and a negative error ++ * code in case of failure. The read indexing node is validated and if anything ++ * is wrong with it, this function prints complaint messages and returns ++ * %-EINVAL. ++ */ ++static int read_znode(struct ubifs_info *c, int lnum, int offs, int len, ++ struct ubifs_znode *znode) ++{ ++ int i, err, type, cmp; ++ struct ubifs_idx_node *idx; ++ ++ idx = kmalloc(c->max_idx_node_sz, GFP_NOFS); ++ if (!idx) ++ return -ENOMEM; ++ ++ err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs); ++ if (err < 0) { ++ kfree(idx); ++ return err; ++ } ++ ++ znode->child_cnt = le16_to_cpu(idx->child_cnt); ++ znode->level = le16_to_cpu(idx->level); ++ ++ dbg_tnc("LEB %d:%d, level %d, %d branch", ++ lnum, offs, znode->level, znode->child_cnt); ++ ++ if (znode->child_cnt > c->fanout || znode->level > UBIFS_MAX_LEVELS) { ++ dbg_err("current fanout %d, branch count %d", ++ c->fanout, znode->child_cnt); ++ dbg_err("max levels %d, znode level %d", ++ UBIFS_MAX_LEVELS, znode->level); ++ err = 1; ++ goto out_dump; ++ } ++ ++ for (i = 0; i < znode->child_cnt; i++) { ++ const struct ubifs_branch *br = ubifs_idx_branch(c, idx, i); ++ struct ubifs_zbranch *zbr = &znode->zbranch[i]; ++ ++ key_read(c, &br->key, &zbr->key); ++ zbr->lnum = le32_to_cpu(br->lnum); ++ zbr->offs = le32_to_cpu(br->offs); ++ zbr->len = le32_to_cpu(br->len); ++ zbr->znode = NULL; ++ ++ /* Validate branch */ ++ ++ if (zbr->lnum < c->main_first || ++ zbr->lnum >= c->leb_cnt || zbr->offs < 0 || ++ zbr->offs + zbr->len > c->leb_size || zbr->offs & 7) { ++ dbg_err("bad branch %d", i); ++ err = 2; ++ goto out_dump; ++ } ++ ++ switch (key_type(c, &zbr->key)) { ++ case UBIFS_INO_KEY: ++ case UBIFS_DATA_KEY: ++ case UBIFS_DENT_KEY: ++ case UBIFS_XENT_KEY: ++ break; ++ default: ++ dbg_msg("bad key type at slot %d: %s", i, ++ DBGKEY(&zbr->key)); ++ err = 3; ++ goto out_dump; ++ } ++ ++ if (znode->level) ++ continue; ++ ++ type = key_type(c, &zbr->key); ++ if (c->ranges[type].max_len == 0) { ++ if (zbr->len != c->ranges[type].len) { ++ dbg_err("bad target node (type %d) length (%d)", ++ type, zbr->len); ++ dbg_err("have to be %d", c->ranges[type].len); ++ err = 4; ++ goto out_dump; ++ } ++ } else if (zbr->len < c->ranges[type].min_len || ++ zbr->len > c->ranges[type].max_len) { ++ dbg_err("bad target node (type %d) length (%d)", ++ type, zbr->len); ++ dbg_err("have to be in range of %d-%d", ++ c->ranges[type].min_len, ++ c->ranges[type].max_len); ++ err = 5; ++ goto out_dump; ++ } ++ } ++ ++ /* ++ * Ensure that the next key is greater or equivalent to the ++ * previous one. ++ */ ++ for (i = 0; i < znode->child_cnt - 1; i++) { ++ const union ubifs_key *key1, *key2; ++ ++ key1 = &znode->zbranch[i].key; ++ key2 = &znode->zbranch[i + 1].key; ++ ++ cmp = keys_cmp(c, key1, key2); ++ if (cmp > 0) { ++ dbg_err("bad key order (keys %d and %d)", i, i + 1); ++ err = 6; ++ goto out_dump; ++ } else if (cmp == 0 && !is_hash_key(c, key1)) { ++ /* These can only be keys with colliding hash */ ++ dbg_err("keys %d and %d are not hashed but equivalent", ++ i, i + 1); ++ err = 7; ++ goto out_dump; ++ } ++ } ++ ++ kfree(idx); ++ return 0; ++ ++out_dump: ++ ubifs_err("bad indexing node at LEB %d:%d, error %d", lnum, offs, err); ++ dbg_dump_node(c, idx); ++ kfree(idx); ++ return -EINVAL; ++} ++ ++/** ++ * ubifs_load_znode - load znode to TNC cache. ++ * @c: UBIFS file-system description object ++ * @zbr: znode branch ++ * @parent: znode's parent ++ * @iip: index in parent ++ * ++ * This function loads znode pointed to by @zbr into the TNC cache and ++ * returns pointer to it in case of success and a negative error code in case ++ * of failure. ++ */ ++struct ubifs_znode *ubifs_load_znode(struct ubifs_info *c, ++ struct ubifs_zbranch *zbr, ++ struct ubifs_znode *parent, int iip) ++{ ++ int err; ++ struct ubifs_znode *znode; ++ ++ ubifs_assert(!zbr->znode); ++ /* ++ * A slab cache is not presently used for znodes because the znode size ++ * depends on the fanout which is stored in the superblock. ++ */ ++ znode = kzalloc(c->max_znode_sz, GFP_NOFS); ++ if (!znode) ++ return ERR_PTR(-ENOMEM); ++ ++ err = read_znode(c, zbr->lnum, zbr->offs, zbr->len, znode); ++ if (err) ++ goto out; ++ ++ atomic_long_inc(&c->clean_zn_cnt); ++ ++ /* ++ * Increment the global clean znode counter as well. It is OK that ++ * global and per-FS clean znode counters may be inconsistent for some ++ * short time (because we might be preempted at this point), the global ++ * one is only used in shrinker. ++ */ ++ atomic_long_inc(&ubifs_clean_zn_cnt); ++ ++ zbr->znode = znode; ++ znode->parent = parent; ++ znode->time = get_seconds(); ++ znode->iip = iip; ++ ++ return znode; ++ ++out: ++ kfree(znode); ++ return ERR_PTR(err); ++} ++ ++/** ++ * ubifs_tnc_read_node - read a leaf node from the flash media. ++ * @c: UBIFS file-system description object ++ * @zbr: key and position of the node ++ * @node: node is returned here ++ * ++ * This function reads a node defined by @zbr from the flash media. Returns ++ * zero in case of success or a negative negative error code in case of ++ * failure. ++ */ ++int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr, ++ void *node) ++{ ++ union ubifs_key key1, *key = &zbr->key; ++ int err, type = key_type(c, key); ++ struct ubifs_wbuf *wbuf; ++ ++ ubifs_assert(!zbr->leaf); ++ ++ /* ++ * 'zbr' has to point to on-flash node. The node may sit in a bud and ++ * may even be in a write buffer, so we have to take care about this. ++ */ ++ wbuf = ubifs_get_wbuf(c, zbr->lnum); ++ if (wbuf) ++ err = ubifs_read_node_wbuf(wbuf, node, type, zbr->len, ++ zbr->lnum, zbr->offs); ++ else ++ err = ubifs_read_node(c, node, type, zbr->len, zbr->lnum, ++ zbr->offs); ++ ++ if (err) { ++ dbg_tnc("key %s", DBGKEY(key)); ++ return err; ++ } ++ ++ /* Make sure the key of the read node is correct */ ++ key_read(c, key, &key1); ++ if (memcmp(node + UBIFS_KEY_OFFSET, &key1, c->key_len)) { ++ ubifs_err("bad key in node at LEB %d:%d", ++ zbr->lnum, zbr->offs); ++ dbg_tnc("looked for key %s found node's key %s", ++ DBGKEY(key), DBGKEY1(&key1)); ++ dbg_dump_node(c, node); ++ return -EINVAL; ++ } ++ ++ return 0; ++} +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/ubifs.h avr32-2.6/fs/ubifs/ubifs.h +--- linux-2.6.25.6/fs/ubifs/ubifs.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/ubifs.h 2008-06-12 15:09:45.603817614 +0200 +@@ -0,0 +1,1605 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Artem Bityutskiy (Битюцкий Артём) ++ * Adrian Hunter ++ */ ++ ++/* Implementation version 0.7 */ ++ ++#ifndef __UBIFS_H__ ++#define __UBIFS_H__ ++ ++#include <asm/div64.h> ++#include <linux/statfs.h> ++#include <linux/fs.h> ++#include <linux/err.h> ++#include <linux/sched.h> ++#include <linux/vmalloc.h> ++#include <linux/spinlock.h> ++#include <linux/mutex.h> ++#include <linux/rwsem.h> ++#include <linux/mtd/ubi.h> ++#include <linux/pagemap.h> ++#include <linux/backing-dev.h> ++#include "ubifs-media.h" ++ ++/* Version of this UBIFS implementation */ ++#define UBIFS_VERSION 1 ++ ++/* Normal UBIFS messages */ ++#define ubifs_msg(fmt, ...) \ ++ printk(KERN_NOTICE "UBIFS: " fmt "\n", ##__VA_ARGS__) ++/* UBIFS error messages */ ++#define ubifs_err(fmt, ...) \ ++ printk(KERN_ERR "UBIFS error (pid %d): %s: " fmt "\n", current->pid, \ ++ __func__, ##__VA_ARGS__) ++/* UBIFS warning messages */ ++#define ubifs_warn(fmt, ...) \ ++ printk(KERN_WARNING "UBIFS warning (pid %d): %s: " fmt "\n", \ ++ current->pid, __func__, ##__VA_ARGS__) ++ ++/* UBIFS file system VFS magic number */ ++#define UBIFS_SUPER_MAGIC 0x24051905 ++ ++/* Number of UBIFS blocks per VFS page */ ++#define UBIFS_BLOCKS_PER_PAGE (PAGE_CACHE_SIZE / UBIFS_BLOCK_SIZE) ++#define UBIFS_BLOCKS_PER_PAGE_SHIFT (PAGE_CACHE_SHIFT - UBIFS_BLOCK_SHIFT) ++ ++/* "File system end of life" sequence number watermark */ ++#define SQNUM_WARN_WATERMARK 0xFFFFFFFF00000000ULL ++#define SQNUM_WATERMARK 0xFFFFFFFFFF000000ULL ++ ++/* Minimum amount of data UBIFS writes to the flash */ ++#define MIN_WRITE_SZ (UBIFS_DATA_NODE_SZ + 8) ++ ++/* ++ * Currently we do not support inode number overlapping and re-using, so this ++ * watermark defines dangerous inode number level. This should be fixed later, ++ * although it is difficult to exceed current limit. Another option is to use ++ * 64-bit inode numbers, but this means more overhead. ++ */ ++#define INUM_WARN_WATERMARK 0xFFF00000 ++#define INUM_WATERMARK 0xFFFFFF00 ++ ++/* Largest key size supported in this implementation */ ++#define CUR_MAX_KEY_LEN UBIFS_SK_LEN ++ ++/* Maximum number of entries in each LPT (LEB category) heap */ ++#define LPT_HEAP_SZ 256 ++ ++/* ++ * Background thread name pattern. The numbers are UBI device and volume ++ * numbers. ++ */ ++#define BGT_NAME_PATTERN "ubifs_bgt%d_%d" ++ ++/* Default write-buffer synchronization timeout (5 secs) */ ++#define DEFAULT_WBUF_TIMEOUT (5 * HZ) ++ ++/* Maximum possible inode number (only 32-bit inodes are supported now) */ ++#define MAX_INUM 0xFFFFFFFF ++ ++/* Number of non-data journal heads */ ++#define NONDATA_JHEADS_CNT 2 ++ ++/* Garbage collector head */ ++#define GCHD 0 ++/* Base journal head number */ ++#define BASEHD 1 ++/* First "general purpose" journal head */ ++#define DATAHD 2 ++ ++/* 'No change' value for 'ubifs_change_lp()' */ ++#define LPROPS_NC 0x80000001 ++ ++/* ++ * There is no notion of truncation key because truncation nodes do not exist ++ * in TNC. However, when replaying, it is handy to introduce fake "truncation" ++ * keys for truncation nodes because the code becomes simpler. So we define ++ * %UBIFS_TRUN_KEY type. ++ */ ++#define UBIFS_TRUN_KEY UBIFS_KEY_TYPES_CNT ++ ++/* ++ * How much a directory entry/extended attribute entry adds to the parent/host ++ * inode. ++ */ ++#define CALC_DENT_SIZE(name_len) ALIGN(UBIFS_DENT_NODE_SZ + (name_len) + 1, 8) ++ ++/* How much an extended attribute adds to the host inode */ ++#define CALC_XATTR_BYTES(data_len) ALIGN(UBIFS_INO_NODE_SZ + (data_len) + 1, 8) ++ ++/* ++ * Znodes which were not touched for 'OLD_ZNODE_AGE' seconds are considered ++ * "old", and znode which were touched last 'YOUNG_ZNODE_AGE' seconds ago are ++ * considered "young". This is used by shrinker when selecting znode to trim ++ * off. ++ */ ++#define OLD_ZNODE_AGE 20 ++#define YOUNG_ZNODE_AGE 5 ++ ++/* ++ * Some compressors, like LZO, may end up with more data then the input buffer. ++ * So UBIFS always allocates larger output buffer, to be sure the compressor ++ * will not corrupt memory in case of worst case compression. ++ */ ++#define WORST_COMPR_FACTOR 2 ++ ++/* Maximum expected tree height for use by bottom_up_buf */ ++#define BOTTOM_UP_HEIGHT 64 ++ ++/* ++ * Znode flags (actually, bit numbers which store the flags). ++ * ++ * DIRTY_ZNODE: znode is dirty ++ * COW_ZNODE: znode is being committed and a new instance of this znode has to ++ * be created before changing this znode ++ * OBSOLETE_ZNODE: znode is obsolete, which means it was deleted, but it is ++ * still in the commit list and the ongoing commit operation ++ * will commit it, and delete this znode after it is done ++ */ ++enum { ++ DIRTY_ZNODE = 0, ++ COW_ZNODE = 1, ++ OBSOLETE_ZNODE = 2 ++}; ++ ++/* ++ * Commit states. ++ * ++ * COMMIT_RESTING: commit is not wanted ++ * COMMIT_BACKGROUND: background commit has been requested ++ * COMMIT_REQUIRED: commit is required ++ * COMMIT_RUNNING_BACKGROUND: background commit is running ++ * COMMIT_RUNNING_REQUIRED: commit is running and it is required ++ * COMMIT_BROKEN: commit failed ++ */ ++enum { ++ COMMIT_RESTING = 0, ++ COMMIT_BACKGROUND, ++ COMMIT_REQUIRED, ++ COMMIT_RUNNING_BACKGROUND, ++ COMMIT_RUNNING_REQUIRED, ++ COMMIT_BROKEN, ++}; ++ ++/* ++ * 'ubifs_scan_a_node()' return values. ++ * ++ * SCANNED_GARBAGE: scanned garbage ++ * SCANNED_EMPTY_SPACE: scanned empty space ++ * SCANNED_A_NODE: scanned a valid node ++ * SCANNED_A_CORRUPT_NODE: scanned a corrupted node ++ * SCANNED_A_BAD_PAD_NODE: scanned a padding node with invalid pad length ++ * ++ * Greater than zero means: 'scanned that number of padding bytes' ++ */ ++enum { ++ SCANNED_GARBAGE = 0, ++ SCANNED_EMPTY_SPACE = -1, ++ SCANNED_A_NODE = -2, ++ SCANNED_A_CORRUPT_NODE = -3, ++ SCANNED_A_BAD_PAD_NODE = -4, ++}; ++ ++/* ++ * LPT cnode flag bits. ++ * ++ * DIRTY_CNODE: cnode is dirty ++ * COW_CNODE: cnode is being committed and must be copied before writing ++ * OBSOLETE_CNODE: cnode is being committed and has been copied (or deleted), ++ * so it can (and must) be freed when the commit is finished ++ */ ++enum { ++ DIRTY_CNODE = 0, ++ COW_CNODE = 1, ++ OBSOLETE_CNODE = 2, ++}; ++ ++/* ++ * Dirty flag bits (lpt_drty_flgs) for LPT special nodes. ++ * ++ * LTAB_DIRTY: ltab node is dirty ++ * LSAVE_DIRTY: lsave node is dirty ++ */ ++enum { ++ LTAB_DIRTY = 1, ++ LSAVE_DIRTY = 2, ++}; ++ ++/* ++ * Return codes used by the garbage collector. ++ * @LEB_FREED: the logical eraseblock was freed and is ready to use ++ * @LEB_FREED_IDX: indexing LEB was freed and can be used only after the commit ++ * @LEB_RETAINED: the logical eraseblock was freed and retained for GC purposes ++ */ ++enum { ++ LEB_FREED, ++ LEB_FREED_IDX, ++ LEB_RETAINED, ++}; ++ ++/** ++ * struct ubifs_old_idx - index node obsoleted since last commit start. ++ * @rb: rb-tree node ++ * @lnum: LEB number of obsoleted index node ++ * @offs: offset of obsoleted index node ++ */ ++struct ubifs_old_idx { ++ struct rb_node rb; ++ int lnum; ++ int offs; ++}; ++ ++/* The below union makes it easier to deal with keys */ ++union ubifs_key { ++ uint8_t u8[CUR_MAX_KEY_LEN]; ++ uint32_t u32[CUR_MAX_KEY_LEN/4]; ++ uint64_t u64[CUR_MAX_KEY_LEN/8]; ++ __le32 j32[CUR_MAX_KEY_LEN/4]; ++}; ++ ++/** ++ * struct ubifs_scan_node - UBIFS scanned node information. ++ * @list: list of scanned nodes ++ * @key: key of node scanned (if it has one) ++ * @sqnum: sequence number ++ * @type: type of node scanned ++ * @offs: offset with LEB of node scanned ++ * @len: length of node scanned ++ * @node: raw node ++ */ ++struct ubifs_scan_node { ++ struct list_head list; ++ union ubifs_key key; ++ unsigned long long sqnum; ++ int type; ++ int offs; ++ int len; ++ void *node; ++}; ++ ++/** ++ * struct ubifs_scan_leb - UBIFS scanned LEB information. ++ * @lnum: logical eraseblock number ++ * @nodes_cnt: number of nodes scanned ++ * @nodes: list of struct ubifs_scan_node ++ * @endpt: end point (and therefore the start of empty space) ++ * @ecc: read returned -EBADMSG ++ * @buf: buffer containing entire LEB scanned ++ */ ++struct ubifs_scan_leb { ++ int lnum; ++ int nodes_cnt; ++ struct list_head nodes; ++ int endpt; ++ int ecc; ++ void *buf; ++}; ++ ++/** ++ * struct ubifs_gced_idx_leb - garbage-collected indexing LEB. ++ * @list: list ++ * @lnum: LEB number ++ * @unmap: OK to unmap this LEB ++ * ++ * This data structure is used to temporary store garbage-collected indexing ++ * LEBs - they are not released immediately, but only after the next commit. ++ * This is needed to guarantee recoverability. ++ */ ++struct ubifs_gced_idx_leb { ++ struct list_head list; ++ int lnum; ++ int unmap; ++}; ++ ++/** ++ * struct ubifs_inode - UBIFS in-memory inode description. ++ * @vfs_inode: VFS inode description object ++ * @creat_sqnum: sequence number at time of creation ++ * @xattr_size: summarized size of all extended attributes in bytes, protected ++ * by @inode->i_lock ++ * @xattr_cnt: count of extended attributes this inode has ++ * @xattr_names: sum of lengths of all extended attribute names belonging to ++ * this inode ++ * @dirty: non-zero if the inode is dirty ++ * @xattr: non-zero if this is an extended attribute inode ++ * @budgeted: non-zero if the inode has been budgeted (used for debugging) ++ * @budg_mutex: serializes inode budgeting and write-back ++ * @flags: inode flags (@UBIFS_COMPR_FL, etc) ++ * @compr_type: default compression type used for this inode ++ * @data_len: length of the data attached to the inode ++ * @data: inode's data ++ * ++ * UBIFS has its own inode mutex, besides the VFS 'i_mutex'. The reason for ++ * this is budgeting - UBIFS has to budget each operation. So, if an operation ++ * is going to mark an inode dirty, it has to allocate budget for this. It ++ * cannot just mark it dirty because there is no guarantee there will be enough ++ * flash space when it is time to write the inode back. This means that UBIFS ++ * has to have full control over "clean <-> dirty" transitions of inodes (and ++ * pages actually, but it is easy for pages, because we have ++ * 'ubifs_prepare_write()' which is called _before_ every page change). But ++ * unfortunately, VFS marks inodes dirty in many places, and it does not ask ++ * the file-system if it is allowed to do so (there is a notifier, but it is ++ * not enough), i.e., there is no mechanism to synchronize with this. So we ++ * introduce our own dirty flag to UBIFS inodes and our own inode mutex to ++ * serialize "clean <-> dirty" transitions. ++ */ ++struct ubifs_inode { ++ struct inode vfs_inode; ++ unsigned long long creat_sqnum; ++ long long xattr_size; ++ int xattr_cnt; ++ int xattr_names; ++ unsigned int dirty:1; ++ unsigned int xattr:1; ++#ifdef CONFIG_UBIFS_FS_DEBUG ++ unsigned int budgeted:1; ++#endif ++ struct mutex budg_mutex; ++ int flags; ++ int compr_type; ++ int data_len; ++ void *data; ++}; ++ ++/** ++ * struct ubifs_unclean_leb - records a LEB recovered under read-only mode. ++ * @list: list ++ * @lnum: LEB number of recovered LEB ++ * @endpt: offset where recovery ended ++ * ++ * This structure records a LEB identified during recovery that needs to be ++ * cleaned but was not because UBIFS was mounted read-only. The information ++ * is used to clean the LEB when remounting to read-write mode. ++ */ ++struct ubifs_unclean_leb { ++ struct list_head list; ++ int lnum; ++ int endpt; ++}; ++ ++/* ++ * LEB properties flags. ++ * ++ * LPROPS_UNCAT: not categorized ++ * LPROPS_DIRTY: dirty > 0, not index ++ * LPROPS_DIRTY_IDX: dirty + free > UBIFS_CH_SZ and index ++ * LPROPS_FREE: free > 0, not empty, not index ++ * LPROPS_HEAP_CNT: number of heaps used for storing categorized LEBs ++ * LPROPS_EMPTY: LEB is empty, not taken ++ * LPROPS_FREEABLE: free + dirty == leb_size, not index, not taken ++ * LPROPS_FRDI_IDX: free + dirty == leb_size and index, may be taken ++ * LPROPS_CAT_MASK: mask for the LEB categories above ++ * LPROPS_TAKEN: LEB was taken (this flag is not saved on the media) ++ * LPROPS_INDEX: LEB contains indexing nodes (this flag also exists on flash) ++ */ ++enum { ++ LPROPS_UNCAT = 0, ++ LPROPS_DIRTY = 1, ++ LPROPS_DIRTY_IDX = 2, ++ LPROPS_FREE = 3, ++ LPROPS_HEAP_CNT = 3, ++ LPROPS_EMPTY = 4, ++ LPROPS_FREEABLE = 5, ++ LPROPS_FRDI_IDX = 6, ++ LPROPS_CAT_MASK = 15, ++ LPROPS_TAKEN = 16, ++ LPROPS_INDEX = 32, ++}; ++ ++/** ++ * struct ubifs_lprops - logical eraseblock properties. ++ * @free: amount of free space in bytes ++ * @dirty: amount of dirty space in bytes ++ * @flags: LEB properties flags (see above) ++ * @lnum: LEB number ++ * @list: list of same-category lprops (for LPROPS_EMPTY and LPROPS_FREEABLE) ++ * @hpos: heap position in heap of same-category lprops (other categories) ++ */ ++struct ubifs_lprops { ++ int free; ++ int dirty; ++ int flags; ++ int lnum; ++ union { ++ struct list_head list; ++ int hpos; ++ }; ++}; ++ ++/** ++ * struct ubifs_lpt_lprops - LPT logical eraseblock properties. ++ * @free: amount of free space in bytes ++ * @dirty: amount of dirty space in bytes ++ * @tgc: trivial GC flag (1 => unmap after commit end) ++ * @cmt: commit flag (1 => reserved for commit) ++ */ ++struct ubifs_lpt_lprops { ++ int free; ++ int dirty; ++ unsigned tgc : 1; ++ unsigned cmt : 1; ++}; ++ ++/** ++ * struct ubifs_lp_stats - statistics of eraseblocks in the main area. ++ * @empty_lebs: number of empty LEBs ++ * @taken_empty_lebs: number of taken LEBs ++ * @idx_lebs: number of indexing LEBs ++ * @total_free: total free space in bytes ++ * @total_dirty: total dirty space in bytes ++ * @total_used: total used space in bytes (includes only data LEBs) ++ * @total_dead: total dead space in bytes (includes only data LEBs) ++ * @total_dark: total dark space in bytes (includes only data LEBs) ++ * ++ * N.B. total_dirty and total_used are different to other total_* fields, ++ * because they account _all_ LEBs, not just data LEBs. ++ * ++ * 'taken_empty_lebs' counts the LEBs that are in the transient state of having ++ * been 'taken' for use but not yet written to. 'taken_empty_lebs' is needed ++ * to account correctly for gc_lnum, otherwise 'empty_lebs' could be used ++ * by itself (in which case 'unused_lebs' would be a better name). In the case ++ * of gc_lnum, it is 'taken' at mount time or whenever a LEB is retained by GC, ++ * but unlike other empty LEBs that are 'taken', it may not be written straight ++ * away (i.e. before the next commit start or unmount), so either gc_lnum must ++ * be specially accounted for, or the current approach followed i.e. count it ++ * under 'taken_empty_lebs'. ++ */ ++struct ubifs_lp_stats { ++ int empty_lebs; ++ int taken_empty_lebs; ++ int idx_lebs; ++ long long total_free; ++ long long total_dirty; ++ long long total_used; ++ long long total_dead; ++ long long total_dark; ++}; ++ ++struct ubifs_nnode; ++ ++/** ++ * struct ubifs_cnode - LEB Properties Tree common node. ++ * @parent: parent nnode ++ * @cnext: next cnode to commit ++ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE) ++ * @iip: index in parent ++ * @level: level in the tree (zero for pnodes, greater than zero for nnodes) ++ * @num: node number ++ */ ++struct ubifs_cnode { ++ struct ubifs_nnode *parent; ++ struct ubifs_cnode *cnext; ++ unsigned long flags; ++ int iip; ++ int level; ++ int num; ++}; ++ ++/** ++ * struct ubifs_pnode - LEB Properties Tree leaf node. ++ * @parent: parent nnode ++ * @cnext: next cnode to commit ++ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE) ++ * @iip: index in parent ++ * @level: level in the tree (always zero for pnodes) ++ * @num: node number ++ * @lprops: LEB properties array ++ */ ++struct ubifs_pnode { ++ struct ubifs_nnode *parent; ++ struct ubifs_cnode *cnext; ++ unsigned long flags; ++ int iip; ++ int level; ++ int num; ++ struct ubifs_lprops lprops[UBIFS_LPT_FANOUT]; ++}; ++ ++/** ++ * struct ubifs_nbranch - LEB Properties Tree internal node branch. ++ * @lnum: LEB number of child ++ * @offs: offset of child ++ * @nnode: nnode child ++ * @pnode: pnode child ++ * @cnode: cnode child ++ */ ++struct ubifs_nbranch { ++ int lnum; ++ int offs; ++ union { ++ struct ubifs_nnode *nnode; ++ struct ubifs_pnode *pnode; ++ struct ubifs_cnode *cnode; ++ }; ++}; ++ ++/** ++ * struct ubifs_nnode - LEB Properties Tree internal node. ++ * @parent: parent nnode ++ * @cnext: next cnode to commit ++ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE) ++ * @iip: index in parent ++ * @level: level in the tree (always greater than zero for nnodes) ++ * @num: node number ++ * @nbranch: branches to child nodes ++ */ ++struct ubifs_nnode { ++ struct ubifs_nnode *parent; ++ struct ubifs_cnode *cnext; ++ unsigned long flags; ++ int iip; ++ int level; ++ int num; ++ struct ubifs_nbranch nbranch[UBIFS_LPT_FANOUT]; ++}; ++ ++/** ++ * struct ubifs_lpt_heap - heap of categorized lprops. ++ * @arr: heap array ++ * @cnt: number in heap ++ * @max_cnt: maximum number allowed in heap ++ * ++ * There are %LPROPS_HEAP_CNT heaps. ++ */ ++struct ubifs_lpt_heap { ++ struct ubifs_lprops **arr; ++ int cnt; ++ int max_cnt; ++}; ++ ++/* ++ * Return codes for LPT scan callback function. ++ * ++ * LPT_SCAN_CONTINUE: continue scanning ++ * LPT_SCAN_ADD: add the LEB properties scanned to the tree in memory ++ * LPT_SCAN_STOP: stop scanning ++ */ ++enum { ++ LPT_SCAN_CONTINUE = 0, ++ LPT_SCAN_ADD = 1, ++ LPT_SCAN_STOP = 2, ++}; ++ ++struct ubifs_info; ++ ++/* Callback used by the 'ubifs_lpt_scan_nolock()' function */ ++typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c, ++ const struct ubifs_lprops *lprops, ++ int in_tree, void *data); ++ ++/** ++ * struct ubifs_wbuf - UBIFS write-buffer. ++ * @c: UBIFS file-system description object ++ * @buf: write-buffer (of min. flash I/O unit size) ++ * @lnum: logical eraseblock number the write-buffer points to ++ * @offs: write-buffer offset in this logical eraseblock ++ * @avail: number of bytes available in the write-buffer ++ * @used: number of used bytes in the write-buffer ++ * @dtype: type of data stored in this LEB (%UBI_LONGTERM, %UBI_SHORTTERM, ++ * %UBI_UNKNOWN) ++ * @jhead: journal head the mutex belongs to (note, needed only to shut lockdep ++ * up by 'mutex_lock_nested()). ++ * @sync_callback: write-buffer synchronization callback ++ * @io_mutex: serializes write-buffer I/O ++ * @lock: serializes @buf, @lnum, @offs, @avail, @used, @next_ino and @inodes ++ * fields ++ * @timer: write-buffer timer ++ * @timeout: timer expire interval in jiffies ++ * @need_sync: it is set if its timer expired and needs sync ++ * @next_ino: points to the next position of the following inode number ++ * @inodes: stores the inode numbers of the nodes which are in wbuf ++ * ++ * The write-buffer synchronization callback is called when the write-buffer is ++ * synchronized in order to notify how much space was wasted due to ++ * write-buffer padding and how much free space is left in the LEB. ++ * ++ * Note: the fields @buf, @lnum, @offs, @avail and @used can be read under ++ * spin-lock or mutex because they are written under both mutex and spin-lock. ++ * @buf is appended to under mutex but overwritten under both mutex and ++ * spin-lock. Thus the data between @buf and @buf + @used can be read under ++ * spinlock. ++ */ ++struct ubifs_wbuf { ++ struct ubifs_info *c; ++ void *buf; ++ int lnum; ++ int offs; ++ int avail; ++ int used; ++ int dtype; ++ int jhead; ++ int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad); ++ struct mutex io_mutex; ++ spinlock_t lock; ++ struct timer_list timer; ++ int timeout; ++ int need_sync; ++ int next_ino; ++ ino_t *inodes; ++}; ++ ++/** ++ * struct ubifs_bud - bud logical eraseblock. ++ * @lnum: logical eraseblock number ++ * @start: where the (uncommitted) bud data starts ++ * @jhead: journal head number this bud belongs to ++ * @list: link in the list buds belonging to the same journal head ++ * @rb: link in the tree of all buds ++ */ ++struct ubifs_bud { ++ int lnum; ++ int start; ++ int jhead; ++ struct list_head list; ++ struct rb_node rb; ++}; ++ ++/** ++ * struct ubifs_jhead - journal head. ++ * @wbuf: head's write-buffer ++ * @buds_list: list of bud LEBs belonging to this journal head ++ * ++ * Note, the @buds list is protected by the @c->buds_lock. ++ */ ++struct ubifs_jhead { ++ struct ubifs_wbuf wbuf; ++ struct list_head buds_list; ++}; ++ ++/** ++ * struct ubifs_zbranch - key/coordinate/length branch stored in znodes. ++ * @key: key ++ * @znode: znode address in memory ++ * @lnum: LEB number of the indexing node ++ * @offs: offset of the indexing node within @lnum ++ * @len: target node length ++ */ ++struct ubifs_zbranch { ++ union ubifs_key key; ++ union { ++ struct ubifs_znode *znode; ++ void *leaf; ++ }; ++ int lnum; ++ int offs; ++ int len; ++}; ++ ++/** ++ * struct ubifs_znode - in-memory representation of an indexing node. ++ * @parent: parent znode or NULL if it is the root ++ * @cnext: next znode to commit ++ * @flags: znode flags (%DIRTY_ZNODE, %COW_ZNODE or %OBSOLETE_ZNODE) ++ * @time: last access time (seconds) ++ * @level: level of the entry in the TNC tree ++ * @child_cnt: count of child znodes ++ * @iip: index in parent's zbranch array ++ * @alt: lower bound of key range has altered i.e. child inserted at slot 0 ++ * @lnum: LEB number of the corresponding indexing node ++ * @offs: offset of the corresponding indexing node ++ * @len: length of the corresponding indexing node ++ * @zbranch: array of znode branches (@c->fanout elements) ++ */ ++struct ubifs_znode { ++ struct ubifs_znode *parent; ++ struct ubifs_znode *cnext; ++ unsigned long flags; ++ unsigned long time; ++ int level; ++ int child_cnt; ++ int iip; ++ int alt; ++#ifdef CONFIG_UBIFS_FS_DEBUG ++ int lnum, offs, len; ++#endif ++ struct ubifs_zbranch zbranch[]; ++}; ++ ++/** ++ * struct ubifs_node_range - node length range description data structure. ++ * @len: fixed node length ++ * @min_len: minimum possible node length ++ * @max_len: maximum possible node length ++ * ++ * If @max_len is %0, the node has fixed length @len. ++ */ ++struct ubifs_node_range { ++ union { ++ int len; ++ int min_len; ++ }; ++ int max_len; ++}; ++ ++/** ++ * struct ubifs_compressor - UBIFS compressor description structure. ++ * @compr_type: compressor type (%UBIFS_COMPR_LZO, etc) ++ * @cc: cryptoapi compressor handle ++ * @comp_mutex: mutex used during compression ++ * @decomp_mutex: mutex used during decompression ++ * @name: compressor name ++ * @capi_name: cryptoapi compressor name ++ */ ++struct ubifs_compressor { ++ int compr_type; ++ struct crypto_comp *cc; ++ struct mutex *comp_mutex; ++ struct mutex *decomp_mutex; ++ const char *name; ++ const char *capi_name; ++}; ++ ++/** ++ * struct ubifs_budget_req - budget requirements of an operation. ++ * ++ * @new_ino: non-zero if the operation adds a new inode ++ * @dirtied_ino: how many inodes the operation makes dirty ++ * @new_page: non-zero if the operation adds a new page ++ * @dirtied_page: non-zero if the operation makes a page dirty ++ * @new_dent: non-zero if the operation adds a new directory entry ++ * @mod_dent: non-zero if the operation removes or modifies an existing ++ * directory entry ++ * @new_ino_d: now much data newly created inode contains ++ * @dirtied_ino_d: now much data dirtied inode contains ++ * @idx_growth: how much the index will supposedly grow ++ * @data_growth: how much new data the operation will supposedly add ++ * @dd_growth: how much data that makes other data dirty the operation will ++ * supposedly add ++ * ++ * @idx_growth, @data_growth and @dd_growth are not used in budget request. The ++ * budgeting subsystem caches index and data growth values there to avoid ++ * re-calculating them when the budget is released. However, if @idx_growth is ++ * %-1, it is calculated by the release function using other fields. ++ * ++ * An inode may contain 4KiB of data at max., thus the widths of @new_ino_d ++ * is 13 bits, and @dirtied_ino_d - 15, because up to 4 inodes may be made ++ * dirty by the re-name operation. ++ */ ++struct ubifs_budget_req { ++ unsigned int new_ino:1; ++ unsigned int dirtied_ino:4; ++ unsigned int new_page:1; ++ unsigned int dirtied_page:1; ++ unsigned int new_dent:1; ++ unsigned int mod_dent:1; ++ unsigned int new_ino_d:13; ++ unsigned int dirtied_ino_d:15; ++ int idx_growth; ++ int data_growth; ++ int dd_growth; ++}; ++ ++/** ++ * struct ubifs_orphan - stores the inode number of an orphan. ++ * @rb: rb-tree node of rb-tree of orphans sorted by inode number ++ * @list: list head of list of orphans in order added ++ * @new_list: list head of list of orphans added since the last commit ++ * @cnext: next orphan to commit ++ * @dnext: next orphan to delete ++ * @inum: inode number ++ * @new: %1 => added since the last commit, otherwise %0 ++ */ ++struct ubifs_orphan { ++ struct rb_node rb; ++ struct list_head list; ++ struct list_head new_list; ++ struct ubifs_orphan *cnext; ++ struct ubifs_orphan *dnext; ++ ino_t inum; ++ int new; ++}; ++ ++/** ++ * struct ubifs_mount_opts - UBIFS-specific mount options information. ++ * @unmount_mode: selected unmount mode (%0 default, %1 normal, %2 fast) ++ */ ++struct ubifs_mount_opts { ++ unsigned int unmount_mode:2; ++}; ++ ++/** ++ * struct ubifs_info - UBIFS file-system description data structure ++ * (per-superblock). ++ * @vfs_sb: VFS @struct super_block object ++ * ++ * @highest_inum: highest used inode number ++ * @vfs_gen: VFS inode generation counter ++ * @max_sqnum: current global sequence number ++ * @cmt_no: commit number (last successfully completed commit) ++ * @cnt_lock: protects @highest_inum, @vfs_gen, and @max_sqnum counters ++ * @fmt_version: UBIFS on-flash format version ++ * @uuid: UUID from super block ++ * ++ * @lhead_lnum: log head logical eraseblock number ++ * @lhead_offs: log head offset ++ * @ltail_lnum: log tail logical eraseblock number (offset is always 0) ++ * @log_mutex: protects the log, @lhead_lnum, @lhead_offs, @ltail_lnum, and ++ * @bud_bytes ++ * @min_log_bytes: minimum required number of bytes in the log ++ * @cmt_bud_bytes: used during commit to temporarily amount of bytes in ++ * committed buds ++ * ++ * @buds: tree of all buds indexed by bud LEB number ++ * @bud_bytes: how many bytes of flash is used by buds ++ * @buds_lock: protects the @buds tree, @bud_bytes, and per-journal head bud ++ * lists ++ * @jhead_cnt: count of journal heads ++ * @jheads: journal heads (head zero is base head) ++ * @max_bud_bytes: maximum number of bytes allowed in buds ++ * @bg_bud_bytes: number of bud bytes when background commit is initiated ++ * @old_buds: buds to be released after commit ends ++ * @max_bud_cnt: maximum number of buds ++ * ++ * @commit_sem: synchronizes committer with other processes ++ * @cmt_state: commit state ++ * @cs_lock: commit state lock ++ * @cmt_wq: wait queue to sleep on if the log is full and a commit is running ++ * @fast_unmount: do not run journal commit before unmounting ++ * @big_lpt: flag that LPT is too big to write whole during commit ++ * ++ * @tnc_mutex: protects the Tree Node Cache (TNC), @zroot, @cnext, @enext, and ++ * @calc_idx_sz ++ * @zroot: zbranch which points to the root index node and znode ++ * @cnext: next znode to commit ++ * @enext: next znode to commit to empty space ++ * @gap_lebs: array of LEBs used by the in-gaps commit method ++ * @cbuf: commit buffer ++ * @ileb_buf: buffer for commit in-the-gaps method ++ * @ileb_len: length of data in ileb_buf ++ * @ihead_lnum: LEB number of index head ++ * @ihead_offs: offset of index head ++ * @ilebs: pre-allocated index LEBs ++ * @ileb_cnt: number of pre-allocated index LEBs ++ * @ileb_nxt: next pre-allocated index LEBs ++ * @old_idx: tree of index nodes obsoleted since the last commit start ++ * @bottom_up_buf: a buffer which is used by 'dirty_cow_bottom_up()' in tnc.c ++ * @new_ihead_lnum: used by debugging to check ihead_lnum ++ * @new_ihead_offs: used by debugging to check ihead_offs ++ * ++ * @mst_node: master node ++ * @mst_offs: offset of valid master node ++ * @mst_mutex: protects the master node area, @mst_node, and @mst_offs ++ * ++ * @log_lebs: number of logical eraseblocks in the log ++ * @log_bytes: log size in bytes ++ * @log_last: last LEB of the log ++ * @lpt_lebs: number of LEBs used for lprops table ++ * @lpt_first: first LEB of the lprops table area ++ * @lpt_last: last LEB of the lprops table area ++ * @orph_lebs: number of LEBs used for the orphan area ++ * @orph_first: first LEB of the orphan area ++ * @orph_last: last LEB of the orphan area ++ * @main_lebs: count of LEBs in the main area ++ * @main_first: first LEB of the main area ++ * @main_bytes: main area size in bytes ++ * @default_compr: default compression type ++ * ++ * @key_hash_type: type of the key hash ++ * @key_hash: direntry key hash function ++ * @key_fmt: key format ++ * @key_len: key length ++ * @fanout: fanout of the index tree (number of links per indexing node) ++ * ++ * @min_io_size: minimal input/output unit size ++ * @min_io_shift: number of bits in @min_io_size minus one ++ * @leb_size: logical eraseblock size in bytes ++ * @half_leb_size: half LEB size ++ * @leb_cnt: count of logical eraseblocks ++ * @max_leb_cnt: maximum count of logical eraseblocks ++ * @old_leb_cnt: count of logical eraseblocks before resize ++ * @ro_media: the underlying UBI volume is read-only ++ * ++ * @dirty_pg_cnt: number of dirty pages (not used) ++ * @dirty_ino_cnt: number of dirty inodes (not used) ++ * @dirty_zn_cnt: number of dirty znodes ++ * @clean_zn_cnt: number of clean znodes ++ * ++ * @budg_idx_growth: amount of bytes budgeted for index growth ++ * @budg_data_growth: amount of bytes budgeted for cached data ++ * @budg_dd_growth: amount of bytes budgeted for cached data that will make ++ * other data dirty ++ * @budg_uncommitted_idx: amount of bytes were budgeted for growth of the index, ++ * but which still have to be taken into account because ++ * the index has not been committed so far ++ * @space_lock: protects @budg_idx_growth, @budg_data_growth, @budg_dd_growth, ++ * @budg_uncommited_idx, @min_idx_lebs, @old_idx_sz, and @lst; ++ * @min_idx_lebs: minimum number of LEBs required for the index ++ * @old_idx_sz: size of index on flash ++ * @calc_idx_sz: temporary variable which is used to calculate new index size ++ * (contains accurate new index size at end of TNC commit start) ++ * @lst: lprops statistics ++ * ++ * @page_budget: budget for a page ++ * @inode_budget: budget for an inode ++ * @dent_budget: budget for a directory entry ++ * ++ * @ref_node_alsz: size of the LEB reference node aligned to the min. flash ++ * I/O unit ++ * @mst_node_alsz: master node aligned size ++ * @min_idx_node_sz: minimum indexing node aligned on 8-bytes boundary ++ * @max_idx_node_sz: maximum indexing node aligned on 8-bytes boundary ++ * @max_inode_sz: maximum possible inode size in bytes ++ * @max_znode_sz: size of znode in bytes ++ * @dead_wm: LEB dead space watermark ++ * @dark_wm: LEB dark space watermark ++ * @block_cnt: count of 4KiB blocks on the FS ++ * ++ * @ranges: UBIFS node length ranges ++ * @ubi: UBI volume descriptor ++ * @di: UBI device information ++ * @vi: UBI volume information ++ * ++ * @orph_tree: rb-tree of orphan inode numbers ++ * @orph_list: list of orphan inode numbers in order added ++ * @orph_new: list of orphan inode numbers added since last commit ++ * @orph_cnext: next orphan to commit ++ * @orph_dnext: next orphan to delete ++ * @orphan_lock: lock for orph_tree and orph_new ++ * @orph_buf: buffer for orphan nodes ++ * @new_orphans: number of orphans since last commit ++ * @cmt_orphans: number of orphans being committed ++ * @tot_orphans: number of orphans in the rb_tree ++ * @max_orphans: maximum number of orphans allowed ++ * @ohead_lnum: orphan head LEB number ++ * @ohead_offs: orphan head offset ++ * @no_orphs: non-zero if there are no orphans ++ * ++ * @bgt: UBIFS background thread ++ * @bgt_name: background thread name ++ * @need_bgt: if background thread should run ++ * @need_wbuf_sync: if write-buffers have to be synchronized ++ * ++ * @gc_lnum: LEB number used for garbage collection ++ * @sbuf: a buffer of LEB size used by GC and replay for scanning ++ * @idx_gc: list of index LEBs that have been garbage collected ++ * @idx_gc_cnt: number of elements on the idx_gc list ++ * ++ * @infos_list: links all 'ubifs_info' objects ++ * @umount_mutex: serializes shrinker and un-mount ++ * @shrinker_run_no: shrinker run number ++ * ++ * @space_bits: number of bits needed to record free or dirty space ++ * @lpt_lnum_bits: number of bits needed to record a LEB number in the LPT ++ * @lpt_offs_bits: number of bits needed to record an offset in the LPT ++ * @lpt_spc_bits: number of bits needed to space in the LPT ++ * @pcnt_bits: number of bits needed to record pnode or nnode number ++ * @lnum_bits: number of bits needed to record LEB number ++ * @nnode_sz: size of on-flash nnode ++ * @pnode_sz: size of on-flash pnode ++ * @ltab_sz: size of on-flash LPT lprops table ++ * @lsave_sz: size of on-flash LPT save table ++ * @pnode_cnt: number of pnodes ++ * @nnode_cnt: number of nnodes ++ * @lpt_hght: height of the LPT ++ * @pnodes_have: number of pnodes in memory ++ * ++ * @lp_mutex: protects lprops table and all the other lprops-related fields ++ * @lpt_lnum: LEB number of the root nnode of the LPT ++ * @lpt_offs: offset of the root nnode of the LPT ++ * @nhead_lnum: LEB number of LPT head ++ * @nhead_offs: offset of LPT head ++ * @lpt_drty_flgs: dirty flags for LPT special nodes e.g. ltab ++ * @dirty_nn_cnt: number of dirty nnodes ++ * @dirty_pn_cnt: number of dirty pnodes ++ * @lpt_sz: LPT size ++ * @lpt_nod_buf: buffer for an on-flash nnode or pnode ++ * @lpt_buf: buffer of LEB size used by LPT ++ * @nroot: address in memory of the root nnode of the LPT ++ * @lpt_cnext: next LPT node to commit ++ * @lpt_heap: array of heaps of categorized lprops ++ * @dirty_idx: a (reverse sorted) copy of the LPROPS_DIRTY_IDX heap as at ++ * previous commit start ++ * @uncat_list: list of un-categorized LEBs ++ * @empty_list: list of empty LEBs ++ * @freeable_list: list of freeable non-index LEBs (free + dirty == leb_size) ++ * @frdi_idx_list: list of freeable index LEBs (free + dirty == leb_size) ++ * @freeable_cnt: number of freeable LEBs in @freeable_list ++ * ++ * @ltab_lnum: LEB number of LPT's own lprops table ++ * @ltab_offs: offset of LPT's own lprops table ++ * @ltab: LPT's own lprops table ++ * @ltab_cmt: LPT's own lprops table (commit copy) ++ * @lsave_cnt: number of LEB numbers in LPT's save table ++ * @lsave_lnum: LEB number of LPT's save table ++ * @lsave_offs: offset of LPT's save table ++ * @lsave: LPT's save table ++ * @lscan_lnum: LEB number of last LPT scan ++ * ++ * @rp_size: size of the reserved pool in bytes ++ * @report_rp_size: size of the reserved pool reported to userspace ++ * @rp_uid: reserved pool user ID ++ * @rp_gid: reserved pool group ID ++ * ++ * @empty: if the UBI device is empty ++ * @replay_tree: temporary tree used during journal replay ++ * @replay_list: temporary list used during journal replay ++ * @replay_buds: list of buds to replay ++ * @cs_sqnum: sequence number of first node in the log (commit start node) ++ * @replay_sqnum: sequence number of node currently being replayed ++ * @need_recovery: file-system needs recovery ++ * @replaying: set to %1 during journal replay ++ * @unclean_leb_list: LEBs to recover when mounting ro to rw ++ * @rcvrd_mst_node: recovered master node to write when mounting ro to rw ++ * @size_tree: inode size information for recovery ++ * @remounting_rw: set while remounting from ro to rw (sb flags have MS_RDONLY) ++ * @mount_opts: UBIFS-specific mount options ++ * ++ * @dbg_buf: a buffer of LEB size used for debugging purposes ++ * @old_zroot: old index root - used by 'dbg_check_old_index()' ++ * @old_zroot_level: old index root level - used by 'dbg_check_old_index()' ++ * @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()' ++ * @failure_mode: failure mode for recovery testing ++ * @fail_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls ++ * @fail_timeout: time in jiffies when delay of failure mode expires ++ * @fail_cnt: current number of calls to failure mode I/O functions ++ * @fail_cnt_max: number of calls by which to delay failure mode ++ */ ++struct ubifs_info { ++ struct super_block *vfs_sb; ++ ++ ino_t highest_inum; ++ unsigned int vfs_gen; ++ unsigned long long max_sqnum; ++ unsigned long long cmt_no; ++ spinlock_t cnt_lock; ++ int fmt_version; ++ unsigned char uuid[16]; ++ ++ int lhead_lnum; ++ int lhead_offs; ++ int ltail_lnum; ++ struct mutex log_mutex; ++ int min_log_bytes; ++ long long cmt_bud_bytes; ++ ++ struct rb_root buds; ++ long long bud_bytes; ++ spinlock_t buds_lock; ++ int jhead_cnt; ++ struct ubifs_jhead *jheads; ++ long long max_bud_bytes; ++ long long bg_bud_bytes; ++ struct list_head old_buds; ++ int max_bud_cnt; ++ ++ struct rw_semaphore commit_sem; ++ int cmt_state; ++ spinlock_t cs_lock; ++ wait_queue_head_t cmt_wq; ++ unsigned int fast_unmount:1; ++ unsigned int big_lpt:1; ++ ++ struct mutex tnc_mutex; ++ struct ubifs_zbranch zroot; ++ struct ubifs_znode *cnext; ++ struct ubifs_znode *enext; ++ int *gap_lebs; ++ void *cbuf; ++ void *ileb_buf; ++ int ileb_len; ++ int ihead_lnum; ++ int ihead_offs; ++ int *ilebs; ++ int ileb_cnt; ++ int ileb_nxt; ++ struct rb_root old_idx; ++ int *bottom_up_buf; ++#ifdef CONFIG_UBIFS_FS_DEBUG ++ int new_ihead_lnum; ++ int new_ihead_offs; ++#endif ++ ++ struct ubifs_mst_node *mst_node; ++ int mst_offs; ++ struct mutex mst_mutex; ++ ++ int log_lebs; ++ long long log_bytes; ++ int log_last; ++ int lpt_lebs; ++ int lpt_first; ++ int lpt_last; ++ int orph_lebs; ++ int orph_first; ++ int orph_last; ++ int main_lebs; ++ int main_first; ++ long long main_bytes; ++ int default_compr; ++ ++ uint8_t key_hash_type; ++ uint32_t (*key_hash)(const char *str, int len); ++ int key_fmt; ++ int key_len; ++ int fanout; ++ ++ int min_io_size; ++ int min_io_shift; ++ int leb_size; ++ int half_leb_size; ++ int leb_cnt; ++ int max_leb_cnt; ++ int old_leb_cnt; ++ int ro_media; ++ ++ atomic_long_t dirty_pg_cnt; ++ atomic_long_t dirty_ino_cnt; ++ atomic_long_t dirty_zn_cnt; ++ atomic_long_t clean_zn_cnt; ++ ++ long long budg_idx_growth; ++ long long budg_data_growth; ++ long long budg_dd_growth; ++ long long budg_uncommitted_idx; ++ spinlock_t space_lock; ++ int min_idx_lebs; ++ unsigned long long old_idx_sz; ++ unsigned long long calc_idx_sz; ++ struct ubifs_lp_stats lst; ++ ++ int page_budget; ++ int inode_budget; ++ int dent_budget; ++ ++ int ref_node_alsz; ++ int mst_node_alsz; ++ int min_idx_node_sz; ++ int max_idx_node_sz; ++ long long max_inode_sz; ++ int max_znode_sz; ++ int dead_wm; ++ int dark_wm; ++ int block_cnt; ++ ++ struct ubifs_node_range ranges[UBIFS_NODE_TYPES_CNT]; ++ struct ubi_volume_desc *ubi; ++ struct ubi_device_info di; ++ struct ubi_volume_info vi; ++ ++ struct rb_root orph_tree; ++ struct list_head orph_list; ++ struct list_head orph_new; ++ struct ubifs_orphan *orph_cnext; ++ struct ubifs_orphan *orph_dnext; ++ spinlock_t orphan_lock; ++ void *orph_buf; ++ int new_orphans; ++ int cmt_orphans; ++ int tot_orphans; ++ int max_orphans; ++ int ohead_lnum; ++ int ohead_offs; ++ int no_orphs; ++ ++ struct task_struct *bgt; ++ char bgt_name[sizeof(BGT_NAME_PATTERN) + 9]; ++ int need_bgt; ++ int need_wbuf_sync; ++ ++ int gc_lnum; ++ void *sbuf; ++ struct list_head idx_gc; ++ int idx_gc_cnt; ++ ++ struct list_head infos_list; ++ struct mutex umount_mutex; ++ unsigned int shrinker_run_no; ++ ++ int space_bits; ++ int lpt_lnum_bits; ++ int lpt_offs_bits; ++ int lpt_spc_bits; ++ int pcnt_bits; ++ int lnum_bits; ++ int nnode_sz; ++ int pnode_sz; ++ int ltab_sz; ++ int lsave_sz; ++ int pnode_cnt; ++ int nnode_cnt; ++ int lpt_hght; ++ int pnodes_have; ++ ++ struct mutex lp_mutex; ++ int lpt_lnum; ++ int lpt_offs; ++ int nhead_lnum; ++ int nhead_offs; ++ int lpt_drty_flgs; ++ int dirty_nn_cnt; ++ int dirty_pn_cnt; ++ long long lpt_sz; ++ void *lpt_nod_buf; ++ void *lpt_buf; ++ struct ubifs_nnode *nroot; ++ struct ubifs_cnode *lpt_cnext; ++ struct ubifs_lpt_heap lpt_heap[LPROPS_HEAP_CNT]; ++ struct ubifs_lpt_heap dirty_idx; ++ struct list_head uncat_list; ++ struct list_head empty_list; ++ struct list_head freeable_list; ++ struct list_head frdi_idx_list; ++ int freeable_cnt; ++ ++ int ltab_lnum; ++ int ltab_offs; ++ struct ubifs_lpt_lprops *ltab; ++ struct ubifs_lpt_lprops *ltab_cmt; ++ int lsave_cnt; ++ int lsave_lnum; ++ int lsave_offs; ++ int *lsave; ++ int lscan_lnum; ++ ++ long long rp_size; ++ long long report_rp_size; ++ uid_t rp_uid; ++ gid_t rp_gid; ++ ++ /* The below fields are used only during mounting and re-mounting */ ++ int empty; ++ struct rb_root replay_tree; ++ struct list_head replay_list; ++ struct list_head replay_buds; ++ unsigned long long cs_sqnum; ++ unsigned long long replay_sqnum; ++ int need_recovery; ++ int replaying; ++ struct list_head unclean_leb_list; ++ struct ubifs_mst_node *rcvrd_mst_node; ++ struct rb_root size_tree; ++ int remounting_rw; ++ struct ubifs_mount_opts mount_opts; ++ ++#ifdef CONFIG_UBIFS_FS_DEBUG ++ void *dbg_buf; ++ struct ubifs_zbranch old_zroot; ++ int old_zroot_level; ++ unsigned long long old_zroot_sqnum; ++ int failure_mode; ++ int fail_delay; ++ unsigned long fail_timeout; ++ unsigned int fail_cnt; ++ unsigned int fail_cnt_max; ++#endif ++}; ++ ++extern struct list_head ubifs_infos; ++extern spinlock_t ubifs_infos_lock; ++extern atomic_long_t ubifs_clean_zn_cnt; ++extern struct kmem_cache *ubifs_inode_slab; ++extern struct super_operations ubifs_super_operations; ++extern struct address_space_operations ubifs_file_address_operations; ++extern struct file_operations ubifs_file_operations; ++extern struct inode_operations ubifs_file_inode_operations; ++extern struct file_operations ubifs_dir_operations; ++extern struct inode_operations ubifs_dir_inode_operations; ++extern struct inode_operations ubifs_symlink_inode_operations; ++extern struct backing_dev_info ubifs_backing_dev_info; ++extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT]; ++ ++/* io.c */ ++int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len); ++int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs, ++ int dtype); ++int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf); ++int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len, ++ int lnum, int offs); ++int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len, ++ int lnum, int offs); ++int ubifs_write_node(struct ubifs_info *c, void *node, int len, int lnum, ++ int offs, int dtype); ++int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum, ++ int offs, int quiet); ++void ubifs_prepare_node(struct ubifs_info *c, void *buf, int len, int pad); ++void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last); ++int ubifs_io_init(struct ubifs_info *c); ++void ubifs_pad(const struct ubifs_info *c, void *buf, int pad); ++int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf); ++int ubifs_bg_wbufs_sync(struct ubifs_info *c); ++void ubifs_wbuf_add_ino_nolock(struct ubifs_wbuf *wbuf, ino_t inum); ++int ubifs_sync_wbufs_by_inodes(struct ubifs_info *c, ++ struct inode * const *inodes, int count); ++ ++/* scan.c */ ++struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum, ++ int offs, void *sbuf); ++void ubifs_scan_destroy(struct ubifs_scan_leb *sleb); ++int ubifs_scan_a_node(const struct ubifs_info *c, void *buf, int len, int lnum, ++ int offs, int quiet); ++struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum, ++ int offs, void *sbuf); ++void ubifs_end_scan(const struct ubifs_info *c, struct ubifs_scan_leb *sleb, ++ int lnum, int offs); ++int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb, ++ void *buf, int offs); ++void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs, ++ void *buf); ++ ++/* log.c */ ++void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud); ++void ubifs_create_buds_lists(struct ubifs_info *c); ++int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs); ++struct ubifs_bud *ubifs_search_bud(struct ubifs_info *c, int lnum); ++struct ubifs_wbuf *ubifs_get_wbuf(struct ubifs_info *c, int lnum); ++int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum); ++int ubifs_log_end_commit(struct ubifs_info *c, int new_ltail_lnum); ++int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum); ++int ubifs_consolidate_log(struct ubifs_info *c); ++ ++/* journal.c */ ++int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, ++ const struct qstr *nm, const struct inode *inode, ++ int deletion, int sync, int xent); ++int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, ++ const union ubifs_key *key, const void *buf, int len); ++int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode, ++ int last_reference, int sync); ++int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, ++ const struct dentry *old_dentry, ++ const struct inode *new_dir, ++ const struct dentry *new_dentry, int sync); ++int ubifs_jnl_truncate(struct ubifs_info *c, ino_t inum, ++ loff_t old_size, loff_t new_size); ++int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host, ++ const struct inode *inode, const struct qstr *nm, ++ int sync); ++int ubifs_jnl_write_2_inodes(struct ubifs_info *c, const struct inode *inode1, ++ const struct inode *inode2, int sync); ++ ++/* budget.c */ ++int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req); ++void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req); ++int ubifs_budget_inode_op(struct ubifs_info *c, struct inode *inode, ++ struct ubifs_budget_req *req); ++void ubifs_release_ino_dirty(struct ubifs_info *c, struct inode *inode, ++ struct ubifs_budget_req *req); ++void ubifs_cancel_ino_op(struct ubifs_info *c, struct inode *inode, ++ struct ubifs_budget_req *req); ++int ubifs_budget_ino_cleaning(struct ubifs_info *c, struct inode *inode, ++ struct ubifs_budget_req *req); ++void ubifs_release_ino_clean(struct ubifs_info *c, struct inode *inode, ++ struct ubifs_budget_req *req); ++long long ubifs_budg_get_free_space(struct ubifs_info *c); ++int ubifs_calc_min_idx_lebs(struct ubifs_info *c); ++void ubifs_convert_page_budget(struct ubifs_info *c); ++void ubifs_release_new_page_budget(struct ubifs_info *c); ++long long ubifs_calc_available(const struct ubifs_info *c); ++ ++/* find.c */ ++int ubifs_find_free_space(struct ubifs_info *c, int min_space, int *free, ++ int squeeze); ++int ubifs_find_free_leb_for_idx(struct ubifs_info *c); ++int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp, ++ int min_space, int pick_free); ++int ubifs_find_dirty_idx_leb(struct ubifs_info *c); ++int ubifs_save_dirty_idx_lnums(struct ubifs_info *c); ++ ++/* tnc.c */ ++int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key, ++ struct ubifs_znode **zn, int *n); ++int ubifs_tnc_lookup(struct ubifs_info *c, const union ubifs_key *key, ++ void *node); ++int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, ++ void *node, const struct qstr *nm); ++int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key, ++ void *node, int *lnum, int *offs); ++int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum, ++ int offs, int len); ++int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key, ++ int old_lnum, int old_offs, int lnum, int offs, int len); ++int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key, ++ int lnum, int offs, int len, const struct qstr *nm); ++int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key); ++int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key, ++ const struct qstr *nm); ++int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key, ++ union ubifs_key *to_key); ++int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum); ++struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c, ++ union ubifs_key *key, ++ const struct qstr *nm); ++void ubifs_tnc_close(struct ubifs_info *c); ++int ubifs_tnc_has_node(struct ubifs_info *c, union ubifs_key *key, int level, ++ int lnum, int offs, int is_idx); ++int ubifs_dirty_idx_node(struct ubifs_info *c, union ubifs_key *key, int level, ++ int lnum, int offs); ++/* Shared by tnc.c for tnc_commit.c */ ++void destroy_old_idx(struct ubifs_info *c); ++int is_idx_node_in_tnc(struct ubifs_info *c, union ubifs_key *key, int level, ++ int lnum, int offs); ++int insert_old_idx_znode(struct ubifs_info *c, struct ubifs_znode *znode); ++ ++/* tnc_misc.c */ ++struct ubifs_znode *ubifs_tnc_levelorder_next(struct ubifs_znode *zr, ++ struct ubifs_znode *znode); ++int ubifs_search_zbranch(const struct ubifs_info *c, ++ const struct ubifs_znode *znode, ++ const union ubifs_key *key, int *n); ++struct ubifs_znode *ubifs_tnc_postorder_first(struct ubifs_znode *znode); ++struct ubifs_znode *ubifs_tnc_postorder_next(struct ubifs_znode *znode); ++long ubifs_destroy_tnc_subtree(struct ubifs_znode *zr); ++struct ubifs_znode *ubifs_load_znode(struct ubifs_info *c, ++ struct ubifs_zbranch *zbr, ++ struct ubifs_znode *parent, int iip); ++int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr, ++ void *node); ++ ++/* tnc_commit.c */ ++int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot); ++int ubifs_tnc_end_commit(struct ubifs_info *c); ++ ++/* shrinker.c */ ++int ubifs_shrinker(int nr_to_scan, gfp_t gfp_mask); ++ ++/* commit.c */ ++int ubifs_bg_thread(void *info); ++void ubifs_commit_required(struct ubifs_info *c); ++void ubifs_request_bg_commit(struct ubifs_info *c); ++int ubifs_run_commit(struct ubifs_info *c); ++void ubifs_recovery_commit(struct ubifs_info *c); ++int ubifs_gc_should_commit(struct ubifs_info *c); ++void ubifs_wait_for_commit(struct ubifs_info *c); ++ ++/* master.c */ ++int ubifs_read_master(struct ubifs_info *c); ++int ubifs_write_master(struct ubifs_info *c); ++ ++/* sb.c */ ++int ubifs_read_superblock(struct ubifs_info *c); ++struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c); ++int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup); ++ ++/* replay.c */ ++int ubifs_validate_entry(struct ubifs_info *c, ++ const struct ubifs_dent_node *dent); ++int ubifs_replay_journal(struct ubifs_info *c); ++ ++/* gc.c */ ++int ubifs_garbage_collect(struct ubifs_info *c, int anyway); ++int ubifs_gc_start_commit(struct ubifs_info *c); ++int ubifs_gc_end_commit(struct ubifs_info *c); ++void ubifs_destroy_idx_gc(struct ubifs_info *c); ++int ubifs_get_idx_gc_leb(struct ubifs_info *c); ++int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp); ++ ++/* orphan.c */ ++int ubifs_add_orphan(struct ubifs_info *c, ino_t inum); ++void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum); ++int ubifs_orphan_start_commit(struct ubifs_info *c); ++int ubifs_orphan_end_commit(struct ubifs_info *c); ++int ubifs_mount_orphans(struct ubifs_info *c, int unclean, int read_only); ++ ++/* lpt.c */ ++int ubifs_calc_lpt_geom(struct ubifs_info *c); ++int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, ++ int *lpt_lebs, int *big_lpt); ++int ubifs_lpt_init(struct ubifs_info *c, int rd, int wr); ++struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum); ++struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum); ++int ubifs_lpt_scan_nolock(struct ubifs_info *c, int start_lnum, int end_lnum, ++ ubifs_lpt_scan_callback scan_cb, void *data); ++ ++/* Shared by lpt.c for lpt_commit.c */ ++void ubifs_pack_lsave(struct ubifs_info *c, void *buf, int *lsave); ++void ubifs_pack_ltab(struct ubifs_info *c, void *buf, ++ struct ubifs_lpt_lprops *ltab); ++void ubifs_pack_pnode(struct ubifs_info *c, void *buf, ++ struct ubifs_pnode *pnode); ++void ubifs_pack_nnode(struct ubifs_info *c, void *buf, ++ struct ubifs_nnode *nnode); ++struct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c, ++ struct ubifs_nnode *parent, int iip); ++struct ubifs_nnode *ubifs_get_nnode(struct ubifs_info *c, ++ struct ubifs_nnode *parent, int iip); ++int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip); ++void ubifs_add_lpt_dirt(struct ubifs_info *c, int lnum, int dirty); ++void ubifs_add_nnode_dirt(struct ubifs_info *c, struct ubifs_nnode *nnode); ++uint32_t ubifs_unpack_bits(uint8_t **addr, int *pos, int nrbits); ++struct ubifs_nnode *ubifs_first_nnode(struct ubifs_info *c, int *hght); ++ ++/* lpt_commit.c */ ++int ubifs_lpt_start_commit(struct ubifs_info *c); ++int ubifs_lpt_end_commit(struct ubifs_info *c); ++int ubifs_lpt_post_commit(struct ubifs_info *c); ++void ubifs_lpt_free(struct ubifs_info *c, int wr_only); ++ ++/* lprops.c */ ++void ubifs_get_lprops(struct ubifs_info *c); ++const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c, ++ const struct ubifs_lprops *lp, ++ int free, int dirty, int flags, ++ int idx_gc_cnt); ++void ubifs_release_lprops(struct ubifs_info *c); ++void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *stats); ++void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops, ++ int cat); ++void ubifs_replace_cat(struct ubifs_info *c, struct ubifs_lprops *old_lprops, ++ struct ubifs_lprops *new_lprops); ++void ubifs_ensure_cat(struct ubifs_info *c, struct ubifs_lprops *lprops); ++int ubifs_categorize_lprops(const struct ubifs_info *c, ++ const struct ubifs_lprops *lprops); ++int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty, ++ int flags_set, int flags_clean, int idx_gc_cnt); ++int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty, ++ int flags_set, int flags_clean); ++int ubifs_read_one_lp(struct ubifs_info *c, int lnum, struct ubifs_lprops *lp); ++const struct ubifs_lprops *ubifs_fast_find_free(struct ubifs_info *c); ++const struct ubifs_lprops *ubifs_fast_find_empty(struct ubifs_info *c); ++const struct ubifs_lprops *ubifs_fast_find_freeable(struct ubifs_info *c); ++const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c); ++ ++/* file.c */ ++int ubifs_fsync(struct file *file, struct dentry *dentry, int datasync); ++int ubifs_setattr(struct dentry *dentry, struct iattr *attr); ++ ++/* dir.c */ ++struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir, ++ int mode); ++int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry, ++ struct kstat *stat); ++ ++/* xattr.c */ ++int ubifs_setxattr(struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags); ++ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf, ++ size_t size); ++ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size); ++int ubifs_removexattr(struct dentry *dentry, const char *name); ++ ++/* super.c */ ++struct inode *ubifs_iget(struct super_block *sb, unsigned long inum); ++ ++/* recovery.c */ ++int ubifs_recover_master_node(struct ubifs_info *c); ++int ubifs_write_rcvrd_mst_node(struct ubifs_info *c); ++struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum, ++ int offs, void *sbuf, int grouped); ++struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum, ++ int offs, void *sbuf); ++int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf); ++int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf); ++int ubifs_rcvry_gc_commit(struct ubifs_info *c); ++int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key, ++ int deletion, loff_t new_size); ++int ubifs_recover_size(struct ubifs_info *c); ++void ubifs_destroy_size_tree(struct ubifs_info *c); ++ ++/* ioctl.c */ ++long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); ++void ubifs_set_inode_flags(struct inode *inode); ++#ifdef CONFIG_COMPAT ++long ubifs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); ++#endif ++ ++/* compressor.c */ ++int __init ubifs_compressors_init(void); ++void __exit ubifs_compressors_exit(void); ++void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len, ++ int *compr_type); ++int ubifs_decompress(const void *buf, int len, void *out, int *out_len, ++ int compr_type); ++ ++#include "debug.h" ++#include "misc.h" ++#include "key.h" ++ ++#endif /* !__UBIFS_H__ */ +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/ubifs-media.h avr32-2.6/fs/ubifs/ubifs-media.h +--- linux-2.6.25.6/fs/ubifs/ubifs-media.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/ubifs-media.h 2008-06-12 15:09:45.603817614 +0200 +@@ -0,0 +1,729 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Artem Bityutskiy (Битюцкий Артём) ++ * Adrian Hunter ++ */ ++ ++/* ++ * This file describes UBIFS on-flash format and contains definitions of all the ++ * relevant data structures and constants. ++ * ++ * All UBIFS on-flash objects are stored in the form of nodes. All nodes start ++ * with the UBIFS node magic number and have the same common header. Nodes ++ * always sit at 8-byte aligned positions on the media and node header sizes are ++ * also 8-byte aligned (except for the indexing node and the padding node). ++ */ ++ ++#ifndef __UBIFS_MEDIA_H__ ++#define __UBIFS_MEDIA_H__ ++ ++/* UBIFS node magic number (must not have the padding byte first or last) */ ++#define UBIFS_NODE_MAGIC 0x06101831 ++ ++/* UBIFS on-flash format version */ ++#define UBIFS_FORMAT_VERSION 4 ++ ++/* Minimum logical eraseblock size in bytes */ ++#define UBIFS_MIN_LEB_SZ (15*1024) ++ ++/* Initial CRC32 value used when calculating CRC checksums */ ++#define UBIFS_CRC32_INIT 0xFFFFFFFFU ++ ++/* ++ * UBIFS does not try to compress data if its length is less than the below ++ * constant. ++ */ ++#define UBIFS_MIN_COMPR_LEN 128 ++ ++/* Root inode number */ ++#define UBIFS_ROOT_INO 1 ++ ++/* Lowest inode number used for regular inodes (not UBIFS-only internal ones) */ ++#define UBIFS_FIRST_INO 64 ++ ++/* ++ * Maximum file name and extended attribute length (must be a multiple of 8, ++ * minus 1). ++ */ ++#define UBIFS_MAX_NLEN 255 ++ ++/* Maximum number of data journal heads */ ++#define UBIFS_MAX_JHEADS 1 ++ ++/* ++ * Size of UBIFS data block. Note, UBIFS is not a block oriented file-system, ++ * which means that it does not treat the underlying media as consisting of ++ * blocks like in case of hard drives. Do not be confused. UBIFS block is just ++ * the maximum amount of data which one data node can have or which can be ++ * attached to an inode node. ++ */ ++#define UBIFS_BLOCK_SIZE 4096 ++#define UBIFS_BLOCK_SHIFT 12 ++#define UBIFS_BLOCK_MASK 0x00000FFF ++ ++/* UBIFS padding byte pattern (must not be first or last byte of node magic) */ ++#define UBIFS_PADDING_BYTE 0xCE ++ ++/* Maximum possible key length */ ++#define UBIFS_MAX_KEY_LEN 16 ++ ++/* Key length ("simple" format) */ ++#define UBIFS_SK_LEN 8 ++ ++/* Minimum index tree fanout */ ++#define UBIFS_MIN_FANOUT 2 ++ ++/* Maximum number of levels in UBIFS indexing B-tree */ ++#define UBIFS_MAX_LEVELS 512 ++ ++/* Maximum amount of data attached to an inode in bytes */ ++#define UBIFS_MAX_INO_DATA UBIFS_BLOCK_SIZE ++ ++/* LEB Properties Tree fanout (must be power of 2) and fanout shift */ ++#define UBIFS_LPT_FANOUT 4 ++#define UBIFS_LPT_FANOUT_SHIFT 2 ++ ++/* LEB Properties Tree bit field sizes */ ++#define UBIFS_LPT_CRC_BITS 16 ++#define UBIFS_LPT_CRC_BYTES 2 ++#define UBIFS_LPT_TYPE_BITS 4 ++ ++/* The key is always at the same position in all keyed nodes */ ++#define UBIFS_KEY_OFFSET offsetof(struct ubifs_ino_node, key) ++ ++/* ++ * LEB Properties Tree node types. ++ * ++ * UBIFS_LPT_PNODE: LPT leaf node (contains LEB properties) ++ * UBIFS_LPT_NNODE: LPT internal node ++ * UBIFS_LPT_LTAB: LPT's own lprops table ++ * UBIFS_LPT_LSAVE: LPT's save table (big model only) ++ * UBIFS_LPT_NODE_CNT: count of LPT node types ++ * UBIFS_LPT_NOT_A_NODE: all ones (15 for 4 bits) is never a valid node type ++ */ ++enum { ++ UBIFS_LPT_PNODE, ++ UBIFS_LPT_NNODE, ++ UBIFS_LPT_LTAB, ++ UBIFS_LPT_LSAVE, ++ UBIFS_LPT_NODE_CNT, ++ UBIFS_LPT_NOT_A_NODE = (1 << UBIFS_LPT_TYPE_BITS) - 1, ++}; ++ ++/* ++ * UBIFS inode types. ++ * ++ * UBIFS_ITYPE_REG: regular file ++ * UBIFS_ITYPE_DIR: directory ++ * UBIFS_ITYPE_LNK: soft link ++ * UBIFS_ITYPE_BLK: block device node ++ * UBIFS_ITYPE_CHR: character device node ++ * UBIFS_ITYPE_FIFO: fifo ++ * UBIFS_ITYPE_SOCK: socket ++ * UBIFS_ITYPES_CNT: count of supported file types ++ */ ++enum { ++ UBIFS_ITYPE_REG, ++ UBIFS_ITYPE_DIR, ++ UBIFS_ITYPE_LNK, ++ UBIFS_ITYPE_BLK, ++ UBIFS_ITYPE_CHR, ++ UBIFS_ITYPE_FIFO, ++ UBIFS_ITYPE_SOCK, ++ UBIFS_ITYPES_CNT, ++}; ++ ++/* ++ * Supported key hash functions. ++ * ++ * UBIFS_KEY_HASH_R5: R5 hash ++ * UBIFS_KEY_HASH_TEST: test hash which just returns first 4 bytes of the name ++ */ ++enum { ++ UBIFS_KEY_HASH_R5, ++ UBIFS_KEY_HASH_TEST, ++}; ++ ++/* ++ * Supported key formats. ++ * ++ * UBIFS_SIMPLE_KEY_FMT: simple key format ++ */ ++enum { ++ UBIFS_SIMPLE_KEY_FMT, ++}; ++ ++/* ++ * The simple key format uses 29 bits for storing UBIFS block number and hash ++ * value. ++ */ ++#define UBIFS_S_KEY_BLOCK_BITS 29 ++#define UBIFS_S_KEY_BLOCK_MASK 0x1FFFFFFF ++#define UBIFS_S_KEY_HASH_BITS UBIFS_S_KEY_BLOCK_BITS ++#define UBIFS_S_KEY_HASH_MASK UBIFS_S_KEY_BLOCK_MASK ++ ++/* ++ * Key types. ++ * ++ * UBIFS_INO_KEY: inode node key ++ * UBIFS_DATA_KEY: data node key ++ * UBIFS_DENT_KEY: directory entry node key ++ * UBIFS_XENT_KEY: extended attribute entry key ++ * UBIFS_KEY_TYPES_CNT: number of supported key types ++ */ ++enum { ++ UBIFS_INO_KEY, ++ UBIFS_DATA_KEY, ++ UBIFS_DENT_KEY, ++ UBIFS_XENT_KEY, ++ UBIFS_KEY_TYPES_CNT, ++}; ++ ++/* Count of LEBs reserved for the superblock area */ ++#define UBIFS_SB_LEBS 1 ++/* Count of LEBs reserved for the master area */ ++#define UBIFS_MST_LEBS 2 ++ ++/* First LEB of the superblock area */ ++#define UBIFS_SB_LNUM 0 ++/* First LEB of the master area */ ++#define UBIFS_MST_LNUM (UBIFS_SB_LNUM + UBIFS_SB_LEBS) ++/* First LEB of the log area */ ++#define UBIFS_LOG_LNUM (UBIFS_MST_LNUM + UBIFS_MST_LEBS) ++ ++/* Minimum number of logical eraseblocks in the log */ ++#define UBIFS_MIN_LOG_LEBS 2 ++/* Minimum number of bud logical eraseblocks */ ++#define UBIFS_MIN_BUD_LEBS 2 ++/* Minimum number of journal logical eraseblocks */ ++#define UBIFS_MIN_JNL_LEBS (UBIFS_MIN_LOG_LEBS + UBIFS_MIN_BUD_LEBS) ++/* Minimum number of LPT area logical eraseblocks */ ++#define UBIFS_MIN_LPT_LEBS 2 ++/* Minimum number of orphan area logical eraseblocks */ ++#define UBIFS_MIN_ORPH_LEBS 1 ++/* Minimum number of main area logical eraseblocks */ ++#define UBIFS_MIN_MAIN_LEBS 8 ++ ++/* Minimum number of logical eraseblocks */ ++#define UBIFS_MIN_LEB_CNT (UBIFS_SB_LEBS + UBIFS_MST_LEBS + \ ++ UBIFS_MIN_LOG_LEBS + UBIFS_MIN_BUD_LEBS + \ ++ UBIFS_MIN_LPT_LEBS + UBIFS_MIN_ORPH_LEBS + \ ++ UBIFS_MIN_MAIN_LEBS) ++ ++/* Node sizes (N.B. these are guaranteed to be multiples of 8) */ ++#define UBIFS_CH_SZ sizeof(struct ubifs_ch) ++#define UBIFS_INO_NODE_SZ sizeof(struct ubifs_ino_node) ++#define UBIFS_DATA_NODE_SZ sizeof(struct ubifs_data_node) ++#define UBIFS_DENT_NODE_SZ sizeof(struct ubifs_dent_node) ++#define UBIFS_TRUN_NODE_SZ sizeof(struct ubifs_trun_node) ++#define UBIFS_PAD_NODE_SZ sizeof(struct ubifs_pad_node) ++#define UBIFS_SB_NODE_SZ sizeof(struct ubifs_sb_node) ++#define UBIFS_MST_NODE_SZ sizeof(struct ubifs_mst_node) ++#define UBIFS_REF_NODE_SZ sizeof(struct ubifs_ref_node) ++#define UBIFS_IDX_NODE_SZ sizeof(struct ubifs_idx_node) ++#define UBIFS_CS_NODE_SZ sizeof(struct ubifs_cs_node) ++#define UBIFS_ORPH_NODE_SZ sizeof(struct ubifs_orph_node) ++/* Extended attribute entry nodes are identical to directory entry nodes */ ++#define UBIFS_XENT_NODE_SZ UBIFS_DENT_NODE_SZ ++/* Only this does not have to be multiple of 8 bytes */ ++#define UBIFS_BRANCH_SZ sizeof(struct ubifs_branch) ++ ++/* Maximum node sizes (N.B. these are guaranteed to be multiples of 8) */ ++#define UBIFS_MAX_DATA_NODE_SZ (UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE) ++#define UBIFS_MAX_INO_NODE_SZ (UBIFS_INO_NODE_SZ + UBIFS_MAX_INO_DATA) ++#define UBIFS_MAX_DENT_NODE_SZ (UBIFS_DENT_NODE_SZ + UBIFS_MAX_NLEN + 1) ++#define UBIFS_MAX_XENT_NODE_SZ UBIFS_MAX_DENT_NODE_SZ ++ ++/* The largest UBIFS node */ ++#define UBIFS_MAX_NODE_SZ UBIFS_MAX_INO_NODE_SZ ++ ++/* ++ * On-flash inode flags. ++ * ++ * UBIFS_COMPR_FL: use compression for this inode ++ * UBIFS_SYNC_FL: I/O on this inode has to be synchronous ++ * UBIFS_IMMUTABLE_FL: inode is immutable ++ * UBIFS_APPEND_FL: writes to the inode may only append data ++ * UBIFS_DIRSYNC_FL: I/O on this directory inode has to be synchronous ++ * ++ * Note, these are on-flash flags which correspond to ioctl flags ++ * (@FS_COMPR_FL, etc). They have the same values now, but generally, do not ++ * have to be the same. ++ */ ++enum { ++ UBIFS_COMPR_FL = 0x01, ++ UBIFS_SYNC_FL = 0x02, ++ UBIFS_IMMUTABLE_FL = 0x04, ++ UBIFS_APPEND_FL = 0x08, ++ UBIFS_DIRSYNC_FL = 0x10, ++}; ++ ++/* Inode flag bits used by UBIFS */ ++#define UBIFS_FL_MASK 0x0000001F ++ ++/* ++ * UBIFS compression types. ++ * ++ * UBIFS_COMPR_NONE: no compression ++ * UBIFS_COMPR_LZO: LZO compression ++ * UBIFS_COMPR_ZLIB: ZLIB compression ++ * UBIFS_COMPR_TYPES_CNT: count of supported compression types ++ */ ++enum { ++ UBIFS_COMPR_NONE, ++ UBIFS_COMPR_LZO, ++ UBIFS_COMPR_ZLIB, ++ UBIFS_COMPR_TYPES_CNT, ++}; ++ ++/* ++ * UBIFS node types. ++ * ++ * UBIFS_INO_NODE: inode node ++ * UBIFS_DATA_NODE: data node ++ * UBIFS_DENT_NODE: directory entry node ++ * UBIFS_XENT_NODE: extended attribute node ++ * UBIFS_TRUN_NODE: truncation node ++ * UBIFS_PAD_NODE: padding node ++ * UBIFS_SB_NODE: superblock node ++ * UBIFS_MST_NODE: master node ++ * UBIFS_REF_NODE: LEB reference node ++ * UBIFS_IDX_NODE: index node ++ * UBIFS_CS_NODE: commit start node ++ * UBIFS_ORPH_NODE: orphan node ++ * UBIFS_NODE_TYPES_CNT: count of supported node types ++ * ++ * Note, we index arrays by these numbers, so keep them low and contiguous. ++ * Node type constants for inodes, direntries and so on have to be the same as ++ * corresponding key type constants. ++ */ ++enum { ++ UBIFS_INO_NODE, ++ UBIFS_DATA_NODE, ++ UBIFS_DENT_NODE, ++ UBIFS_XENT_NODE, ++ UBIFS_TRUN_NODE, ++ UBIFS_PAD_NODE, ++ UBIFS_SB_NODE, ++ UBIFS_MST_NODE, ++ UBIFS_REF_NODE, ++ UBIFS_IDX_NODE, ++ UBIFS_CS_NODE, ++ UBIFS_ORPH_NODE, ++ UBIFS_NODE_TYPES_CNT, ++}; ++ ++/* ++ * Master node flags. ++ * ++ * UBIFS_MST_DIRTY: rebooted uncleanly - master node is dirty ++ * UBIFS_MST_NO_ORPHS: no orphan inodes present ++ * UBIFS_MST_RCVRY: written by recovery ++ */ ++enum { ++ UBIFS_MST_DIRTY = 1, ++ UBIFS_MST_NO_ORPHS = 2, ++ UBIFS_MST_RCVRY = 4, ++}; ++ ++/* ++ * Node group type (used by recovery to recover whole group or none). ++ * ++ * UBIFS_NO_NODE_GROUP: this node is not part of a group ++ * UBIFS_IN_NODE_GROUP: this node is a part of a group ++ * UBIFS_LAST_OF_NODE_GROUP: this node is the last in a group ++ */ ++enum { ++ UBIFS_NO_NODE_GROUP = 0, ++ UBIFS_IN_NODE_GROUP, ++ UBIFS_LAST_OF_NODE_GROUP, ++}; ++ ++/* ++ * Superblock flags. ++ * ++ * UBIFS_FLG_BIGLPT: if "big" LPT model is used if set ++ */ ++enum { ++ UBIFS_FLG_BIGLPT = 0x02, ++}; ++ ++/** ++ * struct ubifs_ch - common header node. ++ * @magic: UBIFS node magic number (%UBIFS_NODE_MAGIC) ++ * @crc: CRC-32 checksum of the node header ++ * @sqnum: sequence number ++ * @len: full node length ++ * @node_type: node type ++ * @group_type: node group type ++ * @padding: reserved for future, zeroes ++ * ++ * Every UBIFS node starts with this common part. If the node has a key, the ++ * key always goes next. ++ */ ++struct ubifs_ch { ++ __le32 magic; ++ __le32 crc; ++ __le64 sqnum; ++ __le32 len; ++ __u8 node_type; ++ __u8 group_type; ++ __u8 padding[2]; ++} __attribute__ ((packed)); ++ ++/** ++ * union ubifs_dev_desc - device node descriptor. ++ * @new: new type device descriptor ++ * @huge: huge type device descriptor ++ * ++ * This data structure describes major/minor numbers of a device node. In an ++ * inode is a device node then its data contains an object of this type. UBIFS ++ * uses standard Linux "new" and "huge" device node encodings. ++ */ ++union ubifs_dev_desc { ++ __le32 new; ++ __le64 huge; ++} __attribute__ ((packed)); ++ ++/** ++ * struct ubifs_ino_node - inode node. ++ * @ch: common header ++ * @key: node key ++ * @creat_sqnum: sequence number at time of creation ++ * @size: inode size in bytes (amount of uncompressed data) ++ * @atime_sec: access time seconds ++ * @ctime_sec: creation time seconds ++ * @mtime_sec: modification time seconds ++ * @atime_nsec: access time nanoseconds ++ * @ctime_nsec: creation time nanoseconds ++ * @mtime_nsec: modification time nanoseconds ++ * @nlink: number of hard links ++ * @uid: owner ID ++ * @gid: group ID ++ * @mode: access flags ++ * @flags: per-inode flags (%UBIFS_COMPR_FL, %UBIFS_SYNC_FL, etc) ++ * @data_len: inode data length ++ * @xattr_cnt: count of extended attributes this inode has ++ * @xattr_size: summarized size of all extended attributes in bytes ++ * @xattr_names: sum of lengths of all extended attribute names belonging to ++ * this inode ++ * @compr_type: compression type used for this inode ++ * @padding: reserved for future, zeroes ++ * @data: data attached to the inode ++ * ++ * Note, even though inode compression type is defined by @compr_type, some ++ * nodes of this inode may be compressed with different compressor - this ++ * happens if compression type is changed while the inode already has data ++ * nodes. But @compr_type will be use for further writes to the inode. ++ * ++ * Note, do not forget to amend 'zero_ino_node_unused()' function when changing ++ * the padding fields. ++ */ ++struct ubifs_ino_node { ++ struct ubifs_ch ch; ++ __u8 key[UBIFS_MAX_KEY_LEN]; ++ __le64 creat_sqnum; ++ __le64 size; ++ __le64 atime_sec; ++ __le64 ctime_sec; ++ __le64 mtime_sec; ++ __le32 atime_nsec; ++ __le32 ctime_nsec; ++ __le32 mtime_nsec; ++ __le32 nlink; ++ __le32 uid; ++ __le32 gid; ++ __le32 mode; ++ __le32 flags; ++ __le32 data_len; ++ __le32 xattr_cnt; ++ __le64 xattr_size; ++ __le32 xattr_names; ++ __le16 compr_type; ++ __u8 padding[26]; /* Watch 'zero_ino_node_unused()' if changing! */ ++ __u8 data[]; ++} __attribute__ ((packed)); ++ ++/** ++ * struct ubifs_dent_node - directory entry node. ++ * @ch: common header ++ * @key: node key ++ * @inum: target inode number ++ * @padding1: reserved for future, zeroes ++ * @type: type of the target inode (%UBIFS_ITYPE_REG, %UBIFS_ITYPE_DIR, etc) ++ * @nlen: name length ++ * @padding2: reserved for future, zeroes ++ * @name: zero-terminated name ++ * ++ * Note, do not forget to amend 'zero_dent_node_unused()' function when ++ * changing the padding fields. ++ */ ++struct ubifs_dent_node { ++ struct ubifs_ch ch; ++ __u8 key[UBIFS_MAX_KEY_LEN]; ++ __le64 inum; ++ __u8 padding1; ++ __u8 type; ++ __le16 nlen; ++ __u8 padding2[4]; /* Watch 'zero_dent_node_unused()' if changing! */ ++ __u8 name[]; ++} __attribute__ ((packed)); ++ ++/** ++ * struct ubifs_data_node - data node. ++ * @ch: common header ++ * @key: node key ++ * @size: uncompressed data size in bytes ++ * @compr_type: compression type (%UBIFS_COMPR_NONE, %UBIFS_COMPR_LZO, etc) ++ * @padding: reserved for future, zeroes ++ * @data: data ++ * ++ * Note, do not forget to amend 'zero_data_node_unused()' function when ++ * changing the padding fields. ++ */ ++struct ubifs_data_node { ++ struct ubifs_ch ch; ++ __u8 key[UBIFS_MAX_KEY_LEN]; ++ __le32 size; ++ __le16 compr_type; ++ __u8 padding[2]; /* Watch 'zero_data_node_unused()' if changing! */ ++ __u8 data[]; ++} __attribute__ ((packed)); ++ ++/** ++ * struct ubifs_trun_node - truncation node. ++ * @ch: common header ++ * @inum: truncated inode number ++ * @padding: reserved for future, zeroes ++ * @old_size: size before truncation ++ * @new_size: size after truncation ++ * ++ * This node exists only in the journal and never goes to the main area. Note, ++ * do not forget to amend 'zero_trun_node_unused()' function when changing the ++ * padding fields. ++ */ ++struct ubifs_trun_node { ++ struct ubifs_ch ch; ++ __le32 inum; ++ __u8 padding[12]; /* Watch 'zero_trun_node_unused()' if changing! */ ++ __le64 old_size; ++ __le64 new_size; ++} __attribute__ ((packed)); ++ ++/** ++ * struct ubifs_pad_node - padding node. ++ * @ch: common header ++ * @pad_len: how many bytes after this node are unused (because padded) ++ * @padding: reserved for future, zeroes ++ */ ++struct ubifs_pad_node { ++ struct ubifs_ch ch; ++ __le32 pad_len; ++} __attribute__ ((packed)); ++ ++/** ++ * struct ubifs_sb_node - superblock node. ++ * @ch: common header ++ * @padding: reserved for future, zeroes ++ * @key_hash: type of hash function used in keys ++ * @key_fmt: format of the key ++ * @flags: file-system flags (%UBIFS_FLG_BIGLPT, etc) ++ * @min_io_size: minimal input/output unit size ++ * @leb_size: logical eraseblock size in bytes ++ * @leb_cnt: count of LEBs used by filesystem ++ * @max_leb_cnt: maximum count of LEBs used by filesystem ++ * @max_bud_bytes: maximum amount of data stored in buds ++ * @log_lebs: log size in logical eraseblocks ++ * @lpt_lebs: number of LEBs used for lprops table ++ * @orph_lebs: number of LEBs used for recording orphans ++ * @jhead_cnt: count of journal heads ++ * @fanout: tree fanout (max. number of links per indexing node) ++ * @lsave_cnt: number of LEB numbers in LPT's save table ++ * @fmt_version: UBIFS on-flash format version ++ * @default_compr: default compression ++ * @padding1: reserved for future, zeroes ++ * @rp_uid: reserve pool UID ++ * @rp_gid: reserve pool GID ++ * @rp_size: size of the reserved pool in bytes ++ * @padding2: reserved for future, zeroes ++ * @time_gran: time granularity in nanoseconds ++ * @uuid: UUID generated when the file system image was created ++ */ ++struct ubifs_sb_node { ++ struct ubifs_ch ch; ++ __u8 padding[2]; ++ __u8 key_hash; ++ __u8 key_fmt; ++ __le32 flags; ++ __le32 min_io_size; ++ __le32 leb_size; ++ __le32 leb_cnt; ++ __le32 max_leb_cnt; ++ __le64 max_bud_bytes; ++ __le32 log_lebs; ++ __le32 lpt_lebs; ++ __le32 orph_lebs; ++ __le32 jhead_cnt; ++ __le32 fanout; ++ __le32 lsave_cnt; ++ __le32 fmt_version; ++ __le16 default_compr; ++ __u8 padding1[2]; ++ __le32 rp_uid; ++ __le32 rp_gid; ++ __le64 rp_size; ++ __le32 time_gran; ++ __u8 uuid[16]; ++ __u8 padding2[3972]; ++} __attribute__ ((packed)); ++ ++/** ++ * struct ubifs_mst_node - master node. ++ * @ch: common header ++ * @highest_inum: highest inode number in the committed index ++ * @cmt_no: commit number ++ * @flags: various flags (%UBIFS_MST_DIRTY, etc) ++ * @log_lnum: start of the log ++ * @root_lnum: LEB number of the root indexing node ++ * @root_offs: offset within @root_lnum ++ * @root_len: root indexing node length ++ * @gc_lnum: LEB reserved for garbage collection (%-1 value means the LEB was ++ * not reserved and should be reserved on mount) ++ * @ihead_lnum: LEB number of index head ++ * @ihead_offs: offset of index head ++ * @index_size: size of index on flash ++ * @total_free: total free space in bytes ++ * @total_dirty: total dirty space in bytes ++ * @total_used: total used space in bytes (includes only data LEBs) ++ * @total_dead: total dead space in bytes (includes only data LEBs) ++ * @total_dark: total dark space in bytes (includes only data LEBs) ++ * @lpt_lnum: LEB number of LPT root nnode ++ * @lpt_offs: offset of LPT root nnode ++ * @nhead_lnum: LEB number of LPT head ++ * @nhead_offs: offset of LPT head ++ * @ltab_lnum: LEB number of LPT's own lprops table ++ * @ltab_offs: offset of LPT's own lprops table ++ * @lsave_lnum: LEB number of LPT's save table (big model only) ++ * @lsave_offs: offset of LPT's save table (big model only) ++ * @lscan_lnum: LEB number of last LPT scan ++ * @empty_lebs: number of empty logical eraseblocks ++ * @idx_lebs: number of indexing logical eraseblocks ++ * @leb_cnt: count of LEBs used by filesystem ++ * @padding: reserved for future, zeroes ++ */ ++struct ubifs_mst_node { ++ struct ubifs_ch ch; ++ __le64 highest_inum; ++ __le64 cmt_no; ++ __le32 flags; ++ __le32 log_lnum; ++ __le32 root_lnum; ++ __le32 root_offs; ++ __le32 root_len; ++ __le32 gc_lnum; ++ __le32 ihead_lnum; ++ __le32 ihead_offs; ++ __le64 index_size; ++ __le64 total_free; ++ __le64 total_dirty; ++ __le64 total_used; ++ __le64 total_dead; ++ __le64 total_dark; ++ __le32 lpt_lnum; ++ __le32 lpt_offs; ++ __le32 nhead_lnum; ++ __le32 nhead_offs; ++ __le32 ltab_lnum; ++ __le32 ltab_offs; ++ __le32 lsave_lnum; ++ __le32 lsave_offs; ++ __le32 lscan_lnum; ++ __le32 empty_lebs; ++ __le32 idx_lebs; ++ __le32 leb_cnt; ++ __u8 padding[344]; ++} __attribute__ ((packed)); ++ ++/** ++ * struct ubifs_ref_node - logical eraseblock reference node. ++ * @ch: common header ++ * @lnum: the referred logical eraseblock number ++ * @offs: start offset in the referred LEB ++ * @jhead: journal head number ++ * @padding: reserved for future, zeroes ++ */ ++struct ubifs_ref_node { ++ struct ubifs_ch ch; ++ __le32 lnum; ++ __le32 offs; ++ __le32 jhead; ++ __u8 padding[28]; ++} __attribute__ ((packed)); ++ ++/** ++ * struct ubifs_branch - key/reference/length branch ++ * @lnum: LEB number of the target node ++ * @offs: offset within @lnum ++ * @len: target node length ++ * @key: key ++ */ ++struct ubifs_branch { ++ __le32 lnum; ++ __le32 offs; ++ __le32 len; ++ __u8 key[]; ++} __attribute__ ((packed)); ++ ++/** ++ * struct ubifs_idx_node - indexing node. ++ * @ch: common header ++ * @child_cnt: number of child index nodes ++ * @level: tree level ++ * @branches: LEB number / offset / length / key branches ++ */ ++struct ubifs_idx_node { ++ struct ubifs_ch ch; ++ __le16 child_cnt; ++ __le16 level; ++ __u8 branches[]; ++} __attribute__ ((packed)); ++ ++/** ++ * struct ubifs_cs_node - commit start node. ++ * @ch: common header ++ * @cmt_no: commit number ++ */ ++struct ubifs_cs_node { ++ struct ubifs_ch ch; ++ __le64 cmt_no; ++} __attribute__ ((packed)); ++ ++/** ++ * struct ubifs_orph_node - orphan node. ++ * @ch: common header ++ * @cmt_no: commit number (also top bit is set on the last node of the commit) ++ * @inos: inode numbers of orphans ++ */ ++struct ubifs_orph_node { ++ struct ubifs_ch ch; ++ __le64 cmt_no; ++ __le64 inos[]; ++} __attribute__ ((packed)); ++ ++#endif /* __UBIFS_MEDIA_H__ */ +diff --exclude=.git -urN linux-2.6.25.6/fs/ubifs/xattr.c avr32-2.6/fs/ubifs/xattr.c +--- linux-2.6.25.6/fs/ubifs/xattr.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/fs/ubifs/xattr.c 2008-06-12 15:09:45.603817614 +0200 +@@ -0,0 +1,581 @@ ++/* ++ * This file is part of UBIFS. ++ * ++ * Copyright (C) 2006-2008 Nokia Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation. ++ * ++ * 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, Inc., 51 ++ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ * Authors: Artem Bityutskiy (Битюцкий Артём) ++ * Adrian Hunter ++ */ ++ ++/* ++ * This file implements UBIFS extended attributes support. ++ * ++ * Extended attributes are implemented as regular inodes with attached data, ++ * which limits extended attribute size to UBIFS block size (4KiB). Names of ++ * extended attributes are described by extended attribute entries (xentries), ++ * which are almost identical to directory entries, but have different key type. ++ * ++ * In other words, the situation with extended attributes is very similar to ++ * directories. Indeed, any inode (but of course not xattr inodes) may have a ++ * number of associated xentries, just like directory inodes have associated ++ * directory entries. Extended attribute entries store the name of the extended ++ * attribute, the host inode number, and the extended attribute inode number. ++ * Similarly, direntries store the name, the parent and the target inode ++ * numbers. Thus, most of the common UBIFS mechanisms may be re-used for ++ * extended attributes. ++ * ++ * The number of extended attributes is not limited, but there is Linux ++ * limitation on the maximum possible size of the list of all extended ++ * attributes associated with an inode (%XATTR_LIST_MAX), so UBIFS makes sure ++ * the sum of all extended attribute names of the inode does not exceed that ++ * limit. ++ * ++ * Extended attributes are synchronous, which means they are written to the ++ * flash media synchronously and there is no write-back for extended attribute ++ * inodes. The extended attribute values are not stored in compressed form on ++ * the media. ++ * ++ * Since extended attributes are represented by regular inodes, they are cached ++ * in the VFS inode cache. The xentries are cached in the LNC cache (see ++ * tnc.c). ++ * ++ * ACL support is not implemented. ++ */ ++ ++#include <linux/xattr.h> ++#include <linux/posix_acl_xattr.h> ++#include "ubifs.h" ++ ++/* ++ * Extended attribute type constants. ++ * ++ * USER_XATTR: user extended attribute ("user.*") ++ * TRUSTED_XATTR: trusted extended attribute ("trusted.*) ++ * SECURITY_XATTR: security extended attribute ("security.*") ++ */ ++enum { ++ USER_XATTR, ++ TRUSTED_XATTR, ++ SECURITY_XATTR, ++}; ++ ++static struct inode_operations none_inode_operations; ++static struct address_space_operations none_address_operations; ++static struct file_operations none_file_operations; ++ ++/** ++ * create_xattr - create an extended attribute. ++ * @c: UBIFS file-system description object ++ * @host: host inode ++ * @nm: extended attribute name ++ * @value: extended attribute value ++ * @size: size of extended attribute value ++ * ++ * This is a helper function which creates an extended attribute of name @nm ++ * and value @value for inode @host. The host inode is also updated on flash ++ * because the ctime and extended attribute accounting data changes. This ++ * function returns zero in case of success and a negative error code in case ++ * of failure. ++ */ ++static int create_xattr(struct ubifs_info *c, struct inode *host, ++ const struct qstr *nm, const void *value, int size) ++{ ++ struct ubifs_inode *ui, *host_ui = ubifs_inode(host); ++ struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, ++ .new_ino_d = size }; ++ struct inode *inode; ++ int err; ++ ++ /* ++ * Linux limits the maximum size of the extended attribute names list ++ * to %XATTR_LIST_MAX. This means we should not allow creating more* ++ * extended attributes if the name list becomes larger. This limitation ++ * is artificial for UBIFS, though. ++ */ ++ if (host_ui->xattr_names + host_ui->xattr_cnt + ++ nm->len + 1 > XATTR_LIST_MAX) ++ return -ENOSPC; ++ ++ err = ubifs_budget_inode_op(c, host, &req); ++ if (err) ++ return err; ++ ++ inode = ubifs_new_inode(c, host, S_IFREG | S_IRWXUGO); ++ if (IS_ERR(inode)) { ++ err = PTR_ERR(inode); ++ goto out_budg; ++ } ++ ++ /* Re-define all operations to be "nothing" */ ++ inode->i_mapping->a_ops = &none_address_operations; ++ inode->i_op = &none_inode_operations; ++ inode->i_fop = &none_file_operations; ++ ++ inode->i_flags |= S_SYNC | S_NOATIME | S_NOCMTIME | S_NOQUOTA; ++ ui = ubifs_inode(inode); ++ ui->xattr = 1; ++ ui->data = kmalloc(size, GFP_NOFS); ++ if (!ui->data) { ++ err = -ENOMEM; ++ goto out_inode; ++ } ++ ++ memcpy(ui->data, value, size); ++ host->i_ctime = ubifs_current_time(host); ++ host_ui->xattr_cnt += 1; ++ spin_lock(&host->i_lock); ++ host_ui->xattr_size += CALC_DENT_SIZE(nm->len); ++ host_ui->xattr_size += CALC_XATTR_BYTES(size); ++ spin_unlock(&host->i_lock); ++ host_ui->xattr_names += nm->len; ++ ++ /* ++ * We do not use i_size_write() because nobody can race with us as we ++ * are holding host @host->i_mutex - every xattr operation for this ++ * inode is serialized by it. ++ */ ++ inode->i_size = size; ++ ui->data_len = size; ++ ++ /* ++ * Note, it is important that 'ubifs_jnl_update()' writes the @host ++ * inode last, so when it gets synchronized and the write-buffer is ++ * flushed, the extended attribute is flushed as well. ++ */ ++ err = ubifs_jnl_update(c, host, nm, inode, 0, IS_DIRSYNC(host), 1); ++ if (err) ++ goto out_cancel; ++ ++ ubifs_release_ino_clean(c, host, &req); ++ insert_inode_hash(inode); ++ iput(inode); ++ return 0; ++ ++out_cancel: ++ host_ui->xattr_cnt -= 1; ++ spin_lock(&host->i_lock); ++ host_ui->xattr_size -= CALC_DENT_SIZE(nm->len); ++ host_ui->xattr_size -= CALC_XATTR_BYTES(size); ++ spin_unlock(&host->i_lock); ++out_inode: ++ make_bad_inode(inode); ++ iput(inode); ++out_budg: ++ ubifs_cancel_ino_op(c, host, &req); ++ return err; ++} ++ ++/** ++ * change_xattr - change an extended attribute. ++ * @c: UBIFS file-system description object ++ * @host: host inode ++ * @inode: extended attribute inode ++ * @value: extended attribute value ++ * @size: size of extended attribute value ++ * ++ * This helper function changes the value of extended attribute @inode with new ++ * data from @value. Returns zero in case of success and a negative error code ++ * in case of failure. ++ */ ++static int change_xattr(struct ubifs_info *c, struct inode *host, ++ struct inode *inode, const void *value, int size) ++{ ++ struct ubifs_inode *host_ui = ubifs_inode(host); ++ struct ubifs_inode *ui = ubifs_inode(inode); ++ struct ubifs_budget_req req = { .dirtied_ino = 1, ++ .dirtied_ino_d = ui->data_len }; ++ int err; ++ ++ ubifs_assert(ui->data_len == inode->i_size); ++ ++ err = ubifs_budget_inode_op(c, host, &req); ++ if (err) ++ return err; ++ ++ host->i_ctime = ubifs_current_time(host); ++ spin_lock(&host->i_lock); ++ host_ui->xattr_size -= CALC_XATTR_BYTES(ui->data_len); ++ host_ui->xattr_size += CALC_XATTR_BYTES(size); ++ spin_unlock(&host->i_lock); ++ ++ kfree(ui->data); ++ ui->data = kmalloc(size, GFP_NOFS); ++ if (!ui->data) { ++ err = -ENOMEM; ++ goto out_budg; ++ } ++ ++ memcpy(ui->data, value, size); ++ inode->i_size = size; ++ ui->data_len = size; ++ ++ /* ++ * It is important to write the host inode after the xattr inode ++ * because if the host inode gets synchronized, then the extended ++ * attribute inode gets synchronized, because it goes before the host ++ * inode in the write-buffer. ++ */ ++ err = ubifs_jnl_write_2_inodes(c, inode, host, IS_DIRSYNC(host)); ++ if (err) ++ goto out_cancel; ++ ++ ubifs_release_ino_clean(c, host, &req); ++ return 0; ++ ++out_cancel: ++ spin_lock(&host->i_lock); ++ host_ui->xattr_size -= CALC_XATTR_BYTES(size); ++ host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len); ++ spin_unlock(&host->i_lock); ++ make_bad_inode(inode); ++out_budg: ++ ubifs_cancel_ino_op(c, host, &req); ++ return err; ++} ++ ++/** ++ * check_namespace - check extended attribute name-space. ++ * @nm: extended attribute name ++ * ++ * This function makes sure the extended attribute name belongs to one of the ++ * supported extended attribute name-spaces. Returns name-space index in case ++ * of success and a negative error code in case of failure. ++ */ ++static int check_namespace(const struct qstr *nm) ++{ ++ int type; ++ ++ if (nm->len > UBIFS_MAX_NLEN) ++ return -ENAMETOOLONG; ++ ++ if (!strncmp(nm->name, XATTR_TRUSTED_PREFIX, ++ XATTR_TRUSTED_PREFIX_LEN)) { ++ if (nm->name[sizeof(XATTR_TRUSTED_PREFIX) - 1] == '\0') ++ return -EINVAL; ++ type = TRUSTED_XATTR; ++ } else if (!strncmp(nm->name, XATTR_USER_PREFIX, ++ XATTR_USER_PREFIX_LEN)) { ++ if (nm->name[XATTR_USER_PREFIX_LEN] == '\0') ++ return -EINVAL; ++ type = USER_XATTR; ++ } else if (!strncmp(nm->name, XATTR_SECURITY_PREFIX, ++ XATTR_SECURITY_PREFIX_LEN)) { ++ if (nm->name[sizeof(XATTR_SECURITY_PREFIX) - 1] == '\0') ++ return -EINVAL; ++ type = SECURITY_XATTR; ++ } else ++ return -EOPNOTSUPP; ++ ++ return type; ++} ++ ++int ubifs_setxattr(struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ struct inode *inode, *host = dentry->d_inode; ++ struct ubifs_info *c = host->i_sb->s_fs_info; ++ struct qstr nm = { .name = name, .len = strlen(name) }; ++ struct ubifs_dent_node *xent; ++ union ubifs_key key; ++ int err, type; ++ ++ dbg_gen("xattr '%s', host ino %lu ('%.*s'), size %zd", name, ++ host->i_ino, dentry->d_name.len, dentry->d_name.name, size); ++ ubifs_assert(ubifs_inode(host)->xattr_cnt >= 0); ++ ubifs_assert(ubifs_inode(host)->xattr_size >= 0); ++ ubifs_assert(ubifs_inode(host)->xattr_names >= 0); ++ ++ if (size > UBIFS_MAX_INO_DATA) ++ return -ERANGE; ++ ++ type = check_namespace(&nm); ++ if (type < 0) ++ return type; ++ ++ xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS); ++ if (!xent) ++ return -ENOMEM; ++ ++ /* ++ * The extended attribute entries are stored in LNC, so multiple ++ * look-ups do not involve reading the flash. ++ */ ++ xent_key_init(c, &key, host->i_ino, &nm); ++ err = ubifs_tnc_lookup_nm(c, &key, xent, &nm); ++ if (err) { ++ if (err != -ENOENT) ++ goto out_free; ++ ++ if (flags & XATTR_REPLACE) ++ /* We are asked not to create the xattr */ ++ err = -ENODATA; ++ else ++ err = create_xattr(c, host, &nm, value, size); ++ goto out_free; ++ } ++ ++ if (flags & XATTR_CREATE) { ++ /* We are asked not to replace the xattr */ ++ err = -EEXIST; ++ goto out_free; ++ } ++ ++ inode = ubifs_iget(c->vfs_sb, le64_to_cpu(xent->inum)); ++ if (IS_ERR(inode)) { ++ ubifs_err("dead extended attribute entry, error %d", err); ++ ubifs_ro_mode(c, err); ++ err = PTR_ERR(inode); ++ goto out_free; ++ } ++ ++ err = change_xattr(c, host, inode, value, size); ++ iput(inode); ++ ++out_free: ++ kfree(xent); ++ return err; ++} ++ ++ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf, ++ size_t size) ++{ ++ struct inode *inode, *host = dentry->d_inode; ++ struct ubifs_info *c = host->i_sb->s_fs_info; ++ struct qstr nm = { .name = name, .len = strlen(name) }; ++ struct ubifs_inode *ui; ++ struct ubifs_dent_node *xent; ++ union ubifs_key key; ++ int err; ++ ++ dbg_gen("xattr '%s', ino %lu ('%.*s'), buf size %zd", name, ++ host->i_ino, dentry->d_name.len, dentry->d_name.name, size); ++ ubifs_assert(ubifs_inode(host)->xattr_cnt >= 0); ++ ubifs_assert(ubifs_inode(host)->xattr_size >= 0); ++ ubifs_assert(ubifs_inode(host)->xattr_names >= 0); ++ ++ err = check_namespace(&nm); ++ if (err < 0) ++ return err; ++ ++ xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS); ++ if (!xent) ++ return -ENOMEM; ++ ++ mutex_lock(&host->i_mutex); ++ xent_key_init(c, &key, host->i_ino, &nm); ++ err = ubifs_tnc_lookup_nm(c, &key, xent, &nm); ++ if (err) { ++ if (err == -ENOENT) ++ err = -ENODATA; ++ goto out_unlock; ++ } ++ ++ inode = ubifs_iget(c->vfs_sb, le64_to_cpu(xent->inum)); ++ if (IS_ERR(inode)) { ++ ubifs_err("dead extended attribute entry, error %d", err); ++ ubifs_ro_mode(c, err); ++ err = PTR_ERR(inode); ++ goto out_unlock; ++ } ++ ++ ui = ubifs_inode(inode); ++ ubifs_assert(inode->i_size == ui->data_len); ++ ubifs_assert(ubifs_inode(host)->xattr_size > ui->data_len); ++ ++ if (buf) { ++ /* If @buf is %NULL we are supposed to return the length */ ++ if (ui->data_len > size) { ++ dbg_err("buffer size %zd, xattr len %d", ++ size, ui->data_len); ++ err = -ERANGE; ++ goto out_iput; ++ } ++ ++ memcpy(buf, ui->data, ui->data_len); ++ } ++ err = ui->data_len; ++ ++out_iput: ++ iput(inode); ++out_unlock: ++ mutex_unlock(&host->i_mutex); ++ kfree(xent); ++ return err; ++} ++ ++ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size) ++{ ++ struct inode *host = dentry->d_inode; ++ struct ubifs_info *c = host->i_sb->s_fs_info; ++ struct ubifs_inode *host_ui = ubifs_inode(host); ++ union ubifs_key key; ++ struct ubifs_dent_node *xent, *pxent = NULL; ++ int err, len, written = 0; ++ struct qstr nm = { .name = NULL }; ++ ++ dbg_gen("ino %lu ('%.*s'), buffer size %zd", host->i_ino, ++ dentry->d_name.len, dentry->d_name.name, size); ++ ubifs_assert(host_ui->xattr_cnt >= 0); ++ ubifs_assert(host_ui->xattr_size >= 0); ++ ubifs_assert(host_ui->xattr_names >= 0); ++ ++ len = host_ui->xattr_names + host_ui->xattr_cnt; ++ if (!buffer) ++ /* ++ * We should return the minimum buffer size which will fit a ++ * null-terminated list of all the extended attribute names. ++ */ ++ return len; ++ ++ if (len > size) ++ return -ERANGE; ++ ++ lowest_xent_key(c, &key, host->i_ino); ++ ++ mutex_lock(&host->i_mutex); ++ while (1) { ++ int type; ++ ++ xent = ubifs_tnc_next_ent(c, &key, &nm); ++ if (unlikely(IS_ERR(xent))) { ++ err = PTR_ERR(xent); ++ break; ++ } ++ ++ nm.name = xent->name; ++ nm.len = le16_to_cpu(xent->nlen); ++ ++ type = check_namespace(&nm); ++ if (unlikely(type < 0)) { ++ err = type; ++ break; ++ } ++ ++ /* Show trusted namespace only for "power" users */ ++ if (type != TRUSTED_XATTR || capable(CAP_SYS_ADMIN)) { ++ memcpy(buffer + written, nm.name, nm.len + 1); ++ written += nm.len + 1; ++ } ++ ++ kfree(pxent); ++ pxent = xent; ++ key_read(c, &xent->key, &key); ++ } ++ mutex_unlock(&host->i_mutex); ++ ++ kfree(pxent); ++ if (err != -ENOENT) { ++ ubifs_err("cannot find next direntry, error %d", err); ++ return err; ++ } ++ ++ ubifs_assert(written <= size); ++ return written; ++} ++ ++static int remove_xattr(struct ubifs_info *c, struct inode *host, ++ struct inode *inode, const struct qstr *nm) ++{ ++ struct ubifs_inode *host_ui = ubifs_inode(host); ++ struct ubifs_inode *ui = ubifs_inode(inode); ++ struct ubifs_budget_req req = { .dirtied_ino = 1, .mod_dent = 1 }; ++ int err; ++ ++ ubifs_assert(ui->data_len == inode->i_size); ++ ++ err = ubifs_budget_inode_op(c, host, &req); ++ if (err) ++ return err; ++ ++ host->i_ctime = ubifs_current_time(host); ++ host_ui->xattr_cnt -= 1; ++ spin_lock(&host->i_lock); ++ host_ui->xattr_size -= CALC_DENT_SIZE(nm->len); ++ host_ui->xattr_size -= CALC_XATTR_BYTES(ui->data_len); ++ spin_unlock(&host->i_lock); ++ host_ui->xattr_names -= nm->len; ++ ++ err = ubifs_jnl_delete_xattr(c, host, inode, nm, IS_DIRSYNC(host)); ++ if (err) ++ goto out_cancel; ++ ++ ubifs_release_ino_clean(c, host, &req); ++ return 0; ++ ++out_cancel: ++ ubifs_cancel_ino_op(c, host, &req); ++ host_ui->xattr_cnt += 1; ++ spin_lock(&host->i_lock); ++ host_ui->xattr_size += CALC_DENT_SIZE(nm->len); ++ host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len); ++ spin_unlock(&host->i_lock); ++ make_bad_inode(inode); ++ return err; ++} ++ ++int ubifs_removexattr(struct dentry *dentry, const char *name) ++{ ++ struct inode *inode, *host = dentry->d_inode; ++ struct ubifs_info *c = host->i_sb->s_fs_info; ++ struct qstr nm = { .name = name, .len = strlen(name) }; ++ struct ubifs_dent_node *xent; ++ union ubifs_key key; ++ int err; ++ ++ dbg_gen("xattr '%s', ino %lu ('%.*s')", name, ++ host->i_ino, dentry->d_name.len, dentry->d_name.name); ++ ubifs_assert(mutex_is_locked(&host->i_mutex)); ++ ubifs_assert(ubifs_inode(host)->xattr_cnt >= 0); ++ ubifs_assert(ubifs_inode(host)->xattr_size >= 0); ++ ubifs_assert(ubifs_inode(host)->xattr_names >= 0); ++ ++ err = check_namespace(&nm); ++ if (err < 0) ++ return err; ++ ++ xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS); ++ if (!xent) ++ return -ENOMEM; ++ ++ xent_key_init(c, &key, host->i_ino, &nm); ++ err = ubifs_tnc_lookup_nm(c, &key, xent, &nm); ++ if (err) { ++ if (err == -ENOENT) ++ err = -ENODATA; ++ goto out_free; ++ } ++ ++ inode = ubifs_iget(c->vfs_sb, le64_to_cpu(xent->inum)); ++ if (IS_ERR(inode)) { ++ ubifs_err("dead extended attribute node entry"); ++ ubifs_ro_mode(c, err); ++ err = PTR_ERR(inode); ++ goto out_free; ++ } ++ ++ ubifs_assert(inode->i_nlink == 1); ++ inode->i_nlink = 0; ++ err = remove_xattr(c, host, inode, &nm); ++ if (err) ++ inode->i_nlink = 1; ++ ++ /* If @i_nlink is 0, 'iput()' will delete the inode */ ++ iput(inode); ++ ++out_free: ++ kfree(xent); ++ return err; ++} +diff --exclude=.git -urN linux-2.6.25.6/include/asm-arm/arch-at91/at91_ecc.h avr32-2.6/include/asm-arm/arch-at91/at91_ecc.h +--- linux-2.6.25.6/include/asm-arm/arch-at91/at91_ecc.h 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/include/asm-arm/arch-at91/at91_ecc.h 1970-01-01 01:00:00.000000000 +0100 +@@ -1,38 +0,0 @@ -/* -- * Pin definitions for AT32AP7000. +- * include/asm-arm/arch-at91/at91_ecc.h - * -- * Copyright (C) 2006 Atmel Corporation +- * Error Corrected Code Controller (ECC) - System peripherals regsters. +- * Based on AT91SAM9260 datasheet revision B. - * -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License version 2 as -- * published by the Free Software Foundation. +- * 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. - */ --#ifndef __ASM_ARCH_AT32AP7000_H__ --#define __ASM_ARCH_AT32AP7000_H__ - --#define GPIO_PERIPH_A 0 --#define GPIO_PERIPH_B 1 +-#ifndef AT91_ECC_H +-#define AT91_ECC_H - --#define NR_GPIO_CONTROLLERS 4 +-#define AT91_ECC_CR (AT91_ECC + 0x00) /* Control register */ +-#define AT91_ECC_RST (1 << 0) /* Reset parity */ - --/* -- * Pin numbers identifying specific GPIO pins on the chip. They can -- * also be converted to IRQ numbers by passing them through -- * gpio_to_irq(). -- */ --#define GPIO_PIOA_BASE (0) --#define GPIO_PIOB_BASE (GPIO_PIOA_BASE + 32) --#define GPIO_PIOC_BASE (GPIO_PIOB_BASE + 32) --#define GPIO_PIOD_BASE (GPIO_PIOC_BASE + 32) --#define GPIO_PIOE_BASE (GPIO_PIOD_BASE + 32) +-#define AT91_ECC_MR (AT91_ECC + 0x04) /* Mode register */ +-#define AT91_ECC_PAGESIZE (3 << 0) /* Page Size */ +-#define AT91_ECC_PAGESIZE_528 (0) +-#define AT91_ECC_PAGESIZE_1056 (1) +-#define AT91_ECC_PAGESIZE_2112 (2) +-#define AT91_ECC_PAGESIZE_4224 (3) - --#define GPIO_PIN_PA(N) (GPIO_PIOA_BASE + (N)) --#define GPIO_PIN_PB(N) (GPIO_PIOB_BASE + (N)) --#define GPIO_PIN_PC(N) (GPIO_PIOC_BASE + (N)) --#define GPIO_PIN_PD(N) (GPIO_PIOD_BASE + (N)) --#define GPIO_PIN_PE(N) (GPIO_PIOE_BASE + (N)) +-#define AT91_ECC_SR (AT91_ECC + 0x08) /* Status register */ +-#define AT91_ECC_RECERR (1 << 0) /* Recoverable Error */ +-#define AT91_ECC_ECCERR (1 << 1) /* ECC Single Bit Error */ +-#define AT91_ECC_MULERR (1 << 2) /* Multiple Errors */ - --#endif /* __ASM_ARCH_AT32AP7000_H__ */ ---- /dev/null -+++ b/include/asm-avr32/arch-at32ap/at32ap700x.h -@@ -0,0 +1,35 @@ +-#define AT91_ECC_PR (AT91_ECC + 0x0c) /* Parity register */ +-#define AT91_ECC_BITADDR (0xf << 0) /* Bit Error Address */ +-#define AT91_ECC_WORDADDR (0xfff << 4) /* Word Error Address */ +- +-#define AT91_ECC_NPR (AT91_ECC + 0x10) /* NParity register */ +-#define AT91_ECC_NPARITY (0xffff << 0) /* NParity */ +- +-#endif +diff --exclude=.git -urN linux-2.6.25.6/include/asm-arm/arch-at91/board.h avr32-2.6/include/asm-arm/arch-at91/board.h +--- linux-2.6.25.6/include/asm-arm/arch-at91/board.h 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/include/asm-arm/arch-at91/board.h 2008-06-12 15:09:45.803815435 +0200 +@@ -85,7 +85,7 @@ + extern void __init at91_add_device_usbh(struct at91_usbh_data *data); + + /* NAND / SmartMedia */ +-struct at91_nand_data { ++struct atmel_nand_data { + u8 enable_pin; /* chip enable */ + u8 det_pin; /* card detect */ + u8 rdy_pin; /* ready/busy */ +@@ -94,7 +94,7 @@ + u8 bus_width_16; /* buswidth is 16 bit */ + struct mtd_partition* (*partition_info)(int, int*); + }; +-extern void __init at91_add_device_nand(struct at91_nand_data *data); ++extern void __init at91_add_device_nand(struct atmel_nand_data *data); + + /* I2C*/ + extern void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices); +diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/arch-at32ap/board.h avr32-2.6/include/asm-avr32/arch-at32ap/board.h +--- linux-2.6.25.6/include/asm-avr32/arch-at32ap/board.h 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/include/asm-avr32/arch-at32ap/board.h 2008-06-12 15:09:45.855816193 +0200 +@@ -8,6 +8,12 @@ + + #define GPIO_PIN_NONE (-1) + +/* -+ * Pin definitions for AT32AP7000. -+ * -+ * Copyright (C) 2006 Atmel Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. ++ * Clock rates for various on-board oscillators. The number of entries ++ * in this array is chip-dependent. + */ -+#ifndef __ASM_ARCH_AT32AP700X_H__ -+#define __ASM_ARCH_AT32AP700X_H__ -+ -+#define GPIO_PERIPH_A 0 -+#define GPIO_PERIPH_B 1 -+ -+#define NR_GPIO_CONTROLLERS 4 -+ -+/* -+ * Pin numbers identifying specific GPIO pins on the chip. They can -+ * also be converted to IRQ numbers by passing them through -+ * gpio_to_irq(). -+ */ -+#define GPIO_PIOA_BASE (0) -+#define GPIO_PIOB_BASE (GPIO_PIOA_BASE + 32) -+#define GPIO_PIOC_BASE (GPIO_PIOB_BASE + 32) -+#define GPIO_PIOD_BASE (GPIO_PIOC_BASE + 32) -+#define GPIO_PIOE_BASE (GPIO_PIOD_BASE + 32) -+ -+#define GPIO_PIN_PA(N) (GPIO_PIOA_BASE + (N)) -+#define GPIO_PIN_PB(N) (GPIO_PIOB_BASE + (N)) -+#define GPIO_PIN_PC(N) (GPIO_PIOC_BASE + (N)) -+#define GPIO_PIN_PD(N) (GPIO_PIOD_BASE + (N)) -+#define GPIO_PIN_PE(N) (GPIO_PIOE_BASE + (N)) -+ -+#endif /* __ASM_ARCH_AT32AP700X_H__ */ ---- a/include/asm-avr32/arch-at32ap/board.h -+++ b/include/asm-avr32/arch-at32ap/board.h -@@ -38,9 +38,7 @@ ++extern unsigned long at32_board_osc_rates[]; ++ + /* Add basic devices: system manager, interrupt controller, portmuxes, etc. */ + void at32_add_system_devices(void); + +@@ -36,11 +42,10 @@ + struct atmel_lcdfb_info; + struct platform_device * at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data, - unsigned long fbmem_start, unsigned long fbmem_len); +- unsigned long fbmem_start, unsigned long fbmem_len); ++ unsigned long fbmem_start, unsigned long fbmem_len, ++ unsigned int pin_config); -struct usba_platform_data { - int vbus_pin; @@ -18406,17 +47366,7 @@ struct platform_device * at32_add_device_usba(unsigned int id, struct usba_platform_data *data); -@@ -51,6 +49,9 @@ - at32_add_device_ide(unsigned int id, unsigned int extint, - struct ide_platform_data *data); - -+/* mask says which PWM channels to mux */ -+struct platform_device *at32_add_device_pwm(u32 mask); -+ - /* depending on what's hooked up, not all SSC pins will be used */ - #define ATMEL_SSC_TK 0x01 - #define ATMEL_SSC_TF 0x02 -@@ -65,8 +66,17 @@ +@@ -68,8 +73,17 @@ struct platform_device * at32_add_device_ssc(unsigned int id, unsigned int flags); @@ -18424,8 +47374,8 @@ -struct platform_device *at32_add_device_mci(unsigned int id); +struct i2c_board_info; +struct platform_device *at32_add_device_twi(unsigned int id, -+ struct i2c_board_info *b, -+ unsigned int n); ++ struct i2c_board_info *b, ++ unsigned int n); + +struct mci_platform_data { + int detect_pin; @@ -18436,48 +47386,45 @@ struct platform_device *at32_add_device_ac97c(unsigned int id); struct platform_device *at32_add_device_abdac(unsigned int id); -@@ -81,4 +91,7 @@ +@@ -84,4 +98,20 @@ at32_add_device_cf(unsigned int id, unsigned int extint, struct cf_platform_data *data); +struct platform_device * +at32_add_device_psif(unsigned int id); + ++/* NAND / SmartMedia */ ++struct atmel_nand_data { ++ int enable_pin; /* chip enable */ ++ int det_pin; /* card detect */ ++ int rdy_pin; /* ready/busy */ ++ u8 ale; /* address line number connected to ALE */ ++ u8 cle; /* address line number connected to CLE */ ++ u8 bus_width_16; /* buswidth is 16 bit */ ++ struct mtd_partition *(*partition_info)(int size, int *num_partitions); ++}; ++struct platform_device * ++at32_add_device_nand(unsigned int id, struct atmel_nand_data *data); ++ #endif /* __ASM_ARCH_BOARD_H */ ---- a/include/asm-avr32/arch-at32ap/cpu.h -+++ b/include/asm-avr32/arch-at32ap/cpu.h -@@ -14,7 +14,7 @@ - * Only AT32AP7000 is defined for now. We can identify the specific - * chip at runtime, but I'm not sure if it's really worth it. - */ --#ifdef CONFIG_CPU_AT32AP7000 -+#ifdef CONFIG_CPU_AT32AP700X - # define cpu_is_at32ap7000() (1) - #else - # define cpu_is_at32ap7000() (0) ---- a/include/asm-avr32/arch-at32ap/io.h -+++ b/include/asm-avr32/arch-at32ap/io.h -@@ -4,7 +4,7 @@ - /* For "bizarre" halfword swapping */ - #include <linux/byteorder/swabb.h> - --#if defined(CONFIG_AP7000_32_BIT_SMC) -+#if defined(CONFIG_AP700X_32_BIT_SMC) - # define __swizzle_addr_b(addr) (addr ^ 3UL) - # define __swizzle_addr_w(addr) (addr ^ 2UL) - # define __swizzle_addr_l(addr) (addr) -@@ -14,7 +14,7 @@ - # define __mem_ioswabb(a, x) (x) - # define __mem_ioswabw(a, x) swab16(x) - # define __mem_ioswabl(a, x) swab32(x) --#elif defined(CONFIG_AP7000_16_BIT_SMC) -+#elif defined(CONFIG_AP700X_16_BIT_SMC) - # define __swizzle_addr_b(addr) (addr ^ 1UL) - # define __swizzle_addr_w(addr) (addr) - # define __swizzle_addr_l(addr) (addr) ---- /dev/null -+++ b/include/asm-avr32/arch-at32ap/pm.h -@@ -0,0 +1,48 @@ +diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/arch-at32ap/init.h avr32-2.6/include/asm-avr32/arch-at32ap/init.h +--- linux-2.6.25.6/include/asm-avr32/arch-at32ap/init.h 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/include/asm-avr32/arch-at32ap/init.h 2008-06-12 15:09:45.855816193 +0200 +@@ -13,10 +13,6 @@ + void setup_platform(void); + void setup_board(void); + +-/* Called by setup_platform */ +-void at32_clock_init(void); +-void at32_portmux_init(void); +- + void at32_setup_serial_console(unsigned int usart_id); + + #endif /* __ASM_AVR32_AT32AP_INIT_H__ */ +diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/arch-at32ap/pm.h avr32-2.6/include/asm-avr32/arch-at32ap/pm.h +--- linux-2.6.25.6/include/asm-avr32/arch-at32ap/pm.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/include/asm-avr32/arch-at32ap/pm.h 2008-06-12 15:09:45.855816193 +0200 +@@ -0,0 +1,51 @@ +/* + * AVR32 AP Power Management. + * @@ -18499,6 +47446,7 @@ + +#ifndef __ASSEMBLY__ +extern void cpu_enter_idle(void); ++extern void cpu_enter_standby(unsigned long sdramc_base); + +extern bool disable_idle_sleep; + @@ -18523,11 +47471,14 @@ + else + cpu_enter_idle(); +} ++ ++void intc_set_suspend_handler(unsigned long offset); +#endif + +#endif /* __ASM_AVR32_ARCH_PM_H */ ---- a/include/asm-avr32/arch-at32ap/portmux.h -+++ b/include/asm-avr32/arch-at32ap/portmux.h +diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/arch-at32ap/portmux.h avr32-2.6/include/asm-avr32/arch-at32ap/portmux.h +--- linux-2.6.25.6/include/asm-avr32/arch-at32ap/portmux.h 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/include/asm-avr32/arch-at32ap/portmux.h 2008-06-12 15:09:45.859816144 +0200 @@ -26,4 +26,16 @@ void at32_select_gpio(unsigned int pin, unsigned long flags); void at32_reserve_pin(unsigned int pin); @@ -18545,8 +47496,43 @@ +#endif /* CONFIG_GPIO_DEV */ + #endif /* __ASM_ARCH_PORTMUX_H__ */ ---- a/include/asm-avr32/arch-at32ap/time.h -+++ /dev/null +diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/arch-at32ap/sram.h avr32-2.6/include/asm-avr32/arch-at32ap/sram.h +--- linux-2.6.25.6/include/asm-avr32/arch-at32ap/sram.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/include/asm-avr32/arch-at32ap/sram.h 2008-06-12 15:09:45.859816144 +0200 +@@ -0,0 +1,30 @@ ++/* ++ * Simple SRAM allocator ++ * ++ * Copyright (C) 2008 Atmel Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __ASM_AVR32_ARCH_SRAM_H ++#define __ASM_AVR32_ARCH_SRAM_H ++ ++#include <linux/genalloc.h> ++ ++extern struct gen_pool *sram_pool; ++ ++static inline unsigned long sram_alloc(size_t len) ++{ ++ if (!sram_pool) ++ return 0UL; ++ ++ return gen_pool_alloc(sram_pool, len); ++} ++ ++static inline void sram_free(unsigned long addr, size_t len) ++{ ++ return gen_pool_free(sram_pool, addr, len); ++} ++ ++#endif /* __ASM_AVR32_ARCH_SRAM_H */ +diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/arch-at32ap/time.h avr32-2.6/include/asm-avr32/arch-at32ap/time.h +--- linux-2.6.25.6/include/asm-avr32/arch-at32ap/time.h 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/include/asm-avr32/arch-at32ap/time.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2007 Atmel Corporation @@ -18660,8 +47646,9 @@ - __raw_writel((value), port + (0x40 * instance) + TIMER_##reg) - -#endif /* _ASM_AVR32_ARCH_AT32AP_TIME_H */ ---- a/include/asm-avr32/asm.h -+++ b/include/asm-avr32/asm.h +diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/asm.h avr32-2.6/include/asm-avr32/asm.h +--- linux-2.6.25.6/include/asm-avr32/asm.h 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/include/asm-avr32/asm.h 2008-06-12 15:04:04.683816631 +0200 @@ -12,10 +12,10 @@ #include <asm/asm-offsets.h> #include <asm/thread_info.h> @@ -18677,21 +47664,9 @@ #ifdef CONFIG_FRAME_POINTER .macro save_fp ---- a/include/asm-avr32/byteorder.h -+++ b/include/asm-avr32/byteorder.h -@@ -12,8 +12,10 @@ - extern unsigned short __builtin_bswap_16(unsigned short x); - #endif - -+#if 0 - #define __arch__swab32(x) __builtin_bswap_32(x) - #define __arch__swab16(x) __builtin_bswap_16(x) -+#endif - - #if !defined(__STRICT_ANSI__) || defined(__KERNEL__) - # define __BYTEORDER_HAS_U64__ ---- /dev/null -+++ b/include/asm-avr32/dma-controller.h +diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/dma-controller.h avr32-2.6/include/asm-avr32/dma-controller.h +--- linux-2.6.25.6/include/asm-avr32/dma-controller.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/include/asm-avr32/dma-controller.h 2008-06-12 15:09:45.859816144 +0200 @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation @@ -18859,8 +47834,9 @@ +extern struct dma_controller *find_dma_controller(int id); + +#endif /* __ASM_AVR32_DMA_CONTROLLER_H */ ---- a/include/asm-avr32/intc.h -+++ /dev/null +diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/intc.h avr32-2.6/include/asm-avr32/intc.h +--- linux-2.6.25.6/include/asm-avr32/intc.h 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/include/asm-avr32/intc.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,128 +0,0 @@ -#ifndef __ASM_AVR32_INTC_H -#define __ASM_AVR32_INTC_H @@ -18990,329 +47966,92 @@ -extern int intc_register_controller(struct irq_controller *ctrl); - -#endif /* __ASM_AVR32_INTC_H */ ---- a/include/asm-avr32/irq.h -+++ b/include/asm-avr32/irq.h -@@ -11,4 +11,14 @@ - - #define irq_canonicalize(i) (i) - -+#ifndef __ASSEMBLER__ -+int nmi_enable(void); -+void nmi_disable(void); +diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/irq.h avr32-2.6/include/asm-avr32/irq.h +--- linux-2.6.25.6/include/asm-avr32/irq.h 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/include/asm-avr32/irq.h 2008-06-12 15:04:04.687816302 +0200 +@@ -14,6 +14,11 @@ + #ifndef __ASSEMBLER__ + int nmi_enable(void); + void nmi_disable(void); + +/* + * Returns a bitmask of pending interrupts in a group. + */ +extern unsigned long intc_get_pending(unsigned int group); -+#endif -+ - #endif /* __ASM_AVR32_IOCTLS_H */ ---- a/include/asm-avr32/kdebug.h -+++ b/include/asm-avr32/kdebug.h -@@ -5,6 +5,7 @@ - enum die_val { - DIE_BREAKPOINT, - DIE_SSTEP, -+ DIE_NMI, - }; - - #endif /* __ASM_AVR32_KDEBUG_H */ ---- a/include/asm-avr32/ocd.h -+++ b/include/asm-avr32/ocd.h -@@ -533,6 +533,11 @@ - #define ocd_read(reg) __ocd_read(OCD_##reg) - #define ocd_write(reg, value) __ocd_write(OCD_##reg, value) - -+struct task_struct; -+ -+void ocd_enable(struct task_struct *child); -+void ocd_disable(struct task_struct *child); -+ - #endif /* !__ASSEMBLER__ */ - - #endif /* __ASM_AVR32_OCD_H */ ---- a/include/asm-avr32/pgtable.h -+++ b/include/asm-avr32/pgtable.h -@@ -157,6 +157,7 @@ - #define _PAGE_S(x) _PAGE_NORMAL(x) - - #define PAGE_COPY _PAGE_P(PAGE_WRITE | PAGE_READ) -+#define PAGE_SHARED _PAGE_S(PAGE_WRITE | PAGE_READ) + #endif - #ifndef __ASSEMBLY__ - /* ---- a/include/asm-avr32/processor.h -+++ b/include/asm-avr32/processor.h -@@ -57,11 +57,25 @@ - unsigned short cpu_revision; - enum tlb_config tlb_config; - unsigned long features; -+ u32 device_id; - - struct cache_info icache; - struct cache_info dcache; - }; + #endif /* __ASM_AVR32_IOCTLS_H */ +diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/page.h avr32-2.6/include/asm-avr32/page.h +--- linux-2.6.25.6/include/asm-avr32/page.h 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/include/asm-avr32/page.h 2008-06-12 15:04:04.691816253 +0200 +@@ -8,13 +8,11 @@ + #ifndef __ASM_AVR32_PAGE_H + #define __ASM_AVR32_PAGE_H + ++#include <linux/const.h> ++ + /* PAGE_SHIFT determines the page size */ + #define PAGE_SHIFT 12 +-#ifdef __ASSEMBLY__ +-#define PAGE_SIZE (1 << PAGE_SHIFT) +-#else +-#define PAGE_SIZE (1UL << PAGE_SHIFT) +-#endif ++#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) + #define PAGE_MASK (~(PAGE_SIZE-1)) + #define PTE_MASK PAGE_MASK -+static inline unsigned int avr32_get_manufacturer_id(struct avr32_cpuinfo *cpu) -+{ -+ return (cpu->device_id >> 1) & 0x7f; -+} -+static inline unsigned int avr32_get_product_number(struct avr32_cpuinfo *cpu) -+{ -+ return (cpu->device_id >> 12) & 0xffff; -+} -+static inline unsigned int avr32_get_chip_revision(struct avr32_cpuinfo *cpu) -+{ -+ return (cpu->device_id >> 28) & 0x0f; -+} -+ - extern struct avr32_cpuinfo boot_cpu_data; +diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/pci.h avr32-2.6/include/asm-avr32/pci.h +--- linux-2.6.25.6/include/asm-avr32/pci.h 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/include/asm-avr32/pci.h 2008-06-12 15:09:45.859816144 +0200 +@@ -5,4 +5,6 @@ - #ifdef CONFIG_SMP ---- a/include/asm-avr32/ptrace.h -+++ b/include/asm-avr32/ptrace.h -@@ -121,7 +121,15 @@ - }; + #define PCI_DMA_BUS_IS_PHYS (1) - #ifdef __KERNEL__ --# define user_mode(regs) (((regs)->sr & MODE_MASK) == MODE_USER) ++#include <asm-generic/pci-dma-compat.h> + -+#include <asm/ocd.h> + #endif /* __ASM_AVR32_PCI_H__ */ +diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/serial.h avr32-2.6/include/asm-avr32/serial.h +--- linux-2.6.25.6/include/asm-avr32/serial.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/include/asm-avr32/serial.h 2008-06-12 15:04:04.695816483 +0200 +@@ -0,0 +1,13 @@ ++#ifndef _ASM_SERIAL_H ++#define _ASM_SERIAL_H + -+#define arch_ptrace_attach(child) ocd_enable(child) -+ -+#define user_mode(regs) (((regs)->sr & MODE_MASK) == MODE_USER) -+#define instruction_pointer(regs) ((regs)->pc) -+#define profile_pc(regs) instruction_pointer(regs) ++/* ++ * This assumes you have a 1.8432 MHz clock for your UART. ++ * ++ * It'd be nice if someone built a serial card with a 24.576 MHz ++ * clock, since the 16550A is capable of handling a top speed of 1.5 ++ * megabits/second; but this requires the faster clock. ++ */ ++#define BASE_BAUD (1843200 / 16) + - extern void show_regs (struct pt_regs *); - - static __inline__ int valid_user_regs(struct pt_regs *regs) -@@ -141,9 +149,6 @@ - return 0; - } - --#define instruction_pointer(regs) ((regs)->pc) -- --#define profile_pc(regs) instruction_pointer(regs) - - #endif /* __KERNEL__ */ - ---- a/include/asm-avr32/thread_info.h -+++ b/include/asm-avr32/thread_info.h ++#endif /* _ASM_SERIAL_H */ +diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/thread_info.h avr32-2.6/include/asm-avr32/thread_info.h +--- linux-2.6.25.6/include/asm-avr32/thread_info.h 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/include/asm-avr32/thread_info.h 2008-06-12 15:09:45.859816144 +0200 @@ -88,6 +88,7 @@ #define TIF_MEMDIE 6 #define TIF_RESTORE_SIGMASK 7 /* restore signal mask in do_signal */ #define TIF_CPU_GOING_TO_SLEEP 8 /* CPU is entering sleep 0 mode */ -+#define TIF_DEBUG 30 /* debugging enabled */ ++#define TIF_FREEZE 29 + #define TIF_DEBUG 30 /* debugging enabled */ #define TIF_USERSPACE 31 /* true if FS sets userspace */ - #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) ---- /dev/null -+++ b/include/linux/atmel_pwm.h -@@ -0,0 +1,70 @@ -+#ifndef __LINUX_ATMEL_PWM_H -+#define __LINUX_ATMEL_PWM_H -+ -+/** -+ * struct pwm_channel - driver handle to a PWM channel -+ * @regs: base of this channel's registers -+ * @index: number of this channel (0..31) -+ * @mck: base clock rate, which can be prescaled and maybe subdivided -+ * -+ * Drivers initialize a pwm_channel structure using pwm_channel_alloc(). -+ * Then they configure its clock rate (derived from MCK), alignment, -+ * polarity, and duty cycle by writing directly to the channel registers, -+ * before enabling the channel by calling pwm_channel_enable(). -+ * -+ * After emitting a PWM signal for the desired length of time, drivers -+ * may then pwm_channel_disable() or pwm_channel_free(). Both of these -+ * disable the channel, but when it's freed the IRQ is deconfigured and -+ * the channel must later be re-allocated and reconfigured. -+ * -+ * Note that if the period or duty cycle need to be changed while the -+ * PWM channel is operating, drivers must use the PWM_CUPD double buffer -+ * mechanism, either polling until they change or getting implicitly -+ * notified through a once-per-period interrupt handler. -+ */ -+struct pwm_channel { -+ void __iomem *regs; -+ unsigned index; -+ unsigned long mck; -+}; -+ -+extern int pwm_channel_alloc(int index, struct pwm_channel *ch); -+extern int pwm_channel_free(struct pwm_channel *ch); -+ -+extern int pwm_clk_alloc(unsigned prescale, unsigned div); -+extern void pwm_clk_free(unsigned clk); -+ -+extern int __pwm_channel_onoff(struct pwm_channel *ch, int enabled); -+ -+#define pwm_channel_enable(ch) __pwm_channel_onoff((ch), 1) -+#define pwm_channel_disable(ch) __pwm_channel_onoff((ch), 0) -+ -+/* periodic interrupts, mostly for CUPD changes to period or cycle */ -+extern int pwm_channel_handler(struct pwm_channel *ch, -+ void (*handler)(struct pwm_channel *ch)); -+ -+/* per-channel registers (banked at pwm_channel->regs) */ -+#define PWM_CMR 0x00 /* mode register */ -+#define PWM_CPR_CPD (1 << 10) /* set: CUPD modifies period */ -+#define PWM_CPR_CPOL (1 << 9) /* set: idle high */ -+#define PWM_CPR_CALG (1 << 8) /* set: center align */ -+#define PWM_CPR_CPRE (0xf << 0) /* mask: rate is mck/(2^pre) */ -+#define PWM_CPR_CLKA (0xb << 0) /* rate CLKA */ -+#define PWM_CPR_CLKB (0xc << 0) /* rate CLKB */ -+#define PWM_CDTY 0x04 /* duty cycle (max of CPRD) */ -+#define PWM_CPRD 0x08 /* period (count up from zero) */ -+#define PWM_CCNT 0x0c /* counter (20 bits?) */ -+#define PWM_CUPD 0x10 /* update CPRD (or CDTY) next period */ -+ -+static inline void -+pwm_channel_writel(struct pwm_channel *pwmc, unsigned offset, u32 val) -+{ -+ __raw_writel(val, pwmc->regs + offset); -+} -+ -+static inline u32 pwm_channel_readl(struct pwm_channel *pwmc, unsigned offset) -+{ -+ return __raw_readl(pwmc->regs + offset); -+} -+ -+#endif /* __LINUX_ATMEL_PWM_H */ ---- /dev/null -+++ b/include/linux/atmel_serial.h -@@ -0,0 +1,127 @@ -+/* -+ * include/linux/atmel_serial.h -+ * -+ * Copyright (C) 2005 Ivan Kokshaysky -+ * Copyright (C) SAN People -+ * -+ * USART registers. -+ * Based on AT91RM9200 datasheet revision E. -+ * -+ * 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. -+ */ +diff --exclude=.git -urN linux-2.6.25.6/include/asm-avr32/xor.h avr32-2.6/include/asm-avr32/xor.h +--- linux-2.6.25.6/include/asm-avr32/xor.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/include/asm-avr32/xor.h 2008-06-12 15:04:04.707817453 +0200 +@@ -0,0 +1,6 @@ ++#ifndef _ASM_XOR_H ++#define _ASM_XOR_H + -+#ifndef ATMEL_SERIAL_H -+#define ATMEL_SERIAL_H -+ -+#define ATMEL_US_CR 0x00 /* Control Register */ -+#define ATMEL_US_RSTRX (1 << 2) /* Reset Receiver */ -+#define ATMEL_US_RSTTX (1 << 3) /* Reset Transmitter */ -+#define ATMEL_US_RXEN (1 << 4) /* Receiver Enable */ -+#define ATMEL_US_RXDIS (1 << 5) /* Receiver Disable */ -+#define ATMEL_US_TXEN (1 << 6) /* Transmitter Enable */ -+#define ATMEL_US_TXDIS (1 << 7) /* Transmitter Disable */ -+#define ATMEL_US_RSTSTA (1 << 8) /* Reset Status Bits */ -+#define ATMEL_US_STTBRK (1 << 9) /* Start Break */ -+#define ATMEL_US_STPBRK (1 << 10) /* Stop Break */ -+#define ATMEL_US_STTTO (1 << 11) /* Start Time-out */ -+#define ATMEL_US_SENDA (1 << 12) /* Send Address */ -+#define ATMEL_US_RSTIT (1 << 13) /* Reset Iterations */ -+#define ATMEL_US_RSTNACK (1 << 14) /* Reset Non Acknowledge */ -+#define ATMEL_US_RETTO (1 << 15) /* Rearm Time-out */ -+#define ATMEL_US_DTREN (1 << 16) /* Data Terminal Ready Enable [AT91RM9200 only] */ -+#define ATMEL_US_DTRDIS (1 << 17) /* Data Terminal Ready Disable [AT91RM9200 only] */ -+#define ATMEL_US_RTSEN (1 << 18) /* Request To Send Enable */ -+#define ATMEL_US_RTSDIS (1 << 19) /* Request To Send Disable */ -+ -+#define ATMEL_US_MR 0x04 /* Mode Register */ -+#define ATMEL_US_USMODE (0xf << 0) /* Mode of the USART */ -+#define ATMEL_US_USMODE_NORMAL 0 -+#define ATMEL_US_USMODE_RS485 1 -+#define ATMEL_US_USMODE_HWHS 2 -+#define ATMEL_US_USMODE_MODEM 3 -+#define ATMEL_US_USMODE_ISO7816_T0 4 -+#define ATMEL_US_USMODE_ISO7816_T1 6 -+#define ATMEL_US_USMODE_IRDA 8 -+#define ATMEL_US_USCLKS (3 << 4) /* Clock Selection */ -+#define ATMEL_US_USCLKS_MCK (0 << 4) -+#define ATMEL_US_USCLKS_MCK_DIV8 (1 << 4) -+#define ATMEL_US_USCLKS_SCK (3 << 4) -+#define ATMEL_US_CHRL (3 << 6) /* Character Length */ -+#define ATMEL_US_CHRL_5 (0 << 6) -+#define ATMEL_US_CHRL_6 (1 << 6) -+#define ATMEL_US_CHRL_7 (2 << 6) -+#define ATMEL_US_CHRL_8 (3 << 6) -+#define ATMEL_US_SYNC (1 << 8) /* Synchronous Mode Select */ -+#define ATMEL_US_PAR (7 << 9) /* Parity Type */ -+#define ATMEL_US_PAR_EVEN (0 << 9) -+#define ATMEL_US_PAR_ODD (1 << 9) -+#define ATMEL_US_PAR_SPACE (2 << 9) -+#define ATMEL_US_PAR_MARK (3 << 9) -+#define ATMEL_US_PAR_NONE (4 << 9) -+#define ATMEL_US_PAR_MULTI_DROP (6 << 9) -+#define ATMEL_US_NBSTOP (3 << 12) /* Number of Stop Bits */ -+#define ATMEL_US_NBSTOP_1 (0 << 12) -+#define ATMEL_US_NBSTOP_1_5 (1 << 12) -+#define ATMEL_US_NBSTOP_2 (2 << 12) -+#define ATMEL_US_CHMODE (3 << 14) /* Channel Mode */ -+#define ATMEL_US_CHMODE_NORMAL (0 << 14) -+#define ATMEL_US_CHMODE_ECHO (1 << 14) -+#define ATMEL_US_CHMODE_LOC_LOOP (2 << 14) -+#define ATMEL_US_CHMODE_REM_LOOP (3 << 14) -+#define ATMEL_US_MSBF (1 << 16) /* Bit Order */ -+#define ATMEL_US_MODE9 (1 << 17) /* 9-bit Character Length */ -+#define ATMEL_US_CLKO (1 << 18) /* Clock Output Select */ -+#define ATMEL_US_OVER (1 << 19) /* Oversampling Mode */ -+#define ATMEL_US_INACK (1 << 20) /* Inhibit Non Acknowledge */ -+#define ATMEL_US_DSNACK (1 << 21) /* Disable Successive NACK */ -+#define ATMEL_US_MAX_ITER (7 << 24) /* Max Iterations */ -+#define ATMEL_US_FILTER (1 << 28) /* Infrared Receive Line Filter */ -+ -+#define ATMEL_US_IER 0x08 /* Interrupt Enable Register */ -+#define ATMEL_US_RXRDY (1 << 0) /* Receiver Ready */ -+#define ATMEL_US_TXRDY (1 << 1) /* Transmitter Ready */ -+#define ATMEL_US_RXBRK (1 << 2) /* Break Received / End of Break */ -+#define ATMEL_US_ENDRX (1 << 3) /* End of Receiver Transfer */ -+#define ATMEL_US_ENDTX (1 << 4) /* End of Transmitter Transfer */ -+#define ATMEL_US_OVRE (1 << 5) /* Overrun Error */ -+#define ATMEL_US_FRAME (1 << 6) /* Framing Error */ -+#define ATMEL_US_PARE (1 << 7) /* Parity Error */ -+#define ATMEL_US_TIMEOUT (1 << 8) /* Receiver Time-out */ -+#define ATMEL_US_TXEMPTY (1 << 9) /* Transmitter Empty */ -+#define ATMEL_US_ITERATION (1 << 10) /* Max number of Repetitions Reached */ -+#define ATMEL_US_TXBUFE (1 << 11) /* Transmission Buffer Empty */ -+#define ATMEL_US_RXBUFF (1 << 12) /* Reception Buffer Full */ -+#define ATMEL_US_NACK (1 << 13) /* Non Acknowledge */ -+#define ATMEL_US_RIIC (1 << 16) /* Ring Indicator Input Change [AT91RM9200 only] */ -+#define ATMEL_US_DSRIC (1 << 17) /* Data Set Ready Input Change [AT91RM9200 only] */ -+#define ATMEL_US_DCDIC (1 << 18) /* Data Carrier Detect Input Change [AT91RM9200 only] */ -+#define ATMEL_US_CTSIC (1 << 19) /* Clear to Send Input Change */ -+#define ATMEL_US_RI (1 << 20) /* RI */ -+#define ATMEL_US_DSR (1 << 21) /* DSR */ -+#define ATMEL_US_DCD (1 << 22) /* DCD */ -+#define ATMEL_US_CTS (1 << 23) /* CTS */ -+ -+#define ATMEL_US_IDR 0x0c /* Interrupt Disable Register */ -+#define ATMEL_US_IMR 0x10 /* Interrupt Mask Register */ -+#define ATMEL_US_CSR 0x14 /* Channel Status Register */ -+#define ATMEL_US_RHR 0x18 /* Receiver Holding Register */ -+#define ATMEL_US_THR 0x1c /* Transmitter Holding Register */ -+#define ATMEL_US_SYNH (1 << 15) /* Transmit/Receive Sync [AT91SAM9261 only] */ -+ -+#define ATMEL_US_BRGR 0x20 /* Baud Rate Generator Register */ -+#define ATMEL_US_CD (0xffff << 0) /* Clock Divider */ -+ -+#define ATMEL_US_RTOR 0x24 /* Receiver Time-out Register */ -+#define ATMEL_US_TO (0xffff << 0) /* Time-out Value */ -+ -+#define ATMEL_US_TTGR 0x28 /* Transmitter Timeguard Register */ -+#define ATMEL_US_TG (0xff << 0) /* Timeguard Value */ -+ -+#define ATMEL_US_FIDI 0x40 /* FI DI Ratio Register */ -+#define ATMEL_US_NER 0x44 /* Number of Errors Register */ -+#define ATMEL_US_IF 0x4c /* IrDA Filter Register */ ++#include <asm-generic/xor.h> + +#endif ---- /dev/null -+++ b/include/linux/atmel_tc.h +diff --exclude=.git -urN linux-2.6.25.6/include/linux/atmel_tc.h avr32-2.6/include/linux/atmel_tc.h +--- linux-2.6.25.6/include/linux/atmel_tc.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/include/linux/atmel_tc.h 2008-06-12 15:04:07.586819080 +0200 @@ -0,0 +1,252 @@ +/* + * Timer/Counter Unit (TC) registers. @@ -19566,8 +48305,21 @@ +#define ATMEL_TC_ETRGS (1 << 7) /* external trigger */ + +#endif ---- /dev/null -+++ b/include/linux/usb/atmel_usba_udc.h +diff --exclude=.git -urN linux-2.6.25.6/include/linux/fs.h avr32-2.6/include/linux/fs.h +--- linux-2.6.25.6/include/linux/fs.h 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/include/linux/fs.h 2008-06-12 15:09:46.255815187 +0200 +@@ -1691,6 +1691,8 @@ + extern int invalidate_inode_pages2(struct address_space *mapping); + extern int invalidate_inode_pages2_range(struct address_space *mapping, + pgoff_t start, pgoff_t end); ++extern void generic_sync_sb_inodes(struct super_block *sb, ++ struct writeback_control *wbc); + extern int write_inode_now(struct inode *, int); + extern int filemap_fdatawrite(struct address_space *); + extern int filemap_flush(struct address_space *); +diff --exclude=.git -urN linux-2.6.25.6/include/linux/usb/atmel_usba_udc.h avr32-2.6/include/linux/usb/atmel_usba_udc.h +--- linux-2.6.25.6/include/linux/usb/atmel_usba_udc.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/include/linux/usb/atmel_usba_udc.h 2008-06-12 15:04:07.986816119 +0200 @@ -0,0 +1,22 @@ +/* + * Platform data definitions for Atmel USBA gadget driver. @@ -19591,64 +48343,395 @@ +}; + +#endif /* __LINUX_USB_USBA_H */ ---- a/include/video/atmel_lcdc.h -+++ b/include/video/atmel_lcdc.h -@@ -22,7 +22,7 @@ - #ifndef __ATMEL_LCDC_H__ - #define __ATMEL_LCDC_H__ - -- /* LCD Controller info data structure */ -+ /* LCD Controller info data structure, stored in device platform_data */ - struct atmel_lcdfb_info { - spinlock_t lock; - struct fb_info *info; -@@ -33,7 +33,14 @@ - struct platform_device *pdev; - struct clk *bus_clk; - struct clk *lcdc_clk; -- unsigned int default_bpp; -+ -+#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC -+ struct backlight_device *backlight; -+ u8 bl_power; -+#endif -+ bool lcdcon_is_backlight; -+ -+ u8 default_bpp; - unsigned int default_lcdcon2; - unsigned int default_dmacon; - void (*atmel_lcdfb_power_control)(int on); -@@ -115,20 +122,20 @@ - #define ATMEL_LCDC_MEMOR_LITTLE (1 << 31) - - #define ATMEL_LCDC_TIM1 0x0808 --#define ATMEL_LCDC_VFP (0xff << 0) -+#define ATMEL_LCDC_VFP (0xffU << 0) - #define ATMEL_LCDC_VBP_OFFSET 8 --#define ATMEL_LCDC_VBP (0xff << ATMEL_LCDC_VBP_OFFSET) -+#define ATMEL_LCDC_VBP (0xffU << ATMEL_LCDC_VBP_OFFSET) - #define ATMEL_LCDC_VPW_OFFSET 16 --#define ATMEL_LCDC_VPW (0x3f << ATMEL_LCDC_VPW_OFFSET) -+#define ATMEL_LCDC_VPW (0x3fU << ATMEL_LCDC_VPW_OFFSET) - #define ATMEL_LCDC_VHDLY_OFFSET 24 --#define ATMEL_LCDC_VHDLY (0xf << ATMEL_LCDC_VHDLY_OFFSET) -+#define ATMEL_LCDC_VHDLY (0xfU << ATMEL_LCDC_VHDLY_OFFSET) - - #define ATMEL_LCDC_TIM2 0x080c --#define ATMEL_LCDC_HBP (0xff << 0) -+#define ATMEL_LCDC_HBP (0xffU << 0) - #define ATMEL_LCDC_HPW_OFFSET 8 --#define ATMEL_LCDC_HPW (0x3f << ATMEL_LCDC_HPW_OFFSET) -+#define ATMEL_LCDC_HPW (0x3fU << ATMEL_LCDC_HPW_OFFSET) - #define ATMEL_LCDC_HFP_OFFSET 21 --#define ATMEL_LCDC_HFP (0x7ff << ATMEL_LCDC_HFP_OFFSET) -+#define ATMEL_LCDC_HFP (0x7ffU << ATMEL_LCDC_HFP_OFFSET) - - #define ATMEL_LCDC_LCDFRMCFG 0x0810 - #define ATMEL_LCDC_LINEVAL (0x7ff << 0) ---- a/init/do_mounts.c -+++ b/init/do_mounts.c -@@ -219,8 +219,14 @@ +diff --exclude=.git -urN linux-2.6.25.6/include/mtd/Kbuild avr32-2.6/include/mtd/Kbuild +--- linux-2.6.25.6/include/mtd/Kbuild 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/include/mtd/Kbuild 2008-06-12 15:04:08.018816005 +0200 +@@ -3,5 +3,4 @@ + header-y += mtd-abi.h + header-y += mtd-user.h + header-y += nftl-user.h +-header-y += ubi-header.h + header-y += ubi-user.h +diff --exclude=.git -urN linux-2.6.25.6/include/mtd/ubi-header.h avr32-2.6/include/mtd/ubi-header.h +--- linux-2.6.25.6/include/mtd/ubi-header.h 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/include/mtd/ubi-header.h 1970-01-01 01:00:00.000000000 +0100 +@@ -1,372 +0,0 @@ +-/* +- * Copyright (c) International Business Machines Corp., 2006 +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- * +- * Authors: Artem Bityutskiy (Битюцкий Артём) +- * Thomas Gleixner +- * Frank Haverkamp +- * Oliver Lohmann +- * Andreas Arnez +- */ +- +-/* +- * This file defines the layout of UBI headers and all the other UBI on-flash +- * data structures. May be included by user-space. +- */ +- +-#ifndef __UBI_HEADER_H__ +-#define __UBI_HEADER_H__ +- +-#include <asm/byteorder.h> +- +-/* The version of UBI images supported by this implementation */ +-#define UBI_VERSION 1 +- +-/* The highest erase counter value supported by this implementation */ +-#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF +- +-/* The initial CRC32 value used when calculating CRC checksums */ +-#define UBI_CRC32_INIT 0xFFFFFFFFU +- +-/* Erase counter header magic number (ASCII "UBI#") */ +-#define UBI_EC_HDR_MAGIC 0x55424923 +-/* Volume identifier header magic number (ASCII "UBI!") */ +-#define UBI_VID_HDR_MAGIC 0x55424921 +- +-/* +- * Volume type constants used in the volume identifier header. +- * +- * @UBI_VID_DYNAMIC: dynamic volume +- * @UBI_VID_STATIC: static volume +- */ +-enum { +- UBI_VID_DYNAMIC = 1, +- UBI_VID_STATIC = 2 +-}; +- +-/* +- * Volume flags used in the volume table record. +- * +- * @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume +- * +- * %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume +- * table. UBI automatically re-sizes the volume which has this flag and makes +- * the volume to be of largest possible size. This means that if after the +- * initialization UBI finds out that there are available physical eraseblocks +- * present on the device, it automatically appends all of them to the volume +- * (the physical eraseblocks reserved for bad eraseblocks handling and other +- * reserved physical eraseblocks are not taken). So, if there is a volume with +- * the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical +- * eraseblocks will be zero after UBI is loaded, because all of them will be +- * reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared +- * after the volume had been initialized. +- * +- * The auto-resize feature is useful for device production purposes. For +- * example, different NAND flash chips may have different amount of initial bad +- * eraseblocks, depending of particular chip instance. Manufacturers of NAND +- * chips usually guarantee that the amount of initial bad eraseblocks does not +- * exceed certain percent, e.g. 2%. When one creates an UBI image which will be +- * flashed to the end devices in production, he does not know the exact amount +- * of good physical eraseblocks the NAND chip on the device will have, but this +- * number is required to calculate the volume sized and put them to the volume +- * table of the UBI image. In this case, one of the volumes (e.g., the one +- * which will store the root file system) is marked as "auto-resizable", and +- * UBI will adjust its size on the first boot if needed. +- * +- * Note, first UBI reserves some amount of physical eraseblocks for bad +- * eraseblock handling, and then re-sizes the volume, not vice-versa. This +- * means that the pool of reserved physical eraseblocks will always be present. +- */ +-enum { +- UBI_VTBL_AUTORESIZE_FLG = 0x01, +-}; +- +-/* +- * Compatibility constants used by internal volumes. +- * +- * @UBI_COMPAT_DELETE: delete this internal volume before anything is written +- * to the flash +- * @UBI_COMPAT_RO: attach this device in read-only mode +- * @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its +- * physical eraseblocks, don't allow the wear-leveling unit to move them +- * @UBI_COMPAT_REJECT: reject this UBI image +- */ +-enum { +- UBI_COMPAT_DELETE = 1, +- UBI_COMPAT_RO = 2, +- UBI_COMPAT_PRESERVE = 4, +- UBI_COMPAT_REJECT = 5 +-}; +- +-/* Sizes of UBI headers */ +-#define UBI_EC_HDR_SIZE sizeof(struct ubi_ec_hdr) +-#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr) +- +-/* Sizes of UBI headers without the ending CRC */ +-#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(__be32)) +-#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(__be32)) +- +-/** +- * struct ubi_ec_hdr - UBI erase counter header. +- * @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC) +- * @version: version of UBI implementation which is supposed to accept this +- * UBI image +- * @padding1: reserved for future, zeroes +- * @ec: the erase counter +- * @vid_hdr_offset: where the VID header starts +- * @data_offset: where the user data start +- * @padding2: reserved for future, zeroes +- * @hdr_crc: erase counter header CRC checksum +- * +- * The erase counter header takes 64 bytes and has a plenty of unused space for +- * future usage. The unused fields are zeroed. The @version field is used to +- * indicate the version of UBI implementation which is supposed to be able to +- * work with this UBI image. If @version is greater then the current UBI +- * version, the image is rejected. This may be useful in future if something +- * is changed radically. This field is duplicated in the volume identifier +- * header. +- * +- * The @vid_hdr_offset and @data_offset fields contain the offset of the the +- * volume identifier header and user data, relative to the beginning of the +- * physical eraseblock. These values have to be the same for all physical +- * eraseblocks. +- */ +-struct ubi_ec_hdr { +- __be32 magic; +- __u8 version; +- __u8 padding1[3]; +- __be64 ec; /* Warning: the current limit is 31-bit anyway! */ +- __be32 vid_hdr_offset; +- __be32 data_offset; +- __u8 padding2[36]; +- __be32 hdr_crc; +-} __attribute__ ((packed)); +- +-/** +- * struct ubi_vid_hdr - on-flash UBI volume identifier header. +- * @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC) +- * @version: UBI implementation version which is supposed to accept this UBI +- * image (%UBI_VERSION) +- * @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC) +- * @copy_flag: if this logical eraseblock was copied from another physical +- * eraseblock (for wear-leveling reasons) +- * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE, +- * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT) +- * @vol_id: ID of this volume +- * @lnum: logical eraseblock number +- * @leb_ver: version of this logical eraseblock (IMPORTANT: obsolete, to be +- * removed, kept only for not breaking older UBI users) +- * @data_size: how many bytes of data this logical eraseblock contains +- * @used_ebs: total number of used logical eraseblocks in this volume +- * @data_pad: how many bytes at the end of this physical eraseblock are not +- * used +- * @data_crc: CRC checksum of the data stored in this logical eraseblock +- * @padding1: reserved for future, zeroes +- * @sqnum: sequence number +- * @padding2: reserved for future, zeroes +- * @hdr_crc: volume identifier header CRC checksum +- * +- * The @sqnum is the value of the global sequence counter at the time when this +- * VID header was created. The global sequence counter is incremented each time +- * UBI writes a new VID header to the flash, i.e. when it maps a logical +- * eraseblock to a new physical eraseblock. The global sequence counter is an +- * unsigned 64-bit integer and we assume it never overflows. The @sqnum +- * (sequence number) is used to distinguish between older and newer versions of +- * logical eraseblocks. +- * +- * There are 2 situations when there may be more then one physical eraseblock +- * corresponding to the same logical eraseblock, i.e., having the same @vol_id +- * and @lnum values in the volume identifier header. Suppose we have a logical +- * eraseblock L and it is mapped to the physical eraseblock P. +- * +- * 1. Because UBI may erase physical eraseblocks asynchronously, the following +- * situation is possible: L is asynchronously erased, so P is scheduled for +- * erasure, then L is written to,i.e. mapped to another physical eraseblock P1, +- * so P1 is written to, then an unclean reboot happens. Result - there are 2 +- * physical eraseblocks P and P1 corresponding to the same logical eraseblock +- * L. But P1 has greater sequence number, so UBI picks P1 when it attaches the +- * flash. +- * +- * 2. From time to time UBI moves logical eraseblocks to other physical +- * eraseblocks for wear-leveling reasons. If, for example, UBI moves L from P +- * to P1, and an unclean reboot happens before P is physically erased, there +- * are two physical eraseblocks P and P1 corresponding to L and UBI has to +- * select one of them when the flash is attached. The @sqnum field says which +- * PEB is the original (obviously P will have lower @sqnum) and the copy. But +- * it is not enough to select the physical eraseblock with the higher sequence +- * number, because the unclean reboot could have happen in the middle of the +- * copying process, so the data in P is corrupted. It is also not enough to +- * just select the physical eraseblock with lower sequence number, because the +- * data there may be old (consider a case if more data was added to P1 after +- * the copying). Moreover, the unclean reboot may happen when the erasure of P +- * was just started, so it result in unstable P, which is "mostly" OK, but +- * still has unstable bits. +- * +- * UBI uses the @copy_flag field to indicate that this logical eraseblock is a +- * copy. UBI also calculates data CRC when the data is moved and stores it at +- * the @data_crc field of the copy (P1). So when UBI needs to pick one physical +- * eraseblock of two (P or P1), the @copy_flag of the newer one (P1) is +- * examined. If it is cleared, the situation* is simple and the newer one is +- * picked. If it is set, the data CRC of the copy (P1) is examined. If the CRC +- * checksum is correct, this physical eraseblock is selected (P1). Otherwise +- * the older one (P) is selected. +- * +- * Note, there is an obsolete @leb_ver field which was used instead of @sqnum +- * in the past. But it is not used anymore and we keep it in order to be able +- * to deal with old UBI images. It will be removed at some point. +- * +- * There are 2 sorts of volumes in UBI: user volumes and internal volumes. +- * Internal volumes are not seen from outside and are used for various internal +- * UBI purposes. In this implementation there is only one internal volume - the +- * layout volume. Internal volumes are the main mechanism of UBI extensions. +- * For example, in future one may introduce a journal internal volume. Internal +- * volumes have their own reserved range of IDs. +- * +- * The @compat field is only used for internal volumes and contains the "degree +- * of their compatibility". It is always zero for user volumes. This field +- * provides a mechanism to introduce UBI extensions and to be still compatible +- * with older UBI binaries. For example, if someone introduced a journal in +- * future, he would probably use %UBI_COMPAT_DELETE compatibility for the +- * journal volume. And in this case, older UBI binaries, which know nothing +- * about the journal volume, would just delete this volume and work perfectly +- * fine. This is similar to what Ext2fs does when it is fed by an Ext3fs image +- * - it just ignores the Ext3fs journal. +- * +- * The @data_crc field contains the CRC checksum of the contents of the logical +- * eraseblock if this is a static volume. In case of dynamic volumes, it does +- * not contain the CRC checksum as a rule. The only exception is when the +- * data of the physical eraseblock was moved by the wear-leveling unit, then +- * the wear-leveling unit calculates the data CRC and stores it in the +- * @data_crc field. And of course, the @copy_flag is %in this case. +- * +- * The @data_size field is used only for static volumes because UBI has to know +- * how many bytes of data are stored in this eraseblock. For dynamic volumes, +- * this field usually contains zero. The only exception is when the data of the +- * physical eraseblock was moved to another physical eraseblock for +- * wear-leveling reasons. In this case, UBI calculates CRC checksum of the +- * contents and uses both @data_crc and @data_size fields. In this case, the +- * @data_size field contains data size. +- * +- * The @used_ebs field is used only for static volumes and indicates how many +- * eraseblocks the data of the volume takes. For dynamic volumes this field is +- * not used and always contains zero. +- * +- * The @data_pad is calculated when volumes are created using the alignment +- * parameter. So, effectively, the @data_pad field reduces the size of logical +- * eraseblocks of this volume. This is very handy when one uses block-oriented +- * software (say, cramfs) on top of the UBI volume. +- */ +-struct ubi_vid_hdr { +- __be32 magic; +- __u8 version; +- __u8 vol_type; +- __u8 copy_flag; +- __u8 compat; +- __be32 vol_id; +- __be32 lnum; +- __be32 leb_ver; /* obsolete, to be removed, don't use */ +- __be32 data_size; +- __be32 used_ebs; +- __be32 data_pad; +- __be32 data_crc; +- __u8 padding1[4]; +- __be64 sqnum; +- __u8 padding2[12]; +- __be32 hdr_crc; +-} __attribute__ ((packed)); +- +-/* Internal UBI volumes count */ +-#define UBI_INT_VOL_COUNT 1 +- +-/* +- * Starting ID of internal volumes. There is reserved room for 4096 internal +- * volumes. +- */ +-#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096) +- +-/* The layout volume contains the volume table */ +- +-#define UBI_LAYOUT_VOLUME_ID UBI_INTERNAL_VOL_START +-#define UBI_LAYOUT_VOLUME_TYPE UBI_VID_DYNAMIC +-#define UBI_LAYOUT_VOLUME_ALIGN 1 +-#define UBI_LAYOUT_VOLUME_EBS 2 +-#define UBI_LAYOUT_VOLUME_NAME "layout volume" +-#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT +- +-/* The maximum number of volumes per one UBI device */ +-#define UBI_MAX_VOLUMES 128 +- +-/* The maximum volume name length */ +-#define UBI_VOL_NAME_MAX 127 +- +-/* Size of the volume table record */ +-#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record) +- +-/* Size of the volume table record without the ending CRC */ +-#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(__be32)) +- +-/** +- * struct ubi_vtbl_record - a record in the volume table. +- * @reserved_pebs: how many physical eraseblocks are reserved for this volume +- * @alignment: volume alignment +- * @data_pad: how many bytes are unused at the end of the each physical +- * eraseblock to satisfy the requested alignment +- * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) +- * @upd_marker: if volume update was started but not finished +- * @name_len: volume name length +- * @name: the volume name +- * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG) +- * @padding: reserved, zeroes +- * @crc: a CRC32 checksum of the record +- * +- * The volume table records are stored in the volume table, which is stored in +- * the layout volume. The layout volume consists of 2 logical eraseblock, each +- * of which contains a copy of the volume table (i.e., the volume table is +- * duplicated). The volume table is an array of &struct ubi_vtbl_record +- * objects indexed by the volume ID. +- * +- * If the size of the logical eraseblock is large enough to fit +- * %UBI_MAX_VOLUMES records, the volume table contains %UBI_MAX_VOLUMES +- * records. Otherwise, it contains as many records as it can fit (i.e., size of +- * logical eraseblock divided by sizeof(struct ubi_vtbl_record)). +- * +- * The @upd_marker flag is used to implement volume update. It is set to %1 +- * before update and set to %0 after the update. So if the update operation was +- * interrupted, UBI knows that the volume is corrupted. +- * +- * The @alignment field is specified when the volume is created and cannot be +- * later changed. It may be useful, for example, when a block-oriented file +- * system works on top of UBI. The @data_pad field is calculated using the +- * logical eraseblock size and @alignment. The alignment must be multiple to the +- * minimal flash I/O unit. If @alignment is 1, all the available space of +- * the physical eraseblocks is used. +- * +- * Empty records contain all zeroes and the CRC checksum of those zeroes. +- */ +-struct ubi_vtbl_record { +- __be32 reserved_pebs; +- __be32 alignment; +- __be32 data_pad; +- __u8 vol_type; +- __u8 upd_marker; +- __be16 name_len; +- __u8 name[UBI_VOL_NAME_MAX+1]; +- __u8 flags; +- __u8 padding[23]; +- __be32 crc; +-} __attribute__ ((packed)); +- +-#endif /* !__UBI_HEADER_H__ */ +diff --exclude=.git -urN linux-2.6.25.6/init/do_mounts.c avr32-2.6/init/do_mounts.c +--- linux-2.6.25.6/init/do_mounts.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/init/do_mounts.c 2008-06-12 15:09:46.451815572 +0200 +@@ -126,8 +126,14 @@ static int __init rootwait_setup(char *str) { @@ -19664,34 +48747,19 @@ root_wait = 1; return 1; } ---- a/kernel/ptrace.c -+++ b/kernel/ptrace.c -@@ -470,6 +470,8 @@ - lock_kernel(); - if (request == PTRACE_TRACEME) { - ret = ptrace_traceme(); -+ if (!ret) -+ arch_ptrace_attach(current); - goto out; - } - ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -671,6 +671,12 @@ - W: http://www.at91.com/ - S: Maintained - -+ATMEL AT91 / AT32 SERIAL DRIVER -+P: Haavard Skinnemoen -+M: hskinnemoen@atmel.com -+L: linux-kernel@vger.kernel.org -+S: Supported -+ - ATMEL LCDFB DRIVER - P: Nicolas Ferre - M: nicolas.ferre@atmel.com ---- /dev/null -+++ b/sound/avr32/ac97c.c +@@ -347,7 +353,8 @@ + + if (saved_root_name[0]) { + root_device_name = saved_root_name; +- if (!strncmp(root_device_name, "mtd", 3)) { ++ if (!strncmp(root_device_name, "mtd", 3) || ++ !strncmp(root_device_name, "ubi", 3)) { + mount_block_root(root_device_name, root_mountflags); + goto out; + } +diff --exclude=.git -urN linux-2.6.25.6/sound/avr32/ac97c.c avr32-2.6/sound/avr32/ac97c.c +--- linux-2.6.25.6/sound/avr32/ac97c.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/sound/avr32/ac97c.c 2008-06-12 15:09:47.011815952 +0200 @@ -0,0 +1,914 @@ +/* + * Driver for the Atmel AC97 controller @@ -20360,7 +49428,7 @@ + ac97c_writel(chip, COTHR, word); + goto read_reg; + } -+ mdelay(10); ++ udelay(10); + } while (--timeout); + + if (!--write) @@ -20373,7 +49441,7 @@ + unsigned short val = ac97c_readl(chip, CORHR); + return val; + } -+ mdelay(10); ++ udelay(10); + } while (--timeout); + + if (!--write) @@ -20607,8 +49675,9 @@ +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Driver for Atmel AC97 Controller"); +MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>"); ---- /dev/null -+++ b/sound/avr32/ac97c.h +diff --exclude=.git -urN linux-2.6.25.6/sound/avr32/ac97c.h avr32-2.6/sound/avr32/ac97c.h +--- linux-2.6.25.6/sound/avr32/ac97c.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/sound/avr32/ac97c.h 2008-06-12 15:09:47.011815952 +0200 @@ -0,0 +1,71 @@ +/* + * Register definitions for the Atmel AC97 Controller. @@ -20681,8 +49750,9 @@ +#define AC97C_CHANNEL_B 0x2 + +#endif /* __SOUND_AVR32_AC97C_H */ ---- /dev/null -+++ b/sound/avr32/Kconfig +diff --exclude=.git -urN linux-2.6.25.6/sound/avr32/Kconfig avr32-2.6/sound/avr32/Kconfig +--- linux-2.6.25.6/sound/avr32/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/sound/avr32/Kconfig 2008-06-12 15:09:47.011815952 +0200 @@ -0,0 +1,11 @@ +menu "AVR32 devices" + depends on SND != n && AVR32 @@ -20695,14 +49765,16 @@ + ALSA sound driver for the Atmel AC97 controller. + +endmenu ---- /dev/null -+++ b/sound/avr32/Makefile +diff --exclude=.git -urN linux-2.6.25.6/sound/avr32/Makefile avr32-2.6/sound/avr32/Makefile +--- linux-2.6.25.6/sound/avr32/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/sound/avr32/Makefile 2008-06-12 15:09:47.011815952 +0200 @@ -0,0 +1,3 @@ +snd-atmel-ac97-objs := ac97c.o + +obj-$(CONFIG_SND_ATMEL_AC97) += snd-atmel-ac97.o ---- a/sound/Kconfig -+++ b/sound/Kconfig +diff --exclude=.git -urN linux-2.6.25.6/sound/Kconfig avr32-2.6/sound/Kconfig +--- linux-2.6.25.6/sound/Kconfig 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/sound/Kconfig 2008-06-12 15:09:47.011815952 +0200 @@ -63,6 +63,8 @@ source "sound/arm/Kconfig" @@ -20712,8 +49784,9 @@ if SPI source "sound/spi/Kconfig" endif ---- a/sound/Makefile -+++ b/sound/Makefile +diff --exclude=.git -urN linux-2.6.25.6/sound/Makefile avr32-2.6/sound/Makefile +--- linux-2.6.25.6/sound/Makefile 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/sound/Makefile 2008-06-12 15:09:47.011815952 +0200 @@ -6,7 +6,7 @@ obj-$(CONFIG_SOUND_PRIME) += oss/ obj-$(CONFIG_DMASOUND) += oss/ @@ -20723,8 +49796,9 @@ obj-$(CONFIG_SND_AOA) += aoa/ # This one must be compilable even if sound is configured out ---- /dev/null -+++ b/sound/oss/at32_abdac.c +diff --exclude=.git -urN linux-2.6.25.6/sound/oss/at32_abdac.c avr32-2.6/sound/oss/at32_abdac.c +--- linux-2.6.25.6/sound/oss/at32_abdac.c 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/sound/oss/at32_abdac.c 2008-06-12 15:09:47.027815755 +0200 @@ -0,0 +1,722 @@ +/* + * OSS Sound Driver for the Atmel AT32 on-chip DAC. @@ -21448,8 +50522,9 @@ +MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>"); +MODULE_DESCRIPTION("Sound Driver for the Atmel AT32 ABDAC"); +MODULE_LICENSE("GPL"); ---- /dev/null -+++ b/sound/oss/at32_abdac.h +diff --exclude=.git -urN linux-2.6.25.6/sound/oss/at32_abdac.h avr32-2.6/sound/oss/at32_abdac.h +--- linux-2.6.25.6/sound/oss/at32_abdac.h 1970-01-01 01:00:00.000000000 +0100 ++++ avr32-2.6/sound/oss/at32_abdac.h 2008-06-12 15:09:47.027815755 +0200 @@ -0,0 +1,59 @@ +/* + * Register definitions for the Atmel AT32 on-chip DAC. @@ -21510,8 +50585,9 @@ + __raw_writel((value), (port)->regs + DAC_##reg) + +#endif /* __SOUND_OSS_AT32_ABDAC_H__ */ ---- a/sound/oss/Kconfig -+++ b/sound/oss/Kconfig +diff --exclude=.git -urN linux-2.6.25.6/sound/oss/Kconfig avr32-2.6/sound/oss/Kconfig +--- linux-2.6.25.6/sound/oss/Kconfig 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/sound/oss/Kconfig 2008-06-12 15:09:47.023815804 +0200 @@ -654,3 +654,7 @@ int "DAC channel" default "1" @@ -21520,9 +50596,10 @@ +config SOUND_AT32_ABDAC + tristate "Atmel AT32 Audio Bitstream DAC (ABDAC) support" + depends on SOUND_PRIME && AVR32 ---- a/sound/oss/Makefile -+++ b/sound/oss/Makefile -@@ -10,6 +10,7 @@ +diff --exclude=.git -urN linux-2.6.25.6/sound/oss/Makefile avr32-2.6/sound/oss/Makefile +--- linux-2.6.25.6/sound/oss/Makefile 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/sound/oss/Makefile 2008-06-12 15:09:47.023815804 +0200 +@@ -9,6 +9,7 @@ # Please leave it as is, cause the link order is significant ! @@ -21530,9 +50607,10 @@ obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o obj-$(CONFIG_SOUND_HAL2) += hal2.o obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o ---- a/sound/spi/at73c213.c -+++ b/sound/spi/at73c213.c -@@ -744,7 +744,7 @@ +diff --exclude=.git -urN linux-2.6.25.6/sound/spi/at73c213.c avr32-2.6/sound/spi/at73c213.c +--- linux-2.6.25.6/sound/spi/at73c213.c 2008-06-09 20:27:19.000000000 +0200 ++++ avr32-2.6/sound/spi/at73c213.c 2008-06-12 15:09:47.247815006 +0200 +@@ -737,7 +737,7 @@ /* * Device functions */ @@ -21541,7 +50619,7 @@ { /* * Continuous clock output. -@@ -774,7 +774,7 @@ +@@ -767,7 +767,7 @@ return 0; } @@ -21550,7 +50628,7 @@ { int retval; unsigned char dac_ctrl = 0; -@@ -939,7 +939,7 @@ +@@ -933,7 +933,7 @@ return retval; } diff --git a/target/linux/avr32/patches/120-cpufreq_panic.patch b/target/linux/avr32/patches/120-cpufreq_panic.patch deleted file mode 100644 index fe9576ce64..0000000000 --- a/target/linux/avr32/patches/120-cpufreq_panic.patch +++ /dev/null @@ -1,25 +0,0 @@ -From: Haavard Skinnemoen <haavard.skinnemoen@atmel.com> -Date: Tue, 27 May 2008 07:37:42 +0000 (+0200) -Subject: avr32: Fix cpufreq oops when ondemand governor is default -X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fhskinnemoen%2Favr32-2.6.git;a=commitdiff_plain;h=f04d264afc51acdffeba9cdf3baf04116687680c - -avr32: Fix cpufreq oops when ondemand governor is default - -Move the AP7 cpufreq init to late_initcall() so that we don't try to -bring up cpufreq until the governor is ready. x86 also uses -late_initcall() for this. - -Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen@atmel.com> ---- - -diff --git a/arch/avr32/mach-at32ap/cpufreq.c b/arch/avr32/mach-at32ap/cpufreq.c -index 235524b..5dd8d25 100644 ---- a/arch/avr32/mach-at32ap/cpufreq.c -+++ b/arch/avr32/mach-at32ap/cpufreq.c -@@ -108,5 +108,4 @@ static int __init at32_cpufreq_init(void) - { - return cpufreq_register_driver(&at32_driver); - } -- --arch_initcall(at32_cpufreq_init); -+late_initcall(at32_cpufreq_init); |