diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..5c0b4baf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,85 @@
+#
+# NOTE! Don't add files that are generated in specific
+# subdirectories here. Add them in the ".gitignore" file
+# in that subdirectory instead.
+#
+# NOTE! Please use 'git ls-files -i --exclude-standard'
+# command after changing this file, to see if there are
+# any tracked files which get ignored after the change.
+#
+# Normal rules
+#
+.*
+*.o
+*.o.*
+*.a
+*.s
+*.ko
+*.so
+*.so.dbg
+*.mod.c
+*.i
+*.lst
+*.symtypes
+*.order
+modules.builtin
+*.elf
+*.bin
+*.gz
+*.bz2
+*.lzma
+*.lzo
+*.patch
+*.gcno
+
+#
+# Top-level generic files
+#
+tags
+TAGS
+linux
+vmlinux
+vmlinuz
+System.map
+Module.markers
+Module.symvers
+
+#
+# git files that we don't want to ignore even it they are dot-files
+#
+!.gitignore
+!.mailmap
+
+#
+# Generated include files
+#
+include/asm
+include/asm-*/asm-offsets.h
+include/config
+include/linux/autoconf.h
+include/linux/compile.h
+include/linux/version.h
+include/linux/generated
+include/linux/bounds.h
+include/linux/utsrelease.h
+
+# stgit generated dirs
+patches-*
+
+# quilt's files
+patches
+series
+
+# cscope files
+cscope.*
+ncscope.*
+
+# gnu global files
+GPATH
+GRTAGS
+GSYMS
+GTAGS
+
+*.orig
+*~
+\#*#
diff --git a/arch/arm/configs/incredikernel_defconfig b/arch/arm/configs/incredikernel_defconfig
new file mode 100644
index 00000000..3c75915d
--- /dev/null
+++ b/arch/arm/configs/incredikernel_defconfig
@@ -0,0 +1,1953 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.32.27
+# Tue Dec 28 17:45:30 2010
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_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_ARCH_HAS_CPUFREQ=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION="-incredikernel-12232010"
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP 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_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+# CONFIG_TREE_RCU is not set
+# CONFIG_TREE_PREEMPT_RCU is not set
+CONFIG_TINY_RCU=y
+# CONFIG_TREE_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+# CONFIG_USER_SCHED is not set
+CONFIG_CGROUP_SCHED=y
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+# CONFIG_CGROUP_NS is not set
+CONFIG_CGROUP_FREEZER=y
+# CONFIG_CGROUP_DEVICE is not set
+# CONFIG_CPUSETS is not set
+# CONFIG_CGROUP_CPUACCT is not set
+CONFIG_RESOURCE_COUNTERS=y
+# CONFIG_CGROUP_MEM_RES_CTLR is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_ASHMEM=y
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+
+#
+# GCOV-based kernel profiling
+#
+CONFIG_SLOW_WORK=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_IOSCHED_BFQ=y
+# CONFIG_CGROUP_BFQIO is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_BFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="bfq"
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+CONFIG_ARCH_MSM=y
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_MSM7X00A is not set
+# CONFIG_ARCH_MSM7225 is not set
+# CONFIG_ARCH_MSM7227 is not set
+# CONFIG_ARCH_MSM7X30 is not set
+CONFIG_ARCH_QSD8X50=y
+CONFIG_ARCH_MSM_SCORPION=y
+CONFIG_MSM_MDP31=y
+# CONFIG_PERFLOCK is not set
+CONFIG_MSM_AMSS_VERSION=3200
+# CONFIG_MSM_AMSS_VERSION_6210 is not set
+# CONFIG_MSM_AMSS_VERSION_6220 is not set
+# CONFIG_MSM_AMSS_VERSION_6225 is not set
+# CONFIG_MSM_AMSS_VERSION_6350 is not set
+# CONFIG_MSM_AMSS_VERSION_6355 is not set
+# CONFIG_MSM_AMSS_VERSION_1355 is not set
+# CONFIG_MSM_AMSS_VERSION_4725 is not set
+# CONFIG_MSM_AMSS_VERSION_4735 is not set
+# CONFIG_MSM_AMSS_VERSION_4410 is not set
+CONFIG_MSM_AMSS_VERSION_3200=y
+# CONFIG_MSM_AMSS_VERSION_1170 is not set
+# CONFIG_MSM_AMSS_VERSION_1200 is not set
+CONFIG_MSM_DEBUG_UART=1
+# CONFIG_MSM_DEBUG_UART_NONE is not set
+CONFIG_MSM_DEBUG_UART1=y
+# CONFIG_MSM_DEBUG_UART2 is not set
+# CONFIG_MSM_DEBUG_UART3 is not set
+
+#
+# MSM Board Type
+#
+# CONFIG_MACH_SWORDFISH is not set
+# CONFIG_MACH_ORCA is not set
+# CONFIG_MACH_MAHIMAHI is not set
+# CONFIG_MACH_BRAVO is not set
+# CONFIG_MACH_PASSIONC is not set
+# CONFIG_MACH_BRAVOC is not set
+# CONFIG_MACH_INCREDIBLE is not set
+CONFIG_MACH_INCREDIBLEC=y
+# CONFIG_MACH_SUPERSONIC is not set
+CONFIG_HTC_BATTCHG=y
+CONFIG_HTC_BATTCHG_SMEM=y
+# CONFIG_HTC_PWRSINK is not set
+CONFIG_HTC_SLEEP_MODE_GPIO_DUMP=y
+# CONFIG_HTC_POWER_COLLAPSE_MAGIC is not set
+# CONFIG_SMEM_RPC_SERVER_STATE is not set
+CONFIG_BUILD_OMA_DM=y
+CONFIG_QSD_SVS=y
+CONFIG_QSD_PMIC_DEFAULT_DCDC1=1275
+CONFIG_CACHE_FLUSH_RANGE_LIMIT=0x40000
+CONFIG_MSM7X00A_USE_GP_TIMER=y
+# CONFIG_MSM7X00A_USE_DG_TIMER is not set
+CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND=y
+# CONFIG_MSM7X00A_SLEEP_MODE_POWER_COLLAPSE is not set
+# CONFIG_MSM7X00A_SLEEP_MODE_APPS_SLEEP is not set
+# CONFIG_MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set
+# CONFIG_MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT is not set
+CONFIG_MSM7X00A_SLEEP_MODE=0
+# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND is not set
+# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE is not set
+CONFIG_MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP=y
+# CONFIG_MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT is not set
+# CONFIG_MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT is not set
+CONFIG_MSM7X00A_IDLE_SLEEP_MODE=2
+CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME=20000000
+CONFIG_MSM7X00A_IDLE_SPIN_TIME=80000
+CONFIG_MSM7X00A_SLEEP_NO_LIMIT=y
+# CONFIG_MSM7X00A_SLEEP_LIMITED_SLEEP is not set
+# CONFIG_MSM7X00A_SLEEP_NEGATE_SLEEP is not set
+CONFIG_MSM7X00A_SLEEP_LIMIT=0
+# CONFIG_MSM7X00A_IDLE_SLEEP_NO_LIMIT is not set
+# CONFIG_MSM7X00A_IDLE_SLEEP_LIMITED_SLEEP is not set
+CONFIG_MSM7X00A_IDLE_SLEEP_NEGATE_SLEEP=y
+CONFIG_MSM7X00A_IDLE_SLEEP_LIMIT=2
+CONFIG_MSM_IDLE_STATS=y
+CONFIG_MSM_IDLE_STATS_FIRST_BUCKET=62500
+CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT=2
+CONFIG_MSM_IDLE_STATS_BUCKET_COUNT=10
+CONFIG_MSM_FIQ_SUPPORT=y
+CONFIG_MSM_SERIAL_DEBUGGER=y
+CONFIG_MSM_SERIAL_DEBUGGER_NO_SLEEP=y
+# CONFIG_MSM_SERIAL_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON is not set
+# CONFIG_MSM_SERIAL_DEBUGGER_CONSOLE is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_N_WAY_SMD=y
+CONFIG_MSM_ONCRPCROUTER=y
+CONFIG_MSM_RPCSERVERS=y
+# CONFIG_MSM_RMT_STORAGE_SERVER is not set
+CONFIG_MSM_DALRPC=y
+# CONFIG_MSM_CPU_FREQ_SCREEN is not set
+CONFIG_MSM_CPU_FREQ_ONDEMAND_MAX=1113600
+CONFIG_MSM_CPU_FREQ_ONDEMAND_MIN=245000
+CONFIG_MSM_CPU_AVS=y
+# CONFIG_MSM_HW3D is not set
+# CONFIG_HTC_ACOUSTIC is not set
+CONFIG_HTC_ACOUSTIC_QSD=y
+# CONFIG_MSM_QDSP6 is not set
+CONFIG_WIFI_CONTROL_FUNC=y
+# CONFIG_WIFI_MEM_PREALLOC is not set
+CONFIG_WIFI_NVS_PROC_CREATE=y
+# CONFIG_MMC_SUPPORT_EXTERNEL_DRIVER is not set
+CONFIG_MMC_BUSCLK_PWRSAVE=y
+# CONFIG_VIRTUAL_KPANIC_PARTITION is not set
+CONFIG_QSD_AUDIO=y
+CONFIG_QSD_HTC_FM=y
+CONFIG_ARCH_MSM_FLASHLIGHT=y
+CONFIG_MICROP_COMMON=y
+CONFIG_HTC_HEADSET_MGR=y
+# CONFIG_HTC_HEADSET_H2W is not set
+CONFIG_HTC_HEADSET_GPIO=y
+CONFIG_HTC_HEADSET_MICROP=y
+# CONFIG_HTC_HEADSET_PMIC is not set
+# CONFIG_BUILD_CIQ is not set
+CONFIG_SMD_OFFSET_TCXO_STAT=0xFC2A0
+# CONFIG_AXI_SCREEN_POLICY is not set
+# CONFIG_MSM_NPA is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_VERIFY_PERMISSION_FAULT=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+CONFIG_ARM_THUMBEE=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+CONFIG_HIGHMEM=y
+# CONFIG_HIGHPTE is not set
+CONFIG_VMALLOC_RESERVE=0x30000000
+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_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=64M console=ttyMSM,115200n8"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE 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_CONSERVATIVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_MINMAX is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTASS=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+# CONFIG_CPU_FREQ_GOV_MINMAX is not set
+CONFIG_CPU_FREQ_GOV_SMARTASS=y
+CONFIG_CPU_FREQ_MIN_TICKS=10
+CONFIG_CPU_FREQ_SAMPLING_LATENCY_MULTIPLIER=1000
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_TRACE=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_HAS_WAKELOCK=y
+CONFIG_HAS_EARLYSUSPEND=y
+CONFIG_WAKELOCK=y
+CONFIG_WAKELOCK_STAT=y
+CONFIG_USER_WAKELOCK=y
+CONFIG_EARLYSUSPEND=y
+# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set
+# CONFIG_CONSOLE_EARLYSUSPEND is not set
+CONFIG_FB_EARLYSUSPEND=y
+# CONFIG_APM_EMULATION is not set
+# CONFIG_PM_RUNTIME is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_XFRM_IPCOMP=y
+CONFIG_NET_KEY=y
+# 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_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+CONFIG_INET_ESP=y
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+# 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=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=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+# CONFIG_IPV6_ROUTE_INFO is not set
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_INET6_XFRM_TUNNEL=y
+CONFIG_INET6_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+# CONFIG_IPV6_SUBTREES is not set
+# CONFIG_IPV6_MROUTE is not set
+CONFIG_ANDROID_PARANOID_NETWORK=y
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=y
+CONFIG_NETFILTER_NETLINK_QUEUE=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CT_ACCT=y
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_GRE=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LED=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DCCP=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_ESP=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_HL=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+CONFIG_NETFILTER_XT_MATCH_REALM=y
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
+CONFIG_NETFILTER_XT_MATCH_SCTP=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+# CONFIG_NETFILTER_XT_MATCH_OSF is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_ADDRTYPE=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=y
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_NF_NAT=y
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+# CONFIG_NF_NAT_SNMP_BASIC is not set
+CONFIG_NF_NAT_PROTO_DCCP=y
+CONFIG_NF_NAT_PROTO_GRE=y
+CONFIG_NF_NAT_PROTO_UDPLITE=y
+CONFIG_NF_NAT_PROTO_SCTP=y
+CONFIG_NF_NAT_FTP=y
+CONFIG_NF_NAT_IRC=y
+CONFIG_NF_NAT_TFTP=y
+CONFIG_NF_NAT_AMANDA=y
+CONFIG_NF_NAT_PPTP=y
+CONFIG_NF_NAT_H323=y
+CONFIG_NF_NAT_SIP=y
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_TARGET_TTL is not set
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+
+#
+# IPv6: Netfilter Configuration
+#
+# CONFIG_NF_CONNTRACK_IPV6 is not set
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA 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_PHONET is not set
+# CONFIG_IEEE802154 is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+# CONFIG_NET_SCH_CBQ is not set
+CONFIG_NET_SCH_HTB=y
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_MULTIQ is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_DRR is not set
+CONFIG_NET_SCH_INGRESS=y
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+# CONFIG_NET_CLS_BASIC is not set
+# CONFIG_NET_CLS_TCINDEX is not set
+# CONFIG_NET_CLS_ROUTE4 is not set
+CONFIG_NET_CLS_ROUTE=y
+# CONFIG_NET_CLS_FW is not set
+CONFIG_NET_CLS_U32=y
+# CONFIG_CLS_U32_PERF is not set
+# CONFIG_CLS_U32_MARK is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_CLS_FLOW is not set
+# CONFIG_NET_CLS_CGROUP is not set
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+# CONFIG_NET_EMATCH_CMP is not set
+# CONFIG_NET_EMATCH_NBYTE is not set
+CONFIG_NET_EMATCH_U32=y
+# CONFIG_NET_EMATCH_META is not set
+# CONFIG_NET_EMATCH_TEXT is not set
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+CONFIG_NET_ACT_GACT=y
+# CONFIG_GACT_PROB is not set
+CONFIG_NET_ACT_MIRRED=y
+# CONFIG_NET_ACT_IPT is not set
+# CONFIG_NET_ACT_NAT is not set
+# CONFIG_NET_ACT_PEDIT is not set
+# CONFIG_NET_ACT_SIMP is not set
+# CONFIG_NET_ACT_SKBEDIT is not set
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+# CONFIG_BT_BNEP_MC_FILTER is not set
+# CONFIG_BT_BNEP_PROTO_FILTER is not set
+CONFIG_BT_HIDP=y
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BT_HCIBTSDIO is not set
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+# CONFIG_BT_HCIUART_BCSP is not set
+CONFIG_BT_HCIUART_LL=y
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_BT_MRVL is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_FIB_RULES=y
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+CONFIG_CFG80211_DEFAULT_PS_VALUE=0
+CONFIG_WIRELESS_OLD_REGULATORY=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+# CONFIG_WIMAX is not set
+CONFIG_RFKILL=y
+# CONFIG_RFKILL_PM is not set
+CONFIG_RFKILL_LEDS=y
+# CONFIG_RFKILL_INPUT is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH=""
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS 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
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# 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
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE 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_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_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+CONFIG_MTD_MSM_NAND=y
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
+CONFIG_MISC_DEVICES=y
+CONFIG_ANDROID_PMEM=y
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_KERNEL_DEBUGGER_CORE=y
+# CONFIG_ISL29003 is not set
+CONFIG_UID_STAT=y
+# CONFIG_WL127X_RFKILL is not set
+# CONFIG_APANIC is not set
+CONFIG_SENSORS_BMA150_SPI=y
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# 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
+CONFIG_MD=y
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_DEBUG=y
+CONFIG_DM_CRYPT=y
+# CONFIG_DM_SNAPSHOT is not set
+# CONFIG_DM_MIRROR is not set
+# CONFIG_DM_ZERO is not set
+# CONFIG_DM_MULTIPATH is not set
+# CONFIG_DM_DELAY is not set
+CONFIG_DM_UEVENT=y
+CONFIG_NETDEVICES=y
+# CONFIG_IFB is not set
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMC911X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET 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_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+CONFIG_WLAN=y
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+CONFIG_BCM4329=m
+CONFIG_BCM4329_SOFTAP=y
+CONFIG_BCM4329_FW_PATH="/system/etc/firmware/fw_bcm4329.bin"
+CONFIG_BCM4329_NVRAM_PATH="/proc/calibration"
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_MPPE=y
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+# CONFIG_SLIP is not set
+CONFIG_SLHC=y
+# CONFIG_NETCONSOLE is not set
+CONFIG_MSM_RMNET=y
+# CONFIG_MSM_RMNET_DEBUG is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_KINETO_GAN is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+CONFIG_INPUT_KEYRESET=y
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_CYPRESS_TMG is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELAN_I2C_8232 is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_MSM is not set
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI is not set
+# CONFIG_TOUCHSCREEN_COMPATIBLE_REPORT is not set
+# CONFIG_TOUCHSCREEN_CONCATENATE_REPORT is not set
+# CONFIG_TOUCHSCREEN_SYNAPTICS_T1021 is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+CONFIG_INPUT_KEYCHORD=y
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+CONFIG_LIGHTSENSOR_MICROP=y
+# CONFIG_INPUT_CAPELLA_CM3602 is not set
+# CONFIG_LIGHTSENSOR_SMD is not set
+CONFIG_INPUT_DUMMY_KEYPAD=y
+CONFIG_INPUT_OPTICALJOYSTICK=y
+CONFIG_OPTICALJOYSTICK_CRUCIAL=y
+CONFIG_OPTICALJOYSTICK_CRUCIAL_uP=y
+# CONFIG_OPTICALJOYSTICK_CRUCIAL_SPI 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_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_MSM=y
+# CONFIG_SERIAL_MSM_CONSOLE is not set
+# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set
+CONFIG_SERIAL_MSM_HS=y
+# CONFIG_SERIAL_MSM_HS_PURE_ANDROID is not set
+# CONFIG_SERIAL_BCM_BT_LPM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_DCC_TTY is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+# CONFIG_I2C_CHARDEV is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+CONFIG_I2C_MSM=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_AKM8976 is not set
+CONFIG_SENSORS_AKM8973=y
+# CONFIG_SENSORS_AKM8975 is not set
+CONFIG_SMB329=y
+# CONFIG_TPS65200 is not set
+# CONFIG_SENSORS_BMA150 is not set
+# CONFIG_SENSORS_PCA963X is not set
+# CONFIG_SENSORS_MT9T013 is not set
+CONFIG_VP_A1026=y
+CONFIG_AMP_TPA6130A=y
+CONFIG_AMP_TPA2018D1=y
+# CONFIG_AMP_TPA2051D3 is not set
+# CONFIG_INPUT_ISL29028 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_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+CONFIG_SPI_QSD=y
+# CONFIG_SPI_QSD_NEW is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_DS2784 is not set
+# CONFIG_BATTERY_DS2746 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_DEBUG=y
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_LP3971 is not set
+CONFIG_REGULATOR_TPS65023=y
+# CONFIG_REGULATOR_TPS6507X is not set
+CONFIG_MEDIA_SUPPORT=y
+
+#
+# Multimedia core support
+#
+CONFIG_VIDEO_DEV=m
+CONFIG_VIDEO_V4L2_COMMON=m
+CONFIG_VIDEO_ALLOW_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
+# CONFIG_DVB_CORE is not set
+CONFIG_VIDEO_MEDIA=m
+
+#
+# Multimedia drivers
+#
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_MEDIA_TUNER=m
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_MEDIA_TUNER_SIMPLE=m
+CONFIG_MEDIA_TUNER_TDA8290=m
+CONFIG_MEDIA_TUNER_TDA9887=m
+CONFIG_MEDIA_TUNER_TEA5761=m
+CONFIG_MEDIA_TUNER_TEA5767=m
+CONFIG_MEDIA_TUNER_MT20XX=m
+CONFIG_MEDIA_TUNER_XC2028=m
+CONFIG_MEDIA_TUNER_XC5000=m
+CONFIG_MEDIA_TUNER_MC44S803=m
+CONFIG_VIDEO_V4L2=m
+CONFIG_VIDEO_V4L1=m
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_SOC_CAMERA is not set
+
+#
+# Qualcomm MSM Camera And Video
+#
+CONFIG_MSM_CAMERA=y
+CONFIG_MSM_CAMERA_LEGACY=y
+# CONFIG_MSM_CAMERA_7X30 is not set
+CONFIG_720P_CAMERA=y
+# CONFIG_MSM_CAMERA_DEBUG is not set
+
+#
+# Camera Sensor Selection
+#
+# CONFIG_MT9T013 is not set
+# CONFIG_MT9D112 is not set
+# CONFIG_MT9P012 is not set
+# CONFIG_S5K3E2FX is not set
+# CONFIG_S5K4E1GX is not set
+CONFIG_OV8810=y
+# CONFIG_OV9665 is not set
+# CONFIG_S5K3H1GX is not set
+# CONFIG_MT9V113 is not set
+CONFIG_RADIO_ADAPTERS=y
+# CONFIG_I2C_SI4713 is not set
+# CONFIG_RADIO_SI4713 is not set
+# CONFIG_RADIO_SI470X is not set
+# CONFIG_RADIO_TEA5764 is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT 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_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# 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_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_LCDC=y
+CONFIG_FB_MSM_TVOUT=y
+CONFIG_GPU_MSM_KGSL=y
+CONFIG_MSM_KGSL_MMU=y
+# CONFIG_MSM_KGSL_PER_FD_PAGETABLE is not set
+# CONFIG_MSM_HDMI is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_LOGO is not set
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+# CONFIG_HID_PID is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_WACOM is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
+CONFIG_USB_GADGET_MSM_72K=y
+CONFIG_USB_MSM_72K=y
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_ETH 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_USB_G_PRINTER is not set
+CONFIG_USB_ANDROID=y
+# CONFIG_USB_ANDROID_ACM is not set
+CONFIG_USB_ANDROID_ADB=y
+CONFIG_USB_ANDROID_DIAG=y
+CONFIG_USB_ANDROID_MASS_STORAGE=y
+CONFIG_USB_ANDROID_RNDIS=y
+CONFIG_USB_ANDROID_SERIAL=y
+CONFIG_USB_ANDROID_PROJECTOR=y
+# CONFIG_USB_ANDROID_MTP is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+CONFIG_USB_ACCESSORY_DETECT=y
+# CONFIG_USB_ACCESSORY_DETECT_BY_ADC is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
+
+#
+# USB Function Support
+#
+# CONFIG_USB_FUNCTION is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_BLOCK_PARANOID_RESUME=y
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
+CONFIG_MMC_MSM7X00A=y
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP3944 is not set
+CONFIG_LEDS_CPLD=y
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_BD2802 is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+CONFIG_LEDS_TRIGGER_SLEEP=y
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+CONFIG_SWITCH=y
+CONFIG_SWITCH_GPIO=y
+# CONFIG_ACCESSIBILITY 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 is not set
+# CONFIG_RTC_INTF_PROC is not set
+# CONFIG_RTC_INTF_DEV is not set
+CONFIG_RTC_INTF_ALARM=y
+CONFIG_RTC_INTF_ALARM_DEV=y
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# 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
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 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_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 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_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_MSM7X00A=y
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+# CONFIG_ECHO is not set
+
+#
+# Android
+#
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_RAM_CONSOLE_ENABLE_VERBOSE=y
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_DATA_SIZE=128
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_ECC_SIZE=16
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE=8
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL=0x11d
+# CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT is not set
+CONFIG_ANDROID_TIMED_OUTPUT=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+
+#
+# Qualcomm MSM Camera And Video
+#
+# CONFIG_MSM_CAMERA_FLASH is not set
+
+#
+# Camera Sensor Selection
+#
+# CONFIG_DST is not set
+# CONFIG_POHMELFS is not set
+# CONFIG_PLAN9AUTH is not set
+
+#
+# RAR Register Driver
+#
+# CONFIG_RAR_REGISTER is not set
+# CONFIG_IIO is not set
+# CONFIG_BTPORT is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_XATTR=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD=y
+CONFIG_JBD2=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=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
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+CONFIG_YAFFS_DISABLE_TAGS_ECC=y
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
+# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
+# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
+CONFIG_YAFFS_XATTR=y
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_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
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# 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_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# 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_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+# CONFIG_BOOT_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=y
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+CONFIG_CRYPTO_SHA1=y
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_TWOFISH_COMMON=y
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_REED_SOLOMON=y
+CONFIG_REED_SOLOMON_ENC8=y
+CONFIG_REED_SOLOMON_DEC8=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=y
+CONFIG_TEXTSEARCH_BM=y
+CONFIG_TEXTSEARCH_FSM=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/drivers/usb/index.html b/drivers/usb/index.html
new file mode 100644
index 00000000..694d3938
--- /dev/null
+++ b/drivers/usb/index.html
@@ -0,0 +1,167 @@
+
+
+
diff --git a/fs/yaffs2/yaffs_allocator.c b/fs/yaffs2/yaffs_allocator.c
new file mode 100644
index 00000000..a284439c
--- /dev/null
+++ b/fs/yaffs2/yaffs_allocator.c
@@ -0,0 +1,408 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2010 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning
+ *
+ * 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 "yaffs_allocator.h"
+#include "yaffs_guts.h"
+#include "yaffs_trace.h"
+#include "yportenv.h"
+
+#ifdef CONFIG_YAFFS_YMALLOC_ALLOCATOR
+
+void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev)
+{
+ dev = dev;
+}
+
+void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev)
+{
+ dev = dev;
+}
+
+yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev)
+{
+ return (yaffs_Tnode *)YMALLOC(dev->tnodeSize);
+}
+
+void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn)
+{
+ dev = dev;
+ YFREE(tn);
+}
+
+void yaffs_InitialiseRawObjects(yaffs_Device *dev)
+{
+ dev = dev;
+}
+
+void yaffs_DeinitialiseRawObjects(yaffs_Device *dev)
+{
+ dev = dev;
+}
+
+yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev)
+{
+ dev = dev;
+ return (yaffs_Object *) YMALLOC(sizeof(yaffs_Object));
+}
+
+
+void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
+{
+
+ dev = dev;
+ YFREE(obj);
+}
+
+#else
+
+struct yaffs_TnodeList_struct {
+ struct yaffs_TnodeList_struct *next;
+ yaffs_Tnode *tnodes;
+};
+
+typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
+
+struct yaffs_ObjectList_struct {
+ yaffs_Object *objects;
+ struct yaffs_ObjectList_struct *next;
+};
+
+typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
+
+
+struct yaffs_AllocatorStruct {
+ int nTnodesCreated;
+ yaffs_Tnode *freeTnodes;
+ int nFreeTnodes;
+ yaffs_TnodeList *allocatedTnodeList;
+
+ int nObjectsCreated;
+ yaffs_Object *freeObjects;
+ int nFreeObjects;
+
+ yaffs_ObjectList *allocatedObjectList;
+};
+
+typedef struct yaffs_AllocatorStruct yaffs_Allocator;
+
+
+static void yaffs_DeinitialiseRawTnodes(yaffs_Device *dev)
+{
+
+ yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
+
+ yaffs_TnodeList *tmp;
+
+ if(!allocator){
+ YBUG();
+ return;
+ }
+
+ while (allocator->allocatedTnodeList) {
+ tmp = allocator->allocatedTnodeList->next;
+
+ YFREE(allocator->allocatedTnodeList->tnodes);
+ YFREE(allocator->allocatedTnodeList);
+ allocator->allocatedTnodeList = tmp;
+
+ }
+
+ allocator->freeTnodes = NULL;
+ allocator->nFreeTnodes = 0;
+ allocator->nTnodesCreated = 0;
+}
+
+static void yaffs_InitialiseRawTnodes(yaffs_Device *dev)
+{
+ yaffs_Allocator *allocator = dev->allocator;
+
+ if(allocator){
+ allocator->allocatedTnodeList = NULL;
+ allocator->freeTnodes = NULL;
+ allocator->nFreeTnodes = 0;
+ allocator->nTnodesCreated = 0;
+ } else
+ YBUG();
+}
+
+static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
+{
+ yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
+ int i;
+ yaffs_Tnode *newTnodes;
+ __u8 *mem;
+ yaffs_Tnode *curr;
+ yaffs_Tnode *next;
+ yaffs_TnodeList *tnl;
+
+ if(!allocator){
+ YBUG();
+ return YAFFS_FAIL;
+ }
+
+ if (nTnodes < 1)
+ return YAFFS_OK;
+
+
+ /* make these things */
+
+ newTnodes = YMALLOC(nTnodes * dev->tnodeSize);
+ mem = (__u8 *)newTnodes;
+
+ if (!newTnodes) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
+ return YAFFS_FAIL;
+ }
+
+ /* New hookup for wide tnodes */
+ for (i = 0; i < nTnodes - 1; i++) {
+ curr = (yaffs_Tnode *) &mem[i * dev->tnodeSize];
+ next = (yaffs_Tnode *) &mem[(i+1) * dev->tnodeSize];
+ curr->internal[0] = next;
+ }
+
+ curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * dev->tnodeSize];
+ curr->internal[0] = allocator->freeTnodes;
+ allocator->freeTnodes = (yaffs_Tnode *)mem;
+
+ allocator->nFreeTnodes += nTnodes;
+ allocator->nTnodesCreated += nTnodes;
+
+ /* Now add this bunch of tnodes to a list for freeing up.
+ * NB If we can't add this to the management list it isn't fatal
+ * but it just means we can't free this bunch of tnodes later.
+ */
+
+ tnl = YMALLOC(sizeof(yaffs_TnodeList));
+ if (!tnl) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("yaffs: Could not add tnodes to management list" TENDSTR)));
+ return YAFFS_FAIL;
+ } else {
+ tnl->tnodes = newTnodes;
+ tnl->next = allocator->allocatedTnodeList;
+ allocator->allocatedTnodeList = tnl;
+ }
+
+ T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
+
+ return YAFFS_OK;
+}
+
+
+yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev)
+{
+ yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
+ yaffs_Tnode *tn = NULL;
+
+ if(!allocator){
+ YBUG();
+ return NULL;
+ }
+
+ /* If there are none left make more */
+ if (!allocator->freeTnodes)
+ yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
+
+ if (allocator->freeTnodes) {
+ tn = allocator->freeTnodes;
+ allocator->freeTnodes = allocator->freeTnodes->internal[0];
+ allocator->nFreeTnodes--;
+ }
+
+ return tn;
+}
+
+/* FreeTnode frees up a tnode and puts it back on the free list */
+void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn)
+{
+ yaffs_Allocator *allocator = dev->allocator;
+
+ if(!allocator){
+ YBUG();
+ return;
+ }
+
+ if (tn) {
+ tn->internal[0] = allocator->freeTnodes;
+ allocator->freeTnodes = tn;
+ allocator->nFreeTnodes++;
+ }
+ dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
+}
+
+
+
+static void yaffs_InitialiseRawObjects(yaffs_Device *dev)
+{
+ yaffs_Allocator *allocator = dev->allocator;
+
+ if(allocator) {
+ allocator->allocatedObjectList = NULL;
+ allocator->freeObjects = NULL;
+ allocator->nFreeObjects = 0;
+ } else
+ YBUG();
+}
+
+static void yaffs_DeinitialiseRawObjects(yaffs_Device *dev)
+{
+ yaffs_Allocator *allocator = dev->allocator;
+ yaffs_ObjectList *tmp;
+
+ if(!allocator){
+ YBUG();
+ return;
+ }
+
+ while (allocator->allocatedObjectList) {
+ tmp = allocator->allocatedObjectList->next;
+ YFREE(allocator->allocatedObjectList->objects);
+ YFREE(allocator->allocatedObjectList);
+
+ allocator->allocatedObjectList = tmp;
+ }
+
+ allocator->freeObjects = NULL;
+ allocator->nFreeObjects = 0;
+ allocator->nObjectsCreated = 0;
+}
+
+
+static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
+{
+ yaffs_Allocator *allocator = dev->allocator;
+
+ int i;
+ yaffs_Object *newObjects;
+ yaffs_ObjectList *list;
+
+ if(!allocator){
+ YBUG();
+ return YAFFS_FAIL;
+ }
+
+ if (nObjects < 1)
+ return YAFFS_OK;
+
+ /* make these things */
+ newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
+ list = YMALLOC(sizeof(yaffs_ObjectList));
+
+ if (!newObjects || !list) {
+ if (newObjects){
+ YFREE(newObjects);
+ newObjects = NULL;
+ }
+ if (list){
+ YFREE(list);
+ list = NULL;
+ }
+ T(YAFFS_TRACE_ALLOCATE,
+ (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
+ return YAFFS_FAIL;
+ }
+
+ /* Hook them into the free list */
+ for (i = 0; i < nObjects - 1; i++) {
+ newObjects[i].siblings.next =
+ (struct ylist_head *)(&newObjects[i + 1]);
+ }
+
+ newObjects[nObjects - 1].siblings.next = (void *)allocator->freeObjects;
+ allocator->freeObjects = newObjects;
+ allocator->nFreeObjects += nObjects;
+ allocator->nObjectsCreated += nObjects;
+
+ /* Now add this bunch of Objects to a list for freeing up. */
+
+ list->objects = newObjects;
+ list->next = allocator->allocatedObjectList;
+ allocator->allocatedObjectList = list;
+
+ return YAFFS_OK;
+}
+
+yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev)
+{
+ yaffs_Object *obj = NULL;
+ yaffs_Allocator *allocator = dev->allocator;
+
+ if(!allocator) {
+ YBUG();
+ return obj;
+ }
+
+ /* If there are none left make more */
+ if (!allocator->freeObjects)
+ yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
+
+ if (allocator->freeObjects) {
+ obj = allocator->freeObjects;
+ allocator->freeObjects =
+ (yaffs_Object *) (allocator->freeObjects->siblings.next);
+ allocator->nFreeObjects--;
+ }
+
+ return obj;
+}
+
+
+void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
+{
+
+ yaffs_Allocator *allocator = dev->allocator;
+
+ if(!allocator)
+ YBUG();
+ else {
+ /* Link into the free list. */
+ obj->siblings.next = (struct ylist_head *)(allocator->freeObjects);
+ allocator->freeObjects = obj;
+ allocator->nFreeObjects++;
+ }
+}
+
+void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev)
+{
+ if(dev->allocator){
+ yaffs_DeinitialiseRawTnodes(dev);
+ yaffs_DeinitialiseRawObjects(dev);
+
+ YFREE(dev->allocator);
+ dev->allocator=NULL;
+ } else
+ YBUG();
+}
+
+void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev)
+{
+ yaffs_Allocator *allocator;
+
+ if(!dev->allocator){
+ allocator = YMALLOC(sizeof(yaffs_Allocator));
+ if(allocator){
+ dev->allocator = allocator;
+ yaffs_InitialiseRawTnodes(dev);
+ yaffs_InitialiseRawObjects(dev);
+ }
+ } else
+ YBUG();
+}
+
+
+#endif
diff --git a/fs/yaffs2/yaffs_allocator.h b/fs/yaffs2/yaffs_allocator.h
new file mode 100644
index 00000000..b0a5d11b
--- /dev/null
+++ b/fs/yaffs2/yaffs_allocator.h
@@ -0,0 +1,30 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2010 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_ALLOCATOR_H__
+#define __YAFFS_ALLOCATOR_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev);
+void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev);
+
+yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev);
+void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn);
+
+yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev);
+void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj);
+
+#endif
diff --git a/fs/yaffs2/yaffs_bitmap.c b/fs/yaffs2/yaffs_bitmap.c
new file mode 100644
index 00000000..c7e9e8c4
--- /dev/null
+++ b/fs/yaffs2/yaffs_bitmap.c
@@ -0,0 +1,105 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2010 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning
+ *
+ * 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 "yaffs_bitmap.h"
+#include "yaffs_trace.h"
+/*
+ * Chunk bitmap manipulations
+ */
+
+static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
+{
+ if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
+ blk));
+ YBUG();
+ }
+ return dev->chunkBits +
+ (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
+}
+
+void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk)
+{
+ if (blk < dev->internalStartBlock || blk > dev->internalEndBlock ||
+ chunk < 0 || chunk >= dev->param.nChunksPerBlock) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
+ blk, chunk));
+ YBUG();
+ }
+}
+
+void yaffs_ClearChunkBits(yaffs_Device *dev, int blk)
+{
+ __u8 *blkBits = yaffs_BlockBits(dev, blk);
+
+ memset(blkBits, 0, dev->chunkBitmapStride);
+}
+
+void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk)
+{
+ __u8 *blkBits = yaffs_BlockBits(dev, blk);
+
+ yaffs_VerifyChunkBitId(dev, blk, chunk);
+
+ blkBits[chunk / 8] &= ~(1 << (chunk & 7));
+}
+
+void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk)
+{
+ __u8 *blkBits = yaffs_BlockBits(dev, blk);
+
+ yaffs_VerifyChunkBitId(dev, blk, chunk);
+
+ blkBits[chunk / 8] |= (1 << (chunk & 7));
+}
+
+int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk)
+{
+ __u8 *blkBits = yaffs_BlockBits(dev, blk);
+ yaffs_VerifyChunkBitId(dev, blk, chunk);
+
+ return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
+}
+
+int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk)
+{
+ __u8 *blkBits = yaffs_BlockBits(dev, blk);
+ int i;
+ for (i = 0; i < dev->chunkBitmapStride; i++) {
+ if (*blkBits)
+ return 1;
+ blkBits++;
+ }
+ return 0;
+}
+
+int yaffs_CountChunkBits(yaffs_Device *dev, int blk)
+{
+ __u8 *blkBits = yaffs_BlockBits(dev, blk);
+ int i;
+ int n = 0;
+ for (i = 0; i < dev->chunkBitmapStride; i++) {
+ __u8 x = *blkBits;
+ while (x) {
+ if (x & 1)
+ n++;
+ x >>= 1;
+ }
+
+ blkBits++;
+ }
+ return n;
+}
+
diff --git a/fs/yaffs2/yaffs_bitmap.h b/fs/yaffs2/yaffs_bitmap.h
new file mode 100644
index 00000000..00cca2c0
--- /dev/null
+++ b/fs/yaffs2/yaffs_bitmap.h
@@ -0,0 +1,33 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2010 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * Chunk bitmap manipulations
+ */
+
+#ifndef __YAFFS_BITMAP_H__
+#define __YAFFS_BITMAP_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk);
+void yaffs_ClearChunkBits(yaffs_Device *dev, int blk);
+void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk);
+void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk);
+int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk);
+int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk);
+int yaffs_CountChunkBits(yaffs_Device *dev, int blk);
+
+#endif
diff --git a/fs/yaffs2/yaffs_linux.h b/fs/yaffs2/yaffs_linux.h
new file mode 100644
index 00000000..ce059fd2
--- /dev/null
+++ b/fs/yaffs2/yaffs_linux.h
@@ -0,0 +1,43 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2010 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_LINUX_H__
+#define __YAFFS_LINUX_H__
+
+#include "devextras.h"
+#include "yportenv.h"
+
+struct yaffs_LinuxContext {
+ struct ylist_head contextList; /* List of these we have mounted */
+ struct yaffs_DeviceStruct *dev;
+ struct super_block * superBlock;
+ struct task_struct *bgThread; /* Background thread for this device */
+ int bgRunning;
+ struct semaphore grossLock; /* Gross locking semaphore */
+ __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
+ * at compile time so we have to allocate it.
+ */
+ struct ylist_head searchContexts;
+ void (*putSuperFunc)(struct super_block *sb);
+
+ struct task_struct *readdirProcess;
+ unsigned mount_id;
+};
+
+#define yaffs_DeviceToLC(dev) ((struct yaffs_LinuxContext *)((dev)->osContext))
+#define yaffs_DeviceToMtd(dev) ((struct mtd_info *)((dev)->driverContext))
+
+#endif
+
diff --git a/fs/yaffs2/yaffs_linux_allocator.c b/fs/yaffs2/yaffs_linux_allocator.c
new file mode 100644
index 00000000..e91782a1
--- /dev/null
+++ b/fs/yaffs2/yaffs_linux_allocator.c
@@ -0,0 +1,202 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2010 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * Note: Tis code is currently unused. Being checked in in case it becomes useful.
+ */
+
+
+#include "yaffs_allocator.h"
+#include "yaffs_guts.h"
+#include "yaffs_trace.h"
+#include "yportenv.h"
+#include "yaffs_linux.h"
+/*
+ * Start out with the same allocator as yaffs direct.
+ * Todo: Change to Linux slab allocator.
+ */
+
+
+
+#define NAMELEN 20
+struct yaffs_AllocatorStruct {
+ char tnode_name[NAMELEN+1];
+ char object_name[NAMELEN+1];
+ struct kmem_cache *tnode_cache;
+ struct kmem_cache *object_cache;
+};
+
+typedef struct yaffs_AllocatorStruct yaffs_Allocator;
+
+int mount_id;
+
+void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev)
+{
+ yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
+
+ T(YAFFS_TRACE_ALLOCATE,(TSTR("Deinitialising yaffs allocator\n")));
+
+ if(allocator){
+ if(allocator->tnode_cache){
+ kmem_cache_destroy(allocator->tnode_cache);
+ allocator->tnode_cache = NULL;
+ } else {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("NULL tnode cache\n")));
+ YBUG();
+ }
+
+ if(allocator->object_cache){
+ kmem_cache_destroy(allocator->object_cache);
+ allocator->object_cache = NULL;
+ } else {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("NULL object cache\n")));
+ YBUG();
+ }
+
+ YFREE(allocator);
+
+ } else {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("Deinitialising NULL allocator\n")));
+ YBUG();
+ }
+ dev->allocator = NULL;
+}
+
+
+static void fake_ctor0(void *data){data = data;}
+static void fake_ctor1(void *data){data = data;}
+static void fake_ctor2(void *data){data = data;}
+static void fake_ctor3(void *data){data = data;}
+static void fake_ctor4(void *data){data = data;}
+static void fake_ctor5(void *data){data = data;}
+static void fake_ctor6(void *data){data = data;}
+static void fake_ctor7(void *data){data = data;}
+static void fake_ctor8(void *data){data = data;}
+static void fake_ctor9(void *data){data = data;}
+
+static void (*fake_ctor_list[10]) (void *) = {
+ fake_ctor0,
+ fake_ctor1,
+ fake_ctor2,
+ fake_ctor3,
+ fake_ctor4,
+ fake_ctor5,
+ fake_ctor6,
+ fake_ctor7,
+ fake_ctor8,
+ fake_ctor9,
+};
+
+void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev)
+{
+ yaffs_Allocator *allocator;
+ unsigned mount_id = yaffs_DeviceToLC(dev)->mount_id;
+
+ T(YAFFS_TRACE_ALLOCATE,(TSTR("Initialising yaffs allocator\n")));
+
+ if(dev->allocator)
+ YBUG();
+ else if(mount_id >= 10){
+ T(YAFFS_TRACE_ALWAYS,(TSTR("Bad mount_id %u\n"),mount_id));
+ } else {
+ allocator = YMALLOC(sizeof(yaffs_Allocator));
+ memset(allocator,0,sizeof(yaffs_Allocator));
+ dev->allocator = allocator;
+
+ if(!dev->allocator){
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs allocator creation failed\n")));
+ YBUG();
+ return;
+
+ }
+
+ sprintf(allocator->tnode_name,"yaffs_t_%u",mount_id);
+ sprintf(allocator->object_name,"yaffs_o_%u",mount_id);
+
+ allocator->tnode_cache =
+ kmem_cache_create(allocator->tnode_name,
+ dev->tnodeSize,
+ 0, 0,
+ fake_ctor_list[mount_id]);
+ if(allocator->tnode_cache)
+ T(YAFFS_TRACE_ALLOCATE,
+ (TSTR("tnode cache \"%s\" %p\n"),
+ allocator->tnode_name,allocator->tnode_cache));
+ else {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs cache creation failed\n")));
+ YBUG();
+ }
+
+
+ allocator->object_cache =
+ kmem_cache_create(allocator->object_name,
+ sizeof(yaffs_Object),
+ 0, 0,
+ fake_ctor_list[mount_id]);
+
+ if(allocator->object_cache)
+ T(YAFFS_TRACE_ALLOCATE,
+ (TSTR("object cache \"%s\" %p\n"),
+ allocator->object_name,allocator->object_cache));
+
+ else {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs cache creation failed\n")));
+ YBUG();
+ }
+ }
+}
+
+
+yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev)
+{
+ yaffs_Allocator *allocator = dev->allocator;
+ if(!allocator || !allocator->tnode_cache){
+ YBUG();
+ return NULL;
+ }
+ return kmem_cache_alloc(allocator->tnode_cache, GFP_NOFS);
+}
+
+void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn)
+{
+ yaffs_Allocator *allocator = dev->allocator;
+ kmem_cache_free(allocator->tnode_cache,tn);
+}
+
+yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev)
+{
+ yaffs_Allocator *allocator = dev->allocator;
+ if(!allocator){
+ YBUG();
+ return NULL;
+ }
+ if(!allocator->object_cache){
+ YBUG();
+ return NULL;
+ }
+ return kmem_cache_alloc(allocator->object_cache, GFP_NOFS);
+}
+
+void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
+{
+ yaffs_Allocator *allocator = dev->allocator;
+ kmem_cache_free(allocator->object_cache,obj);
+}
diff --git a/fs/yaffs2/yaffs_list.h b/fs/yaffs2/yaffs_list.h
new file mode 100644
index 00000000..09d80b85
--- /dev/null
+++ b/fs/yaffs2/yaffs_list.h
@@ -0,0 +1,127 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2010 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * This file is just holds extra declarations of macros that would normally
+ * be providesd in the Linux kernel. These macros have been written from
+ * scratch but are functionally equivalent to the Linux ones.
+ *
+ */
+
+#ifndef __YAFFS_LIST_H__
+#define __YAFFS_LIST_H__
+
+
+#include "yportenv.h"
+
+/*
+ * This is a simple doubly linked list implementation that matches the
+ * way the Linux kernel doubly linked list implementation works.
+ */
+
+struct ylist_head {
+ struct ylist_head *next; /* next in chain */
+ struct ylist_head *prev; /* previous in chain */
+};
+
+
+/* Initialise a static list */
+#define YLIST_HEAD(name) \
+struct ylist_head name = { &(name), &(name)}
+
+
+
+/* Initialise a list head to an empty list */
+#define YINIT_LIST_HEAD(p) \
+do { \
+ (p)->next = (p);\
+ (p)->prev = (p); \
+} while (0)
+
+
+/* Add an element to a list */
+static Y_INLINE void ylist_add(struct ylist_head *newEntry,
+ struct ylist_head *list)
+{
+ struct ylist_head *listNext = list->next;
+
+ list->next = newEntry;
+ newEntry->prev = list;
+ newEntry->next = listNext;
+ listNext->prev = newEntry;
+
+}
+
+static Y_INLINE void ylist_add_tail(struct ylist_head *newEntry,
+ struct ylist_head *list)
+{
+ struct ylist_head *listPrev = list->prev;
+
+ list->prev = newEntry;
+ newEntry->next = list;
+ newEntry->prev = listPrev;
+ listPrev->next = newEntry;
+
+}
+
+
+/* Take an element out of its current list, with or without
+ * reinitialising the links.of the entry*/
+static Y_INLINE void ylist_del(struct ylist_head *entry)
+{
+ struct ylist_head *listNext = entry->next;
+ struct ylist_head *listPrev = entry->prev;
+
+ listNext->prev = listPrev;
+ listPrev->next = listNext;
+
+}
+
+static Y_INLINE void ylist_del_init(struct ylist_head *entry)
+{
+ ylist_del(entry);
+ entry->next = entry->prev = entry;
+}
+
+
+/* Test if the list is empty */
+static Y_INLINE int ylist_empty(struct ylist_head *entry)
+{
+ return (entry->next == entry);
+}
+
+
+/* ylist_entry takes a pointer to a list entry and offsets it to that
+ * we can find a pointer to the object it is embedded in.
+ */
+
+
+#define ylist_entry(entry, type, member) \
+ ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
+
+
+/* ylist_for_each and list_for_each_safe iterate over lists.
+ * ylist_for_each_safe uses temporary storage to make the list delete safe
+ */
+
+#define ylist_for_each(itervar, list) \
+ for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
+
+#define ylist_for_each_safe(itervar, saveVar, list) \
+ for (itervar = (list)->next, saveVar = (list)->next->next; \
+ itervar != (list); itervar = saveVar, saveVar = saveVar->next)
+
+
+#endif
diff --git a/fs/yaffs2/yaffs_nameval.c b/fs/yaffs2/yaffs_nameval.c
new file mode 100644
index 00000000..a4ed2973
--- /dev/null
+++ b/fs/yaffs2/yaffs_nameval.c
@@ -0,0 +1,197 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2010 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning
+ *
+ * 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 simple implementation of a name-value store assumes a small number of values and fits
+ * into a small finite buffer.
+ *
+ * Each attribute is stored as a record:
+ * sizeof(int) bytes record size.
+ * strnlen+1 bytes name null terminated.
+ * nbytes value.
+ * ----------
+ * total size stored in record size
+ *
+ * This code has not been tested with unicode yet.
+ */
+
+
+#include "yaffs_nameval.h"
+
+#include "yportenv.h"
+
+static int nval_find(const char *xb, int xb_size, const YCHAR *name,
+ int *exist_size)
+{
+ int pos=0;
+ int size;
+
+ memcpy(&size,xb,sizeof(int));
+ while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
+ if(yaffs_strncmp((YCHAR *)(xb+pos+sizeof(int)),name,size) == 0){
+ if(exist_size)
+ *exist_size = size;
+ return pos;
+ }
+ pos += size;
+ if(pos < xb_size -sizeof(int))
+ memcpy(&size,xb + pos,sizeof(int));
+ else
+ size = 0;
+ }
+ if(exist_size)
+ *exist_size = 0;
+ return -1;
+}
+
+static int nval_used(const char *xb, int xb_size)
+{
+ int pos=0;
+ int size;
+
+ memcpy(&size,xb + pos,sizeof(int));
+ while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
+ pos += size;
+ if(pos < xb_size -sizeof(int))
+ memcpy(&size,xb + pos,sizeof(int));
+ else
+ size = 0;
+ }
+ return pos;
+}
+
+int nval_del(char *xb, int xb_size, const YCHAR *name)
+{
+ int pos = nval_find(xb, xb_size, name, NULL);
+ int size;
+
+ if(pos >= 0 && pos < xb_size){
+ /* Find size, shift rest over this record, then zero out the rest of buffer */
+ memcpy(&size,xb+pos,sizeof(int));
+ memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
+ memset(xb + (xb_size - size),0,size);
+ return 0;
+ } else
+ return -ENODATA;
+}
+
+int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags)
+{
+ int pos;
+ int namelen = yaffs_strnlen(name,xb_size);
+ int reclen;
+ int size_exist = 0;
+ int space;
+ int start;
+
+ pos = nval_find(xb,xb_size,name, &size_exist);
+
+ if(flags & XATTR_CREATE && pos >= 0)
+ return -EEXIST;
+ if(flags & XATTR_REPLACE && pos < 0)
+ return -ENODATA;
+
+ start = nval_used(xb,xb_size);
+ space = xb_size - start + size_exist;
+
+ reclen = (sizeof(int) + namelen + 1 + bsize);
+
+ if(reclen > space)
+ return -ENOSPC;
+
+ if(pos >= 0){
+ nval_del(xb,xb_size,name);
+ start = nval_used(xb, xb_size);
+ }
+
+ pos = start;
+
+ memcpy(xb + pos,&reclen,sizeof(int));
+ pos +=sizeof(int);
+ yaffs_strncpy((YCHAR *)(xb + pos), name, reclen);
+ pos+= (namelen+1);
+ memcpy(xb + pos,buf,bsize);
+ return 0;
+}
+
+int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize)
+{
+ int pos = nval_find(xb,xb_size,name,NULL);
+ int size;
+
+ if(pos >= 0 && pos< xb_size){
+
+ memcpy(&size,xb +pos,sizeof(int));
+ pos+=sizeof(int); /* advance past record length */
+ size -= sizeof(int);
+
+ /* Advance over name string */
+ while(xb[pos] && size > 0 && pos < xb_size){
+ pos++;
+ size--;
+ }
+ /*Advance over NUL */
+ pos++;
+ size--;
+
+ if(size <= bsize){
+ memcpy(buf,xb + pos,size);
+ return size;
+ }
+
+ }
+ if(pos >= 0)
+ return -ERANGE;
+ else
+ return -ENODATA;
+}
+
+int nval_list(const char *xb, int xb_size, char *buf, int bsize)
+{
+ int pos = 0;
+ int size;
+ int name_len;
+ int ncopied = 0;
+ int filled = 0;
+
+ memcpy(&size,xb + pos,sizeof(int));
+ while(size > sizeof(int) && size <= xb_size && (pos + size) < xb_size && !filled){
+ pos+= sizeof(int);
+ size-=sizeof(int);
+ name_len = yaffs_strnlen((YCHAR *)(xb + pos), size);
+ if(ncopied + name_len + 1 < bsize){
+ memcpy(buf,xb+pos,name_len * sizeof(YCHAR));
+ buf+= name_len;
+ *buf = '\0';
+ buf++;
+ if(sizeof(YCHAR) > 1){
+ *buf = '\0';
+ buf++;
+ }
+ ncopied += (name_len+1);
+ } else
+ filled = 1;
+ pos+=size;
+ if(pos < xb_size -sizeof(int))
+ memcpy(&size,xb + pos,sizeof(int));
+ else
+ size = 0;
+ }
+ return ncopied;
+}
+
+
+int nval_hasvalues(const char *xb, int xb_size)
+{
+ return nval_used(xb, xb_size) > 0;
+}
diff --git a/fs/yaffs2/yaffs_nameval.h b/fs/yaffs2/yaffs_nameval.h
new file mode 100644
index 00000000..bd808593
--- /dev/null
+++ b/fs/yaffs2/yaffs_nameval.h
@@ -0,0 +1,26 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2010 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __NAMEVAL_H__
+#define __NAMEVAL_H__
+
+#include "yportenv.h"
+
+int nval_del(char *xb, int xb_size, const YCHAR *name);
+int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags);
+int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize);
+int nval_list(const char *xb, int xb_size, char *buf, int bsize);
+int nval_hasvalues(const char *xb, int xb_size);
+#endif
diff --git a/fs/yaffs2/yaffs_trace.h b/fs/yaffs2/yaffs_trace.h
new file mode 100644
index 00000000..8b848edb
--- /dev/null
+++ b/fs/yaffs2/yaffs_trace.h
@@ -0,0 +1,60 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2010 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+
+#ifndef __YTRACE_H__
+#define __YTRACE_H__
+
+extern unsigned int yaffs_traceMask;
+extern unsigned int yaffs_wr_attempts;
+
+/*
+ * Tracing flags.
+ * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
+ */
+
+#define YAFFS_TRACE_OS 0x00000002
+#define YAFFS_TRACE_ALLOCATE 0x00000004
+#define YAFFS_TRACE_SCAN 0x00000008
+#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
+#define YAFFS_TRACE_ERASE 0x00000020
+#define YAFFS_TRACE_GC 0x00000040
+#define YAFFS_TRACE_WRITE 0x00000080
+#define YAFFS_TRACE_TRACING 0x00000100
+#define YAFFS_TRACE_DELETION 0x00000200
+#define YAFFS_TRACE_BUFFERS 0x00000400
+#define YAFFS_TRACE_NANDACCESS 0x00000800
+#define YAFFS_TRACE_GC_DETAIL 0x00001000
+#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
+#define YAFFS_TRACE_MTD 0x00004000
+#define YAFFS_TRACE_CHECKPOINT 0x00008000
+
+#define YAFFS_TRACE_VERIFY 0x00010000
+#define YAFFS_TRACE_VERIFY_NAND 0x00020000
+#define YAFFS_TRACE_VERIFY_FULL 0x00040000
+#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
+
+#define YAFFS_TRACE_SYNC 0x00100000
+#define YAFFS_TRACE_BACKGROUND 0x00200000
+#define YAFFS_TRACE_LOCK 0x00400000
+
+#define YAFFS_TRACE_ERROR 0x40000000
+#define YAFFS_TRACE_BUG 0x80000000
+#define YAFFS_TRACE_ALWAYS 0xF0000000
+
+
+#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
+
+#endif
diff --git a/fs/yaffs2/yaffs_verify.c b/fs/yaffs2/yaffs_verify.c
new file mode 100644
index 00000000..a600aa6b
--- /dev/null
+++ b/fs/yaffs2/yaffs_verify.c
@@ -0,0 +1,626 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2010 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning
+ *
+ * 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 "yaffs_verify.h"
+#include "yaffs_trace.h"
+#include "yaffs_bitmap.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_nand.h"
+
+int yaffs_SkipVerification(yaffs_Device *dev)
+{
+ dev=dev;
+ return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
+}
+
+static int yaffs_SkipFullVerification(yaffs_Device *dev)
+{
+ dev=dev;
+ return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
+}
+
+static int yaffs_SkipNANDVerification(yaffs_Device *dev)
+{
+ dev=dev;
+ return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
+}
+
+
+static const char *blockStateName[] = {
+"Unknown",
+"Needs scanning",
+"Scanning",
+"Empty",
+"Allocating",
+"Full",
+"Dirty",
+"Checkpoint",
+"Collecting",
+"Dead"
+};
+
+
+void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
+{
+ int actuallyUsed;
+ int inUse;
+
+ if (yaffs_SkipVerification(dev))
+ return;
+
+ /* Report illegal runtime states */
+ if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
+ T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState));
+
+ switch (bi->blockState) {
+ case YAFFS_BLOCK_STATE_UNKNOWN:
+ case YAFFS_BLOCK_STATE_SCANNING:
+ case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
+ T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
+ n, blockStateName[bi->blockState]));
+ }
+
+ /* Check pages in use and soft deletions are legal */
+
+ actuallyUsed = bi->pagesInUse - bi->softDeletions;
+
+ if (bi->pagesInUse < 0 || bi->pagesInUse > dev->param.nChunksPerBlock ||
+ bi->softDeletions < 0 || bi->softDeletions > dev->param.nChunksPerBlock ||
+ actuallyUsed < 0 || actuallyUsed > dev->param.nChunksPerBlock)
+ T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
+ n, bi->pagesInUse, bi->softDeletions));
+
+
+ /* Check chunk bitmap legal */
+ inUse = yaffs_CountChunkBits(dev, n);
+ if (inUse != bi->pagesInUse)
+ T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
+ n, bi->pagesInUse, inUse));
+
+}
+
+
+
+void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
+{
+ yaffs_VerifyBlock(dev, bi, n);
+
+ /* After collection the block should be in the erased state */
+
+ if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
+ bi->blockState != YAFFS_BLOCK_STATE_EMPTY) {
+ T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
+ n, bi->blockState));
+ }
+}
+
+void yaffs_VerifyBlocks(yaffs_Device *dev)
+{
+ int i;
+ int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
+ int nIllegalBlockStates = 0;
+
+ if (yaffs_SkipVerification(dev))
+ return;
+
+ memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
+
+ for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
+ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
+ yaffs_VerifyBlock(dev, bi, i);
+
+ if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
+ nBlocksPerState[bi->blockState]++;
+ else
+ nIllegalBlockStates++;
+ }
+
+ T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
+ T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
+
+ T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
+ if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
+ T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
+
+ for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
+ T(YAFFS_TRACE_VERIFY,
+ (TSTR("%s %d blocks"TENDSTR),
+ blockStateName[i], nBlocksPerState[i]));
+
+ if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
+ T(YAFFS_TRACE_VERIFY,
+ (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
+ dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
+
+ if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
+ T(YAFFS_TRACE_VERIFY,
+ (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
+ dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
+
+ if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
+ T(YAFFS_TRACE_VERIFY,
+ (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
+ nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
+
+ T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
+
+}
+
+/*
+ * Verify the object header. oh must be valid, but obj and tags may be NULL in which
+ * case those tests will not be performed.
+ */
+void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
+{
+ if (obj && yaffs_SkipVerification(obj->myDev))
+ return;
+
+ if (!(tags && obj && oh)) {
+ T(YAFFS_TRACE_VERIFY,
+ (TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR),
+ tags, obj, oh));
+ return;
+ }
+
+ if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
+ oh->type > YAFFS_OBJECT_TYPE_MAX)
+ T(YAFFS_TRACE_VERIFY,
+ (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
+ tags->objectId, oh->type));
+
+ if (tags->objectId != obj->objectId)
+ T(YAFFS_TRACE_VERIFY,
+ (TSTR("Obj %d header mismatch objectId %d"TENDSTR),
+ tags->objectId, obj->objectId));
+
+
+ /*
+ * Check that the object's parent ids match if parentCheck requested.
+ *
+ * Tests do not apply to the root object.
+ */
+
+ if (parentCheck && tags->objectId > 1 && !obj->parent)
+ T(YAFFS_TRACE_VERIFY,
+ (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
+ tags->objectId, oh->parentObjectId));
+
+ if (parentCheck && obj->parent &&
+ oh->parentObjectId != obj->parent->objectId &&
+ (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
+ obj->parent->objectId != YAFFS_OBJECTID_DELETED))
+ T(YAFFS_TRACE_VERIFY,
+ (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
+ tags->objectId, oh->parentObjectId, obj->parent->objectId));
+
+ if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */
+ T(YAFFS_TRACE_VERIFY,
+ (TSTR("Obj %d header name is NULL"TENDSTR),
+ obj->objectId));
+
+ if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
+ T(YAFFS_TRACE_VERIFY,
+ (TSTR("Obj %d header name is 0xFF"TENDSTR),
+ obj->objectId));
+}
+
+
+#if 0
+/* Not being used, but don't want to throw away yet */
+int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
+ __u32 level, int chunkOffset)
+{
+ int i;
+ yaffs_Device *dev = obj->myDev;
+ int ok = 1;
+
+ if (tn) {
+ if (level > 0) {
+
+ for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
+ if (tn->internal[i]) {
+ ok = yaffs_VerifyTnodeWorker(obj,
+ tn->internal[i],
+ level - 1,
+ (chunkOffset<objectId;
+
+ chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS;
+
+ for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
+ __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
+
+ if (theChunk > 0) {
+ /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
+ yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
+ if (tags.objectId != objectId || tags.chunkId != chunkOffset) {
+ T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
+ objectId, chunkOffset, theChunk,
+ tags.objectId, tags.chunkId));
+ }
+ }
+ chunkOffset++;
+ }
+ }
+ }
+
+ return ok;
+
+}
+
+#endif
+
+void yaffs_VerifyFile(yaffs_Object *obj)
+{
+ int requiredTallness;
+ int actualTallness;
+ __u32 lastChunk;
+ __u32 x;
+ __u32 i;
+ yaffs_Device *dev;
+ yaffs_ExtendedTags tags;
+ yaffs_Tnode *tn;
+ __u32 objectId;
+
+ if (!obj)
+ return;
+
+ if (yaffs_SkipVerification(obj->myDev))
+ return;
+
+ dev = obj->myDev;
+ objectId = obj->objectId;
+
+ /* Check file size is consistent with tnode depth */
+ lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
+ x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
+ requiredTallness = 0;
+ while (x > 0) {
+ x >>= YAFFS_TNODES_INTERNAL_BITS;
+ requiredTallness++;
+ }
+
+ actualTallness = obj->variant.fileVariant.topLevel;
+
+ /* Check that the chunks in the tnode tree are all correct.
+ * We do this by scanning through the tnode tree and
+ * checking the tags for every chunk match.
+ */
+
+ if (yaffs_SkipNANDVerification(dev))
+ return;
+
+ for (i = 1; i <= lastChunk; i++) {
+ tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i);
+
+ if (tn) {
+ __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
+ if (theChunk > 0) {
+ /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
+ yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
+ if (tags.objectId != objectId || tags.chunkId != i) {
+ T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
+ objectId, i, theChunk,
+ tags.objectId, tags.chunkId));
+ }
+ }
+ }
+ }
+}
+
+
+void yaffs_VerifyHardLink(yaffs_Object *obj)
+{
+ if (obj && yaffs_SkipVerification(obj->myDev))
+ return;
+
+ /* Verify sane equivalent object */
+}
+
+void yaffs_VerifySymlink(yaffs_Object *obj)
+{
+ if (obj && yaffs_SkipVerification(obj->myDev))
+ return;
+
+ /* Verify symlink string */
+}
+
+void yaffs_VerifySpecial(yaffs_Object *obj)
+{
+ if (obj && yaffs_SkipVerification(obj->myDev))
+ return;
+}
+
+void yaffs_VerifyObject(yaffs_Object *obj)
+{
+ yaffs_Device *dev;
+
+ __u32 chunkMin;
+ __u32 chunkMax;
+
+ __u32 chunkIdOk;
+ __u32 chunkInRange;
+ __u32 chunkShouldNotBeDeleted;
+ __u32 chunkValid;
+
+ if (!obj)
+ return;
+
+ if (obj->beingCreated)
+ return;
+
+ dev = obj->myDev;
+
+ if (yaffs_SkipVerification(dev))
+ return;
+
+ /* Check sane object header chunk */
+
+ chunkMin = dev->internalStartBlock * dev->param.nChunksPerBlock;
+ chunkMax = (dev->internalEndBlock+1) * dev->param.nChunksPerBlock - 1;
+
+ chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
+ chunkIdOk = chunkInRange || (obj->hdrChunk == 0);
+ chunkValid = chunkInRange &&
+ yaffs_CheckChunkBit(dev,
+ obj->hdrChunk / dev->param.nChunksPerBlock,
+ obj->hdrChunk % dev->param.nChunksPerBlock);
+ chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
+
+ if (!obj->fake &&
+ (!chunkIdOk || chunkShouldNotBeDeleted)) {
+ T(YAFFS_TRACE_VERIFY,
+ (TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
+ obj->objectId, obj->hdrChunk,
+ chunkIdOk ? "" : ",out of range",
+ chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
+ }
+
+ if (chunkValid && !yaffs_SkipNANDVerification(dev)) {
+ yaffs_ExtendedTags tags;
+ yaffs_ObjectHeader *oh;
+ __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
+
+ oh = (yaffs_ObjectHeader *)buffer;
+
+ yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer,
+ &tags);
+
+ yaffs_VerifyObjectHeader(obj, oh, &tags, 1);
+
+ yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
+ }
+
+ /* Verify it has a parent */
+ if (obj && !obj->fake &&
+ (!obj->parent || obj->parent->myDev != dev)) {
+ T(YAFFS_TRACE_VERIFY,
+ (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
+ obj->objectId, obj->parent));
+ }
+
+ /* Verify parent is a directory */
+ if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ T(YAFFS_TRACE_VERIFY,
+ (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
+ obj->objectId, obj->parent->variantType));
+ }
+
+ switch (obj->variantType) {
+ case YAFFS_OBJECT_TYPE_FILE:
+ yaffs_VerifyFile(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ yaffs_VerifySymlink(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ yaffs_VerifyDirectory(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ yaffs_VerifyHardLink(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ yaffs_VerifySpecial(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ default:
+ T(YAFFS_TRACE_VERIFY,
+ (TSTR("Obj %d has illegaltype %d"TENDSTR),
+ obj->objectId, obj->variantType));
+ break;
+ }
+}
+
+void yaffs_VerifyObjects(yaffs_Device *dev)
+{
+ yaffs_Object *obj;
+ int i;
+ struct ylist_head *lh;
+
+ if (yaffs_SkipVerification(dev))
+ return;
+
+ /* Iterate through the objects in each hash entry */
+
+ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
+ ylist_for_each(lh, &dev->objectBucket[i].list) {
+ if (lh) {
+ obj = ylist_entry(lh, yaffs_Object, hashLink);
+ yaffs_VerifyObject(obj);
+ }
+ }
+ }
+}
+
+
+void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
+{
+ struct ylist_head *lh;
+ yaffs_Object *listObj;
+
+ int count = 0;
+
+ if (!obj) {
+ T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
+ YBUG();
+ return;
+ }
+
+ if (yaffs_SkipVerification(obj->myDev))
+ return;
+
+ if (!obj->parent) {
+ T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
+ YBUG();
+ return;
+ }
+
+ if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
+ YBUG();
+ }
+
+ /* Iterate through the objects in each hash entry */
+
+ ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) {
+ if (lh) {
+ listObj = ylist_entry(lh, yaffs_Object, siblings);
+ yaffs_VerifyObject(listObj);
+ if (obj == listObj)
+ count++;
+ }
+ }
+
+ if (count != 1) {
+ T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
+ YBUG();
+ }
+}
+
+void yaffs_VerifyDirectory(yaffs_Object *directory)
+{
+ struct ylist_head *lh;
+ yaffs_Object *listObj;
+
+ if (!directory) {
+ YBUG();
+ return;
+ }
+
+ if (yaffs_SkipFullVerification(directory->myDev))
+ return;
+
+ if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType));
+ YBUG();
+ }
+
+ /* Iterate through the objects in each hash entry */
+
+ ylist_for_each(lh, &directory->variant.directoryVariant.children) {
+ if (lh) {
+ listObj = ylist_entry(lh, yaffs_Object, siblings);
+ if (listObj->parent != directory) {
+ T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
+ YBUG();
+ }
+ yaffs_VerifyObjectInDirectory(listObj);
+ }
+ }
+}
+
+static int yaffs_freeVerificationFailures;
+
+void yaffs_VerifyFreeChunks(yaffs_Device *dev)
+{
+ int counted;
+ int difference;
+
+ if (yaffs_SkipVerification(dev))
+ return;
+
+ counted = yaffs_CountFreeChunks(dev);
+
+ difference = dev->nFreeChunks - counted;
+
+ if (difference) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
+ dev->nFreeChunks, counted, difference));
+ yaffs_freeVerificationFailures++;
+ }
+}
+
+int yaffs_VerifyFileSanity(yaffs_Object *in)
+{
+#if 0
+ int chunk;
+ int nChunks;
+ int fSize;
+ int failed = 0;
+ int objId;
+ yaffs_Tnode *tn;
+ yaffs_Tags localTags;
+ yaffs_Tags *tags = &localTags;
+ int theChunk;
+ int chunkDeleted;
+
+ if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
+ return YAFFS_FAIL;
+
+ objId = in->objectId;
+ fSize = in->variant.fileVariant.fileSize;
+ nChunks =
+ (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
+
+ for (chunk = 1; chunk <= nChunks; chunk++) {
+ tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
+ chunk);
+
+ if (tn) {
+
+ theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk);
+
+ if (yaffs_CheckChunkBits
+ (dev, theChunk / dev->param.nChunksPerBlock,
+ theChunk % dev->param.nChunksPerBlock)) {
+
+ yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
+ tags,
+ &chunkDeleted);
+ if (yaffs_TagsMatch
+ (tags, in->objectId, chunk, chunkDeleted)) {
+ /* found it; */
+
+ }
+ } else {
+
+ failed = 1;
+ }
+
+ } else {
+ /* T(("No level 0 found for %d\n", chunk)); */
+ }
+ }
+
+ return failed ? YAFFS_FAIL : YAFFS_OK;
+#else
+ in=in;
+ return YAFFS_OK;
+#endif
+}
diff --git a/fs/yaffs2/yaffs_verify.h b/fs/yaffs2/yaffs_verify.h
new file mode 100644
index 00000000..3dbcefd1
--- /dev/null
+++ b/fs/yaffs2/yaffs_verify.h
@@ -0,0 +1,41 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2010 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_VERIFY_H__
+#define __YAFFS_VERIFY_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n);
+void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n);
+void yaffs_VerifyBlocks(yaffs_Device *dev);
+
+void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck);
+void yaffs_VerifyFile(yaffs_Object *obj);
+void yaffs_VerifyHardLink(yaffs_Object *obj);
+void yaffs_VerifySymlink(yaffs_Object *obj);
+void yaffs_VerifySpecial(yaffs_Object *obj);
+void yaffs_VerifyObject(yaffs_Object *obj);
+void yaffs_VerifyObjects(yaffs_Device *dev);
+void yaffs_VerifyObjectInDirectory(yaffs_Object *obj);
+void yaffs_VerifyDirectory(yaffs_Object *directory);
+void yaffs_VerifyFreeChunks(yaffs_Device *dev);
+
+int yaffs_VerifyFileSanity(yaffs_Object *obj);
+
+int yaffs_SkipVerification(yaffs_Device *dev);
+
+#endif
+
diff --git a/fs/yaffs2/yaffs_vfs_glue.c b/fs/yaffs2/yaffs_vfs_glue.c
new file mode 100644
index 00000000..c61da67d
--- /dev/null
+++ b/fs/yaffs2/yaffs_vfs_glue.c
@@ -0,0 +1,3577 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2010 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning
+ * Acknowledgements:
+ * Luc van OostenRyck for numerous patches.
+ * Nick Bane for numerous patches.
+ * Nick Bane for 2.5/2.6 integration.
+ * Andras Toth for mknod rdev issue.
+ * Michael Fischer for finding the problem with inode inconsistency.
+ * Some code bodily lifted from JFFS
+ *
+ * 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 is the file system front-end to YAFFS that hooks it up to
+ * the VFS.
+ *
+ * Special notes:
+ * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with
+ * this superblock
+ * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this
+ * superblock
+ * >> inode->u.generic_ip points to the associated yaffs_Object.
+ */
+
+/*
+ * There are two variants of the VFS glue code. This variant should compile
+ * for any version of Linux.
+ */
+#include
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
+#define YAFFS_COMPILE_BACKGROUND
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6, 23))
+#define YAFFS_COMPILE_FREEZER
+#endif
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
+#define YAFFS_COMPILE_EXPORTFS
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
+#define YAFFS_USE_SETATTR_COPY
+#define YAFFS_USE_TRUNCATE_SETSIZE
+#endif
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
+#define YAFFS_HAS_EVICT_INODE
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
+#define YAFFS_NEW_FOLLOW_LINK 1
+#else
+#define YAFFS_NEW_FOLLOW_LINK 0
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
+#include
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+#include
+#endif
+
+#ifdef YAFFS_COMPILE_EXPORTFS
+#include
+#endif
+
+#ifdef YAFFS_COMPILE_BACKGROUND
+#include
+#include
+#endif
+#ifdef YAFFS_COMPILE_FREEZER
+#include
+#endif
+
+#include
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+
+#include
+
+#define UnlockPage(p) unlock_page(p)
+#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
+
+/* FIXME: use sb->s_id instead ? */
+#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
+
+#else
+
+#include
+#define BDEVNAME_SIZE 0
+#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
+/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
+#define __user
+#endif
+
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
+#define YPROC_ROOT (&proc_root)
+#else
+#define YPROC_ROOT NULL
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26))
+#define Y_INIT_TIMER(a) init_timer(a)
+#else
+#define Y_INIT_TIMER(a) init_timer_on_stack(a)
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+#define WRITE_SIZE_STR "writesize"
+#define WRITE_SIZE(mtd) ((mtd)->writesize)
+#else
+#define WRITE_SIZE_STR "oobblock"
+#define WRITE_SIZE(mtd) ((mtd)->oobblock)
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
+#define YAFFS_USE_WRITE_BEGIN_END 1
+#else
+#define YAFFS_USE_WRITE_BEGIN_END 0
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
+static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
+{
+ uint64_t result = partition_size;
+ do_div(result, block_size);
+ return (uint32_t)result;
+}
+#else
+#define YCALCBLOCKS(s, b) ((s)/(b))
+#endif
+
+#include
+#include
+
+#include "yportenv.h"
+#include "yaffs_trace.h"
+#include "yaffs_guts.h"
+
+#include "yaffs_linux.h"
+
+#include "yaffs_mtdif.h"
+#include "yaffs_mtdif1.h"
+#include "yaffs_mtdif2.h"
+
+unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS;
+unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
+unsigned int yaffs_auto_checkpoint = 1;
+unsigned int yaffs_gc_control = 1;
+unsigned int yaffs_bg_enable = 1;
+
+/* Module Parameters */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+module_param(yaffs_traceMask, uint, 0644);
+module_param(yaffs_wr_attempts, uint, 0644);
+module_param(yaffs_auto_checkpoint, uint, 0644);
+module_param(yaffs_gc_control, uint, 0644);
+module_param(yaffs_bg_enable, uint, 0644);
+#else
+MODULE_PARM(yaffs_traceMask, "i");
+MODULE_PARM(yaffs_wr_attempts, "i");
+MODULE_PARM(yaffs_auto_checkpoint, "i");
+MODULE_PARM(yaffs_gc_control, "i");
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
+/* use iget and read_inode */
+#define Y_IGET(sb, inum) iget((sb), (inum))
+static void yaffs_read_inode(struct inode *inode);
+
+#else
+/* Call local equivalent */
+#define YAFFS_USE_OWN_IGET
+#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
+
+static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
+#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)
+#else
+#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)
+#endif
+
+#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
+#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
+#else
+#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
+#endif
+
+
+#define update_dir_time(dir) do {\
+ (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
+ } while(0)
+
+static void yaffs_put_super(struct super_block *sb);
+
+static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
+ loff_t *pos);
+static ssize_t yaffs_hold_space(struct file *f);
+static void yaffs_release_space(struct file *f);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_file_flush(struct file *file, fl_owner_t id);
+#else
+static int yaffs_file_flush(struct file *file);
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
+static int yaffs_sync_object(struct file *file, int datasync);
+#else
+static int yaffs_sync_object(struct file *file, struct dentry *dentry,
+ int datasync);
+#endif
+
+static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
+ struct nameidata *n);
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
+ struct nameidata *n);
+#else
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
+#endif
+static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
+ struct dentry *dentry);
+static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
+static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
+ const char *symname);
+static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+ dev_t dev);
+#else
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+ int dev);
+#endif
+static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry);
+static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_sync_fs(struct super_block *sb, int wait);
+static void yaffs_write_super(struct super_block *sb);
+#else
+static int yaffs_sync_fs(struct super_block *sb);
+static int yaffs_write_super(struct super_block *sb);
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
+#else
+static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
+#endif
+
+#ifdef YAFFS_HAS_PUT_INODE
+static void yaffs_put_inode(struct inode *inode);
+#endif
+
+#ifdef YAFFS_HAS_EVICT_INODE
+static void yaffs_evict_inode(struct inode *);
+#else
+static void yaffs_delete_inode(struct inode *);
+static void yaffs_clear_inode(struct inode *);
+#endif
+
+static int yaffs_readpage(struct file *file, struct page *page);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
+#else
+static int yaffs_writepage(struct page *page);
+#endif
+
+#ifdef CONFIG_YAFFS_XATTR
+int yaffs_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags);
+ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
+ size_t size);
+int yaffs_removexattr(struct dentry *dentry, const char *name);
+ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size);
+#endif
+
+
+#if (YAFFS_USE_WRITE_BEGIN_END != 0)
+static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned flags,
+ struct page **pagep, void **fsdata);
+static int yaffs_write_end(struct file *filp, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *pg, void *fsdadata);
+#else
+static int yaffs_prepare_write(struct file *f, struct page *pg,
+ unsigned offset, unsigned to);
+static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
+ unsigned to);
+
+#endif
+
+static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
+ int buflen);
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias);
+static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
+#else
+static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
+#endif
+
+static void yaffs_MarkSuperBlockDirty(yaffs_Device *dev);
+
+static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin);
+
+static int yaffs_vfs_setattr(struct inode *, struct iattr *);
+
+
+static struct address_space_operations yaffs_file_address_operations = {
+ .readpage = yaffs_readpage,
+ .writepage = yaffs_writepage,
+#if (YAFFS_USE_WRITE_BEGIN_END > 0)
+ .write_begin = yaffs_write_begin,
+ .write_end = yaffs_write_end,
+#else
+ .prepare_write = yaffs_prepare_write,
+ .commit_write = yaffs_commit_write,
+#endif
+};
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
+static const struct file_operations yaffs_file_operations = {
+ .read = do_sync_read,
+ .write = do_sync_write,
+ .aio_read = generic_file_aio_read,
+ .aio_write = generic_file_aio_write,
+ .mmap = generic_file_mmap,
+ .flush = yaffs_file_flush,
+ .fsync = yaffs_sync_object,
+ .splice_read = generic_file_splice_read,
+ .splice_write = generic_file_splice_write,
+ .llseek = generic_file_llseek,
+};
+
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
+
+static const struct file_operations yaffs_file_operations = {
+ .read = do_sync_read,
+ .write = do_sync_write,
+ .aio_read = generic_file_aio_read,
+ .aio_write = generic_file_aio_write,
+ .mmap = generic_file_mmap,
+ .flush = yaffs_file_flush,
+ .fsync = yaffs_sync_object,
+ .sendfile = generic_file_sendfile,
+};
+
+#else
+
+static const struct file_operations yaffs_file_operations = {
+ .read = generic_file_read,
+ .write = generic_file_write,
+ .mmap = generic_file_mmap,
+ .flush = yaffs_file_flush,
+ .fsync = yaffs_sync_object,
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+ .sendfile = generic_file_sendfile,
+#endif
+};
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
+static void zero_user_segment(struct page *page, unsigned start, unsigned end)
+{
+ void * kaddr = kmap_atomic(page, KM_USER0);
+ memset(kaddr + start, 0, end - start);
+ kunmap_atomic(kaddr, KM_USER0);
+ flush_dcache_page(page);
+}
+#endif
+
+
+static const struct inode_operations yaffs_file_inode_operations = {
+ .setattr = yaffs_setattr,
+#ifdef CONFIG_YAFFS_XATTR
+ .setxattr = yaffs_setxattr,
+ .getxattr = yaffs_getxattr,
+ .listxattr = yaffs_listxattr,
+ .removexattr = yaffs_removexattr,
+#endif
+};
+
+static const struct inode_operations yaffs_symlink_inode_operations = {
+ .readlink = yaffs_readlink,
+ .follow_link = yaffs_follow_link,
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+ .put_link = yaffs_put_link,
+#endif
+ .setattr = yaffs_setattr,
+#ifdef CONFIG_YAFFS_XATTR
+ .setxattr = yaffs_setxattr,
+ .getxattr = yaffs_getxattr,
+ .listxattr = yaffs_listxattr,
+ .removexattr = yaffs_removexattr,
+#endif
+};
+
+static const struct inode_operations yaffs_dir_inode_operations = {
+ .create = yaffs_create,
+ .lookup = yaffs_lookup,
+ .link = yaffs_link,
+ .unlink = yaffs_unlink,
+ .symlink = yaffs_symlink,
+ .mkdir = yaffs_mkdir,
+ .rmdir = yaffs_unlink,
+ .mknod = yaffs_mknod,
+ .rename = yaffs_rename,
+ .setattr = yaffs_setattr,
+#ifdef CONFIG_YAFFS_XATTR
+ .setxattr = yaffs_setxattr,
+ .getxattr = yaffs_getxattr,
+ .listxattr = yaffs_listxattr,
+ .removexattr = yaffs_removexattr,
+#endif
+};
+
+static const struct file_operations yaffs_dir_operations = {
+ .read = generic_read_dir,
+ .readdir = yaffs_readdir,
+ .fsync = yaffs_sync_object,
+ .llseek = yaffs_dir_llseek,
+};
+
+static const struct super_operations yaffs_super_ops = {
+ .statfs = yaffs_statfs,
+
+#ifndef YAFFS_USE_OWN_IGET
+ .read_inode = yaffs_read_inode,
+#endif
+#ifdef YAFFS_HAS_PUT_INODE
+ .put_inode = yaffs_put_inode,
+#endif
+ .put_super = yaffs_put_super,
+#ifdef YAFFS_HAS_EVICT_INODE
+ .evict_inode = yaffs_evict_inode,
+#else
+ .delete_inode = yaffs_delete_inode,
+ .clear_inode = yaffs_clear_inode,
+#endif
+ .sync_fs = yaffs_sync_fs,
+ .write_super = yaffs_write_super,
+};
+
+
+static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)
+{
+#ifdef YAFFS_USE_SETATTR_COPY
+ setattr_copy(inode,attr);
+ return 0;
+#else
+ return inode_setattr(inode, attr);
+#endif
+
+}
+
+static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize)
+{
+#ifdef YAFFS_USE_TRUNCATE_SETSIZE
+ truncate_setsize(inode,newsize);
+ return 0;
+#else
+ truncate_inode_pages(&inode->i_data,newsize);
+ return 0;
+#endif
+
+}
+
+static unsigned yaffs_gc_control_callback(yaffs_Device *dev)
+{
+ return yaffs_gc_control;
+}
+
+static void yaffs_GrossLock(yaffs_Device *dev)
+{
+ T(YAFFS_TRACE_LOCK, (TSTR("yaffs locking %p\n"), current));
+ down(&(yaffs_DeviceToLC(dev)->grossLock));
+ T(YAFFS_TRACE_LOCK, (TSTR("yaffs locked %p\n"), current));
+}
+
+static void yaffs_GrossUnlock(yaffs_Device *dev)
+{
+ T(YAFFS_TRACE_LOCK, (TSTR("yaffs unlocking %p\n"), current));
+ up(&(yaffs_DeviceToLC(dev)->grossLock));
+}
+
+#ifdef YAFFS_COMPILE_EXPORTFS
+
+static struct inode *
+yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, uint32_t generation)
+{
+ return Y_IGET(sb, ino);
+}
+
+static struct dentry *
+yaffs2_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
+{
+ return generic_fh_to_dentry(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode) ;
+}
+
+static struct dentry *
+ yaffs2_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
+{
+ return generic_fh_to_parent(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode);
+}
+
+struct dentry *yaffs2_get_parent(struct dentry *dentry)
+{
+
+ struct super_block *sb = dentry->d_inode->i_sb;
+ struct dentry *parent = ERR_PTR(-ENOENT);
+ struct inode *inode;
+ unsigned long parent_ino;
+ yaffs_Object *d_obj;
+ yaffs_Object *parent_obj;
+
+ d_obj = yaffs_InodeToObject(dentry->d_inode);
+
+ if (d_obj) {
+ parent_obj = d_obj->parent;
+ if (parent_obj) {
+ parent_ino = yaffs_GetObjectInode(parent_obj);
+ inode = Y_IGET(sb, parent_ino);
+
+ if (IS_ERR(inode)) {
+ parent = ERR_CAST(inode);
+ } else {
+ parent = d_obtain_alias(inode);
+ if (!IS_ERR(parent)) {
+ parent = ERR_PTR(-ENOMEM);
+ iput(inode);
+ }
+ }
+ }
+ }
+
+ return parent;
+}
+
+/* Just declare a zero structure as a NULL value implies
+ * using the default functions of exportfs.
+ */
+
+static struct export_operations yaffs_export_ops =
+{
+ .fh_to_dentry = yaffs2_fh_to_dentry,
+ .fh_to_parent = yaffs2_fh_to_parent,
+ .get_parent = yaffs2_get_parent,
+} ;
+
+#endif
+
+/*-----------------------------------------------------------------*/
+/* Directory search context allows us to unlock access to yaffs during
+ * filldir without causing problems with the directory being modified.
+ * This is similar to the tried and tested mechanism used in yaffs direct.
+ *
+ * A search context iterates along a doubly linked list of siblings in the
+ * directory. If the iterating object is deleted then this would corrupt
+ * the list iteration, likely causing a crash. The search context avoids
+ * this by using the removeObjectCallback to move the search context to the
+ * next object before the object is deleted.
+ *
+ * Many readdirs (and thus seach conexts) may be alive simulateously so
+ * each yaffs_Device has a list of these.
+ *
+ * A seach context lives for the duration of a readdir.
+ *
+ * All these functions must be called while yaffs is locked.
+ */
+
+struct yaffs_SearchContext {
+ yaffs_Device *dev;
+ yaffs_Object *dirObj;
+ yaffs_Object *nextReturn;
+ struct ylist_head others;
+};
+
+/*
+ * yaffs_NewSearch() creates a new search context, initialises it and
+ * adds it to the device's search context list.
+ *
+ * Called at start of readdir.
+ */
+static struct yaffs_SearchContext * yaffs_NewSearch(yaffs_Object *dir)
+{
+ yaffs_Device *dev = dir->myDev;
+ struct yaffs_SearchContext *sc = YMALLOC(sizeof(struct yaffs_SearchContext));
+ if(sc){
+ sc->dirObj = dir;
+ sc->dev = dev;
+ if( ylist_empty(&sc->dirObj->variant.directoryVariant.children))
+ sc->nextReturn = NULL;
+ else
+ sc->nextReturn = ylist_entry(
+ dir->variant.directoryVariant.children.next,
+ yaffs_Object,siblings);
+ YINIT_LIST_HEAD(&sc->others);
+ ylist_add(&sc->others,&(yaffs_DeviceToLC(dev)->searchContexts));
+ }
+ return sc;
+}
+
+/*
+ * yaffs_EndSearch() disposes of a search context and cleans up.
+ */
+static void yaffs_EndSearch(struct yaffs_SearchContext * sc)
+{
+ if(sc){
+ ylist_del(&sc->others);
+ YFREE(sc);
+ }
+}
+
+/*
+ * yaffs_SearchAdvance() moves a search context to the next object.
+ * Called when the search iterates or when an object removal causes
+ * the search context to be moved to the next object.
+ */
+static void yaffs_SearchAdvance(struct yaffs_SearchContext *sc)
+{
+ if(!sc)
+ return;
+
+ if( sc->nextReturn == NULL ||
+ ylist_empty(&sc->dirObj->variant.directoryVariant.children))
+ sc->nextReturn = NULL;
+ else {
+ struct ylist_head *next = sc->nextReturn->siblings.next;
+
+ if( next == &sc->dirObj->variant.directoryVariant.children)
+ sc->nextReturn = NULL; /* end of list */
+ else
+ sc->nextReturn = ylist_entry(next,yaffs_Object,siblings);
+ }
+}
+
+/*
+ * yaffs_RemoveObjectCallback() is called when an object is unlinked.
+ * We check open search contexts and advance any which are currently
+ * on the object being iterated.
+ */
+static void yaffs_RemoveObjectCallback(yaffs_Object *obj)
+{
+
+ struct ylist_head *i;
+ struct yaffs_SearchContext *sc;
+ struct ylist_head *search_contexts = &(yaffs_DeviceToLC(obj->myDev)->searchContexts);
+
+
+ /* Iterate through the directory search contexts.
+ * If any are currently on the object being removed, then advance
+ * the search context to the next object to prevent a hanging pointer.
+ */
+ ylist_for_each(i, search_contexts) {
+ if (i) {
+ sc = ylist_entry(i, struct yaffs_SearchContext,others);
+ if(sc->nextReturn == obj)
+ yaffs_SearchAdvance(sc);
+ }
+ }
+
+}
+
+
+/*-----------------------------------------------------------------*/
+
+static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
+ int buflen)
+{
+ unsigned char *alias;
+ int ret;
+
+ yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
+
+ yaffs_GrossLock(dev);
+
+ alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
+
+ yaffs_GrossUnlock(dev);
+
+ if (!alias)
+ return -ENOMEM;
+
+ ret = vfs_readlink(dentry, buffer, buflen, alias);
+ kfree(alias);
+ return ret;
+}
+
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
+#else
+static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
+#endif
+{
+ unsigned char *alias;
+ int ret;
+ yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
+
+ yaffs_GrossLock(dev);
+
+ alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
+ yaffs_GrossUnlock(dev);
+
+ if (!alias) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+ nd_set_link(nd, alias);
+ ret = (int)alias;
+out:
+ return ERR_PTR(ret);
+#else
+ ret = vfs_follow_link(nd, alias);
+ kfree(alias);
+out:
+ return ret;
+#endif
+}
+
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias) {
+ kfree(alias);
+}
+#endif
+
+struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
+ yaffs_Object *obj);
+
+/*
+ * Lookup is used to find objects in the fs
+ */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
+ struct nameidata *n)
+#else
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
+#endif
+{
+ yaffs_Object *obj;
+ struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
+
+ yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
+
+ if(current != yaffs_DeviceToLC(dev)->readdirProcess)
+ yaffs_GrossLock(dev);
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_lookup for %d:%s\n"),
+ yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
+
+ obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir),
+ dentry->d_name.name);
+
+ obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */
+
+ /* Can't hold gross lock when calling yaffs_get_inode() */
+ if(current != yaffs_DeviceToLC(dev)->readdirProcess)
+ yaffs_GrossUnlock(dev);
+
+ if (obj) {
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_lookup found %d\n"), obj->objectId));
+
+ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
+
+ if (inode) {
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_loookup dentry \n")));
+/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
+ * d_add even if NULL inode */
+#if 0
+ /*dget(dentry); // try to solve directory bug */
+ d_add(dentry, inode);
+
+ /* return dentry; */
+ return NULL;
+#endif
+ }
+
+ } else {
+ T(YAFFS_TRACE_OS,(TSTR("yaffs_lookup not found\n")));
+
+ }
+
+/* added NCB for 2.5/6 compatability - forces add even if inode is
+ * NULL which creates dentry hash */
+ d_add(dentry, inode);
+
+ return NULL;
+}
+
+
+#ifdef YAFFS_HAS_PUT_INODE
+
+/* For now put inode is just for debugging
+ * Put inode is called when the inode **structure** is put.
+ */
+static void yaffs_put_inode(struct inode *inode)
+{
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_put_inode: ino %d, count %d\n"), (int)inode->i_ino,
+ atomic_read(&inode->i_count)));
+
+}
+#endif
+
+
+static void yaffs_UnstitchObject(struct inode *inode, yaffs_Object *obj)
+{
+ /* Clear the association between the inode and
+ * the yaffs_Object.
+ */
+ obj->myInode = NULL;
+ yaffs_InodeToObjectLV(inode) = NULL;
+
+ /* If the object freeing was deferred, then the real
+ * free happens now.
+ * This should fix the inode inconsistency problem.
+ */
+ yaffs_HandleDeferedFree(obj);
+}
+
+#ifdef YAFFS_HAS_EVICT_INODE
+/* yaffs_evict_inode combines into one operation what was previously done in
+ * yaffs_clear_inode() and yaffs_delete_inode()
+ *
+ */
+static void yaffs_evict_inode( struct inode *inode)
+{
+ yaffs_Object *obj;
+ yaffs_Device *dev;
+ int deleteme = 0;
+
+ obj = yaffs_InodeToObject(inode);
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_evict_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
+ atomic_read(&inode->i_count),
+ obj ? "object exists" : "null object"));
+
+ if (!inode->i_nlink && !is_bad_inode(inode))
+ deleteme = 1;
+ truncate_inode_pages(&inode->i_data,0);
+ end_writeback(inode);
+
+ if(deleteme && obj){
+ dev = obj->myDev;
+ yaffs_GrossLock(dev);
+ yaffs_DeleteObject(obj);
+ yaffs_GrossUnlock(dev);
+ }
+ if (obj) {
+ dev = obj->myDev;
+ yaffs_GrossLock(dev);
+ yaffs_UnstitchObject(inode,obj);
+ yaffs_GrossUnlock(dev);
+ }
+
+
+}
+#else
+
+/* clear is called to tell the fs to release any per-inode data it holds.
+ * The object might still exist on disk and is just being thrown out of the cache
+ * or else the object has actually been deleted and we're being called via
+ * the chain
+ * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
+ */
+
+static void yaffs_clear_inode(struct inode *inode)
+{
+ yaffs_Object *obj;
+ yaffs_Device *dev;
+
+ obj = yaffs_InodeToObject(inode);
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_clear_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
+ atomic_read(&inode->i_count),
+ obj ? "object exists" : "null object"));
+
+ if (obj) {
+ dev = obj->myDev;
+ yaffs_GrossLock(dev);
+ yaffs_UnstitchObject(inode,obj);
+ yaffs_GrossUnlock(dev);
+ }
+
+}
+
+/* delete is called when the link count is zero and the inode
+ * is put (ie. nobody wants to know about it anymore, time to
+ * delete the file).
+ * NB Must call clear_inode()
+ */
+static void yaffs_delete_inode(struct inode *inode)
+{
+ yaffs_Object *obj = yaffs_InodeToObject(inode);
+ yaffs_Device *dev;
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_delete_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
+ atomic_read(&inode->i_count),
+ obj ? "object exists" : "null object"));
+
+ if (obj) {
+ dev = obj->myDev;
+ yaffs_GrossLock(dev);
+ yaffs_DeleteObject(obj);
+ yaffs_GrossUnlock(dev);
+ }
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
+ truncate_inode_pages(&inode->i_data, 0);
+#endif
+ clear_inode(inode);
+}
+#endif
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_file_flush(struct file *file, fl_owner_t id)
+#else
+static int yaffs_file_flush(struct file *file)
+#endif
+{
+ yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
+
+ yaffs_Device *dev = obj->myDev;
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_file_flush object %d (%s)\n"), obj->objectId,
+ obj->dirty ? "dirty" : "clean"));
+
+ yaffs_GrossLock(dev);
+
+ yaffs_FlushFile(obj, 1, 0);
+
+ yaffs_GrossUnlock(dev);
+
+ return 0;
+}
+
+static int yaffs_readpage_nolock(struct file *f, struct page *pg)
+{
+ /* Lifted from jffs2 */
+
+ yaffs_Object *obj;
+ unsigned char *pg_buf;
+ int ret;
+
+ yaffs_Device *dev;
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_readpage_nolock at %08x, size %08x\n"),
+ (unsigned)(pg->index << PAGE_CACHE_SHIFT),
+ (unsigned)PAGE_CACHE_SIZE));
+
+ obj = yaffs_DentryToObject(f->f_dentry);
+
+ dev = obj->myDev;
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+ BUG_ON(!PageLocked(pg));
+#else
+ if (!PageLocked(pg))
+ PAGE_BUG(pg);
+#endif
+
+ pg_buf = kmap(pg);
+ /* FIXME: Can kmap fail? */
+
+ yaffs_GrossLock(dev);
+
+ ret = yaffs_ReadDataFromFile(obj, pg_buf,
+ pg->index << PAGE_CACHE_SHIFT,
+ PAGE_CACHE_SIZE);
+
+ yaffs_GrossUnlock(dev);
+
+ if (ret >= 0)
+ ret = 0;
+
+ if (ret) {
+ ClearPageUptodate(pg);
+ SetPageError(pg);
+ } else {
+ SetPageUptodate(pg);
+ ClearPageError(pg);
+ }
+
+ flush_dcache_page(pg);
+ kunmap(pg);
+
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage_nolock done\n")));
+ return ret;
+}
+
+static int yaffs_readpage_unlock(struct file *f, struct page *pg)
+{
+ int ret = yaffs_readpage_nolock(f, pg);
+ UnlockPage(pg);
+ return ret;
+}
+
+static int yaffs_readpage(struct file *f, struct page *pg)
+{
+ int ret;
+
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage\n")));
+ ret=yaffs_readpage_unlock(f, pg);
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage done\n")));
+ return ret;
+}
+
+/* writepage inspired by/stolen from smbfs */
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
+#else
+static int yaffs_writepage(struct page *page)
+#endif
+{
+ yaffs_Device *dev;
+ struct address_space *mapping = page->mapping;
+ struct inode *inode;
+ unsigned long end_index;
+ char *buffer;
+ yaffs_Object *obj;
+ int nWritten = 0;
+ unsigned nBytes;
+ loff_t i_size;
+
+ if (!mapping)
+ BUG();
+ inode = mapping->host;
+ if (!inode)
+ BUG();
+ i_size = i_size_read(inode);
+
+ end_index = i_size >> PAGE_CACHE_SHIFT;
+
+ if(page->index < end_index)
+ nBytes = PAGE_CACHE_SIZE;
+ else {
+ nBytes = i_size & (PAGE_CACHE_SIZE -1);
+
+ if (page->index > end_index || !nBytes) {
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_writepage at %08x, inode size = %08x!!!\n"),
+ (unsigned)(page->index << PAGE_CACHE_SHIFT),
+ (unsigned)inode->i_size));
+ T(YAFFS_TRACE_OS,
+ (TSTR(" -> don't care!!\n")));
+
+ zero_user_segment(page,0,PAGE_CACHE_SIZE);
+ set_page_writeback(page);
+ unlock_page(page);
+ end_page_writeback(page);
+ return 0;
+ }
+ }
+
+ if(nBytes != PAGE_CACHE_SIZE)
+ zero_user_segment(page,nBytes,PAGE_CACHE_SIZE);
+
+ get_page(page);
+
+ buffer = kmap(page);
+
+ obj = yaffs_InodeToObject(inode);
+ dev = obj->myDev;
+ yaffs_GrossLock(dev);
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_writepage at %08x, size %08x\n"),
+ (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
+ T(YAFFS_TRACE_OS,
+ (TSTR("writepag0: obj = %05x, ino = %05x\n"),
+ (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
+
+ nWritten = yaffs_WriteDataToFile(obj, buffer,
+ page->index << PAGE_CACHE_SHIFT, nBytes, 0);
+
+ yaffs_MarkSuperBlockDirty(dev);
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("writepag1: obj = %05x, ino = %05x\n"),
+ (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
+
+ yaffs_GrossUnlock(dev);
+
+ kunmap(page);
+ set_page_writeback(page);
+ unlock_page(page);
+ end_page_writeback(page);
+ put_page(page);
+
+ return (nWritten == nBytes) ? 0 : -ENOSPC;
+}
+
+
+#if (YAFFS_USE_WRITE_BEGIN_END > 0)
+static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned flags,
+ struct page **pagep, void **fsdata)
+{
+ struct page *pg = NULL;
+ pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+
+ int ret = 0;
+ int space_held = 0;
+
+ /* Get a page */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
+ pg = grab_cache_page_write_begin(mapping, index, flags);
+#else
+ pg = __grab_cache_page(mapping, index);
+#endif
+
+ *pagep = pg;
+ if (!pg) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ T(YAFFS_TRACE_OS,
+ (TSTR("start yaffs_write_begin index %d(%x) uptodate %d\n"),
+ (int)index,(int)index,Page_Uptodate(pg) ? 1 : 0));
+
+ /* Get fs space */
+ space_held = yaffs_hold_space(filp);
+
+ if (!space_held) {
+ ret = -ENOSPC;
+ goto out;
+ }
+
+ /* Update page if required */
+
+ if (!Page_Uptodate(pg))
+ ret = yaffs_readpage_nolock(filp, pg);
+
+ if (ret)
+ goto out;
+
+ /* Happy path return */
+ T(YAFFS_TRACE_OS, (TSTR("end yaffs_write_begin - ok\n")));
+
+ return 0;
+
+out:
+ T(YAFFS_TRACE_OS,
+ (TSTR("end yaffs_write_begin fail returning %d\n"), ret));
+ if (space_held)
+ yaffs_release_space(filp);
+ if (pg) {
+ unlock_page(pg);
+ page_cache_release(pg);
+ }
+ return ret;
+}
+
+#else
+
+static int yaffs_prepare_write(struct file *f, struct page *pg,
+ unsigned offset, unsigned to)
+{
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_prepair_write\n")));
+
+ if (!Page_Uptodate(pg))
+ return yaffs_readpage_nolock(f, pg);
+ return 0;
+}
+#endif
+
+#if (YAFFS_USE_WRITE_BEGIN_END > 0)
+static int yaffs_write_end(struct file *filp, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *pg, void *fsdadata)
+{
+ int ret = 0;
+ void *addr, *kva;
+ uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
+
+ kva = kmap(pg);
+ addr = kva + offset_into_page;
+
+ T(YAFFS_TRACE_OS,
+ ("yaffs_write_end addr %p pos %x nBytes %d\n",
+ addr,(unsigned)pos, copied));
+
+ ret = yaffs_file_write(filp, addr, copied, &pos);
+
+ if (ret != copied) {
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_write_end not same size ret %d copied %d\n"),
+ ret, copied));
+ SetPageError(pg);
+ } else {
+ /* Nothing */
+ }
+
+ kunmap(pg);
+
+ yaffs_release_space(filp);
+ unlock_page(pg);
+ page_cache_release(pg);
+ return ret;
+}
+#else
+
+static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
+ unsigned to)
+{
+ void *addr, *kva;
+
+ loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
+ int nBytes = to - offset;
+ int nWritten;
+
+ unsigned spos = pos;
+ unsigned saddr;
+
+ kva = kmap(pg);
+ addr = kva + offset;
+
+ saddr = (unsigned) addr;
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_commit_write addr %x pos %x nBytes %d\n"),
+ saddr, spos, nBytes));
+
+ nWritten = yaffs_file_write(f, addr, nBytes, &pos);
+
+ if (nWritten != nBytes) {
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_commit_write not same size nWritten %d nBytes %d\n"),
+ nWritten, nBytes));
+ SetPageError(pg);
+ } else {
+ /* Nothing */
+ }
+
+ kunmap(pg);
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_commit_write returning %d\n"),
+ nWritten == nBytes ? 0 : nWritten));
+
+ return nWritten == nBytes ? 0 : nWritten;
+}
+#endif
+
+
+static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
+{
+ if (inode && obj) {
+
+
+ /* Check mode against the variant type and attempt to repair if broken. */
+ __u32 mode = obj->yst_mode;
+ switch (obj->variantType) {
+ case YAFFS_OBJECT_TYPE_FILE:
+ if (!S_ISREG(mode)) {
+ obj->yst_mode &= ~S_IFMT;
+ obj->yst_mode |= S_IFREG;
+ }
+
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ if (!S_ISLNK(mode)) {
+ obj->yst_mode &= ~S_IFMT;
+ obj->yst_mode |= S_IFLNK;
+ }
+
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ if (!S_ISDIR(mode)) {
+ obj->yst_mode &= ~S_IFMT;
+ obj->yst_mode |= S_IFDIR;
+ }
+
+ break;
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ default:
+ /* TODO? */
+ break;
+ }
+
+ inode->i_flags |= S_NOATIME;
+
+ inode->i_ino = obj->objectId;
+ inode->i_mode = obj->yst_mode;
+ inode->i_uid = obj->yst_uid;
+ inode->i_gid = obj->yst_gid;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
+ inode->i_blksize = inode->i_sb->s_blocksize;
+#endif
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+
+ inode->i_rdev = old_decode_dev(obj->yst_rdev);
+ inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
+ inode->i_atime.tv_nsec = 0;
+ inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
+ inode->i_mtime.tv_nsec = 0;
+ inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
+ inode->i_ctime.tv_nsec = 0;
+#else
+ inode->i_rdev = obj->yst_rdev;
+ inode->i_atime = obj->yst_atime;
+ inode->i_mtime = obj->yst_mtime;
+ inode->i_ctime = obj->yst_ctime;
+#endif
+ inode->i_size = yaffs_GetObjectFileLength(obj);
+ inode->i_blocks = (inode->i_size + 511) >> 9;
+
+ inode->i_nlink = yaffs_GetObjectLinkCount(obj);
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n"),
+ inode->i_mode, inode->i_uid, inode->i_gid,
+ (int)inode->i_size, atomic_read(&inode->i_count)));
+
+ switch (obj->yst_mode & S_IFMT) {
+ default: /* fifo, device or socket */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+ init_special_inode(inode, obj->yst_mode,
+ old_decode_dev(obj->yst_rdev));
+#else
+ init_special_inode(inode, obj->yst_mode,
+ (dev_t) (obj->yst_rdev));
+#endif
+ break;
+ case S_IFREG: /* file */
+ inode->i_op = &yaffs_file_inode_operations;
+ inode->i_fop = &yaffs_file_operations;
+ inode->i_mapping->a_ops =
+ &yaffs_file_address_operations;
+ break;
+ case S_IFDIR: /* directory */
+ inode->i_op = &yaffs_dir_inode_operations;
+ inode->i_fop = &yaffs_dir_operations;
+ break;
+ case S_IFLNK: /* symlink */
+ inode->i_op = &yaffs_symlink_inode_operations;
+ break;
+ }
+
+ yaffs_InodeToObjectLV(inode) = obj;
+
+ obj->myInode = inode;
+
+ } else {
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_FileInode invalid parameters\n")));
+ }
+
+}
+
+struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
+ yaffs_Object *obj)
+{
+ struct inode *inode;
+
+ if (!sb) {
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_get_inode for NULL super_block!!\n")));
+ return NULL;
+
+ }
+
+ if (!obj) {
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_get_inode for NULL object!!\n")));
+ return NULL;
+
+ }
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_get_inode for object %d\n"), obj->objectId));
+
+ inode = Y_IGET(sb, obj->objectId);
+ if (IS_ERR(inode))
+ return NULL;
+
+ /* NB Side effect: iget calls back to yaffs_read_inode(). */
+ /* iget also increments the inode's i_count */
+ /* NB You can't be holding grossLock or deadlock will happen! */
+
+ return inode;
+}
+
+static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
+ loff_t *pos)
+{
+ yaffs_Object *obj;
+ int nWritten, ipos;
+ struct inode *inode;
+ yaffs_Device *dev;
+
+ obj = yaffs_DentryToObject(f->f_dentry);
+
+ dev = obj->myDev;
+
+ yaffs_GrossLock(dev);
+
+ inode = f->f_dentry->d_inode;
+
+ if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
+ ipos = inode->i_size;
+ else
+ ipos = *pos;
+
+ if (!obj)
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_file_write: hey obj is null!\n")));
+ else
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_file_write about to write writing %u(%x) bytes"
+ "to object %d at %d(%x)\n"),
+ (unsigned) n, (unsigned) n, obj->objectId, ipos,ipos));
+
+ nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
+
+ yaffs_MarkSuperBlockDirty(dev);
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_file_write: %d(%x) bytes written\n"),
+ (unsigned )n,(unsigned)n));
+
+ if (nWritten > 0) {
+ ipos += nWritten;
+ *pos = ipos;
+ if (ipos > inode->i_size) {
+ inode->i_size = ipos;
+ inode->i_blocks = (ipos + 511) >> 9;
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_file_write size updated to %d bytes, "
+ "%d blocks\n"),
+ ipos, (int)(inode->i_blocks)));
+ }
+
+ }
+ yaffs_GrossUnlock(dev);
+ return (nWritten == 0) && (n > 0) ? -ENOSPC : nWritten;
+}
+
+/* Space holding and freeing is done to ensure we have space available for write_begin/end */
+/* For now we just assume few parallel writes and check against a small number. */
+/* Todo: need to do this with a counter to handle parallel reads better */
+
+static ssize_t yaffs_hold_space(struct file *f)
+{
+ yaffs_Object *obj;
+ yaffs_Device *dev;
+
+ int nFreeChunks;
+
+
+ obj = yaffs_DentryToObject(f->f_dentry);
+
+ dev = obj->myDev;
+
+ yaffs_GrossLock(dev);
+
+ nFreeChunks = yaffs_GetNumberOfFreeChunks(dev);
+
+ yaffs_GrossUnlock(dev);
+
+ return (nFreeChunks > 20) ? 1 : 0;
+}
+
+static void yaffs_release_space(struct file *f)
+{
+ yaffs_Object *obj;
+ yaffs_Device *dev;
+
+
+ obj = yaffs_DentryToObject(f->f_dentry);
+
+ dev = obj->myDev;
+
+ yaffs_GrossLock(dev);
+
+
+ yaffs_GrossUnlock(dev);
+}
+
+
+static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin)
+{
+ long long retval;
+
+ lock_kernel();
+
+ switch (origin){
+ case 2:
+ offset += i_size_read(file->f_path.dentry->d_inode);
+ break;
+ case 1:
+ offset += file->f_pos;
+ }
+ retval = -EINVAL;
+
+ if (offset >= 0){
+ if (offset != file->f_pos)
+ file->f_pos = offset;
+
+ retval = offset;
+ }
+ unlock_kernel();
+ return retval;
+}
+
+
+static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
+{
+ yaffs_Object *obj;
+ yaffs_Device *dev;
+ struct yaffs_SearchContext *sc;
+ struct inode *inode = f->f_dentry->d_inode;
+ unsigned long offset, curoffs;
+ yaffs_Object *l;
+ int retVal = 0;
+
+ char name[YAFFS_MAX_NAME_LENGTH + 1];
+
+ obj = yaffs_DentryToObject(f->f_dentry);
+ dev = obj->myDev;
+
+ yaffs_GrossLock(dev);
+
+ yaffs_DeviceToLC(dev)->readdirProcess = current;
+
+ offset = f->f_pos;
+
+ sc = yaffs_NewSearch(obj);
+ if(!sc){
+ retVal = -ENOMEM;
+ goto out;
+ }
+
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_readdir: starting at %d\n"), (int)offset));
+
+ if (offset == 0) {
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_readdir: entry . ino %d \n"),
+ (int)inode->i_ino));
+ yaffs_GrossUnlock(dev);
+ if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0){
+ yaffs_GrossLock(dev);
+ goto out;
+ }
+ yaffs_GrossLock(dev);
+ offset++;
+ f->f_pos++;
+ }
+ if (offset == 1) {
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_readdir: entry .. ino %d \n"),
+ (int)f->f_dentry->d_parent->d_inode->i_ino));
+ yaffs_GrossUnlock(dev);
+ if (filldir(dirent, "..", 2, offset,
+ f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0){
+ yaffs_GrossLock(dev);
+ goto out;
+ }
+ yaffs_GrossLock(dev);
+ offset++;
+ f->f_pos++;
+ }
+
+ curoffs = 1;
+
+ /* If the directory has changed since the open or last call to
+ readdir, rewind to after the 2 canned entries. */
+ if (f->f_version != inode->i_version) {
+ offset = 2;
+ f->f_pos = offset;
+ f->f_version = inode->i_version;
+ }
+
+ while(sc->nextReturn){
+ curoffs++;
+ l = sc->nextReturn;
+ if (curoffs >= offset) {
+ int this_inode = yaffs_GetObjectInode(l);
+ int this_type = yaffs_GetObjectType(l);
+
+ yaffs_GetObjectName(l, name,
+ YAFFS_MAX_NAME_LENGTH + 1);
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_readdir: %s inode %d\n"),
+ name, yaffs_GetObjectInode(l)));
+
+ yaffs_GrossUnlock(dev);
+
+ if (filldir(dirent,
+ name,
+ strlen(name),
+ offset,
+ this_inode,
+ this_type) < 0){
+ yaffs_GrossLock(dev);
+ goto out;
+ }
+
+ yaffs_GrossLock(dev);
+
+ offset++;
+ f->f_pos++;
+ }
+ yaffs_SearchAdvance(sc);
+ }
+
+out:
+ yaffs_EndSearch(sc);
+ yaffs_DeviceToLC(dev)->readdirProcess = NULL;
+ yaffs_GrossUnlock(dev);
+
+ return retVal;
+}
+
+
+
+/*
+ * File creation. Allocate an inode, and we're done..
+ */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
+#define YCRED(x) x
+#else
+#define YCRED(x) (x->cred)
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+ dev_t rdev)
+#else
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+ int rdev)
+#endif
+{
+ struct inode *inode;
+
+ yaffs_Object *obj = NULL;
+ yaffs_Device *dev;
+
+ yaffs_Object *parent = yaffs_InodeToObject(dir);
+
+ int error = -ENOSPC;
+ uid_t uid = YCRED(current)->fsuid;
+ gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+
+ if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
+ mode |= S_ISGID;
+
+ if (parent) {
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_mknod: parent object %d type %d\n"),
+ parent->objectId, parent->variantType));
+ } else {
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_mknod: could not get parent object\n")));
+ return -EPERM;
+ }
+
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making oject for %s, "
+ "mode %x dev %x\n"),
+ dentry->d_name.name, mode, rdev));
+
+ dev = parent->myDev;
+
+ yaffs_GrossLock(dev);
+
+ switch (mode & S_IFMT) {
+ default:
+ /* Special (socket, fifo, device...) */
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making special\n")));
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+ obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
+ gid, old_encode_dev(rdev));
+#else
+ obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
+ gid, rdev);
+#endif
+ break;
+ case S_IFREG: /* file */
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making file\n")));
+ obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
+ gid);
+ break;
+ case S_IFDIR: /* directory */
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_mknod: making directory\n")));
+ obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
+ uid, gid);
+ break;
+ case S_IFLNK: /* symlink */
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making symlink\n")));
+ obj = NULL; /* Do we ever get here? */
+ break;
+ }
+
+ /* Can not call yaffs_get_inode() with gross lock held */
+ yaffs_GrossUnlock(dev);
+
+ if (obj) {
+ inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
+ d_instantiate(dentry, inode);
+ update_dir_time(dir);
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_mknod created object %d count = %d\n"),
+ obj->objectId, atomic_read(&inode->i_count)));
+ error = 0;
+ yaffs_FillInodeFromObject(dir,parent);
+ } else {
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_mknod failed making object\n")));
+ error = -ENOMEM;
+ }
+
+ return error;
+}
+
+static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+ int retVal;
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_mkdir\n")));
+ retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
+ return retVal;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
+ struct nameidata *n)
+#else
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
+#endif
+{
+ T(YAFFS_TRACE_OS,(TSTR("yaffs_create\n")));
+ return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
+}
+
+static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
+{
+ int retVal;
+
+ yaffs_Device *dev;
+ yaffs_Object *obj;
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_unlink %d:%s\n"),
+ (int)(dir->i_ino),
+ dentry->d_name.name));
+ obj = yaffs_InodeToObject(dir);
+ dev = obj->myDev;
+
+ yaffs_GrossLock(dev);
+
+ retVal = yaffs_Unlink(obj, dentry->d_name.name);
+
+ if (retVal == YAFFS_OK) {
+ dentry->d_inode->i_nlink--;
+ dir->i_version++;
+ yaffs_GrossUnlock(dev);
+ mark_inode_dirty(dentry->d_inode);
+ update_dir_time(dir);
+ return 0;
+ }
+ yaffs_GrossUnlock(dev);
+ return -ENOTEMPTY;
+}
+
+/*
+ * Create a link...
+ */
+static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
+ struct dentry *dentry)
+{
+ struct inode *inode = old_dentry->d_inode;
+ yaffs_Object *obj = NULL;
+ yaffs_Object *link = NULL;
+ yaffs_Device *dev;
+
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_link\n")));
+
+ obj = yaffs_InodeToObject(inode);
+ dev = obj->myDev;
+
+ yaffs_GrossLock(dev);
+
+ if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
+ link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
+ obj);
+
+ if (link) {
+ old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
+ d_instantiate(dentry, old_dentry->d_inode);
+ atomic_inc(&old_dentry->d_inode->i_count);
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_link link count %d i_count %d\n"),
+ old_dentry->d_inode->i_nlink,
+ atomic_read(&old_dentry->d_inode->i_count)));
+ }
+
+ yaffs_GrossUnlock(dev);
+
+ if (link){
+ update_dir_time(dir);
+ return 0;
+ }
+
+ return -EPERM;
+}
+
+static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
+ const char *symname)
+{
+ yaffs_Object *obj;
+ yaffs_Device *dev;
+ uid_t uid = YCRED(current)->fsuid;
+ gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_symlink\n")));
+
+ dev = yaffs_InodeToObject(dir)->myDev;
+ yaffs_GrossLock(dev);
+ obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
+ S_IFLNK | S_IRWXUGO, uid, gid, symname);
+ yaffs_GrossUnlock(dev);
+
+ if (obj) {
+ struct inode *inode;
+
+ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
+ d_instantiate(dentry, inode);
+ update_dir_time(dir);
+ T(YAFFS_TRACE_OS, (TSTR("symlink created OK\n")));
+ return 0;
+ } else {
+ T(YAFFS_TRACE_OS, (TSTR("symlink not created\n")));
+ }
+
+ return -ENOMEM;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
+static int yaffs_sync_object(struct file *file, int datasync)
+#else
+static int yaffs_sync_object(struct file *file, struct dentry *dentry,
+ int datasync)
+#endif
+{
+
+ yaffs_Object *obj;
+ yaffs_Device *dev;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
+ struct dentry *dentry = file->f_path.dentry;
+#endif
+
+ obj = yaffs_DentryToObject(dentry);
+
+ dev = obj->myDev;
+
+ T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
+ (TSTR("yaffs_sync_object\n")));
+ yaffs_GrossLock(dev);
+ yaffs_FlushFile(obj, 1, datasync);
+ yaffs_GrossUnlock(dev);
+ return 0;
+}
+
+/*
+ * The VFS layer already does all the dentry stuff for rename.
+ *
+ * NB: POSIX says you can rename an object over an old object of the same name
+ */
+static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
+{
+ yaffs_Device *dev;
+ int retVal = YAFFS_FAIL;
+ yaffs_Object *target;
+
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_rename\n")));
+ dev = yaffs_InodeToObject(old_dir)->myDev;
+
+ yaffs_GrossLock(dev);
+
+ /* Check if the target is an existing directory that is not empty. */
+ target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
+ new_dentry->d_name.name);
+
+
+
+ if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
+ !ylist_empty(&target->variant.directoryVariant.children)) {
+
+ T(YAFFS_TRACE_OS, (TSTR("target is non-empty dir\n")));
+
+ retVal = YAFFS_FAIL;
+ } else {
+ /* Now does unlinking internally using shadowing mechanism */
+ T(YAFFS_TRACE_OS, (TSTR("calling yaffs_RenameObject\n")));
+
+ retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir),
+ old_dentry->d_name.name,
+ yaffs_InodeToObject(new_dir),
+ new_dentry->d_name.name);
+ }
+ yaffs_GrossUnlock(dev);
+
+ if (retVal == YAFFS_OK) {
+ if (target) {
+ new_dentry->d_inode->i_nlink--;
+ mark_inode_dirty(new_dentry->d_inode);
+ }
+
+ update_dir_time(old_dir);
+ if(old_dir != new_dir)
+ update_dir_time(new_dir);
+ return 0;
+ } else {
+ return -ENOTEMPTY;
+ }
+}
+
+static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct inode *inode = dentry->d_inode;
+ int error = 0;
+ yaffs_Device *dev;
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_setattr of object %d\n"),
+ yaffs_InodeToObject(inode)->objectId));
+
+ /* Fail if a requested resize >= 2GB */
+ if (attr->ia_valid & ATTR_SIZE &&
+ (attr->ia_size >> 31))
+ error = -EINVAL;
+
+ if (error == 0)
+ error = inode_change_ok(inode, attr);
+ if (error == 0) {
+ int result;
+ if (!error){
+ error = yaffs_vfs_setattr(inode, attr);
+ T(YAFFS_TRACE_OS,(TSTR("inode_setattr called\n")));
+ if (attr->ia_valid & ATTR_SIZE){
+ yaffs_vfs_setsize(inode,attr->ia_size);
+ inode->i_blocks = (inode->i_size + 511) >> 9;
+ }
+ }
+ dev = yaffs_InodeToObject(inode)->myDev;
+ if (attr->ia_valid & ATTR_SIZE){
+ T(YAFFS_TRACE_OS,(TSTR("resize to %d(%x)\n"),
+ (int)(attr->ia_size),(int)(attr->ia_size)));
+ }
+ yaffs_GrossLock(dev);
+ result = yaffs_SetAttributes(yaffs_InodeToObject(inode), attr);
+ if(result == YAFFS_OK) {
+ error = 0;
+ } else {
+ error = -EPERM;
+ }
+ yaffs_GrossUnlock(dev);
+
+ }
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_setattr done returning %d\n"),error));
+
+ return error;
+}
+
+#ifdef CONFIG_YAFFS_XATTR
+int yaffs_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
+{
+ struct inode *inode = dentry->d_inode;
+ int error = 0;
+ yaffs_Device *dev;
+ yaffs_Object *obj = yaffs_InodeToObject(inode);
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_setxattr of object %d\n"),
+ obj->objectId));
+
+
+ if (error == 0) {
+ int result;
+ dev = obj->myDev;
+ yaffs_GrossLock(dev);
+ result = yaffs_SetXAttribute(obj, name, value, size, flags);
+ if(result == YAFFS_OK)
+ error = 0;
+ else if(result < 0)
+ error = result;
+ yaffs_GrossUnlock(dev);
+
+ }
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_setxattr done returning %d\n"),error));
+
+ return error;
+}
+
+
+ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
+ size_t size)
+{
+ struct inode *inode = dentry->d_inode;
+ int error = 0;
+ yaffs_Device *dev;
+ yaffs_Object *obj = yaffs_InodeToObject(inode);
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_getxattr \"%s\" from object %d\n"),
+ name, obj->objectId));
+
+ if (error == 0) {
+ dev = obj->myDev;
+ yaffs_GrossLock(dev);
+ error = yaffs_GetXAttribute(obj, name, buff, size);
+ yaffs_GrossUnlock(dev);
+
+ }
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_getxattr done returning %d\n"),error));
+
+ return error;
+}
+
+int yaffs_removexattr(struct dentry *dentry, const char *name)
+{
+ struct inode *inode = dentry->d_inode;
+ int error = 0;
+ yaffs_Device *dev;
+ yaffs_Object *obj = yaffs_InodeToObject(inode);
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_removexattr of object %d\n"),
+ obj->objectId));
+
+
+ if (error == 0) {
+ int result;
+ dev = obj->myDev;
+ yaffs_GrossLock(dev);
+ result = yaffs_RemoveXAttribute(obj, name);
+ if(result == YAFFS_OK)
+ error = 0;
+ else if(result < 0)
+ error = result;
+ yaffs_GrossUnlock(dev);
+
+ }
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_removexattr done returning %d\n"),error));
+
+ return error;
+}
+
+ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size)
+{
+ struct inode *inode = dentry->d_inode;
+ int error = 0;
+ yaffs_Device *dev;
+ yaffs_Object *obj = yaffs_InodeToObject(inode);
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_listxattr of object %d\n"),
+ obj->objectId));
+
+
+ if (error == 0) {
+ dev = obj->myDev;
+ yaffs_GrossLock(dev);
+ error = yaffs_ListXAttributes(obj, buff, size);
+ yaffs_GrossUnlock(dev);
+
+ }
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_listxattr done returning %d\n"),error));
+
+ return error;
+}
+
+#endif
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+ yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
+ struct super_block *sb = dentry->d_sb;
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
+{
+ yaffs_Device *dev = yaffs_SuperToDevice(sb);
+#else
+static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
+{
+ yaffs_Device *dev = yaffs_SuperToDevice(sb);
+#endif
+
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_statfs\n")));
+
+ yaffs_GrossLock(dev);
+
+ buf->f_type = YAFFS_MAGIC;
+ buf->f_bsize = sb->s_blocksize;
+ buf->f_namelen = 255;
+
+ if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) {
+ /* Do this if chunk size is not a power of 2 */
+
+ uint64_t bytesInDev;
+ uint64_t bytesFree;
+
+ bytesInDev = ((uint64_t)((dev->param.endBlock - dev->param.startBlock + 1))) *
+ ((uint64_t)(dev->param.nChunksPerBlock * dev->nDataBytesPerChunk));
+
+ do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
+ buf->f_blocks = bytesInDev;
+
+ bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
+ ((uint64_t)(dev->nDataBytesPerChunk));
+
+ do_div(bytesFree, sb->s_blocksize);
+
+ buf->f_bfree = bytesFree;
+
+ } else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
+
+ buf->f_blocks =
+ (dev->param.endBlock - dev->param.startBlock + 1) *
+ dev->param.nChunksPerBlock /
+ (sb->s_blocksize / dev->nDataBytesPerChunk);
+ buf->f_bfree =
+ yaffs_GetNumberOfFreeChunks(dev) /
+ (sb->s_blocksize / dev->nDataBytesPerChunk);
+ } else {
+ buf->f_blocks =
+ (dev->param.endBlock - dev->param.startBlock + 1) *
+ dev->param.nChunksPerBlock *
+ (dev->nDataBytesPerChunk / sb->s_blocksize);
+
+ buf->f_bfree =
+ yaffs_GetNumberOfFreeChunks(dev) *
+ (dev->nDataBytesPerChunk / sb->s_blocksize);
+ }
+
+ buf->f_files = 0;
+ buf->f_ffree = 0;
+ buf->f_bavail = buf->f_bfree;
+
+ yaffs_GrossUnlock(dev);
+ return 0;
+}
+
+
+
+static void yaffs_FlushInodes(struct super_block *sb)
+{
+ struct inode *iptr;
+ yaffs_Object *obj;
+
+ list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){
+ obj = yaffs_InodeToObject(iptr);
+ if(obj){
+ T(YAFFS_TRACE_OS, (TSTR("flushing obj %d\n"),
+ obj->objectId));
+ yaffs_FlushFile(obj,1,0);
+ }
+ }
+}
+
+
+static void yaffs_FlushSuperBlock(struct super_block *sb, int do_checkpoint)
+{
+ yaffs_Device *dev = yaffs_SuperToDevice(sb);
+ if(!dev)
+ return;
+
+ yaffs_FlushInodes(sb);
+ yaffs_UpdateDirtyDirectories(dev);
+ yaffs_FlushEntireDeviceCache(dev);
+ if(do_checkpoint)
+ yaffs_CheckpointSave(dev);
+}
+
+
+static unsigned yaffs_bg_gc_urgency(yaffs_Device *dev)
+{
+ unsigned erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
+ struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
+ unsigned scatteredFree = 0; /* Free chunks not in an erased block */
+
+ if(erasedChunks < dev->nFreeChunks)
+ scatteredFree = (dev->nFreeChunks - erasedChunks);
+
+ if(!context->bgRunning)
+ return 0;
+ else if(scatteredFree < (dev->param.nChunksPerBlock * 2))
+ return 0;
+ else if(erasedChunks > dev->nFreeChunks/2)
+ return 0;
+ else if(erasedChunks > dev->nFreeChunks/4)
+ return 1;
+ else
+ return 2;
+}
+
+static int yaffs_do_sync_fs(struct super_block *sb,
+ int request_checkpoint)
+{
+
+ yaffs_Device *dev = yaffs_SuperToDevice(sb);
+ unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
+ unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
+ int do_checkpoint;
+
+ T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
+ (TSTR("yaffs_do_sync_fs: gc-urgency %d %s %s%s\n"),
+ gc_urgent,
+ sb->s_dirt ? "dirty" : "clean",
+ request_checkpoint ? "checkpoint requested" : "no checkpoint",
+ oneshot_checkpoint ? " one-shot" : "" ));
+
+ yaffs_GrossLock(dev);
+ do_checkpoint = ((request_checkpoint && !gc_urgent) ||
+ oneshot_checkpoint) &&
+ !dev->isCheckpointed;
+
+ if (sb->s_dirt || do_checkpoint) {
+ yaffs_FlushSuperBlock(sb, !dev->isCheckpointed && do_checkpoint);
+ sb->s_dirt = 0;
+ if(oneshot_checkpoint)
+ yaffs_auto_checkpoint &= ~4;
+ }
+ yaffs_GrossUnlock(dev);
+
+ return 0;
+}
+
+/*
+ * yaffs background thread functions .
+ * yaffs_BackgroundThread() the thread function
+ * yaffs_BackgroundStart() launches the background thread.
+ * yaffs_BackgroundStop() cleans up the background thread.
+ *
+ * NB:
+ * The thread should only run after the yaffs is initialised
+ * The thread should be stopped before yaffs is unmounted.
+ * The thread should not do any writing while the fs is in read only.
+ */
+
+#ifdef YAFFS_COMPILE_BACKGROUND
+
+void yaffs_background_waker(unsigned long data)
+{
+ wake_up_process((struct task_struct *)data);
+}
+
+static int yaffs_BackgroundThread(void *data)
+{
+ yaffs_Device *dev = (yaffs_Device *)data;
+ struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
+ unsigned long now = jiffies;
+ unsigned long next_dir_update = now;
+ unsigned long next_gc = now;
+ unsigned long expires;
+ unsigned int urgency;
+
+ int gcResult;
+ struct timer_list timer;
+
+ T(YAFFS_TRACE_BACKGROUND,
+ (TSTR("yaffs_background starting for dev %p\n"),
+ (void *)dev));
+
+#ifdef YAFFS_COMPILE_FREEZER
+ set_freezable();
+#endif
+ while(context->bgRunning){
+ T(YAFFS_TRACE_BACKGROUND,
+ (TSTR("yaffs_background\n")));
+
+ if(kthread_should_stop())
+ break;
+
+#ifdef YAFFS_COMPILE_FREEZER
+ if(try_to_freeze())
+ continue;
+#endif
+ yaffs_GrossLock(dev);
+
+ now = jiffies;
+
+ if(time_after(now, next_dir_update) && yaffs_bg_enable){
+ yaffs_UpdateDirtyDirectories(dev);
+ next_dir_update = now + HZ;
+ }
+
+ if(time_after(now,next_gc) && yaffs_bg_enable){
+ if(!dev->isCheckpointed){
+ urgency = yaffs_bg_gc_urgency(dev);
+ gcResult = yaffs_BackgroundGarbageCollect(dev, urgency);
+ if(urgency > 1)
+ next_gc = now + HZ/20+1;
+ else if(urgency > 0)
+ next_gc = now + HZ/10+1;
+ else
+ next_gc = now + HZ * 2;
+ } else /*
+ * gc not running so set to next_dir_update
+ * to cut down on wake ups
+ */
+ next_gc = next_dir_update;
+ }
+ yaffs_GrossUnlock(dev);
+#if 1
+ expires = next_dir_update;
+ if (time_before(next_gc,expires))
+ expires = next_gc;
+ if(time_before(expires,now))
+ expires = now + HZ;
+
+ Y_INIT_TIMER(&timer);
+ timer.expires = expires+1;
+ timer.data = (unsigned long) current;
+ timer.function = yaffs_background_waker;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_timer(&timer);
+ schedule();
+ del_timer_sync(&timer);
+#else
+ msleep(10);
+#endif
+ }
+
+ return 0;
+}
+
+static int yaffs_BackgroundStart(yaffs_Device *dev)
+{
+ int retval = 0;
+ struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
+
+ if(dev->readOnly)
+ return -1;
+
+ context->bgRunning = 1;
+
+ context->bgThread = kthread_run(yaffs_BackgroundThread,
+ (void *)dev,"yaffs-bg-%d",context->mount_id);
+
+ if(IS_ERR(context->bgThread)){
+ retval = PTR_ERR(context->bgThread);
+ context->bgThread = NULL;
+ context->bgRunning = 0;
+ }
+ return retval;
+}
+
+static void yaffs_BackgroundStop(yaffs_Device *dev)
+{
+ struct yaffs_LinuxContext *ctxt = yaffs_DeviceToLC(dev);
+
+ ctxt->bgRunning = 0;
+
+ if( ctxt->bgThread){
+ kthread_stop(ctxt->bgThread);
+ ctxt->bgThread = NULL;
+ }
+}
+#else
+static int yaffs_BackgroundThread(void *data)
+{
+ return 0;
+}
+
+static int yaffs_BackgroundStart(yaffs_Device *dev)
+{
+ return 0;
+}
+
+static void yaffs_BackgroundStop(yaffs_Device *dev)
+{
+}
+#endif
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static void yaffs_write_super(struct super_block *sb)
+#else
+static int yaffs_write_super(struct super_block *sb)
+#endif
+{
+ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
+
+ T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
+ (TSTR("yaffs_write_super%s\n"),
+ request_checkpoint ? " checkpt" : ""));
+
+ yaffs_do_sync_fs(sb, request_checkpoint);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
+ return 0;
+#endif
+}
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_sync_fs(struct super_block *sb, int wait)
+#else
+static int yaffs_sync_fs(struct super_block *sb)
+#endif
+{
+ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
+
+ T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
+ (TSTR("yaffs_sync_fs%s\n"),
+ request_checkpoint ? " checkpt" : ""));
+
+ yaffs_do_sync_fs(sb, request_checkpoint);
+
+ return 0;
+}
+
+#ifdef YAFFS_USE_OWN_IGET
+
+static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
+{
+ struct inode *inode;
+ yaffs_Object *obj;
+ yaffs_Device *dev = yaffs_SuperToDevice(sb);
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_iget for %lu\n"), ino));
+
+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;
+
+ /* NB This is called as a side effect of other functions, but
+ * we had to release the lock to prevent deadlocks, so
+ * need to lock again.
+ */
+
+ yaffs_GrossLock(dev);
+
+ obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
+
+ yaffs_FillInodeFromObject(inode, obj);
+
+ yaffs_GrossUnlock(dev);
+
+ unlock_new_inode(inode);
+ return inode;
+}
+
+#else
+
+static void yaffs_read_inode(struct inode *inode)
+{
+ /* NB This is called as a side effect of other functions, but
+ * we had to release the lock to prevent deadlocks, so
+ * need to lock again.
+ */
+
+ yaffs_Object *obj;
+ yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_read_inode for %d\n"), (int)inode->i_ino));
+
+ if(current != yaffs_DeviceToLC(dev)->readdirProcess)
+ yaffs_GrossLock(dev);
+
+ obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
+
+ yaffs_FillInodeFromObject(inode, obj);
+
+ if(current != yaffs_DeviceToLC(dev)->readdirProcess)
+ yaffs_GrossUnlock(dev);
+}
+
+#endif
+
+static YLIST_HEAD(yaffs_context_list);
+struct semaphore yaffs_context_lock;
+
+static void yaffs_put_super(struct super_block *sb)
+{
+ yaffs_Device *dev = yaffs_SuperToDevice(sb);
+
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_put_super\n")));
+
+ T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
+ (TSTR("Shutting down yaffs background thread\n")));
+ yaffs_BackgroundStop(dev);
+ T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
+ (TSTR("yaffs background thread shut down\n")));
+
+ yaffs_GrossLock(dev);
+
+ yaffs_FlushSuperBlock(sb,1);
+
+ if (yaffs_DeviceToLC(dev)->putSuperFunc)
+ yaffs_DeviceToLC(dev)->putSuperFunc(sb);
+
+
+ yaffs_Deinitialise(dev);
+
+ yaffs_GrossUnlock(dev);
+
+ down(&yaffs_context_lock);
+ ylist_del_init(&(yaffs_DeviceToLC(dev)->contextList));
+ up(&yaffs_context_lock);
+
+ if (yaffs_DeviceToLC(dev)->spareBuffer) {
+ YFREE(yaffs_DeviceToLC(dev)->spareBuffer);
+ yaffs_DeviceToLC(dev)->spareBuffer = NULL;
+ }
+
+ kfree(dev);
+}
+
+
+static void yaffs_MTDPutSuper(struct super_block *sb)
+{
+ struct mtd_info *mtd = yaffs_DeviceToMtd(yaffs_SuperToDevice(sb));
+
+ if (mtd->sync)
+ mtd->sync(mtd);
+
+ put_mtd_device(mtd);
+}
+
+
+static void yaffs_MarkSuperBlockDirty(yaffs_Device *dev)
+{
+ struct super_block *sb = yaffs_DeviceToLC(dev)->superBlock;
+
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_MarkSuperBlockDirty() sb = %p\n"), sb));
+ if (sb)
+ sb->s_dirt = 1;
+}
+
+typedef struct {
+ int inband_tags;
+ int skip_checkpoint_read;
+ int skip_checkpoint_write;
+ int no_cache;
+ int tags_ecc_on;
+ int tags_ecc_overridden;
+ int lazy_loading_enabled;
+ int lazy_loading_overridden;
+ int empty_lost_and_found;
+ int empty_lost_and_found_overridden;
+} yaffs_options;
+
+#define MAX_OPT_LEN 30
+static int yaffs_parse_options(yaffs_options *options, const char *options_str)
+{
+ char cur_opt[MAX_OPT_LEN + 1];
+ int p;
+ int error = 0;
+
+ /* Parse through the options which is a comma seperated list */
+
+ while (options_str && *options_str && !error) {
+ memset(cur_opt, 0, MAX_OPT_LEN + 1);
+ p = 0;
+
+ while(*options_str == ',')
+ options_str++;
+
+ while (*options_str && *options_str != ',') {
+ if (p < MAX_OPT_LEN) {
+ cur_opt[p] = *options_str;
+ p++;
+ }
+ options_str++;
+ }
+
+ if (!strcmp(cur_opt, "inband-tags"))
+ options->inband_tags = 1;
+ else if (!strcmp(cur_opt, "tags-ecc-off")){
+ options->tags_ecc_on = 0;
+ options->tags_ecc_overridden=1;
+ } else if (!strcmp(cur_opt, "tags-ecc-on")){
+ options->tags_ecc_on = 1;
+ options->tags_ecc_overridden = 1;
+ } else if (!strcmp(cur_opt, "lazy-loading-off")){
+ options->lazy_loading_enabled = 0;
+ options->lazy_loading_overridden=1;
+ } else if (!strcmp(cur_opt, "lazy-loading-on")){
+ options->lazy_loading_enabled = 1;
+ options->lazy_loading_overridden = 1;
+ } else if (!strcmp(cur_opt, "empty-lost-and-found-off")){
+ options->empty_lost_and_found = 0;
+ options->empty_lost_and_found_overridden=1;
+ } else if (!strcmp(cur_opt, "empty-lost-and-found-on")){
+ options->empty_lost_and_found = 1;
+ options->empty_lost_and_found_overridden=1;
+ } else if (!strcmp(cur_opt, "no-cache"))
+ options->no_cache = 1;
+ else if (!strcmp(cur_opt, "no-checkpoint-read"))
+ options->skip_checkpoint_read = 1;
+ else if (!strcmp(cur_opt, "no-checkpoint-write"))
+ options->skip_checkpoint_write = 1;
+ else if (!strcmp(cur_opt, "no-checkpoint")) {
+ options->skip_checkpoint_read = 1;
+ options->skip_checkpoint_write = 1;
+ } else {
+ printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
+ cur_opt);
+ error = 1;
+ }
+ }
+
+ return error;
+}
+
+static struct super_block *yaffs_internal_read_super(int yaffsVersion,
+ struct super_block *sb,
+ void *data, int silent)
+{
+ int nBlocks;
+ struct inode *inode = NULL;
+ struct dentry *root;
+ yaffs_Device *dev = 0;
+ char devname_buf[BDEVNAME_SIZE + 1];
+ struct mtd_info *mtd;
+ int err;
+ char *data_str = (char *)data;
+ struct yaffs_LinuxContext *context = NULL;
+ yaffs_DeviceParam *param;
+
+ int readOnly = 0;
+
+ yaffs_options options;
+
+ unsigned mount_id;
+ int found;
+ struct yaffs_LinuxContext *context_iterator;
+ struct ylist_head *l;
+
+ sb->s_magic = YAFFS_MAGIC;
+ sb->s_op = &yaffs_super_ops;
+ sb->s_flags |= MS_NOATIME;
+
+ readOnly =((sb->s_flags & MS_RDONLY) != 0);
+
+
+#ifdef YAFFS_COMPILE_EXPORTFS
+ sb->s_export_op = &yaffs_export_ops;
+#endif
+
+ if (!sb)
+ printk(KERN_INFO "yaffs: sb is NULL\n");
+ else if (!sb->s_dev)
+ printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
+ else if (!yaffs_devname(sb, devname_buf))
+ printk(KERN_INFO "yaffs: devname is NULL\n");
+ else
+ printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n",
+ sb->s_dev,
+ yaffs_devname(sb, devname_buf),
+ readOnly ? "ro" : "rw");
+
+ if (!data_str)
+ data_str = "";
+
+ printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
+
+ memset(&options, 0, sizeof(options));
+
+ if (yaffs_parse_options(&options, data_str)) {
+ /* Option parsing failed */
+ return NULL;
+ }
+
+
+ sb->s_blocksize = PAGE_CACHE_SIZE;
+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_read_super: Using yaffs%d\n"), yaffsVersion));
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_read_super: block size %d\n"),
+ (int)(sb->s_blocksize)));
+
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: Attempting MTD mount of %u.%u,\"%s\"\n"),
+ MAJOR(sb->s_dev), MINOR(sb->s_dev),
+ yaffs_devname(sb, devname_buf)));
+
+ /* Check it's an mtd device..... */
+ if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
+ return NULL; /* This isn't an mtd device */
+
+ /* Get the device */
+ mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
+ if (!mtd) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: MTD device #%u doesn't appear to exist\n"),
+ MINOR(sb->s_dev)));
+ return NULL;
+ }
+ /* Check it's NAND */
+ if (mtd->type != MTD_NANDFLASH) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: MTD device is not NAND it's type %d\n"),
+ mtd->type));
+ return NULL;
+ }
+
+ T(YAFFS_TRACE_OS, (TSTR(" erase %p\n"), mtd->erase));
+ T(YAFFS_TRACE_OS, (TSTR(" read %p\n"), mtd->read));
+ T(YAFFS_TRACE_OS, (TSTR(" write %p\n"), mtd->write));
+ T(YAFFS_TRACE_OS, (TSTR(" readoob %p\n"), mtd->read_oob));
+ T(YAFFS_TRACE_OS, (TSTR(" writeoob %p\n"), mtd->write_oob));
+ T(YAFFS_TRACE_OS, (TSTR(" block_isbad %p\n"), mtd->block_isbad));
+ T(YAFFS_TRACE_OS, (TSTR(" block_markbad %p\n"), mtd->block_markbad));
+ T(YAFFS_TRACE_OS, (TSTR(" %s %d\n"), WRITE_SIZE_STR, WRITE_SIZE(mtd)));
+ T(YAFFS_TRACE_OS, (TSTR(" oobsize %d\n"), mtd->oobsize));
+ T(YAFFS_TRACE_OS, (TSTR(" erasesize %d\n"), mtd->erasesize));
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
+ T(YAFFS_TRACE_OS, (TSTR(" size %u\n"), mtd->size));
+#else
+ T(YAFFS_TRACE_OS, (TSTR(" size %lld\n"), mtd->size));
+#endif
+
+#ifdef CONFIG_YAFFS_AUTO_YAFFS2
+
+ if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: auto selecting yaffs2\n")));
+ yaffsVersion = 2;
+ }
+
+ /* Added NCB 26/5/2006 for completeness */
+ if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: auto selecting yaffs1\n")));
+ yaffsVersion = 1;
+ }
+
+#endif
+
+ if (yaffsVersion == 2) {
+ /* Check for version 2 style functions */
+ if (!mtd->erase ||
+ !mtd->block_isbad ||
+ !mtd->block_markbad ||
+ !mtd->read ||
+ !mtd->write ||
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+ !mtd->read_oob || !mtd->write_oob) {
+#else
+ !mtd->write_ecc ||
+ !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
+#endif
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: MTD device does not support required "
+ "functions\n")));
+ return NULL;
+ }
+
+ if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
+ mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
+ !options.inband_tags) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: MTD device does not have the "
+ "right page sizes\n")));
+ return NULL;
+ }
+ } else {
+ /* Check for V1 style functions */
+ if (!mtd->erase ||
+ !mtd->read ||
+ !mtd->write ||
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+ !mtd->read_oob || !mtd->write_oob) {
+#else
+ !mtd->write_ecc ||
+ !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
+#endif
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: MTD device does not support required "
+ "functions\n")));
+ return NULL;
+ }
+
+ if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
+ mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: MTD device does not support have the "
+ "right page sizes\n")));
+ return NULL;
+ }
+ }
+
+ /* OK, so if we got here, we have an MTD that's NAND and looks
+ * like it has the right capabilities
+ * Set the yaffs_Device up for mtd
+ */
+
+ if (!readOnly && !(mtd->flags & MTD_WRITEABLE)){
+ readOnly = 1;
+ printk(KERN_INFO "yaffs: mtd is read only, setting superblock read only");
+ sb->s_flags |= MS_RDONLY;
+ }
+
+ dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
+ context = kmalloc(sizeof(struct yaffs_LinuxContext),GFP_KERNEL);
+
+ if(!dev || !context ){
+ if(dev)
+ kfree(dev);
+ if(context)
+ kfree(context);
+ dev = NULL;
+ context = NULL;
+ }
+
+ if (!dev) {
+ /* Deep shit could not allocate device structure */
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs_read_super: Failed trying to allocate "
+ "yaffs_Device. \n")));
+ return NULL;
+ }
+ memset(dev, 0, sizeof(yaffs_Device));
+ param = &(dev->param);
+
+ memset(context,0,sizeof(struct yaffs_LinuxContext));
+ dev->osContext = context;
+ YINIT_LIST_HEAD(&(context->contextList));
+ context->dev = dev;
+ context->superBlock = sb;
+
+ dev->readOnly = readOnly;
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+ sb->s_fs_info = dev;
+#else
+ sb->u.generic_sbp = dev;
+#endif
+
+ dev->driverContext = mtd;
+ param->name = mtd->name;
+
+ /* Set up the memory size parameters.... */
+
+ nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
+
+ param->startBlock = 0;
+ param->endBlock = nBlocks - 1;
+ param->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
+ param->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
+ param->nReservedBlocks = 5;
+ param->nShortOpCaches = (options.no_cache) ? 0 : 10;
+ param->inbandTags = options.inband_tags;
+
+#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
+ param->disableLazyLoad = 1;
+#endif
+#ifdef CONFIG_YAFFS_XATTR
+ param->enableXattr = 1;
+#endif
+ if(options.lazy_loading_overridden)
+ param->disableLazyLoad = !options.lazy_loading_enabled;
+
+#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC
+ param->noTagsECC = 1;
+#endif
+
+#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND
+#else
+ param->deferDirectoryUpdate = 1;
+#endif
+
+ if(options.tags_ecc_overridden)
+ param->noTagsECC = !options.tags_ecc_on;
+
+#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
+ param->emptyLostAndFound = 1;
+#endif
+
+#ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING
+ param->refreshPeriod = 0;
+#else
+ param->refreshPeriod = 500;
+#endif
+
+#ifdef CONFIG_YAFFS__ALWAYS_CHECK_CHUNK_ERASED
+ param->alwaysCheckErased = 1;
+#endif
+
+ if(options.empty_lost_and_found_overridden)
+ param->emptyLostAndFound = options.empty_lost_and_found;
+
+ /* ... and the functions. */
+ if (yaffsVersion == 2) {
+ param->writeChunkWithTagsToNAND =
+ nandmtd2_WriteChunkWithTagsToNAND;
+ param->readChunkWithTagsFromNAND =
+ nandmtd2_ReadChunkWithTagsFromNAND;
+ param->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
+ param->queryNANDBlock = nandmtd2_QueryNANDBlock;
+ yaffs_DeviceToLC(dev)->spareBuffer = YMALLOC(mtd->oobsize);
+ param->isYaffs2 = 1;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+ param->totalBytesPerChunk = mtd->writesize;
+ param->nChunksPerBlock = mtd->erasesize / mtd->writesize;
+#else
+ param->totalBytesPerChunk = mtd->oobblock;
+ param->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
+#endif
+ nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
+
+ param->startBlock = 0;
+ param->endBlock = nBlocks - 1;
+ } else {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+ /* use the MTD interface in yaffs_mtdif1.c */
+ param->writeChunkWithTagsToNAND =
+ nandmtd1_WriteChunkWithTagsToNAND;
+ param->readChunkWithTagsFromNAND =
+ nandmtd1_ReadChunkWithTagsFromNAND;
+ param->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
+ param->queryNANDBlock = nandmtd1_QueryNANDBlock;
+#else
+ param->writeChunkToNAND = nandmtd_WriteChunkToNAND;
+ param->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
+#endif
+ param->isYaffs2 = 0;
+ }
+ /* ... and common functions */
+ param->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
+ param->initialiseNAND = nandmtd_InitialiseNAND;
+
+ yaffs_DeviceToLC(dev)->putSuperFunc = yaffs_MTDPutSuper;
+
+ param->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
+ param->gcControl = yaffs_gc_control_callback;
+
+ yaffs_DeviceToLC(dev)->superBlock= sb;
+
+
+#ifndef CONFIG_YAFFS_DOES_ECC
+ param->useNANDECC = 1;
+#endif
+
+#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
+ param->wideTnodesDisabled = 1;
+#endif
+
+ param->skipCheckpointRead = options.skip_checkpoint_read;
+ param->skipCheckpointWrite = options.skip_checkpoint_write;
+
+ down(&yaffs_context_lock);
+ /* Get a mount id */
+ found = 0;
+ for(mount_id=0; ! found; mount_id++){
+ found = 1;
+ ylist_for_each(l,&yaffs_context_list){
+ context_iterator = ylist_entry(l,struct yaffs_LinuxContext,contextList);
+ if(context_iterator->mount_id == mount_id)
+ found = 0;
+ }
+ }
+ context->mount_id = mount_id;
+
+ ylist_add_tail(&(yaffs_DeviceToLC(dev)->contextList), &yaffs_context_list);
+ up(&yaffs_context_lock);
+
+ /* Directory search handling...*/
+ YINIT_LIST_HEAD(&(yaffs_DeviceToLC(dev)->searchContexts));
+ param->removeObjectCallback = yaffs_RemoveObjectCallback;
+
+ init_MUTEX(&(yaffs_DeviceToLC(dev)->grossLock));
+
+ yaffs_GrossLock(dev);
+
+ err = yaffs_GutsInitialise(dev);
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_read_super: guts initialised %s\n"),
+ (err == YAFFS_OK) ? "OK" : "FAILED"));
+
+ if(err == YAFFS_OK)
+ yaffs_BackgroundStart(dev);
+
+ if(!context->bgThread)
+ param->deferDirectoryUpdate = 0;
+
+
+ /* Release lock before yaffs_get_inode() */
+ yaffs_GrossUnlock(dev);
+
+ /* Create root inode */
+ if (err == YAFFS_OK)
+ inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
+ yaffs_Root(dev));
+
+ if (!inode)
+ return NULL;
+
+ inode->i_op = &yaffs_dir_inode_operations;
+ inode->i_fop = &yaffs_dir_operations;
+
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: got root inode\n")));
+
+ root = d_alloc_root(inode);
+
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: d_alloc_root done\n")));
+
+ if (!root) {
+ iput(inode);
+ return NULL;
+ }
+ sb->s_root = root;
+ sb->s_dirt = !dev->isCheckpointed;
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs_read_super: isCheckpointed %d\n"),
+ dev->isCheckpointed));
+
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: done\n")));
+ return sb;
+}
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
+ int silent)
+{
+ return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_read_super(struct file_system_type *fs,
+ int flags, const char *dev_name,
+ void *data, struct vfsmount *mnt)
+{
+
+ return get_sb_bdev(fs, flags, dev_name, data,
+ yaffs_internal_read_super_mtd, mnt);
+}
+#else
+static struct super_block *yaffs_read_super(struct file_system_type *fs,
+ int flags, const char *dev_name,
+ void *data)
+{
+
+ return get_sb_bdev(fs, flags, dev_name, data,
+ yaffs_internal_read_super_mtd);
+}
+#endif
+
+static struct file_system_type yaffs_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "yaffs",
+ .get_sb = yaffs_read_super,
+ .kill_sb = kill_block_super,
+ .fs_flags = FS_REQUIRES_DEV,
+};
+#else
+static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
+ int silent)
+{
+ return yaffs_internal_read_super(1, sb, data, silent);
+}
+
+static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
+ FS_REQUIRES_DEV);
+#endif
+
+
+#ifdef CONFIG_YAFFS_YAFFS2
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
+ int silent)
+{
+ return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs2_read_super(struct file_system_type *fs,
+ int flags, const char *dev_name, void *data,
+ struct vfsmount *mnt)
+{
+ return get_sb_bdev(fs, flags, dev_name, data,
+ yaffs2_internal_read_super_mtd, mnt);
+}
+#else
+static struct super_block *yaffs2_read_super(struct file_system_type *fs,
+ int flags, const char *dev_name,
+ void *data)
+{
+
+ return get_sb_bdev(fs, flags, dev_name, data,
+ yaffs2_internal_read_super_mtd);
+}
+#endif
+
+static struct file_system_type yaffs2_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "yaffs2",
+ .get_sb = yaffs2_read_super,
+ .kill_sb = kill_block_super,
+ .fs_flags = FS_REQUIRES_DEV,
+};
+#else
+static struct super_block *yaffs2_read_super(struct super_block *sb,
+ void *data, int silent)
+{
+ return yaffs_internal_read_super(2, sb, data, silent);
+}
+
+static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
+ FS_REQUIRES_DEV);
+#endif
+
+#endif /* CONFIG_YAFFS_YAFFS2 */
+
+static struct proc_dir_entry *my_proc_entry;
+static struct proc_dir_entry *debug_proc_entry;
+
+static char *yaffs_dump_dev_part0(char *buf, yaffs_Device * dev)
+{
+ buf += sprintf(buf, "startBlock......... %d\n", dev->param.startBlock);
+ buf += sprintf(buf, "endBlock........... %d\n", dev->param.endBlock);
+ buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->param.totalBytesPerChunk);
+ buf += sprintf(buf, "useNANDECC......... %d\n", dev->param.useNANDECC);
+ buf += sprintf(buf, "noTagsECC.......... %d\n", dev->param.noTagsECC);
+ buf += sprintf(buf, "isYaffs2........... %d\n", dev->param.isYaffs2);
+ buf += sprintf(buf, "inbandTags......... %d\n", dev->param.inbandTags);
+ buf += sprintf(buf, "emptyLostAndFound.. %d\n", dev->param.emptyLostAndFound);
+ buf += sprintf(buf, "disableLazyLoad.... %d\n", dev->param.disableLazyLoad);
+ buf += sprintf(buf, "refreshPeriod...... %d\n", dev->param.refreshPeriod);
+ buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->param.nShortOpCaches);
+ buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->param.nReservedBlocks);
+ buf += sprintf(buf, "alwaysCheckErased.. %d\n", dev->param.alwaysCheckErased);
+
+ buf += sprintf(buf, "\n");
+
+ return buf;
+}
+
+
+static char *yaffs_dump_dev_part1(char *buf, yaffs_Device * dev)
+{
+ buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
+ buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
+ buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
+ buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
+ buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
+ buf += sprintf(buf, "\n");
+ buf += sprintf(buf, "nTnodes............ %d\n", dev->nTnodes);
+ buf += sprintf(buf, "nObjects........... %d\n", dev->nObjects);
+ buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
+ buf += sprintf(buf, "\n");
+ buf += sprintf(buf, "nPageWrites........ %u\n", dev->nPageWrites);
+ buf += sprintf(buf, "nPageReads......... %u\n", dev->nPageReads);
+ buf += sprintf(buf, "nBlockErasures..... %u\n", dev->nBlockErasures);
+ buf += sprintf(buf, "nGCCopies.......... %u\n", dev->nGCCopies);
+ buf += sprintf(buf, "allGCs............. %u\n", dev->allGCs);
+ buf += sprintf(buf, "passiveGCs......... %u\n", dev->passiveGCs);
+ buf += sprintf(buf, "oldestDirtyGCs..... %u\n", dev->oldestDirtyGCs);
+ buf += sprintf(buf, "nGCBlocks.......... %u\n", dev->nGCBlocks);
+ buf += sprintf(buf, "backgroundGCs...... %u\n", dev->backgroundGCs);
+ buf += sprintf(buf, "nRetriedWrites..... %u\n", dev->nRetriedWrites);
+ buf += sprintf(buf, "nRetireBlocks...... %u\n", dev->nRetiredBlocks);
+ buf += sprintf(buf, "eccFixed........... %u\n", dev->eccFixed);
+ buf += sprintf(buf, "eccUnfixed......... %u\n", dev->eccUnfixed);
+ buf += sprintf(buf, "tagsEccFixed....... %u\n", dev->tagsEccFixed);
+ buf += sprintf(buf, "tagsEccUnfixed..... %u\n", dev->tagsEccUnfixed);
+ buf += sprintf(buf, "cacheHits.......... %u\n", dev->cacheHits);
+ buf += sprintf(buf, "nDeletedFiles...... %u\n", dev->nDeletedFiles);
+ buf += sprintf(buf, "nUnlinkedFiles..... %u\n", dev->nUnlinkedFiles);
+ buf += sprintf(buf, "refreshCount....... %u\n", dev->refreshCount);
+ buf +=
+ sprintf(buf, "nBackgroudDeletions %u\n", dev->nBackgroundDeletions);
+
+ return buf;
+}
+
+static int yaffs_proc_read(char *page,
+ char **start,
+ off_t offset, int count, int *eof, void *data)
+{
+ struct ylist_head *item;
+ char *buf = page;
+ int step = offset;
+ int n = 0;
+
+ /* Get proc_file_read() to step 'offset' by one on each sucessive call.
+ * We use 'offset' (*ppos) to indicate where we are in devList.
+ * This also assumes the user has posted a read buffer large
+ * enough to hold the complete output; but that's life in /proc.
+ */
+
+ *(int *)start = 1;
+
+ /* Print header first */
+ if (step == 0)
+ buf += sprintf(buf, "Multi-version YAFFS built:" __DATE__ " " __TIME__"\n");
+ else if (step == 1)
+ buf += sprintf(buf,"\n");
+ else {
+ step-=2;
+
+ down(&yaffs_context_lock);
+
+ /* Locate and print the Nth entry. Order N-squared but N is small. */
+ ylist_for_each(item, &yaffs_context_list) {
+ struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList);
+ yaffs_Device *dev = dc->dev;
+
+ if (n < (step & ~1)) {
+ n+=2;
+ continue;
+ }
+ if((step & 1)==0){
+ buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->param.name);
+ buf = yaffs_dump_dev_part0(buf, dev);
+ } else
+ buf = yaffs_dump_dev_part1(buf, dev);
+
+ break;
+ }
+ up(&yaffs_context_lock);
+ }
+
+ return buf - page < count ? buf - page : count;
+}
+
+static int yaffs_stats_proc_read(char *page,
+ char **start,
+ off_t offset, int count, int *eof, void *data)
+{
+ struct ylist_head *item;
+ char *buf = page;
+ int n = 0;
+
+ down(&yaffs_context_lock);
+
+ /* Locate and print the Nth entry. Order N-squared but N is small. */
+ ylist_for_each(item, &yaffs_context_list) {
+ struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList);
+ yaffs_Device *dev = dc->dev;
+
+ int erasedChunks;
+
+ erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
+
+ buf += sprintf(buf,"%d, %d, %d, %u, %u, %u, %u\n",
+ n, dev->nFreeChunks, erasedChunks,
+ dev->backgroundGCs, dev->oldestDirtyGCs,
+ dev->nObjects, dev->nTnodes);
+ }
+ up(&yaffs_context_lock);
+
+
+ return buf - page < count ? buf - page : count;
+}
+
+/**
+ * Set the verbosity of the warnings and error messages.
+ *
+ * Note that the names can only be a..z or _ with the current code.
+ */
+
+static struct {
+ char *mask_name;
+ unsigned mask_bitfield;
+} mask_flags[] = {
+ {"allocate", YAFFS_TRACE_ALLOCATE},
+ {"always", YAFFS_TRACE_ALWAYS},
+ {"background", YAFFS_TRACE_BACKGROUND},
+ {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
+ {"buffers", YAFFS_TRACE_BUFFERS},
+ {"bug", YAFFS_TRACE_BUG},
+ {"checkpt", YAFFS_TRACE_CHECKPOINT},
+ {"deletion", YAFFS_TRACE_DELETION},
+ {"erase", YAFFS_TRACE_ERASE},
+ {"error", YAFFS_TRACE_ERROR},
+ {"gc_detail", YAFFS_TRACE_GC_DETAIL},
+ {"gc", YAFFS_TRACE_GC},
+ {"lock", YAFFS_TRACE_LOCK},
+ {"mtd", YAFFS_TRACE_MTD},
+ {"nandaccess", YAFFS_TRACE_NANDACCESS},
+ {"os", YAFFS_TRACE_OS},
+ {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
+ {"scan", YAFFS_TRACE_SCAN},
+ {"tracing", YAFFS_TRACE_TRACING},
+ {"sync", YAFFS_TRACE_SYNC},
+ {"write", YAFFS_TRACE_WRITE},
+
+ {"verify", YAFFS_TRACE_VERIFY},
+ {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
+ {"verify_full", YAFFS_TRACE_VERIFY_FULL},
+ {"verify_all", YAFFS_TRACE_VERIFY_ALL},
+
+ {"all", 0xffffffff},
+ {"none", 0},
+ {NULL, 0},
+};
+
+#define MAX_MASK_NAME_LENGTH 40
+static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
+ unsigned long count, void *data)
+{
+ unsigned rg = 0, mask_bitfield;
+ char *end;
+ char *mask_name;
+ const char *x;
+ char substring[MAX_MASK_NAME_LENGTH + 1];
+ int i;
+ int done = 0;
+ int add, len = 0;
+ int pos = 0;
+
+ rg = yaffs_traceMask;
+
+ while (!done && (pos < count)) {
+ done = 1;
+ while ((pos < count) && isspace(buf[pos]))
+ pos++;
+
+ switch (buf[pos]) {
+ case '+':
+ case '-':
+ case '=':
+ add = buf[pos];
+ pos++;
+ break;
+
+ default:
+ add = ' ';
+ break;
+ }
+ mask_name = NULL;
+
+ mask_bitfield = simple_strtoul(buf + pos, &end, 0);
+
+ if (end > buf + pos) {
+ mask_name = "numeral";
+ len = end - (buf + pos);
+ pos += len;
+ done = 0;
+ } else {
+ for (x = buf + pos, i = 0;
+ (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
+ i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
+ substring[i] = *x;
+ substring[i] = '\0';
+
+ for (i = 0; mask_flags[i].mask_name != NULL; i++) {
+ if (strcmp(substring, mask_flags[i].mask_name) == 0) {
+ mask_name = mask_flags[i].mask_name;
+ mask_bitfield = mask_flags[i].mask_bitfield;
+ done = 0;
+ break;
+ }
+ }
+ }
+
+ if (mask_name != NULL) {
+ done = 0;
+ switch (add) {
+ case '-':
+ rg &= ~mask_bitfield;
+ break;
+ case '+':
+ rg |= mask_bitfield;
+ break;
+ case '=':
+ rg = mask_bitfield;
+ break;
+ default:
+ rg |= mask_bitfield;
+ break;
+ }
+ }
+ }
+
+ yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
+
+ printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask);
+
+ if (rg & YAFFS_TRACE_ALWAYS) {
+ for (i = 0; mask_flags[i].mask_name != NULL; i++) {
+ char flag;
+ flag = ((rg & mask_flags[i].mask_bitfield) ==
+ mask_flags[i].mask_bitfield) ? '+' : '-';
+ printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
+ }
+ }
+
+ return count;
+}
+
+
+static int yaffs_proc_write(struct file *file, const char *buf,
+ unsigned long count, void *data)
+{
+ return yaffs_proc_write_trace_options(file, buf, count, data);
+}
+
+/* Stuff to handle installation of file systems */
+struct file_system_to_install {
+ struct file_system_type *fst;
+ int installed;
+};
+
+static struct file_system_to_install fs_to_install[] = {
+ {&yaffs_fs_type, 0},
+ {&yaffs2_fs_type, 0},
+ {NULL, 0}
+};
+
+static int __init init_yaffs_fs(void)
+{
+ int error = 0;
+ struct file_system_to_install *fsinst;
+
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs built " __DATE__ " " __TIME__ " Installing. \n")));
+
+#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR(" \n\n\n\nYAFFS-WARNING CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED selected.\n\n\n\n")));
+#endif
+
+
+
+
+ init_MUTEX(&yaffs_context_lock);
+
+ /* Install the proc_fs entries */
+ my_proc_entry = create_proc_entry("yaffs",
+ S_IRUGO | S_IFREG,
+ YPROC_ROOT);
+
+ if (my_proc_entry) {
+ my_proc_entry->write_proc = yaffs_proc_write;
+ my_proc_entry->read_proc = yaffs_proc_read;
+ my_proc_entry->data = NULL;
+ } else
+ return -ENOMEM;
+
+ debug_proc_entry = create_proc_entry("yaffs_stats",
+ S_IRUGO | S_IFREG,
+ YPROC_ROOT);
+
+ if (debug_proc_entry) {
+ debug_proc_entry->write_proc = NULL;
+ debug_proc_entry->read_proc = yaffs_stats_proc_read;
+ debug_proc_entry->data = NULL;
+ } else
+ return -ENOMEM;
+
+ /* Now add the file system entries */
+
+ fsinst = fs_to_install;
+
+ while (fsinst->fst && !error) {
+ error = register_filesystem(fsinst->fst);
+ if (!error)
+ fsinst->installed = 1;
+ fsinst++;
+ }
+
+ /* Any errors? uninstall */
+ if (error) {
+ fsinst = fs_to_install;
+
+ while (fsinst->fst) {
+ if (fsinst->installed) {
+ unregister_filesystem(fsinst->fst);
+ fsinst->installed = 0;
+ }
+ fsinst++;
+ }
+ }
+
+ return error;
+}
+
+static void __exit exit_yaffs_fs(void)
+{
+
+ struct file_system_to_install *fsinst;
+
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs built " __DATE__ " " __TIME__ " removing. \n")));
+
+ remove_proc_entry("yaffs", YPROC_ROOT);
+ remove_proc_entry("yaffs_stats", YPROC_ROOT);
+
+ fsinst = fs_to_install;
+
+ while (fsinst->fst) {
+ if (fsinst->installed) {
+ unregister_filesystem(fsinst->fst);
+ fsinst->installed = 0;
+ }
+ fsinst++;
+ }
+}
+
+module_init(init_yaffs_fs)
+module_exit(exit_yaffs_fs)
+
+MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
+MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2010");
+MODULE_LICENSE("GPL");
diff --git a/fs/yaffs2/yaffs_yaffs1.c b/fs/yaffs2/yaffs_yaffs1.c
new file mode 100644
index 00000000..642fd5a4
--- /dev/null
+++ b/fs/yaffs2/yaffs_yaffs1.c
@@ -0,0 +1,466 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2010 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning
+ *
+ * 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 "yaffs_yaffs1.h"
+#include "yportenv.h"
+#include "yaffs_trace.h"
+#include "yaffs_bitmap.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_nand.h"
+
+
+int yaffs1_Scan(yaffs_Device *dev)
+{
+ yaffs_ExtendedTags tags;
+ int blk;
+ int blockIterator;
+ int startIterator;
+ int endIterator;
+ int result;
+
+ int chunk;
+ int c;
+ int deleted;
+ yaffs_BlockState state;
+ yaffs_Object *hardList = NULL;
+ yaffs_BlockInfo *bi;
+ __u32 sequenceNumber;
+ yaffs_ObjectHeader *oh;
+ yaffs_Object *in;
+ yaffs_Object *parent;
+
+ int alloc_failed = 0;
+
+ struct yaffs_ShadowFixerStruct *shadowFixerList = NULL;
+
+
+ __u8 *chunkData;
+
+
+
+ T(YAFFS_TRACE_SCAN,
+ (TSTR("yaffs1_Scan starts intstartblk %d intendblk %d..." TENDSTR),
+ dev->internalStartBlock, dev->internalEndBlock));
+
+ chunkData = yaffs_GetTempBuffer(dev, __LINE__);
+
+ dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
+
+ /* Scan all the blocks to determine their state */
+ bi = dev->blockInfo;
+ for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
+ yaffs_ClearChunkBits(dev, blk);
+ bi->pagesInUse = 0;
+ bi->softDeletions = 0;
+
+ yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
+
+ bi->blockState = state;
+ bi->sequenceNumber = sequenceNumber;
+
+ if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
+ bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
+
+ T(YAFFS_TRACE_SCAN_DEBUG,
+ (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
+ state, sequenceNumber));
+
+ if (state == YAFFS_BLOCK_STATE_DEAD) {
+ T(YAFFS_TRACE_BAD_BLOCKS,
+ (TSTR("block %d is bad" TENDSTR), blk));
+ } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
+ T(YAFFS_TRACE_SCAN_DEBUG,
+ (TSTR("Block empty " TENDSTR)));
+ dev->nErasedBlocks++;
+ dev->nFreeChunks += dev->param.nChunksPerBlock;
+ }
+ bi++;
+ }
+
+ startIterator = dev->internalStartBlock;
+ endIterator = dev->internalEndBlock;
+
+ /* For each block.... */
+ for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
+ blockIterator++) {
+
+ YYIELD();
+
+ YYIELD();
+
+ blk = blockIterator;
+
+ bi = yaffs_GetBlockInfo(dev, blk);
+ state = bi->blockState;
+
+ deleted = 0;
+
+ /* For each chunk in each block that needs scanning....*/
+ for (c = 0; !alloc_failed && c < dev->param.nChunksPerBlock &&
+ state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
+ /* Read the tags and decide what to do */
+ chunk = blk * dev->param.nChunksPerBlock + c;
+
+ result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
+ &tags);
+
+ /* Let's have a good look at this chunk... */
+
+ if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) {
+ /* YAFFS1 only...
+ * A deleted chunk
+ */
+ deleted++;
+ dev->nFreeChunks++;
+ /*T((" %d %d deleted\n",blk,c)); */
+ } else if (!tags.chunkUsed) {
+ /* An unassigned chunk in the block
+ * This means that either the block is empty or
+ * this is the one being allocated from
+ */
+
+ if (c == 0) {
+ /* We're looking at the first chunk in the block so the block is unused */
+ state = YAFFS_BLOCK_STATE_EMPTY;
+ dev->nErasedBlocks++;
+ } else {
+ /* this is the block being allocated from */
+ T(YAFFS_TRACE_SCAN,
+ (TSTR
+ (" Allocating from %d %d" TENDSTR),
+ blk, c));
+ state = YAFFS_BLOCK_STATE_ALLOCATING;
+ dev->allocationBlock = blk;
+ dev->allocationPage = c;
+ dev->allocationBlockFinder = blk;
+ /* Set block finder here to encourage the allocator to go forth from here. */
+
+ }
+
+ dev->nFreeChunks += (dev->param.nChunksPerBlock - c);
+ } else if (tags.chunkId > 0) {
+ /* chunkId > 0 so it is a data chunk... */
+ unsigned int endpos;
+
+ yaffs_SetChunkBit(dev, blk, c);
+ bi->pagesInUse++;
+
+ in = yaffs_FindOrCreateObjectByNumber(dev,
+ tags.
+ objectId,
+ YAFFS_OBJECT_TYPE_FILE);
+ /* PutChunkIntoFile checks for a clash (two data chunks with
+ * the same chunkId).
+ */
+
+ if (!in)
+ alloc_failed = 1;
+
+ if (in) {
+ if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1))
+ alloc_failed = 1;
+ }
+
+ endpos =
+ (tags.chunkId - 1) * dev->nDataBytesPerChunk +
+ tags.byteCount;
+ if (in &&
+ in->variantType == YAFFS_OBJECT_TYPE_FILE
+ && in->variant.fileVariant.scannedFileSize <
+ endpos) {
+ in->variant.fileVariant.
+ scannedFileSize = endpos;
+ if (!dev->param.useHeaderFileSize) {
+ in->variant.fileVariant.
+ fileSize =
+ in->variant.fileVariant.
+ scannedFileSize;
+ }
+
+ }
+ /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */
+ } else {
+ /* chunkId == 0, so it is an ObjectHeader.
+ * Thus, we read in the object header and make the object
+ */
+ yaffs_SetChunkBit(dev, blk, c);
+ bi->pagesInUse++;
+
+ result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk,
+ chunkData,
+ NULL);
+
+ oh = (yaffs_ObjectHeader *) chunkData;
+
+ in = yaffs_FindObjectByNumber(dev,
+ tags.objectId);
+ if (in && in->variantType != oh->type) {
+ /* This should not happen, but somehow
+ * Wev'e ended up with an objectId that has been reused but not yet
+ * deleted, and worse still it has changed type. Delete the old object.
+ */
+
+ yaffs_DeleteObject(in);
+
+ in = 0;
+ }
+
+ in = yaffs_FindOrCreateObjectByNumber(dev,
+ tags.
+ objectId,
+ oh->type);
+
+ if (!in)
+ alloc_failed = 1;
+
+ if (in && oh->shadowsObject > 0) {
+
+ struct yaffs_ShadowFixerStruct *fixer;
+ fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct));
+ if (fixer) {
+ fixer->next = shadowFixerList;
+ shadowFixerList = fixer;
+ fixer->objectId = tags.objectId;
+ fixer->shadowedId = oh->shadowsObject;
+ T(YAFFS_TRACE_SCAN,
+ (TSTR
+ (" Shadow fixer: %d shadows %d" TENDSTR),
+ fixer->objectId, fixer->shadowedId));
+
+ }
+
+ }
+
+ if (in && in->valid) {
+ /* We have already filled this one. We have a duplicate and need to resolve it. */
+
+ unsigned existingSerial = in->serial;
+ unsigned newSerial = tags.serialNumber;
+
+ if (((existingSerial + 1) & 3) == newSerial) {
+ /* Use new one - destroy the exisiting one */
+ yaffs_DeleteChunk(dev,
+ in->hdrChunk,
+ 1, __LINE__);
+ in->valid = 0;
+ } else {
+ /* Use existing - destroy this one. */
+ yaffs_DeleteChunk(dev, chunk, 1,
+ __LINE__);
+ }
+ }
+
+ if (in && !in->valid &&
+ (tags.objectId == YAFFS_OBJECTID_ROOT ||
+ tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {
+ /* We only load some info, don't fiddle with directory structure */
+ in->valid = 1;
+ in->variantType = oh->type;
+
+ in->yst_mode = oh->yst_mode;
+#ifdef CONFIG_YAFFS_WINCE
+ in->win_atime[0] = oh->win_atime[0];
+ in->win_ctime[0] = oh->win_ctime[0];
+ in->win_mtime[0] = oh->win_mtime[0];
+ in->win_atime[1] = oh->win_atime[1];
+ in->win_ctime[1] = oh->win_ctime[1];
+ in->win_mtime[1] = oh->win_mtime[1];
+#else
+ in->yst_uid = oh->yst_uid;
+ in->yst_gid = oh->yst_gid;
+ in->yst_atime = oh->yst_atime;
+ in->yst_mtime = oh->yst_mtime;
+ in->yst_ctime = oh->yst_ctime;
+ in->yst_rdev = oh->yst_rdev;
+#endif
+ in->hdrChunk = chunk;
+ in->serial = tags.serialNumber;
+
+ } else if (in && !in->valid) {
+ /* we need to load this info */
+
+ in->valid = 1;
+ in->variantType = oh->type;
+
+ in->yst_mode = oh->yst_mode;
+#ifdef CONFIG_YAFFS_WINCE
+ in->win_atime[0] = oh->win_atime[0];
+ in->win_ctime[0] = oh->win_ctime[0];
+ in->win_mtime[0] = oh->win_mtime[0];
+ in->win_atime[1] = oh->win_atime[1];
+ in->win_ctime[1] = oh->win_ctime[1];
+ in->win_mtime[1] = oh->win_mtime[1];
+#else
+ in->yst_uid = oh->yst_uid;
+ in->yst_gid = oh->yst_gid;
+ in->yst_atime = oh->yst_atime;
+ in->yst_mtime = oh->yst_mtime;
+ in->yst_ctime = oh->yst_ctime;
+ in->yst_rdev = oh->yst_rdev;
+#endif
+ in->hdrChunk = chunk;
+ in->serial = tags.serialNumber;
+
+ yaffs_SetObjectNameFromOH(in, oh);
+ in->dirty = 0;
+
+ /* directory stuff...
+ * hook up to parent
+ */
+
+ parent =
+ yaffs_FindOrCreateObjectByNumber
+ (dev, oh->parentObjectId,
+ YAFFS_OBJECT_TYPE_DIRECTORY);
+ if (!parent)
+ alloc_failed = 1;
+ if (parent && parent->variantType ==
+ YAFFS_OBJECT_TYPE_UNKNOWN) {
+ /* Set up as a directory */
+ parent->variantType =
+ YAFFS_OBJECT_TYPE_DIRECTORY;
+ YINIT_LIST_HEAD(&parent->variant.
+ directoryVariant.
+ children);
+ } else if (!parent || parent->variantType !=
+ YAFFS_OBJECT_TYPE_DIRECTORY) {
+ /* Hoosterman, another problem....
+ * We're trying to use a non-directory as a directory
+ */
+
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
+ TENDSTR)));
+ parent = dev->lostNFoundDir;
+ }
+
+ yaffs_AddObjectToDirectory(parent, in);
+
+ if (0 && (parent == dev->deletedDir ||
+ parent == dev->unlinkedDir)) {
+ in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
+ dev->nDeletedFiles++;
+ }
+ /* Note re hardlinks.
+ * Since we might scan a hardlink before its equivalent object is scanned
+ * we put them all in a list.
+ * After scanning is complete, we should have all the objects, so we run through this
+ * list and fix up all the chains.
+ */
+
+ switch (in->variantType) {
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ /* Todo got a problem */
+ break;
+ case YAFFS_OBJECT_TYPE_FILE:
+ if (dev->param.useHeaderFileSize)
+
+ in->variant.fileVariant.
+ fileSize =
+ oh->fileSize;
+
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ in->variant.hardLinkVariant.
+ equivalentObjectId =
+ oh->equivalentObjectId;
+ in->hardLinks.next =
+ (struct ylist_head *)
+ hardList;
+ hardList = in;
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ /* Do nothing */
+ break;
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ /* Do nothing */
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ in->variant.symLinkVariant.alias =
+ yaffs_CloneString(oh->alias);
+ if (!in->variant.symLinkVariant.alias)
+ alloc_failed = 1;
+ break;
+ }
+
+ }
+ }
+ }
+
+ if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
+ /* If we got this far while scanning, then the block is fully allocated.*/
+ state = YAFFS_BLOCK_STATE_FULL;
+ }
+
+ if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
+ /* If the block was partially allocated then treat it as fully allocated.*/
+ state = YAFFS_BLOCK_STATE_FULL;
+ dev->allocationBlock = -1;
+ }
+
+ bi->blockState = state;
+
+ /* Now let's see if it was dirty */
+ if (bi->pagesInUse == 0 &&
+ !bi->hasShrinkHeader &&
+ bi->blockState == YAFFS_BLOCK_STATE_FULL) {
+ yaffs_BlockBecameDirty(dev, blk);
+ }
+
+ }
+
+
+ /* Ok, we've done all the scanning.
+ * Fix up the hard link chains.
+ * We should now have scanned all the objects, now it's time to add these
+ * hardlinks.
+ */
+
+ yaffs_HardlinkFixup(dev, hardList);
+
+ /* Fix up any shadowed objects */
+ {
+ struct yaffs_ShadowFixerStruct *fixer;
+ yaffs_Object *obj;
+
+ while (shadowFixerList) {
+ fixer = shadowFixerList;
+ shadowFixerList = fixer->next;
+ /* Complete the rename transaction by deleting the shadowed object
+ * then setting the object header to unshadowed.
+ */
+ obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId);
+ if (obj)
+ yaffs_DeleteObject(obj);
+
+ obj = yaffs_FindObjectByNumber(dev, fixer->objectId);
+
+ if (obj)
+ yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0, NULL);
+
+ YFREE(fixer);
+ }
+ }
+
+ yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
+
+ if (alloc_failed)
+ return YAFFS_FAIL;
+
+ T(YAFFS_TRACE_SCAN, (TSTR("yaffs1_Scan ends" TENDSTR)));
+
+
+ return YAFFS_OK;
+}
+
diff --git a/fs/yaffs2/yaffs_yaffs1.h b/fs/yaffs2/yaffs_yaffs1.h
new file mode 100644
index 00000000..9769eed3
--- /dev/null
+++ b/fs/yaffs2/yaffs_yaffs1.h
@@ -0,0 +1,22 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2010 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_YAFFS1_H__
+#define __YAFFS_YAFFS1_H__
+
+#include "yaffs_guts.h"
+int yaffs1_Scan(yaffs_Device *dev);
+
+#endif
diff --git a/fs/yaffs2/yaffs_yaffs2.c b/fs/yaffs2/yaffs_yaffs2.c
new file mode 100644
index 00000000..e13dd41c
--- /dev/null
+++ b/fs/yaffs2/yaffs_yaffs2.c
@@ -0,0 +1,1540 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2010 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning
+ *
+ * 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 "yaffs_guts.h"
+#include "yaffs_trace.h"
+#include "yaffs_yaffs2.h"
+#include "yaffs_checkptrw.h"
+#include "yaffs_bitmap.h"
+#include "yaffs_qsort.h"
+#include "yaffs_nand.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_verify.h"
+
+/*
+ * Checkpoints are really no benefit on very small partitions.
+ *
+ * To save space on small partitions don't bother with checkpoints unless
+ * the partition is at least this big.
+ */
+#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
+
+#define YAFFS_SMALL_HOLE_THRESHOLD 4
+
+
+/*
+ * Oldest Dirty Sequence Number handling.
+ */
+
+/* yaffs2_CalcOldestDirtySequence()
+ * yaffs2_FindOldestDirtySequence()
+ * Calculate the oldest dirty sequence number if we don't know it.
+ */
+void yaffs2_CalcOldestDirtySequence(yaffs_Device *dev)
+{
+ int i;
+ unsigned seq;
+ unsigned blockNo = 0;
+ yaffs_BlockInfo *b;
+
+ if(!dev->param.isYaffs2)
+ return;
+
+ /* Find the oldest dirty sequence number. */
+ seq = dev->sequenceNumber + 1;
+ b = dev->blockInfo;
+ for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
+ if (b->blockState == YAFFS_BLOCK_STATE_FULL &&
+ (b->pagesInUse - b->softDeletions) < dev->param.nChunksPerBlock &&
+ b->sequenceNumber < seq) {
+ seq = b->sequenceNumber;
+ blockNo = i;
+ }
+ b++;
+ }
+
+ if(blockNo){
+ dev->oldestDirtySequence = seq;
+ dev->oldestDirtyBlock = blockNo;
+ }
+
+}
+
+
+void yaffs2_FindOldestDirtySequence(yaffs_Device *dev)
+{
+ if(!dev->param.isYaffs2)
+ return;
+
+ if(!dev->oldestDirtySequence)
+ yaffs2_CalcOldestDirtySequence(dev);
+}
+
+/*
+ * yaffs_ClearOldestDirtySequence()
+ * Called when a block is erased or marked bad. (ie. when its sequenceNumber
+ * becomes invalid). If the value matches the oldest then we clear
+ * dev->oldestDirtySequence to force its recomputation.
+ */
+void yaffs2_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *bi)
+{
+
+ if(!dev->param.isYaffs2)
+ return;
+
+ if(!bi || bi->sequenceNumber == dev->oldestDirtySequence){
+ dev->oldestDirtySequence = 0;
+ dev->oldestDirtyBlock = 0;
+ }
+}
+
+/*
+ * yaffs2_UpdateOldestDirtySequence()
+ * Update the oldest dirty sequence number whenever we dirty a block.
+ * Only do this if the oldestDirtySequence is actually being tracked.
+ */
+void yaffs2_UpdateOldestDirtySequence(yaffs_Device *dev, unsigned blockNo, yaffs_BlockInfo *bi)
+{
+ if(!dev->param.isYaffs2)
+ return;
+
+ if(dev->oldestDirtySequence){
+ if(dev->oldestDirtySequence > bi->sequenceNumber){
+ dev->oldestDirtySequence = bi->sequenceNumber;
+ dev->oldestDirtyBlock = blockNo;
+ }
+ }
+}
+
+int yaffs2_BlockNotDisqualifiedFromGC(yaffs_Device *dev,
+ yaffs_BlockInfo *bi)
+{
+
+ if (!dev->param.isYaffs2)
+ return 1; /* disqualification only applies to yaffs2. */
+
+ if (!bi->hasShrinkHeader)
+ return 1; /* can gc */
+
+ yaffs2_FindOldestDirtySequence(dev);
+
+ /* Can't do gc of this block if there are any blocks older than this one that have
+ * discarded pages.
+ */
+ return (bi->sequenceNumber <= dev->oldestDirtySequence);
+}
+
+/*
+ * yaffs2_FindRefreshBlock()
+ * periodically finds the oldest full block by sequence number for refreshing.
+ * Only for yaffs2.
+ */
+__u32 yaffs2_FindRefreshBlock(yaffs_Device *dev)
+{
+ __u32 b ;
+
+ __u32 oldest = 0;
+ __u32 oldestSequence = 0;
+
+ yaffs_BlockInfo *bi;
+
+ if(!dev->param.isYaffs2)
+ return oldest;
+
+ /*
+ * If refresh period < 10 then refreshing is disabled.
+ */
+ if(dev->param.refreshPeriod < 10)
+ return oldest;
+
+ /*
+ * Fix broken values.
+ */
+ if(dev->refreshSkip > dev->param.refreshPeriod)
+ dev->refreshSkip = dev->param.refreshPeriod;
+
+ if(dev->refreshSkip > 0)
+ return oldest;
+
+ /*
+ * Refresh skip is now zero.
+ * We'll do a refresh this time around....
+ * Update the refresh skip and find the oldest block.
+ */
+ dev->refreshSkip = dev->param.refreshPeriod;
+ dev->refreshCount++;
+ bi = dev->blockInfo;
+ for (b = dev->internalStartBlock; b <=dev->internalEndBlock; b++){
+
+ if (bi->blockState == YAFFS_BLOCK_STATE_FULL){
+
+ if(oldest < 1 ||
+ bi->sequenceNumber < oldestSequence){
+ oldest = b;
+ oldestSequence = bi->sequenceNumber;
+ }
+ }
+ bi++;
+ }
+
+ if (oldest > 0) {
+ T(YAFFS_TRACE_GC,
+ (TSTR("GC refresh count %d selected block %d with sequenceNumber %d" TENDSTR),
+ dev->refreshCount, oldest, oldestSequence));
+ }
+
+ return oldest;
+}
+
+int yaffs2_CheckpointRequired(yaffs_Device *dev)
+{
+ int nblocks;
+
+ if(!dev->param.isYaffs2)
+ return 0;
+
+ nblocks = dev->internalEndBlock - dev->internalStartBlock + 1 ;
+
+ return !dev->param.skipCheckpointWrite &&
+ !dev->readOnly &&
+ (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
+}
+
+int yaffs2_CalcCheckpointBlocksRequired(yaffs_Device *dev)
+{
+ int retval;
+
+ if(!dev->param.isYaffs2)
+ return 0;
+
+ if (!dev->nCheckpointBlocksRequired &&
+ yaffs2_CheckpointRequired(dev)){
+ /* Not a valid value so recalculate */
+ int nBytes = 0;
+ int nBlocks;
+ int devBlocks = (dev->param.endBlock - dev->param.startBlock + 1);
+
+ nBytes += sizeof(yaffs_CheckpointValidity);
+ nBytes += sizeof(yaffs_CheckpointDevice);
+ nBytes += devBlocks * sizeof(yaffs_BlockInfo);
+ nBytes += devBlocks * dev->chunkBitmapStride;
+ nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjects);
+ nBytes += (dev->tnodeSize + sizeof(__u32)) * (dev->nTnodes);
+ nBytes += sizeof(yaffs_CheckpointValidity);
+ nBytes += sizeof(__u32); /* checksum*/
+
+ /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
+
+ nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->param.nChunksPerBlock)) + 3;
+
+ dev->nCheckpointBlocksRequired = nBlocks;
+ }
+
+ retval = dev->nCheckpointBlocksRequired - dev->blocksInCheckpoint;
+ if(retval < 0)
+ retval = 0;
+ return retval;
+}
+
+/*--------------------- Checkpointing --------------------*/
+
+
+static int yaffs2_WriteCheckpointValidityMarker(yaffs_Device *dev, int head)
+{
+ yaffs_CheckpointValidity cp;
+
+ memset(&cp, 0, sizeof(cp));
+
+ cp.structType = sizeof(cp);
+ cp.magic = YAFFS_MAGIC;
+ cp.version = YAFFS_CHECKPOINT_VERSION;
+ cp.head = (head) ? 1 : 0;
+
+ return (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
+ 1 : 0;
+}
+
+static int yaffs2_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
+{
+ yaffs_CheckpointValidity cp;
+ int ok;
+
+ ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
+
+ if (ok)
+ ok = (cp.structType == sizeof(cp)) &&
+ (cp.magic == YAFFS_MAGIC) &&
+ (cp.version == YAFFS_CHECKPOINT_VERSION) &&
+ (cp.head == ((head) ? 1 : 0));
+ return ok ? 1 : 0;
+}
+
+static void yaffs2_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
+ yaffs_Device *dev)
+{
+ cp->nErasedBlocks = dev->nErasedBlocks;
+ cp->allocationBlock = dev->allocationBlock;
+ cp->allocationPage = dev->allocationPage;
+ cp->nFreeChunks = dev->nFreeChunks;
+
+ cp->nDeletedFiles = dev->nDeletedFiles;
+ cp->nUnlinkedFiles = dev->nUnlinkedFiles;
+ cp->nBackgroundDeletions = dev->nBackgroundDeletions;
+ cp->sequenceNumber = dev->sequenceNumber;
+
+}
+
+static void yaffs2_CheckpointDeviceToDevice(yaffs_Device *dev,
+ yaffs_CheckpointDevice *cp)
+{
+ dev->nErasedBlocks = cp->nErasedBlocks;
+ dev->allocationBlock = cp->allocationBlock;
+ dev->allocationPage = cp->allocationPage;
+ dev->nFreeChunks = cp->nFreeChunks;
+
+ dev->nDeletedFiles = cp->nDeletedFiles;
+ dev->nUnlinkedFiles = cp->nUnlinkedFiles;
+ dev->nBackgroundDeletions = cp->nBackgroundDeletions;
+ dev->sequenceNumber = cp->sequenceNumber;
+}
+
+
+static int yaffs2_WriteCheckpointDevice(yaffs_Device *dev)
+{
+ yaffs_CheckpointDevice cp;
+ __u32 nBytes;
+ __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
+
+ int ok;
+
+ /* Write device runtime values*/
+ yaffs2_DeviceToCheckpointDevice(&cp, dev);
+ cp.structType = sizeof(cp);
+
+ ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
+
+ /* Write block info */
+ if (ok) {
+ nBytes = nBlocks * sizeof(yaffs_BlockInfo);
+ ok = (yaffs2_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes);
+ }
+
+ /* Write chunk bits */
+ if (ok) {
+ nBytes = nBlocks * dev->chunkBitmapStride;
+ ok = (yaffs2_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes);
+ }
+ return ok ? 1 : 0;
+
+}
+
+static int yaffs2_ReadCheckpointDevice(yaffs_Device *dev)
+{
+ yaffs_CheckpointDevice cp;
+ __u32 nBytes;
+ __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
+
+ int ok;
+
+ ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
+ if (!ok)
+ return 0;
+
+ if (cp.structType != sizeof(cp))
+ return 0;
+
+
+ yaffs2_CheckpointDeviceToDevice(dev, &cp);
+
+ nBytes = nBlocks * sizeof(yaffs_BlockInfo);
+
+ ok = (yaffs2_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes);
+
+ if (!ok)
+ return 0;
+ nBytes = nBlocks * dev->chunkBitmapStride;
+
+ ok = (yaffs2_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes);
+
+ return ok ? 1 : 0;
+}
+
+static void yaffs2_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
+ yaffs_Object *obj)
+{
+
+ cp->objectId = obj->objectId;
+ cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
+ cp->hdrChunk = obj->hdrChunk;
+ cp->variantType = obj->variantType;
+ cp->deleted = obj->deleted;
+ cp->softDeleted = obj->softDeleted;
+ cp->unlinked = obj->unlinked;
+ cp->fake = obj->fake;
+ cp->renameAllowed = obj->renameAllowed;
+ cp->unlinkAllowed = obj->unlinkAllowed;
+ cp->serial = obj->serial;
+ cp->nDataChunks = obj->nDataChunks;
+
+ if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
+ cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize;
+ else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
+ cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
+}
+
+static int yaffs2_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp)
+{
+
+ yaffs_Object *parent;
+
+ if (obj->variantType != cp->variantType) {
+ T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
+ TCONT("chunk %d does not match existing object type %d")
+ TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk,
+ obj->variantType));
+ return 0;
+ }
+
+ obj->objectId = cp->objectId;
+
+ if (cp->parentId)
+ parent = yaffs_FindOrCreateObjectByNumber(
+ obj->myDev,
+ cp->parentId,
+ YAFFS_OBJECT_TYPE_DIRECTORY);
+ else
+ parent = NULL;
+
+ if (parent) {
+ if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d"
+ TCONT(" chunk %d Parent type, %d, not directory")
+ TENDSTR),
+ cp->objectId, cp->parentId, cp->variantType,
+ cp->hdrChunk, parent->variantType));
+ return 0;
+ }
+ yaffs_AddObjectToDirectory(parent, obj);
+ }
+
+ obj->hdrChunk = cp->hdrChunk;
+ obj->variantType = cp->variantType;
+ obj->deleted = cp->deleted;
+ obj->softDeleted = cp->softDeleted;
+ obj->unlinked = cp->unlinked;
+ obj->fake = cp->fake;
+ obj->renameAllowed = cp->renameAllowed;
+ obj->unlinkAllowed = cp->unlinkAllowed;
+ obj->serial = cp->serial;
+ obj->nDataChunks = cp->nDataChunks;
+
+ if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
+ obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;
+ else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
+ obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;
+
+ if (obj->hdrChunk > 0)
+ obj->lazyLoaded = 1;
+ return 1;
+}
+
+
+
+static int yaffs2_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn,
+ __u32 level, int chunkOffset)
+{
+ int i;
+ yaffs_Device *dev = in->myDev;
+ int ok = 1;
+
+ if (tn) {
+ if (level > 0) {
+
+ for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
+ if (tn->internal[i]) {
+ ok = yaffs2_CheckpointTnodeWorker(in,
+ tn->internal[i],
+ level - 1,
+ (chunkOffset<tnodeSize) == dev->tnodeSize);
+ }
+ }
+
+ return ok;
+
+}
+
+static int yaffs2_WriteCheckpointTnodes(yaffs_Object *obj)
+{
+ __u32 endMarker = ~0;
+ int ok = 1;
+
+ if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
+ ok = yaffs2_CheckpointTnodeWorker(obj,
+ obj->variant.fileVariant.top,
+ obj->variant.fileVariant.topLevel,
+ 0);
+ if (ok)
+ ok = (yaffs2_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) ==
+ sizeof(endMarker));
+ }
+
+ return ok ? 1 : 0;
+}
+
+static int yaffs2_ReadCheckpointTnodes(yaffs_Object *obj)
+{
+ __u32 baseChunk;
+ int ok = 1;
+ yaffs_Device *dev = obj->myDev;
+ yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
+ yaffs_Tnode *tn;
+ int nread = 0;
+
+ ok = (yaffs2_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
+
+ while (ok && (~baseChunk)) {
+ nread++;
+ /* Read level 0 tnode */
+
+
+ tn = yaffs_GetTnode(dev);
+ if (tn){
+ ok = (yaffs2_CheckpointRead(dev, tn, dev->tnodeSize) == dev->tnodeSize);
+ } else
+ ok = 0;
+
+ if (tn && ok)
+ ok = yaffs_AddOrFindLevel0Tnode(dev,
+ fileStructPtr,
+ baseChunk,
+ tn) ? 1 : 0;
+
+ if (ok)
+ ok = (yaffs2_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
+
+ }
+
+ T(YAFFS_TRACE_CHECKPOINT, (
+ TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
+ nread, baseChunk, ok));
+
+ return ok ? 1 : 0;
+}
+
+
+static int yaffs2_WriteCheckpointObjects(yaffs_Device *dev)
+{
+ yaffs_Object *obj;
+ yaffs_CheckpointObject cp;
+ int i;
+ int ok = 1;
+ struct ylist_head *lh;
+
+
+ /* Iterate through the objects in each hash entry,
+ * dumping them to the checkpointing stream.
+ */
+
+ for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
+ ylist_for_each(lh, &dev->objectBucket[i].list) {
+ if (lh) {
+ obj = ylist_entry(lh, yaffs_Object, hashLink);
+ if (!obj->deferedFree) {
+ yaffs2_ObjectToCheckpointObject(&cp, obj);
+ cp.structType = sizeof(cp);
+
+ T(YAFFS_TRACE_CHECKPOINT, (
+ TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %p" TENDSTR),
+ cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, obj));
+
+ ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
+
+ if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE)
+ ok = yaffs2_WriteCheckpointTnodes(obj);
+ }
+ }
+ }
+ }
+
+ /* Dump end of list */
+ memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject));
+ cp.structType = sizeof(cp);
+
+ if (ok)
+ ok = (yaffs2_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
+
+ return ok ? 1 : 0;
+}
+
+static int yaffs2_ReadCheckpointObjects(yaffs_Device *dev)
+{
+ yaffs_Object *obj;
+ yaffs_CheckpointObject cp;
+ int ok = 1;
+ int done = 0;
+ yaffs_Object *hardList = NULL;
+
+ while (ok && !done) {
+ ok = (yaffs2_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
+ if (cp.structType != sizeof(cp)) {
+ T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
+ cp.structType, (int)sizeof(cp), ok));
+ ok = 0;
+ }
+
+ T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
+ cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk));
+
+ if (ok && cp.objectId == ~0)
+ done = 1;
+ else if (ok) {
+ obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType);
+ if (obj) {
+ ok = yaffs2_CheckpointObjectToObject(obj, &cp);
+ if (!ok)
+ break;
+ if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
+ ok = yaffs2_ReadCheckpointTnodes(obj);
+ } else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
+ obj->hardLinks.next =
+ (struct ylist_head *) hardList;
+ hardList = obj;
+ }
+ } else
+ ok = 0;
+ }
+ }
+
+ if (ok)
+ yaffs_HardlinkFixup(dev, hardList);
+
+ return ok ? 1 : 0;
+}
+
+static int yaffs2_WriteCheckpointSum(yaffs_Device *dev)
+{
+ __u32 checkpointSum;
+ int ok;
+
+ yaffs2_GetCheckpointSum(dev, &checkpointSum);
+
+ ok = (yaffs2_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum));
+
+ if (!ok)
+ return 0;
+
+ return 1;
+}
+
+static int yaffs2_ReadCheckpointSum(yaffs_Device *dev)
+{
+ __u32 checkpointSum0;
+ __u32 checkpointSum1;
+ int ok;
+
+ yaffs2_GetCheckpointSum(dev, &checkpointSum0);
+
+ ok = (yaffs2_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1));
+
+ if (!ok)
+ return 0;
+
+ if (checkpointSum0 != checkpointSum1)
+ return 0;
+
+ return 1;
+}
+
+
+static int yaffs2_WriteCheckpointData(yaffs_Device *dev)
+{
+ int ok = 1;
+
+ if (!yaffs2_CheckpointRequired(dev)) {
+ T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
+ ok = 0;
+ }
+
+ if (ok)
+ ok = yaffs2_CheckpointOpen(dev, 1);
+
+ if (ok) {
+ T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
+ ok = yaffs2_WriteCheckpointValidityMarker(dev, 1);
+ }
+ if (ok) {
+ T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
+ ok = yaffs2_WriteCheckpointDevice(dev);
+ }
+ if (ok) {
+ T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
+ ok = yaffs2_WriteCheckpointObjects(dev);
+ }
+ if (ok) {
+ T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
+ ok = yaffs2_WriteCheckpointValidityMarker(dev, 0);
+ }
+
+ if (ok)
+ ok = yaffs2_WriteCheckpointSum(dev);
+
+ if (!yaffs2_CheckpointClose(dev))
+ ok = 0;
+
+ if (ok)
+ dev->isCheckpointed = 1;
+ else
+ dev->isCheckpointed = 0;
+
+ return dev->isCheckpointed;
+}
+
+static int yaffs2_ReadCheckpointData(yaffs_Device *dev)
+{
+ int ok = 1;
+
+ if(!dev->param.isYaffs2)
+ ok = 0;
+
+ if (ok && dev->param.skipCheckpointRead) {
+ T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
+ ok = 0;
+ }
+
+ if (ok)
+ ok = yaffs2_CheckpointOpen(dev, 0); /* open for read */
+
+ if (ok) {
+ T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
+ ok = yaffs2_ReadCheckpointValidityMarker(dev, 1);
+ }
+ if (ok) {
+ T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
+ ok = yaffs2_ReadCheckpointDevice(dev);
+ }
+ if (ok) {
+ T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
+ ok = yaffs2_ReadCheckpointObjects(dev);
+ }
+ if (ok) {
+ T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
+ ok = yaffs2_ReadCheckpointValidityMarker(dev, 0);
+ }
+
+ if (ok) {
+ ok = yaffs2_ReadCheckpointSum(dev);
+ T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
+ }
+
+ if (!yaffs2_CheckpointClose(dev))
+ ok = 0;
+
+ if (ok)
+ dev->isCheckpointed = 1;
+ else
+ dev->isCheckpointed = 0;
+
+ return ok ? 1 : 0;
+
+}
+
+void yaffs2_InvalidateCheckpoint(yaffs_Device *dev)
+{
+ if (dev->isCheckpointed ||
+ dev->blocksInCheckpoint > 0) {
+ dev->isCheckpointed = 0;
+ yaffs2_CheckpointInvalidateStream(dev);
+ }
+ if (dev->param.markSuperBlockDirty)
+ dev->param.markSuperBlockDirty(dev);
+}
+
+
+int yaffs_CheckpointSave(yaffs_Device *dev)
+{
+
+ T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
+
+ yaffs_VerifyObjects(dev);
+ yaffs_VerifyBlocks(dev);
+ yaffs_VerifyFreeChunks(dev);
+
+ if (!dev->isCheckpointed) {
+ yaffs2_InvalidateCheckpoint(dev);
+ yaffs2_WriteCheckpointData(dev);
+ }
+
+ T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
+
+ return dev->isCheckpointed;
+}
+
+int yaffs2_CheckpointRestore(yaffs_Device *dev)
+{
+ int retval;
+ T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
+
+ retval = yaffs2_ReadCheckpointData(dev);
+
+ if (dev->isCheckpointed) {
+ yaffs_VerifyObjects(dev);
+ yaffs_VerifyBlocks(dev);
+ yaffs_VerifyFreeChunks(dev);
+ }
+
+ T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
+
+ return retval;
+}
+
+int yaffs2_HandleHole(yaffs_Object *obj, loff_t newSize)
+{
+ /* if newsSize > oldFileSize.
+ * We're going to be writing a hole.
+ * If the hole is small then write zeros otherwise write a start of hole marker.
+ */
+
+
+ loff_t oldFileSize;
+ int increase;
+ int smallHole ;
+ int result = YAFFS_OK;
+ yaffs_Device *dev = NULL;
+
+ __u8 *localBuffer = NULL;
+
+ int smallIncreaseOk = 0;
+
+ if(!obj)
+ return YAFFS_FAIL;
+
+ if(obj->variantType != YAFFS_OBJECT_TYPE_FILE)
+ return YAFFS_FAIL;
+
+ dev = obj->myDev;
+
+ /* Bail out if not yaffs2 mode */
+ if(!dev->param.isYaffs2)
+ return YAFFS_OK;
+
+ oldFileSize = obj->variant.fileVariant.fileSize;
+
+ if (newSize <= oldFileSize)
+ return YAFFS_OK;
+
+ increase = newSize - oldFileSize;
+
+ if(increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->nDataBytesPerChunk &&
+ yaffs_CheckSpaceForAllocation(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
+ smallHole = 1;
+ else
+ smallHole = 0;
+
+ if(smallHole)
+ localBuffer= yaffs_GetTempBuffer(dev, __LINE__);
+
+ if(localBuffer){
+ /* fill hole with zero bytes */
+ int pos = oldFileSize;
+ int thisWrite;
+ int written;
+ memset(localBuffer,0,dev->nDataBytesPerChunk);
+ smallIncreaseOk = 1;
+
+ while(increase > 0 && smallIncreaseOk){
+ thisWrite = increase;
+ if(thisWrite > dev->nDataBytesPerChunk)
+ thisWrite = dev->nDataBytesPerChunk;
+ written = yaffs_DoWriteDataToFile(obj,localBuffer,pos,thisWrite,0);
+ if(written == thisWrite){
+ pos += thisWrite;
+ increase -= thisWrite;
+ } else
+ smallIncreaseOk = 0;
+ }
+
+ yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
+
+ /* If we were out of space then reverse any chunks we've added */
+ if(!smallIncreaseOk)
+ yaffs_ResizeDown(obj, oldFileSize);
+ }
+
+ if (!smallIncreaseOk &&
+ obj->parent &&
+ obj->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
+ obj->parent->objectId != YAFFS_OBJECTID_DELETED){
+ /* Write a hole start header with the old file size */
+ yaffs_UpdateObjectHeader(obj, NULL, 0, 1, 0, NULL);
+ }
+
+ return result;
+
+}
+
+
+typedef struct {
+ int seq;
+ int block;
+} yaffs_BlockIndex;
+
+
+static int yaffs2_ybicmp(const void *a, const void *b)
+{
+ register int aseq = ((yaffs_BlockIndex *)a)->seq;
+ register int bseq = ((yaffs_BlockIndex *)b)->seq;
+ register int ablock = ((yaffs_BlockIndex *)a)->block;
+ register int bblock = ((yaffs_BlockIndex *)b)->block;
+ if (aseq == bseq)
+ return ablock - bblock;
+ else
+ return aseq - bseq;
+}
+
+int yaffs2_ScanBackwards(yaffs_Device *dev)
+{
+ yaffs_ExtendedTags tags;
+ int blk;
+ int blockIterator;
+ int startIterator;
+ int endIterator;
+ int nBlocksToScan = 0;
+
+ int chunk;
+ int result;
+ int c;
+ int deleted;
+ yaffs_BlockState state;
+ yaffs_Object *hardList = NULL;
+ yaffs_BlockInfo *bi;
+ __u32 sequenceNumber;
+ yaffs_ObjectHeader *oh;
+ yaffs_Object *in;
+ yaffs_Object *parent;
+ int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
+ int itsUnlinked;
+ __u8 *chunkData;
+
+ int fileSize;
+ int isShrink;
+ int foundChunksInBlock;
+ int equivalentObjectId;
+ int alloc_failed = 0;
+
+
+ yaffs_BlockIndex *blockIndex = NULL;
+ int altBlockIndex = 0;
+
+ T(YAFFS_TRACE_SCAN,
+ (TSTR
+ ("yaffs2_ScanBackwards starts intstartblk %d intendblk %d..."
+ TENDSTR), dev->internalStartBlock, dev->internalEndBlock));
+
+
+ dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
+
+ blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
+
+ if (!blockIndex) {
+ blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
+ altBlockIndex = 1;
+ }
+
+ if (!blockIndex) {
+ T(YAFFS_TRACE_SCAN,
+ (TSTR("yaffs2_ScanBackwards() could not allocate block index!" TENDSTR)));
+ return YAFFS_FAIL;
+ }
+
+ dev->blocksInCheckpoint = 0;
+
+ chunkData = yaffs_GetTempBuffer(dev, __LINE__);
+
+ /* Scan all the blocks to determine their state */
+ bi = dev->blockInfo;
+ for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
+ yaffs_ClearChunkBits(dev, blk);
+ bi->pagesInUse = 0;
+ bi->softDeletions = 0;
+
+ yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
+
+ bi->blockState = state;
+ bi->sequenceNumber = sequenceNumber;
+
+ if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA)
+ bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT;
+ if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
+ bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
+
+ T(YAFFS_TRACE_SCAN_DEBUG,
+ (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
+ state, sequenceNumber));
+
+
+ if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
+ dev->blocksInCheckpoint++;
+
+ } else if (state == YAFFS_BLOCK_STATE_DEAD) {
+ T(YAFFS_TRACE_BAD_BLOCKS,
+ (TSTR("block %d is bad" TENDSTR), blk));
+ } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
+ T(YAFFS_TRACE_SCAN_DEBUG,
+ (TSTR("Block empty " TENDSTR)));
+ dev->nErasedBlocks++;
+ dev->nFreeChunks += dev->param.nChunksPerBlock;
+ } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
+
+ /* Determine the highest sequence number */
+ if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
+ sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
+
+ blockIndex[nBlocksToScan].seq = sequenceNumber;
+ blockIndex[nBlocksToScan].block = blk;
+
+ nBlocksToScan++;
+
+ if (sequenceNumber >= dev->sequenceNumber)
+ dev->sequenceNumber = sequenceNumber;
+ } else {
+ /* TODO: Nasty sequence number! */
+ T(YAFFS_TRACE_SCAN,
+ (TSTR
+ ("Block scanning block %d has bad sequence number %d"
+ TENDSTR), blk, sequenceNumber));
+
+ }
+ }
+ bi++;
+ }
+
+ T(YAFFS_TRACE_SCAN,
+ (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
+
+
+
+ YYIELD();
+
+ /* Sort the blocks by sequence number*/
+ yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), yaffs2_ybicmp);
+
+ YYIELD();
+
+ T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
+
+ /* Now scan the blocks looking at the data. */
+ startIterator = 0;
+ endIterator = nBlocksToScan - 1;
+ T(YAFFS_TRACE_SCAN_DEBUG,
+ (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
+
+ /* For each block.... backwards */
+ for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
+ blockIterator--) {
+ /* Cooperative multitasking! This loop can run for so
+ long that watchdog timers expire. */
+ YYIELD();
+
+ /* get the block to scan in the correct order */
+ blk = blockIndex[blockIterator].block;
+
+ bi = yaffs_GetBlockInfo(dev, blk);
+
+
+ state = bi->blockState;
+
+ deleted = 0;
+
+ /* For each chunk in each block that needs scanning.... */
+ foundChunksInBlock = 0;
+ for (c = dev->param.nChunksPerBlock - 1;
+ !alloc_failed && c >= 0 &&
+ (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
+ state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
+ /* Scan backwards...
+ * Read the tags and decide what to do
+ */
+
+ chunk = blk * dev->param.nChunksPerBlock + c;
+
+ result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
+ &tags);
+
+ /* Let's have a good look at this chunk... */
+
+ if (!tags.chunkUsed) {
+ /* An unassigned chunk in the block.
+ * If there are used chunks after this one, then
+ * it is a chunk that was skipped due to failing the erased
+ * check. Just skip it so that it can be deleted.
+ * But, more typically, We get here when this is an unallocated
+ * chunk and his means that either the block is empty or
+ * this is the one being allocated from
+ */
+
+ if (foundChunksInBlock) {
+ /* This is a chunk that was skipped due to failing the erased check */
+ } else if (c == 0) {
+ /* We're looking at the first chunk in the block so the block is unused */
+ state = YAFFS_BLOCK_STATE_EMPTY;
+ dev->nErasedBlocks++;
+ } else {
+ if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
+ state == YAFFS_BLOCK_STATE_ALLOCATING) {
+ if (dev->sequenceNumber == bi->sequenceNumber) {
+ /* this is the block being allocated from */
+
+ T(YAFFS_TRACE_SCAN,
+ (TSTR
+ (" Allocating from %d %d"
+ TENDSTR), blk, c));
+
+ state = YAFFS_BLOCK_STATE_ALLOCATING;
+ dev->allocationBlock = blk;
+ dev->allocationPage = c;
+ dev->allocationBlockFinder = blk;
+ } else {
+ /* This is a partially written block that is not
+ * the current allocation block.
+ */
+
+ T(YAFFS_TRACE_SCAN,
+ (TSTR("Partially written block %d detected" TENDSTR),
+ blk));
+ }
+ }
+ }
+
+ dev->nFreeChunks++;
+
+ } else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED) {
+ T(YAFFS_TRACE_SCAN,
+ (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
+ blk, c));
+
+ dev->nFreeChunks++;
+
+ } else if (tags.objectId > YAFFS_MAX_OBJECT_ID ||
+ tags.chunkId > YAFFS_MAX_CHUNK_ID ||
+ (tags.chunkId > 0 && tags.byteCount > dev->nDataBytesPerChunk) ||
+ tags.sequenceNumber != bi->sequenceNumber ) {
+ T(YAFFS_TRACE_SCAN,
+ (TSTR("Chunk (%d:%d) with bad tags:obj = %d, chunkId = %d, byteCount = %d, ignored"TENDSTR),
+ blk, c,tags.objectId, tags.chunkId, tags.byteCount));
+
+ dev->nFreeChunks++;
+
+ } else if (tags.chunkId > 0) {
+ /* chunkId > 0 so it is a data chunk... */
+ unsigned int endpos;
+ __u32 chunkBase =
+ (tags.chunkId - 1) * dev->nDataBytesPerChunk;
+
+ foundChunksInBlock = 1;
+
+
+ yaffs_SetChunkBit(dev, blk, c);
+ bi->pagesInUse++;
+
+ in = yaffs_FindOrCreateObjectByNumber(dev,
+ tags.
+ objectId,
+ YAFFS_OBJECT_TYPE_FILE);
+ if (!in) {
+ /* Out of memory */
+ alloc_failed = 1;
+ }
+
+ if (in &&
+ in->variantType == YAFFS_OBJECT_TYPE_FILE
+ && chunkBase < in->variant.fileVariant.shrinkSize) {
+ /* This has not been invalidated by a resize */
+ if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, -1)) {
+ alloc_failed = 1;
+ }
+
+ /* File size is calculated by looking at the data chunks if we have not
+ * seen an object header yet. Stop this practice once we find an object header.
+ */
+ endpos = chunkBase + tags.byteCount;
+
+ if (!in->valid && /* have not got an object header yet */
+ in->variant.fileVariant.scannedFileSize < endpos) {
+ in->variant.fileVariant.scannedFileSize = endpos;
+ in->variant.fileVariant.fileSize = endpos;
+ }
+
+ } else if (in) {
+ /* This chunk has been invalidated by a resize, or a past file deletion
+ * so delete the chunk*/
+ yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
+
+ }
+ } else {
+ /* chunkId == 0, so it is an ObjectHeader.
+ * Thus, we read in the object header and make the object
+ */
+ foundChunksInBlock = 1;
+
+ yaffs_SetChunkBit(dev, blk, c);
+ bi->pagesInUse++;
+
+ oh = NULL;
+ in = NULL;
+
+ if (tags.extraHeaderInfoAvailable) {
+ in = yaffs_FindOrCreateObjectByNumber(dev,
+ tags.objectId,
+ tags.extraObjectType);
+ if (!in)
+ alloc_failed = 1;
+ }
+
+ if (!in ||
+ (!in->valid && dev->param.disableLazyLoad) ||
+ tags.extraShadows ||
+ (!in->valid &&
+ (tags.objectId == YAFFS_OBJECTID_ROOT ||
+ tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) {
+
+ /* If we don't have valid info then we need to read the chunk
+ * TODO In future we can probably defer reading the chunk and
+ * living with invalid data until needed.
+ */
+
+ result = yaffs_ReadChunkWithTagsFromNAND(dev,
+ chunk,
+ chunkData,
+ NULL);
+
+ oh = (yaffs_ObjectHeader *) chunkData;
+
+ if (dev->param.inbandTags) {
+ /* Fix up the header if they got corrupted by inband tags */
+ oh->shadowsObject = oh->inbandShadowsObject;
+ oh->isShrink = oh->inbandIsShrink;
+ }
+
+ if (!in) {
+ in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);
+ if (!in)
+ alloc_failed = 1;
+ }
+
+ }
+
+ if (!in) {
+ /* TODO Hoosterman we have a problem! */
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
+ TENDSTR), tags.objectId, chunk));
+ continue;
+ }
+
+ if (in->valid) {
+ /* We have already filled this one.
+ * We have a duplicate that will be discarded, but
+ * we first have to suck out resize info if it is a file.
+ */
+
+ if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
+ ((oh &&
+ oh->type == YAFFS_OBJECT_TYPE_FILE) ||
+ (tags.extraHeaderInfoAvailable &&
+ tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) {
+ __u32 thisSize =
+ (oh) ? oh->fileSize : tags.
+ extraFileLength;
+ __u32 parentObjectId =
+ (oh) ? oh->
+ parentObjectId : tags.
+ extraParentObjectId;
+
+
+ isShrink =
+ (oh) ? oh->isShrink : tags.
+ extraIsShrinkHeader;
+
+ /* If it is deleted (unlinked at start also means deleted)
+ * we treat the file size as being zeroed at this point.
+ */
+ if (parentObjectId ==
+ YAFFS_OBJECTID_DELETED
+ || parentObjectId ==
+ YAFFS_OBJECTID_UNLINKED) {
+ thisSize = 0;
+ isShrink = 1;
+ }
+
+ if (isShrink && in->variant.fileVariant.shrinkSize > thisSize)
+ in->variant.fileVariant.shrinkSize = thisSize;
+
+ if (isShrink)
+ bi->hasShrinkHeader = 1;
+
+ }
+ /* Use existing - destroy this one. */
+ yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
+
+ }
+
+ if (!in->valid && in->variantType !=
+ (oh ? oh->type : tags.extraObjectType))
+ T(YAFFS_TRACE_ERROR, (
+ TSTR("yaffs tragedy: Bad object type, "
+ TCONT("%d != %d, for object %d at chunk ")
+ TCONT("%d during scan")
+ TENDSTR), oh ?
+ oh->type : tags.extraObjectType,
+ in->variantType, tags.objectId,
+ chunk));
+
+ if (!in->valid &&
+ (tags.objectId == YAFFS_OBJECTID_ROOT ||
+ tags.objectId ==
+ YAFFS_OBJECTID_LOSTNFOUND)) {
+ /* We only load some info, don't fiddle with directory structure */
+ in->valid = 1;
+
+ if (oh) {
+
+ in->yst_mode = oh->yst_mode;
+#ifdef CONFIG_YAFFS_WINCE
+ in->win_atime[0] = oh->win_atime[0];
+ in->win_ctime[0] = oh->win_ctime[0];
+ in->win_mtime[0] = oh->win_mtime[0];
+ in->win_atime[1] = oh->win_atime[1];
+ in->win_ctime[1] = oh->win_ctime[1];
+ in->win_mtime[1] = oh->win_mtime[1];
+#else
+ in->yst_uid = oh->yst_uid;
+ in->yst_gid = oh->yst_gid;
+ in->yst_atime = oh->yst_atime;
+ in->yst_mtime = oh->yst_mtime;
+ in->yst_ctime = oh->yst_ctime;
+ in->yst_rdev = oh->yst_rdev;
+
+ in->lazyLoaded = 0;
+
+#endif
+ } else
+ in->lazyLoaded = 1;
+
+ in->hdrChunk = chunk;
+
+ } else if (!in->valid) {
+ /* we need to load this info */
+
+ in->valid = 1;
+ in->hdrChunk = chunk;
+
+ if (oh) {
+ in->variantType = oh->type;
+
+ in->yst_mode = oh->yst_mode;
+#ifdef CONFIG_YAFFS_WINCE
+ in->win_atime[0] = oh->win_atime[0];
+ in->win_ctime[0] = oh->win_ctime[0];
+ in->win_mtime[0] = oh->win_mtime[0];
+ in->win_atime[1] = oh->win_atime[1];
+ in->win_ctime[1] = oh->win_ctime[1];
+ in->win_mtime[1] = oh->win_mtime[1];
+#else
+ in->yst_uid = oh->yst_uid;
+ in->yst_gid = oh->yst_gid;
+ in->yst_atime = oh->yst_atime;
+ in->yst_mtime = oh->yst_mtime;
+ in->yst_ctime = oh->yst_ctime;
+ in->yst_rdev = oh->yst_rdev;
+#endif
+
+ if (oh->shadowsObject > 0)
+ yaffs_HandleShadowedObject(dev,
+ oh->
+ shadowsObject,
+ 1);
+
+
+
+ yaffs_SetObjectNameFromOH(in, oh);
+ parent =
+ yaffs_FindOrCreateObjectByNumber
+ (dev, oh->parentObjectId,
+ YAFFS_OBJECT_TYPE_DIRECTORY);
+
+ fileSize = oh->fileSize;
+ isShrink = oh->isShrink;
+ equivalentObjectId = oh->equivalentObjectId;
+
+ } else {
+ in->variantType = tags.extraObjectType;
+ parent =
+ yaffs_FindOrCreateObjectByNumber
+ (dev, tags.extraParentObjectId,
+ YAFFS_OBJECT_TYPE_DIRECTORY);
+ fileSize = tags.extraFileLength;
+ isShrink = tags.extraIsShrinkHeader;
+ equivalentObjectId = tags.extraEquivalentObjectId;
+ in->lazyLoaded = 1;
+
+ }
+ in->dirty = 0;
+
+ if (!parent)
+ alloc_failed = 1;
+
+ /* directory stuff...
+ * hook up to parent
+ */
+
+ if (parent && parent->variantType ==
+ YAFFS_OBJECT_TYPE_UNKNOWN) {
+ /* Set up as a directory */
+ parent->variantType =
+ YAFFS_OBJECT_TYPE_DIRECTORY;
+ YINIT_LIST_HEAD(&parent->variant.
+ directoryVariant.
+ children);
+ } else if (!parent || parent->variantType !=
+ YAFFS_OBJECT_TYPE_DIRECTORY) {
+ /* Hoosterman, another problem....
+ * We're trying to use a non-directory as a directory
+ */
+
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
+ TENDSTR)));
+ parent = dev->lostNFoundDir;
+ }
+
+ yaffs_AddObjectToDirectory(parent, in);
+
+ itsUnlinked = (parent == dev->deletedDir) ||
+ (parent == dev->unlinkedDir);
+
+ if (isShrink) {
+ /* Mark the block as having a shrinkHeader */
+ bi->hasShrinkHeader = 1;
+ }
+
+ /* Note re hardlinks.
+ * Since we might scan a hardlink before its equivalent object is scanned
+ * we put them all in a list.
+ * After scanning is complete, we should have all the objects, so we run
+ * through this list and fix up all the chains.
+ */
+
+ switch (in->variantType) {
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ /* Todo got a problem */
+ break;
+ case YAFFS_OBJECT_TYPE_FILE:
+
+ if (in->variant.fileVariant.
+ scannedFileSize < fileSize) {
+ /* This covers the case where the file size is greater
+ * than where the data is
+ * This will happen if the file is resized to be larger
+ * than its current data extents.
+ */
+ in->variant.fileVariant.fileSize = fileSize;
+ in->variant.fileVariant.scannedFileSize = fileSize;
+ }
+
+ if (in->variant.fileVariant.shrinkSize > fileSize)
+ in->variant.fileVariant.shrinkSize = fileSize;
+
+
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ if (!itsUnlinked) {
+ in->variant.hardLinkVariant.equivalentObjectId =
+ equivalentObjectId;
+ in->hardLinks.next =
+ (struct ylist_head *) hardList;
+ hardList = in;
+ }
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ /* Do nothing */
+ break;
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ /* Do nothing */
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ if (oh) {
+ in->variant.symLinkVariant.alias =
+ yaffs_CloneString(oh->alias);
+ if (!in->variant.symLinkVariant.alias)
+ alloc_failed = 1;
+ }
+ break;
+ }
+
+ }
+
+ }
+
+ } /* End of scanning for each chunk */
+
+ if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
+ /* If we got this far while scanning, then the block is fully allocated. */
+ state = YAFFS_BLOCK_STATE_FULL;
+ }
+
+
+ bi->blockState = state;
+
+ /* Now let's see if it was dirty */
+ if (bi->pagesInUse == 0 &&
+ !bi->hasShrinkHeader &&
+ bi->blockState == YAFFS_BLOCK_STATE_FULL) {
+ yaffs_BlockBecameDirty(dev, blk);
+ }
+
+ }
+
+ yaffs_SkipRestOfBlock(dev);
+
+ if (altBlockIndex)
+ YFREE_ALT(blockIndex);
+ else
+ YFREE(blockIndex);
+
+ /* Ok, we've done all the scanning.
+ * Fix up the hard link chains.
+ * We should now have scanned all the objects, now it's time to add these
+ * hardlinks.
+ */
+ yaffs_HardlinkFixup(dev, hardList);
+
+
+ yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
+
+ if (alloc_failed)
+ return YAFFS_FAIL;
+
+ T(YAFFS_TRACE_SCAN, (TSTR("yaffs2_ScanBackwards ends" TENDSTR)));
+
+ return YAFFS_OK;
+}
diff --git a/fs/yaffs2/yaffs_yaffs2.h b/fs/yaffs2/yaffs_yaffs2.h
new file mode 100644
index 00000000..08ba3630
--- /dev/null
+++ b/fs/yaffs2/yaffs_yaffs2.h
@@ -0,0 +1,38 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2010 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_YAFFS2_H__
+#define __YAFFS_YAFFS2_H__
+
+#include "yaffs_guts.h"
+
+void yaffs2_CalcOldestDirtySequence(yaffs_Device *dev);
+void yaffs2_FindOldestDirtySequence(yaffs_Device *dev);
+void yaffs2_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *bi);
+void yaffs2_UpdateOldestDirtySequence(yaffs_Device *dev, unsigned blockNo, yaffs_BlockInfo *bi);
+int yaffs2_BlockNotDisqualifiedFromGC(yaffs_Device *dev, yaffs_BlockInfo *bi);
+__u32 yaffs2_FindRefreshBlock(yaffs_Device *dev);
+int yaffs2_CheckpointRequired(yaffs_Device *dev);
+int yaffs2_CalcCheckpointBlocksRequired(yaffs_Device *dev);
+
+
+void yaffs2_InvalidateCheckpoint(yaffs_Device *dev);
+int yaffs2_CheckpointSave(yaffs_Device *dev);
+int yaffs2_CheckpointRestore(yaffs_Device *dev);
+
+int yaffs2_HandleHole(yaffs_Object *obj, loff_t newSize);
+int yaffs2_ScanBackwards(yaffs_Device *dev);
+
+#endif