Changeset 9249


Ignore:
Timestamp:
2007-10-10T20:05:48+02:00 (10 years ago)
Author:
juhosg
Message:

[kernel] dissect yaffs patch

Location:
trunk/target/linux/generic-2.6
Files:
35 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/target/linux/generic-2.6/patches-2.6.22/510-Yaffs.patch

    r7534 r9249  
    1818 obj-$(CONFIG_GFS2_FS)           += gfs2/ 
    1919+obj-$(CONFIG_YAFFS_FS)         += yaffs2/ 
    20 diff -urN linux-2.6.21.1/fs/yaffs2/Kconfig linux-2.6.21.1.new/fs/yaffs2/Kconfig 
    21 --- linux-2.6.21.1/fs/yaffs2/Kconfig    1970-01-01 01:00:00.000000000 +0100 
    22 +++ linux-2.6.21.1.new/fs/yaffs2/Kconfig        2007-06-08 14:07:26.000000000 +0200 
    23 @@ -0,0 +1,175 @@ 
    24 +# 
    25 +# YAFFS file system configurations 
    26 +# 
    27 + 
    28 +config YAFFS_FS 
    29 +       tristate "YAFFS2 file system support" 
    30 +       default n 
    31 +       depends on MTD 
    32 +       select YAFFS_YAFFS1 
    33 +       select YAFFS_YAFFS2 
    34 +       help 
    35 +         YAFFS2, or Yet Another Flash Filing System, is a filing system 
    36 +         optimised for NAND Flash chips. 
    37 + 
    38 +         To compile the YAFFS2 file system support as a module, choose M 
    39 +         here: the module will be called yaffs2. 
    40 + 
    41 +         If unsure, say N. 
    42 + 
    43 +         Further information on YAFFS2 is available at 
    44 +         <http://www.aleph1.co.uk/yaffs/>. 
    45 + 
    46 +config YAFFS_YAFFS1 
    47 +       bool "512 byte / page devices" 
    48 +       depends on YAFFS_FS 
    49 +       default y 
    50 +       help 
    51 +         Enable YAFFS1 support -- yaffs for 512 byte / page devices 
    52 +          
    53 +         Not needed for 2K-page devices. 
    54 + 
    55 +         If unsure, say Y. 
    56 + 
    57 +config YAFFS_9BYTE_TAGS 
    58 +       bool "Use older-style on-NAND data format with pageStatus byte" 
    59 +       depends on YAFFS_YAFFS1 
    60 +       default n 
    61 +       help 
    62 + 
    63 +         Older-style on-NAND data format has a "pageStatus" byte to record 
    64 +         chunk/page state.  This byte is zero when the page is discarded. 
    65 +         Choose this option if you have existing on-NAND data using this 
    66 +         format that you need to continue to support.  New data written 
    67 +         also uses the older-style format.  Note: Use of this option 
    68 +         generally requires that MTD's oob layout be adjusted to use the 
    69 +         older-style format.  See notes on tags formats and MTD versions. 
    70 + 
    71 +         If unsure, say N. 
    72 + 
    73 +config YAFFS_DOES_ECC 
    74 +       bool "Lets Yaffs do its own ECC" 
    75 +       depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS 
    76 +       default n 
    77 +       help 
    78 +         This enables Yaffs to use its own ECC functions instead of using 
    79 +         the ones from the generic MTD-NAND driver. 
    80 + 
    81 +         If unsure, say N. 
    82 + 
    83 +config YAFFS_ECC_WRONG_ORDER 
    84 +       bool "Use the same ecc byte order as Steven Hill's nand_ecc.c" 
    85 +       depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS 
    86 +       default n 
    87 +       help 
    88 +         This makes yaffs_ecc.c use the same ecc byte order as Steven 
    89 +         Hill's nand_ecc.c. If not set, then you get the same ecc byte 
    90 +         order as SmartMedia. 
    91 + 
    92 +         If unsure, say N. 
    93 + 
    94 +config YAFFS_YAFFS2 
    95 +       bool "2048 byte (or larger) / page devices" 
    96 +       depends on YAFFS_FS 
    97 +       default y 
    98 +       help 
    99 +         Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices 
    100 + 
    101 +         If unsure, say Y. 
    102 + 
    103 +config YAFFS_AUTO_YAFFS2 
    104 +       bool "Autoselect yaffs2 format" 
    105 +       depends on YAFFS_YAFFS2 
    106 +       default y 
    107 +       help 
    108 +         Without this, you need to explicitely use yaffs2 as the file 
    109 +         system type. With this, you can say "yaffs" and yaffs or yaffs2 
    110 +         will be used depending on the device page size (yaffs on 
    111 +         512-byte page devices, yaffs2 on 2K page devices). 
    112 + 
    113 +         If unsure, say Y. 
    114 + 
    115 +config YAFFS_DISABLE_LAZY_LOAD 
    116 +       bool "Disable lazy loading" 
    117 +       depends on YAFFS_YAFFS2 
    118 +       default n 
    119 +       help 
    120 +         "Lazy loading" defers loading file details until they are 
    121 +         required. This saves mount time, but makes the first look-up 
    122 +         a bit longer. 
    123 + 
    124 +         Lazy loading will only happen if enabled by this option being 'n' 
    125 +         and if the appropriate tags are available, else yaffs2 will 
    126 +         automatically fall back to immediate loading and do the right 
    127 +         thing. 
    128 + 
    129 +         Lazy laoding will be required by checkpointing. 
    130 + 
    131 +         Setting this to 'y' will disable lazy loading. 
    132 + 
    133 +         If unsure, say N. 
    134 + 
    135 +config YAFFS_CHECKPOINT_RESERVED_BLOCKS 
    136 +       int "Reserved blocks for checkpointing" 
    137 +       depends on YAFFS_YAFFS2 
    138 +       default 10 
    139 +       help 
    140 +          Give the number of Blocks to reserve for checkpointing. 
    141 +         Checkpointing saves the state at unmount so that mounting is 
    142 +         much faster as a scan of all the flash to regenerate this state 
    143 +         is not needed.  These Blocks are reserved per partition, so if 
    144 +         you have very small partitions the default (10) may be a mess 
    145 +         for you.  You can set this value to 0, but that does not mean 
    146 +         checkpointing is disabled at all. There only won't be any 
    147 +         specially reserved blocks for checkpointing, so if there is 
    148 +         enough free space on the filesystem, it will be used for 
    149 +         checkpointing. 
    150 + 
    151 +         If unsure, leave at default (10), but don't wonder if there are 
    152 +         always 2MB used on your large page device partition (10 x 2k 
    153 +         pagesize). When using small partitions or when being very small 
    154 +         on space, you probably want to set this to zero. 
    155 + 
    156 +config YAFFS_DISABLE_WIDE_TNODES 
    157 +       bool "Turn off wide tnodes" 
    158 +       depends on YAFFS_FS 
    159 +       default n 
    160 +       help 
    161 +         Wide tnodes are only used for NAND arrays >=32MB for 512-byte 
    162 +         page devices and >=128MB for 2k page devices. They use slightly 
    163 +         more RAM but are faster since they eliminate chunk group 
    164 +         searching. 
    165 + 
    166 +         Setting this to 'y' will force tnode width to 16 bits and save 
    167 +         memory but make large arrays slower. 
    168 + 
    169 +         If unsure, say N. 
    170 + 
    171 +config YAFFS_ALWAYS_CHECK_CHUNK_ERASED 
    172 +       bool "Force chunk erase check" 
    173 +       depends on YAFFS_FS 
    174 +       default n 
    175 +       help 
    176 +          Normally YAFFS only checks chunks before writing until an erased 
    177 +         chunk is found. This helps to detect any partially written 
    178 +         chunks that might have happened due to power loss. 
    179 + 
    180 +         Enabling this forces on the test that chunks are erased in flash 
    181 +         before writing to them. This takes more time but is potentially 
    182 +         a bit more secure. 
    183 +  
    184 +         Suggest setting Y during development and ironing out driver 
    185 +         issues etc. Suggest setting to N if you want faster writing.   
    186 + 
    187 +         If unsure, say Y. 
    188 + 
    189 +config YAFFS_SHORT_NAMES_IN_RAM 
    190 +       bool "Cache short names in RAM" 
    191 +       depends on YAFFS_FS 
    192 +       default y 
    193 +       help 
    194 +         If this config is set, then short names are stored with the 
    195 +         yaffs_Object.  This costs an extra 16 bytes of RAM per object, 
    196 +         but makes look-ups faster. 
    197 + 
    198 +         If unsure, say Y. 
    199 diff -urN linux-2.6.21.1/fs/yaffs2/Makefile linux-2.6.21.1.new/fs/yaffs2/Makefile 
    200 --- linux-2.6.21.1/fs/yaffs2/Makefile   1970-01-01 01:00:00.000000000 +0100 
    201 +++ linux-2.6.21.1.new/fs/yaffs2/Makefile       2007-06-08 14:07:26.000000000 +0200 
    202 @@ -0,0 +1,11 @@ 
    203 +# 
    204 +# Makefile for the linux YAFFS filesystem routines. 
    205 +# 
    206 + 
    207 +obj-$(CONFIG_YAFFS_FS) += yaffs.o 
    208 + 
    209 +yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o 
    210 +yaffs-y += yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o 
    211 +yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o 
    212 +yaffs-y += yaffs_mtdif1.o yaffs_packedtags1.o 
    213 +yaffs-y += yaffs_mtdif.o yaffs_mtdif2.o 
    214 diff -urN linux-2.6.21.1/fs/yaffs2/devextras.h linux-2.6.21.1.new/fs/yaffs2/devextras.h 
    215 --- linux-2.6.21.1/fs/yaffs2/devextras.h        1970-01-01 01:00:00.000000000 +0100 
    216 +++ linux-2.6.21.1.new/fs/yaffs2/devextras.h    2007-06-08 14:07:26.000000000 +0200 
    217 @@ -0,0 +1,264 @@ 
    218 +/* 
    219 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.  
    220 + * 
    221 + * Copyright (C) 2002-2007 Aleph One Ltd. 
    222 + *   for Toby Churchill Ltd and Brightstar Engineering 
    223 + * 
    224 + * Created by Charles Manning <charles@aleph1.co.uk> 
    225 + * 
    226 + * This program is free software; you can redistribute it and/or modify 
    227 + * it under the terms of the GNU Lesser General Public License version 2.1 as 
    228 + * published by the Free Software Foundation. 
    229 + * 
    230 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. 
    231 + */ 
    232 + 
    233 +/* 
    234 + * This file is just holds extra declarations used during development. 
    235 + * Most of these are from kernel includes placed here so we can use them in  
    236 + * applications. 
    237 + * 
    238 + */ 
    239 + 
    240 +#ifndef __EXTRAS_H__ 
    241 +#define __EXTRAS_H__ 
    242 + 
    243 +#if defined WIN32 
    244 +#define __inline__ __inline 
    245 +#define new newHack 
    246 +#endif 
    247 + 
    248 +#if !(defined __KERNEL__) || (defined WIN32) 
    249 + 
    250 +/* User space defines */ 
    251 + 
    252 +typedef unsigned char __u8; 
    253 +typedef unsigned short __u16; 
    254 +typedef unsigned __u32; 
    255 + 
    256 +/* 
    257 + * Simple doubly linked list implementation. 
    258 + * 
    259 + * Some of the internal functions ("__xxx") are useful when 
    260 + * manipulating whole lists rather than single entries, as 
    261 + * sometimes we already know the next/prev entries and we can 
    262 + * generate better code by using them directly rather than 
    263 + * using the generic single-entry routines. 
    264 + */ 
    265 + 
    266 +#define prefetch(x) 1 
    267 + 
    268 +struct list_head { 
    269 +       struct list_head *next, *prev; 
    270 +}; 
    271 + 
    272 +#define LIST_HEAD_INIT(name) { &(name), &(name) } 
    273 + 
    274 +#define LIST_HEAD(name) \ 
    275 +       struct list_head name = LIST_HEAD_INIT(name) 
    276 + 
    277 +#define INIT_LIST_HEAD(ptr) do { \ 
    278 +       (ptr)->next = (ptr); (ptr)->prev = (ptr); \ 
    279 +} while (0) 
    280 + 
    281 +/* 
    282 + * Insert a new entry between two known consecutive entries. 
    283 + * 
    284 + * This is only for internal list manipulation where we know 
    285 + * the prev/next entries already! 
    286 + */ 
    287 +static __inline__ void __list_add(struct list_head *new, 
    288 +                                 struct list_head *prev, 
    289 +                                 struct list_head *next) 
    290 +{ 
    291 +       next->prev = new; 
    292 +       new->next = next; 
    293 +       new->prev = prev; 
    294 +       prev->next = new; 
    295 +} 
    296 + 
    297 +/** 
    298 + * list_add - add a new entry 
    299 + * @new: new entry to be added 
    300 + * @head: list head to add it after 
    301 + * 
    302 + * Insert a new entry after the specified head. 
    303 + * This is good for implementing stacks. 
    304 + */ 
    305 +static __inline__ void list_add(struct list_head *new, struct list_head *head) 
    306 +{ 
    307 +       __list_add(new, head, head->next); 
    308 +} 
    309 + 
    310 +/** 
    311 + * list_add_tail - add a new entry 
    312 + * @new: new entry to be added 
    313 + * @head: list head to add it before 
    314 + * 
    315 + * Insert a new entry before the specified head. 
    316 + * This is useful for implementing queues. 
    317 + */ 
    318 +static __inline__ void list_add_tail(struct list_head *new, 
    319 +                                    struct list_head *head) 
    320 +{ 
    321 +       __list_add(new, head->prev, head); 
    322 +} 
    323 + 
    324 +/* 
    325 + * Delete a list entry by making the prev/next entries 
    326 + * point to each other. 
    327 + * 
    328 + * This is only for internal list manipulation where we know 
    329 + * the prev/next entries already! 
    330 + */ 
    331 +static __inline__ void __list_del(struct list_head *prev, 
    332 +                                 struct list_head *next) 
    333 +{ 
    334 +       next->prev = prev; 
    335 +       prev->next = next; 
    336 +} 
    337 + 
    338 +/** 
    339 + * list_del - deletes entry from list. 
    340 + * @entry: the element to delete from the list. 
    341 + * Note: list_empty on entry does not return true after this, the entry is 
    342 + * in an undefined state. 
    343 + */ 
    344 +static __inline__ void list_del(struct list_head *entry) 
    345 +{ 
    346 +       __list_del(entry->prev, entry->next); 
    347 +} 
    348 + 
    349 +/** 
    350 + * list_del_init - deletes entry from list and reinitialize it. 
    351 + * @entry: the element to delete from the list. 
    352 + */ 
    353 +static __inline__ void list_del_init(struct list_head *entry) 
    354 +{ 
    355 +       __list_del(entry->prev, entry->next); 
    356 +       INIT_LIST_HEAD(entry); 
    357 +} 
    358 + 
    359 +/** 
    360 + * list_empty - tests whether a list is empty 
    361 + * @head: the list to test. 
    362 + */ 
    363 +static __inline__ int list_empty(struct list_head *head) 
    364 +{ 
    365 +       return head->next == head; 
    366 +} 
    367 + 
    368 +/** 
    369 + * list_splice - join two lists 
    370 + * @list: the new list to add. 
    371 + * @head: the place to add it in the first list. 
    372 + */ 
    373 +static __inline__ void list_splice(struct list_head *list, 
    374 +                                  struct list_head *head) 
    375 +{ 
    376 +       struct list_head *first = list->next; 
    377 + 
    378 +       if (first != list) { 
    379 +               struct list_head *last = list->prev; 
    380 +               struct list_head *at = head->next; 
    381 + 
    382 +               first->prev = head; 
    383 +               head->next = first; 
    384 + 
    385 +               last->next = at; 
    386 +               at->prev = last; 
    387 +       } 
    388 +} 
    389 + 
    390 +/** 
    391 + * list_entry - get the struct for this entry 
    392 + * @ptr:       the &struct list_head pointer. 
    393 + * @type:      the type of the struct this is embedded in. 
    394 + * @member:    the name of the list_struct within the struct. 
    395 + */ 
    396 +#define list_entry(ptr, type, member) \ 
    397 +       ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) 
    398 + 
    399 +/** 
    400 + * list_for_each       -       iterate over a list 
    401 + * @pos:       the &struct list_head to use as a loop counter. 
    402 + * @head:      the head for your list. 
    403 + */ 
    404 +#define list_for_each(pos, head) \ 
    405 +       for (pos = (head)->next, prefetch(pos->next); pos != (head); \ 
    406 +               pos = pos->next, prefetch(pos->next)) 
    407 + 
    408 +/** 
    409 + * list_for_each_safe  -       iterate over a list safe against removal 
    410 + *                              of list entry 
    411 + * @pos:       the &struct list_head to use as a loop counter. 
    412 + * @n:         another &struct list_head to use as temporary storage 
    413 + * @head:      the head for your list. 
    414 + */ 
    415 +#define list_for_each_safe(pos, n, head) \ 
    416 +       for (pos = (head)->next, n = pos->next; pos != (head); \ 
    417 +               pos = n, n = pos->next) 
    418 + 
    419 +/* 
    420 + * File types 
    421 + */ 
    422 +#define DT_UNKNOWN     0 
    423 +#define DT_FIFO                1 
    424 +#define DT_CHR         2 
    425 +#define DT_DIR         4 
    426 +#define DT_BLK         6 
    427 +#define DT_REG         8 
    428 +#define DT_LNK         10 
    429 +#define DT_SOCK                12 
    430 +#define DT_WHT         14 
    431 + 
    432 +#ifndef WIN32 
    433 +#include <sys/stat.h> 
    434 +#endif 
    435 + 
    436 +/* 
    437 + * Attribute flags.  These should be or-ed together to figure out what 
    438 + * has been changed! 
    439 + */ 
    440 +#define ATTR_MODE      1 
    441 +#define ATTR_UID       2 
    442 +#define ATTR_GID       4 
    443 +#define ATTR_SIZE      8 
    444 +#define ATTR_ATIME     16 
    445 +#define ATTR_MTIME     32 
    446 +#define ATTR_CTIME     64 
    447 +#define ATTR_ATIME_SET 128 
    448 +#define ATTR_MTIME_SET 256 
    449 +#define ATTR_FORCE     512     /* Not a change, but a change it */ 
    450 +#define ATTR_ATTR_FLAG 1024 
    451 + 
    452 +struct iattr { 
    453 +       unsigned int ia_valid; 
    454 +       unsigned ia_mode; 
    455 +       unsigned ia_uid; 
    456 +       unsigned ia_gid; 
    457 +       unsigned ia_size; 
    458 +       unsigned ia_atime; 
    459 +       unsigned ia_mtime; 
    460 +       unsigned ia_ctime; 
    461 +       unsigned int ia_attr_flags; 
    462 +}; 
    463 + 
    464 +#define KERN_DEBUG 
    465 + 
    466 +#else 
    467 + 
    468 +#ifndef WIN32 
    469 +#include <linux/types.h> 
    470 +#include <linux/list.h> 
    471 +#include <linux/fs.h> 
    472 +#include <linux/stat.h> 
    473 +#endif 
    474 + 
    475 +#endif 
    476 + 
    477 +#if defined WIN32 
    478 +#undef new 
    479 +#endif 
    480 + 
    481 +#endif 
    482 diff -urN linux-2.6.21.1/fs/yaffs2/moduleconfig.h linux-2.6.21.1.new/fs/yaffs2/moduleconfig.h 
    483 --- linux-2.6.21.1/fs/yaffs2/moduleconfig.h     1970-01-01 01:00:00.000000000 +0100 
    484 +++ linux-2.6.21.1.new/fs/yaffs2/moduleconfig.h 2007-06-08 14:07:26.000000000 +0200 
    485 @@ -0,0 +1,65 @@ 
    486 +/* 
    487 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.  
    488 + * 
    489 + * Copyright (C) 2002-2007 Aleph One Ltd. 
    490 + *   for Toby Churchill Ltd and Brightstar Engineering 
    491 + * 
    492 + * Created by Martin Fouts <Martin.Fouts@palmsource.com>  
    493 + * 
    494 + * This program is free software; you can redistribute it and/or modify 
    495 + * it under the terms of the GNU Lesser General Public License version 2.1 as 
    496 + * published by the Free Software Foundation. 
    497 + * 
    498 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. 
    499 + */ 
    500 + 
    501 +#ifndef __YAFFS_CONFIG_H__ 
    502 +#define __YAFFS_CONFIG_H__ 
    503 + 
    504 +#ifdef YAFFS_OUT_OF_TREE 
    505 + 
    506 +/* DO NOT UNSET THESE THREE. YAFFS2 will not compile if you do. */ 
    507 +#define CONFIG_YAFFS_FS 
    508 +#define CONFIG_YAFFS_YAFFS1 
    509 +#define CONFIG_YAFFS_YAFFS2 
    510 + 
    511 +/* These options are independent of each other.  Select those that matter. */ 
    512 + 
    513 +/* Default: Not selected */ 
    514 +/* Meaning: Yaffs does its own ECC, rather than using MTD ECC */ 
    515 +//#define CONFIG_YAFFS_DOES_ECC 
    516 + 
    517 +/* Default: Not selected */ 
    518 +/* Meaning: ECC byte order is 'wrong'.  Only meaningful if */ 
    519 +/*          CONFIG_YAFFS_DOES_ECC is set */ 
    520 +//#define CONFIG_YAFFS_ECC_WRONG_ORDER 
    521 + 
    522 +/* Default: Selected */ 
    523 +/* Meaning: Disables testing whether chunks are erased before writing to them*/ 
    524 +#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK 
    525 + 
    526 +/* Default: Selected */ 
    527 +/* Meaning: Cache short names, taking more RAM, but faster look-ups */ 
    528 +#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM 
    529 + 
    530 +/* Default: 10 */ 
    531 +/* Meaning: set the count of blocks to reserve for checkpointing */ 
    532 +#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10 
    533 + 
    534 +/* 
    535 +Older-style on-NAND data format has a "pageStatus" byte to record 
    536 +chunk/page state.  This byte is zeroed when the page is discarded. 
    537 +Choose this option if you have existing on-NAND data in this format 
    538 +that you need to continue to support.  New data written also uses the 
    539 +older-style format. 
    540 +Note: Use of this option generally requires that MTD's oob layout be 
    541 +adjusted to use the older-style format.  See notes on tags formats and 
    542 +MTD versions. 
    543 +*/ 
    544 +/* Default: Not selected */ 
    545 +/* Meaning: Use older-style on-NAND data format with pageStatus byte */ 
    546 +#define CONFIG_YAFFS_9BYTE_TAGS 
    547 + 
    548 +#endif /* YAFFS_OUT_OF_TREE */ 
    549 + 
    550 +#endif /* __YAFFS_CONFIG_H__ */ 
    551 diff -urN linux-2.6.21.1/fs/yaffs2/yaffs_checkptrw.c linux-2.6.21.1.new/fs/yaffs2/yaffs_checkptrw.c 
    552 --- linux-2.6.21.1/fs/yaffs2/yaffs_checkptrw.c  1970-01-01 01:00:00.000000000 +0100 
    553 +++ linux-2.6.21.1.new/fs/yaffs2/yaffs_checkptrw.c      2007-06-08 14:07:26.000000000 +0200 
    554 @@ -0,0 +1,404 @@ 
    555 +/* 
    556 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. 
    557 + * 
    558 + * Copyright (C) 2002-2007 Aleph One Ltd. 
    559 + *   for Toby Churchill Ltd and Brightstar Engineering 
    560 + * 
    561 + * Created by Charles Manning <charles@aleph1.co.uk> 
    562 + * 
    563 + * This program is free software; you can redistribute it and/or modify 
    564 + * it under the terms of the GNU General Public License version 2 as 
    565 + * published by the Free Software Foundation. 
    566 + */ 
    567 + 
    568 +const char *yaffs_checkptrw_c_version = 
    569 +    "$Id: yaffs_checkptrw.c,v 1.14 2007-05-15 20:07:40 charles Exp $"; 
    570 + 
    571 + 
    572 +#include "yaffs_checkptrw.h" 
    573 + 
    574 + 
    575 +static int yaffs_CheckpointSpaceOk(yaffs_Device *dev) 
    576 +{ 
    577 + 
    578 +       int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks; 
    579 +        
    580 +       T(YAFFS_TRACE_CHECKPOINT, 
    581 +               (TSTR("checkpt blocks available = %d" TENDSTR), 
    582 +               blocksAvailable)); 
    583 +                
    584 +        
    585 +       return (blocksAvailable <= 0) ? 0 : 1; 
    586 +} 
    587 + 
    588 + 
    589 +static int yaffs_CheckpointErase(yaffs_Device *dev) 
    590 +{ 
    591 +        
    592 +       int i; 
    593 +        
    594 + 
    595 +       if(!dev->eraseBlockInNAND)       
    596 +               return 0; 
    597 +       T(YAFFS_TRACE_CHECKPOINT,(TSTR("checking blocks %d to %d"TENDSTR), 
    598 +               dev->internalStartBlock,dev->internalEndBlock)); 
    599 +                
    600 +       for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { 
    601 +               yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); 
    602 +               if(bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT){ 
    603 +                       T(YAFFS_TRACE_CHECKPOINT,(TSTR("erasing checkpt block %d"TENDSTR),i)); 
    604 +                       if(dev->eraseBlockInNAND(dev,i- dev->blockOffset /* realign */)){ 
    605 +                               bi->blockState = YAFFS_BLOCK_STATE_EMPTY; 
    606 +                               dev->nErasedBlocks++; 
    607 +                               dev->nFreeChunks += dev->nChunksPerBlock; 
    608 +                       } 
    609 +                       else { 
    610 +                               dev->markNANDBlockBad(dev,i); 
    611 +                               bi->blockState = YAFFS_BLOCK_STATE_DEAD; 
    612 +                       } 
    613 +               } 
    614 +       } 
    615 +        
    616 +       dev->blocksInCheckpoint = 0; 
    617 +        
    618 +       return 1; 
    619 +} 
    620 + 
    621 + 
    622 +static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev) 
    623 +{ 
    624 +       int  i; 
    625 +       int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks; 
    626 +       T(YAFFS_TRACE_CHECKPOINT, 
    627 +               (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR), 
    628 +               dev->nErasedBlocks,dev->nReservedBlocks,blocksAvailable,dev->checkpointNextBlock)); 
    629 +                
    630 +       if(dev->checkpointNextBlock >= 0 && 
    631 +          dev->checkpointNextBlock <= dev->internalEndBlock && 
    632 +          blocksAvailable > 0){ 
    633 +        
    634 +               for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){ 
    635 +                       yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); 
    636 +                       if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY){ 
    637 +                               dev->checkpointNextBlock = i + 1; 
    638 +                               dev->checkpointCurrentBlock = i; 
    639 +                               T(YAFFS_TRACE_CHECKPOINT,(TSTR("allocating checkpt block %d"TENDSTR),i)); 
    640 +                               return; 
    641 +                       } 
    642 +               } 
    643 +       } 
    644 +       T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR))); 
    645 +        
    646 +       dev->checkpointNextBlock = -1; 
    647 +       dev->checkpointCurrentBlock = -1; 
    648 +} 
    649 + 
    650 +static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev) 
    651 +{ 
    652 +       int  i; 
    653 +       yaffs_ExtendedTags tags; 
    654 +        
    655 +       T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: start:  blocks %d next %d" TENDSTR), 
    656 +               dev->blocksInCheckpoint, dev->checkpointNextBlock)); 
    657 +                
    658 +       if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks)  
    659 +               for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){ 
    660 +                       int chunk = i * dev->nChunksPerBlock; 
    661 +                       int realignedChunk = chunk - dev->chunkOffset; 
    662 + 
    663 +                       dev->readChunkWithTagsFromNAND(dev,realignedChunk,NULL,&tags); 
    664 +                       T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),  
    665 +                               i, tags.objectId,tags.sequenceNumber,tags.eccResult)); 
    666 +                                                      
    667 +                       if(tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA){ 
    668 +                               /* Right kind of block */ 
    669 +                               dev->checkpointNextBlock = tags.objectId; 
    670 +                               dev->checkpointCurrentBlock = i; 
    671 +                               dev->checkpointBlockList[dev->blocksInCheckpoint] = i; 
    672 +                               dev->blocksInCheckpoint++; 
    673 +                               T(YAFFS_TRACE_CHECKPOINT,(TSTR("found checkpt block %d"TENDSTR),i)); 
    674 +                               return; 
    675 +                       } 
    676 +               } 
    677 + 
    678 +       T(YAFFS_TRACE_CHECKPOINT,(TSTR("found no more checkpt blocks"TENDSTR))); 
    679 + 
    680 +       dev->checkpointNextBlock = -1; 
    681 +       dev->checkpointCurrentBlock = -1; 
    682 +} 
    683 + 
    684 + 
    685 +int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting) 
    686 +{ 
    687 +        
    688 +       /* Got the functions we need? */ 
    689 +       if (!dev->writeChunkWithTagsToNAND || 
    690 +           !dev->readChunkWithTagsFromNAND || 
    691 +           !dev->eraseBlockInNAND || 
    692 +           !dev->markNANDBlockBad) 
    693 +               return 0; 
    694 + 
    695 +       if(forWriting && !yaffs_CheckpointSpaceOk(dev)) 
    696 +               return 0; 
    697 +                        
    698 +       if(!dev->checkpointBuffer) 
    699 +               dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk); 
    700 +       if(!dev->checkpointBuffer) 
    701 +               return 0; 
    702 + 
    703 +        
    704 +       dev->checkpointPageSequence = 0; 
    705 +        
    706 +       dev->checkpointOpenForWrite = forWriting; 
    707 +        
    708 +       dev->checkpointByteCount = 0; 
    709 +       dev->checkpointSum = 0; 
    710 +       dev->checkpointXor = 0; 
    711 +       dev->checkpointCurrentBlock = -1; 
    712 +       dev->checkpointCurrentChunk = -1; 
    713 +       dev->checkpointNextBlock = dev->internalStartBlock; 
    714 +        
    715 +       /* Erase all the blocks in the checkpoint area */ 
    716 +       if(forWriting){ 
    717 +               memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk); 
    718 +               dev->checkpointByteOffset = 0; 
    719 +               return yaffs_CheckpointErase(dev); 
    720 +                
    721 +                
    722 +       } else { 
    723 +               int i; 
    724 +               /* Set to a value that will kick off a read */ 
    725 +               dev->checkpointByteOffset = dev->nDataBytesPerChunk; 
    726 +               /* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully) 
    727 +                * going to be way more than we need */ 
    728 +               dev->blocksInCheckpoint = 0; 
    729 +               dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2; 
    730 +               dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks); 
    731 +               for(i = 0; i < dev->checkpointMaxBlocks; i++) 
    732 +                       dev->checkpointBlockList[i] = -1; 
    733 +       } 
    734 +        
    735 +       return 1; 
    736 +} 
    737 + 
    738 +int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum) 
    739 +{ 
    740 +       __u32 compositeSum; 
    741 +       compositeSum =  (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF); 
    742 +       *sum = compositeSum; 
    743 +       return 1; 
    744 +} 
    745 + 
    746 +static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev) 
    747 +{ 
    748 + 
    749 +       int chunk; 
    750 +       int realignedChunk; 
    751 + 
    752 +       yaffs_ExtendedTags tags; 
    753 +        
    754 +       if(dev->checkpointCurrentBlock < 0){ 
    755 +               yaffs_CheckpointFindNextErasedBlock(dev); 
    756 +               dev->checkpointCurrentChunk = 0; 
    757 +       } 
    758 +        
    759 +       if(dev->checkpointCurrentBlock < 0) 
    760 +               return 0; 
    761 +        
    762 +       tags.chunkDeleted = 0; 
    763 +       tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */ 
    764 +       tags.chunkId = dev->checkpointPageSequence + 1; 
    765 +       tags.sequenceNumber =  YAFFS_SEQUENCE_CHECKPOINT_DATA; 
    766 +       tags.byteCount = dev->nDataBytesPerChunk; 
    767 +       if(dev->checkpointCurrentChunk == 0){ 
    768 +               /* First chunk we write for the block? Set block state to 
    769 +                  checkpoint */ 
    770 +               yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointCurrentBlock); 
    771 +               bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT; 
    772 +               dev->blocksInCheckpoint++; 
    773 +       } 
    774 +        
    775 +       chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk; 
    776 + 
    777 +        
    778 +       T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR), 
    779 +               chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk,tags.objectId,tags.chunkId));  
    780 +        
    781 +       realignedChunk = chunk - dev->chunkOffset; 
    782 +        
    783 +       dev->writeChunkWithTagsToNAND(dev,realignedChunk,dev->checkpointBuffer,&tags); 
    784 +       dev->checkpointByteOffset = 0; 
    785 +       dev->checkpointPageSequence++;      
    786 +       dev->checkpointCurrentChunk++; 
    787 +       if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock){ 
    788 +               dev->checkpointCurrentChunk = 0; 
    789 +               dev->checkpointCurrentBlock = -1; 
    790 +       } 
    791 +       memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk); 
    792 +        
    793 +       return 1; 
    794 +} 
    795 + 
    796 + 
    797 +int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes) 
    798 +{ 
    799 +       int i=0; 
    800 +       int ok = 1; 
    801 + 
    802 +        
    803 +       __u8 * dataBytes = (__u8 *)data; 
    804 +        
    805 +        
    806 + 
    807 +       if(!dev->checkpointBuffer) 
    808 +               return 0; 
    809 +                
    810 +       if(!dev->checkpointOpenForWrite) 
    811 +               return -1; 
    812 + 
    813 +       while(i < nBytes && ok) { 
    814 +                
    815 + 
    816 +                
    817 +               dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ; 
    818 +               dev->checkpointSum += *dataBytes; 
    819 +               dev->checkpointXor ^= *dataBytes; 
    820 +                 
    821 +               dev->checkpointByteOffset++; 
    822 +               i++; 
    823 +               dataBytes++; 
    824 +               dev->checkpointByteCount++; 
    825 +                
    826 +                
    827 +               if(dev->checkpointByteOffset < 0 || 
    828 +                  dev->checkpointByteOffset >= dev->nDataBytesPerChunk)  
    829 +                       ok = yaffs_CheckpointFlushBuffer(dev); 
    830 + 
    831 +       } 
    832 +        
    833 +       return  i; 
    834 +} 
    835 + 
    836 +int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) 
    837 +{ 
    838 +       int i=0; 
    839 +       int ok = 1; 
    840 +       yaffs_ExtendedTags tags; 
    841 + 
    842 +        
    843 +       int chunk; 
    844 +       int realignedChunk; 
    845 + 
    846 +       __u8 *dataBytes = (__u8 *)data; 
    847 +                
    848 +       if(!dev->checkpointBuffer) 
    849 +               return 0; 
    850 + 
    851 +       if(dev->checkpointOpenForWrite) 
    852 +               return -1; 
    853 + 
    854 +       while(i < nBytes && ok) { 
    855 +        
    856 +        
    857 +               if(dev->checkpointByteOffset < 0 || 
    858 +                  dev->checkpointByteOffset >= dev->nDataBytesPerChunk) { 
    859 +                   
    860 +                       if(dev->checkpointCurrentBlock < 0){ 
    861 +                               yaffs_CheckpointFindNextCheckpointBlock(dev); 
    862 +                               dev->checkpointCurrentChunk = 0; 
    863 +                       } 
    864 +                        
    865 +                       if(dev->checkpointCurrentBlock < 0) 
    866 +                               ok = 0; 
    867 +                       else { 
    868 +                        
    869 +                               chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock +  
    870 +                                         dev->checkpointCurrentChunk; 
    871 + 
    872 +                               realignedChunk = chunk - dev->chunkOffset; 
    873 + 
    874 +                               /* read in the next chunk */ 
    875 +                               /* printf("read checkpoint page %d\n",dev->checkpointPage); */ 
    876 +                               dev->readChunkWithTagsFromNAND(dev, realignedChunk,  
    877 +                                                              dev->checkpointBuffer, 
    878 +                                                             &tags); 
    879 +                                                      
    880 +                               if(tags.chunkId != (dev->checkpointPageSequence + 1) || 
    881 +                                  tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA) 
    882 +                                  ok = 0; 
    883 + 
    884 +                               dev->checkpointByteOffset = 0; 
    885 +                               dev->checkpointPageSequence++; 
    886 +                               dev->checkpointCurrentChunk++; 
    887 +                        
    888 +                               if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock) 
    889 +                                       dev->checkpointCurrentBlock = -1; 
    890 +                       } 
    891 +               } 
    892 +                
    893 +               if(ok){ 
    894 +                       *dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset]; 
    895 +                       dev->checkpointSum += *dataBytes; 
    896 +                       dev->checkpointXor ^= *dataBytes; 
    897 +                       dev->checkpointByteOffset++; 
    898 +                       i++; 
    899 +                       dataBytes++; 
    900 +                       dev->checkpointByteCount++; 
    901 +               } 
    902 +       } 
    903 +        
    904 +       return  i; 
    905 +} 
    906 + 
    907 +int yaffs_CheckpointClose(yaffs_Device *dev) 
    908 +{ 
    909 + 
    910 +       if(dev->checkpointOpenForWrite){         
    911 +               if(dev->checkpointByteOffset != 0) 
    912 +                       yaffs_CheckpointFlushBuffer(dev); 
    913 +       } else { 
    914 +               int i; 
    915 +               for(i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++){ 
    916 +                       yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointBlockList[i]); 
    917 +                       if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY) 
    918 +                               bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT; 
    919 +                       else { 
    920 +                               // Todo this looks odd... 
    921 +                       } 
    922 +               } 
    923 +               YFREE(dev->checkpointBlockList); 
    924 +               dev->checkpointBlockList = NULL; 
    925 +       } 
    926 + 
    927 +       dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock; 
    928 +       dev->nErasedBlocks -= dev->blocksInCheckpoint; 
    929 + 
    930 +                
    931 +       T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR), 
    932 +                       dev->checkpointByteCount)); 
    933 +                        
    934 +       if(dev->checkpointBuffer){ 
    935 +               /* free the buffer */    
    936 +               YFREE(dev->checkpointBuffer); 
    937 +               dev->checkpointBuffer = NULL; 
    938 +               return 1; 
    939 +       } 
    940 +       else 
    941 +               return 0; 
    942 +        
    943 +} 
    944 + 
    945 +int yaffs_CheckpointInvalidateStream(yaffs_Device *dev) 
    946 +{ 
    947 +       /* Erase the first checksum block */ 
    948 + 
    949 +       T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint invalidate"TENDSTR))); 
    950 + 
    951 +       if(!yaffs_CheckpointSpaceOk(dev)) 
    952 +               return 0; 
    953 + 
    954 +       return yaffs_CheckpointErase(dev); 
    955 +} 
    956 + 
    957 + 
    958 + 
    959 diff -urN linux-2.6.21.1/fs/yaffs2/yaffs_checkptrw.h linux-2.6.21.1.new/fs/yaffs2/yaffs_checkptrw.h 
    960 --- linux-2.6.21.1/fs/yaffs2/yaffs_checkptrw.h  1970-01-01 01:00:00.000000000 +0100 
    961 +++ linux-2.6.21.1.new/fs/yaffs2/yaffs_checkptrw.h      2007-06-08 14:07:26.000000000 +0200 
    962 @@ -0,0 +1,35 @@ 
    963 +/* 
    964 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.  
    965 + * 
    966 + * Copyright (C) 2002-2007 Aleph One Ltd. 
    967 + *   for Toby Churchill Ltd and Brightstar Engineering 
    968 + * 
    969 + * Created by Charles Manning <charles@aleph1.co.uk> 
    970 + * 
    971 + * This program is free software; you can redistribute it and/or modify 
    972 + * it under the terms of the GNU Lesser General Public License version 2.1 as 
    973 + * published by the Free Software Foundation. 
    974 + * 
    975 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. 
    976 + */ 
    977 + 
    978 +#ifndef __YAFFS_CHECKPTRW_H__ 
    979 +#define __YAFFS_CHECKPTRW_H__ 
    980 + 
    981 +#include "yaffs_guts.h" 
    982 + 
    983 +int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting); 
    984 + 
    985 +int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes); 
    986 + 
    987 +int yaffs_CheckpointRead(yaffs_Device *dev,void *data, int nBytes); 
    988 + 
    989 +int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum); 
    990 + 
    991 +int yaffs_CheckpointClose(yaffs_Device *dev); 
    992 + 
    993 +int yaffs_CheckpointInvalidateStream(yaffs_Device *dev); 
    994 + 
    995 + 
    996 +#endif 
    997 + 
    998 diff -urN linux-2.6.21.1/fs/yaffs2/yaffs_ecc.c linux-2.6.21.1.new/fs/yaffs2/yaffs_ecc.c 
    999 --- linux-2.6.21.1/fs/yaffs2/yaffs_ecc.c        1970-01-01 01:00:00.000000000 +0100 
    1000 +++ linux-2.6.21.1.new/fs/yaffs2/yaffs_ecc.c    2007-06-08 14:07:26.000000000 +0200 
    1001 @@ -0,0 +1,331 @@ 
    1002 +/* 
    1003 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. 
    1004 + * 
    1005 + * Copyright (C) 2002-2007 Aleph One Ltd. 
    1006 + *   for Toby Churchill Ltd and Brightstar Engineering 
    1007 + * 
    1008 + * Created by Charles Manning <charles@aleph1.co.uk> 
    1009 + * 
    1010 + * This program is free software; you can redistribute it and/or modify 
    1011 + * it under the terms of the GNU General Public License version 2 as 
    1012 + * published by the Free Software Foundation. 
    1013 + */ 
    1014 + 
    1015 +/* 
    1016 + * This code implements the ECC algorithm used in SmartMedia. 
    1017 + * 
    1018 + * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.  
    1019 + * The two unused bit are set to 1. 
    1020 + * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC  
    1021 + * blocks are used on a 512-byte NAND page. 
    1022 + * 
    1023 + */ 
    1024 + 
    1025 +/* Table generated by gen-ecc.c 
    1026 + * Using a table means we do not have to calculate p1..p4 and p1'..p4' 
    1027 + * for each byte of data. These are instead provided in a table in bits7..2. 
    1028 + * Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore 
    1029 + * this bytes influence on the line parity. 
    1030 + */ 
    1031 + 
    1032 +const char *yaffs_ecc_c_version = 
    1033 +    "$Id: yaffs_ecc.c,v 1.9 2007-02-14 01:09:06 wookey Exp $"; 
    1034 + 
    1035 +#include "yportenv.h" 
    1036 + 
    1037 +#include "yaffs_ecc.h" 
    1038 + 
    1039 +static const unsigned char column_parity_table[] = { 
    1040 +       0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 
    1041 +       0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, 
    1042 +       0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 
    1043 +       0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, 
    1044 +       0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 
    1045 +       0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, 
    1046 +       0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 
    1047 +       0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, 
    1048 +       0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 
    1049 +       0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, 
    1050 +       0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 
    1051 +       0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, 
    1052 +       0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 
    1053 +       0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, 
    1054 +       0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 
    1055 +       0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, 
    1056 +       0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 
    1057 +       0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, 
    1058 +       0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 
    1059 +       0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, 
    1060 +       0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 
    1061 +       0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, 
    1062 +       0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 
    1063 +       0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, 
    1064 +       0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 
    1065 +       0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, 
    1066 +       0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 
    1067 +       0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, 
    1068 +       0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 
    1069 +       0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, 
    1070 +       0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 
    1071 +       0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, 
    1072 +}; 
    1073 + 
    1074 +/* Count the bits in an unsigned char or a U32 */ 
    1075 + 
    1076 +static int yaffs_CountBits(unsigned char x) 
    1077 +{ 
    1078 +       int r = 0; 
    1079 +       while (x) { 
    1080 +               if (x & 1) 
    1081 +                       r++; 
    1082 +               x >>= 1; 
    1083 +       } 
    1084 +       return r; 
    1085 +} 
    1086 + 
    1087 +static int yaffs_CountBits32(unsigned x) 
    1088 +{ 
    1089 +       int r = 0; 
    1090 +       while (x) { 
    1091 +               if (x & 1) 
    1092 +                       r++; 
    1093 +               x >>= 1; 
    1094 +       } 
    1095 +       return r; 
    1096 +} 
    1097 + 
    1098 +/* Calculate the ECC for a 256-byte block of data */ 
    1099 +void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc) 
    1100 +{ 
    1101 +       unsigned int i; 
    1102 + 
    1103 +       unsigned char col_parity = 0; 
    1104 +       unsigned char line_parity = 0; 
    1105 +       unsigned char line_parity_prime = 0; 
    1106 +       unsigned char t; 
    1107 +       unsigned char b; 
    1108 + 
    1109 +       for (i = 0; i < 256; i++) { 
    1110 +               b = column_parity_table[*data++]; 
    1111 +               col_parity ^= b; 
    1112 + 
    1113 +               if (b & 0x01)   // odd number of bits in the byte 
    1114 +               { 
    1115 +                       line_parity ^= i; 
    1116 +                       line_parity_prime ^= ~i; 
    1117 +               } 
    1118 + 
    1119 +       } 
    1120 + 
    1121 +       ecc[2] = (~col_parity) | 0x03; 
    1122 + 
    1123 +       t = 0; 
    1124 +       if (line_parity & 0x80) 
    1125 +               t |= 0x80; 
    1126 +       if (line_parity_prime & 0x80) 
    1127 +               t |= 0x40; 
    1128 +       if (line_parity & 0x40) 
    1129 +               t |= 0x20; 
    1130 +       if (line_parity_prime & 0x40) 
    1131 +               t |= 0x10; 
    1132 +       if (line_parity & 0x20) 
    1133 +               t |= 0x08; 
    1134 +       if (line_parity_prime & 0x20) 
    1135 +               t |= 0x04; 
    1136 +       if (line_parity & 0x10) 
    1137 +               t |= 0x02; 
    1138 +       if (line_parity_prime & 0x10) 
    1139 +               t |= 0x01; 
    1140 +       ecc[1] = ~t; 
    1141 + 
    1142 +       t = 0; 
    1143 +       if (line_parity & 0x08) 
    1144 +               t |= 0x80; 
    1145 +       if (line_parity_prime & 0x08) 
    1146 +               t |= 0x40; 
    1147 +       if (line_parity & 0x04) 
    1148 +               t |= 0x20; 
    1149 +       if (line_parity_prime & 0x04) 
    1150 +               t |= 0x10; 
    1151 +       if (line_parity & 0x02) 
    1152 +               t |= 0x08; 
    1153 +       if (line_parity_prime & 0x02) 
    1154 +               t |= 0x04; 
    1155 +       if (line_parity & 0x01) 
    1156 +               t |= 0x02; 
    1157 +       if (line_parity_prime & 0x01) 
    1158 +               t |= 0x01; 
    1159 +       ecc[0] = ~t; 
    1160 + 
    1161 +#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER 
    1162 +       // Swap the bytes into the wrong order 
    1163 +       t = ecc[0]; 
    1164 +       ecc[0] = ecc[1]; 
    1165 +       ecc[1] = t; 
    1166 +#endif 
    1167 +} 
    1168 + 
    1169 + 
    1170 +/* Correct the ECC on a 256 byte block of data */ 
    1171 + 
    1172 +int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc, 
    1173 +                    const unsigned char *test_ecc) 
    1174 +{ 
    1175 +       unsigned char d0, d1, d2;       /* deltas */ 
    1176 + 
    1177 +       d0 = read_ecc[0] ^ test_ecc[0]; 
    1178 +       d1 = read_ecc[1] ^ test_ecc[1]; 
    1179 +       d2 = read_ecc[2] ^ test_ecc[2]; 
    1180 + 
    1181 +       if ((d0 | d1 | d2) == 0) 
    1182 +               return 0; /* no error */ 
    1183 + 
    1184 +       if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 && 
    1185 +           ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 && 
    1186 +           ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) { 
    1187 +               /* Single bit (recoverable) error in data */ 
    1188 + 
    1189 +               unsigned byte; 
    1190 +               unsigned bit; 
    1191 + 
    1192 +#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER 
    1193 +               // swap the bytes to correct for the wrong order 
    1194 +               unsigned char t; 
    1195 + 
    1196 +               t = d0; 
    1197 +               d0 = d1; 
    1198 +               d1 = t; 
    1199 +#endif 
    1200 + 
    1201 +               bit = byte = 0; 
    1202 + 
    1203 +               if (d1 & 0x80) 
    1204 +                       byte |= 0x80; 
    1205 +               if (d1 & 0x20) 
    1206 +                       byte |= 0x40; 
    1207 +               if (d1 & 0x08) 
    1208 +                       byte |= 0x20; 
    1209 +               if (d1 & 0x02) 
    1210 +                       byte |= 0x10; 
    1211 +               if (d0 & 0x80) 
    1212 +                       byte |= 0x08; 
    1213 +               if (d0 & 0x20) 
    1214 +                       byte |= 0x04; 
    1215 +               if (d0 & 0x08) 
    1216 +                       byte |= 0x02; 
    1217 +               if (d0 & 0x02) 
    1218 +                       byte |= 0x01; 
    1219 + 
    1220 +               if (d2 & 0x80) 
    1221 +                       bit |= 0x04; 
    1222 +               if (d2 & 0x20) 
    1223 +                       bit |= 0x02; 
    1224 +               if (d2 & 0x08) 
    1225 +                       bit |= 0x01; 
    1226 + 
    1227 +               data[byte] ^= (1 << bit); 
    1228 + 
    1229 +               return 1; /* Corrected the error */ 
    1230 +       } 
    1231 + 
    1232 +       if ((yaffs_CountBits(d0) +  
    1233 +            yaffs_CountBits(d1) +  
    1234 +            yaffs_CountBits(d2)) ==  1) { 
    1235 +               /* Reccoverable error in ecc */ 
    1236 + 
    1237 +               read_ecc[0] = test_ecc[0]; 
    1238 +               read_ecc[1] = test_ecc[1]; 
    1239 +               read_ecc[2] = test_ecc[2]; 
    1240 + 
    1241 +               return 1; /* Corrected the error */ 
    1242 +       } 
    1243 +        
    1244 +       /* Unrecoverable error */ 
    1245 + 
    1246 +       return -1; 
    1247 + 
    1248 +} 
    1249 + 
    1250 + 
    1251 +/* 
    1252 + * ECCxxxOther does ECC calcs on arbitrary n bytes of data 
    1253 + */ 
    1254 +void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes, 
    1255 +                            yaffs_ECCOther * eccOther) 
    1256 +{ 
    1257 +       unsigned int i; 
    1258 + 
    1259 +       unsigned char col_parity = 0; 
    1260 +       unsigned line_parity = 0; 
    1261 +       unsigned line_parity_prime = 0; 
    1262 +       unsigned char b; 
    1263 + 
    1264 +       for (i = 0; i < nBytes; i++) { 
    1265 +               b = column_parity_table[*data++]; 
    1266 +               col_parity ^= b; 
    1267 + 
    1268 +               if (b & 0x01)    { 
    1269 +                       /* odd number of bits in the byte */ 
    1270 +                       line_parity ^= i; 
    1271 +                       line_parity_prime ^= ~i; 
    1272 +               } 
    1273 + 
    1274 +       } 
    1275 + 
    1276 +       eccOther->colParity = (col_parity >> 2) & 0x3f; 
    1277 +       eccOther->lineParity = line_parity; 
    1278 +       eccOther->lineParityPrime = line_parity_prime; 
    1279 +} 
    1280 + 
    1281 +int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes, 
    1282 +                         yaffs_ECCOther * read_ecc, 
    1283 +                         const yaffs_ECCOther * test_ecc) 
    1284 +{ 
    1285 +       unsigned char cDelta;   /* column parity delta */ 
    1286 +       unsigned lDelta;        /* line parity delta */ 
    1287 +       unsigned lDeltaPrime;   /* line parity delta */ 
    1288 +       unsigned bit; 
    1289 + 
    1290 +       cDelta = read_ecc->colParity ^ test_ecc->colParity; 
    1291 +       lDelta = read_ecc->lineParity ^ test_ecc->lineParity; 
    1292 +       lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime; 
    1293 + 
    1294 +       if ((cDelta | lDelta | lDeltaPrime) == 0) 
    1295 +               return 0; /* no error */ 
    1296 + 
    1297 +       if (lDelta == ~lDeltaPrime &&  
    1298 +           (((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15)) 
    1299 +       { 
    1300 +               /* Single bit (recoverable) error in data */ 
    1301 + 
    1302 +               bit = 0; 
    1303 + 
    1304 +               if (cDelta & 0x20) 
    1305 +                       bit |= 0x04; 
    1306 +               if (cDelta & 0x08) 
    1307 +                       bit |= 0x02; 
    1308 +               if (cDelta & 0x02) 
    1309 +                       bit |= 0x01; 
    1310 + 
    1311 +               if(lDelta >= nBytes) 
    1312 +                       return -1; 
    1313 +                        
    1314 +               data[lDelta] ^= (1 << bit); 
    1315 + 
    1316 +               return 1; /* corrected */ 
    1317 +       } 
    1318 + 
    1319 +       if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) + 
    1320 +            yaffs_CountBits(cDelta)) == 1) { 
    1321 +               /* Reccoverable error in ecc */ 
    1322 + 
    1323 +               *read_ecc = *test_ecc; 
    1324 +               return 1; /* corrected */ 
    1325 +       } 
    1326 + 
    1327 +       /* Unrecoverable error */ 
    1328 + 
    1329 +       return -1; 
    1330 + 
    1331 +} 
    1332 + 
    1333 diff -urN linux-2.6.21.1/fs/yaffs2/yaffs_ecc.h linux-2.6.21.1.new/fs/yaffs2/yaffs_ecc.h 
    1334 --- linux-2.6.21.1/fs/yaffs2/yaffs_ecc.h        1970-01-01 01:00:00.000000000 +0100 
    1335 +++ linux-2.6.21.1.new/fs/yaffs2/yaffs_ecc.h    2007-06-08 14:07:26.000000000 +0200 
    1336 @@ -0,0 +1,44 @@ 
    1337 +/* 
    1338 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.  
    1339 + * 
    1340 + * Copyright (C) 2002-2007 Aleph One Ltd. 
    1341 + *   for Toby Churchill Ltd and Brightstar Engineering 
    1342 + * 
    1343 + * Created by Charles Manning <charles@aleph1.co.uk> 
    1344 + * 
    1345 + * This program is free software; you can redistribute it and/or modify 
    1346 + * it under the terms of the GNU Lesser General Public License version 2.1 as 
    1347 + * published by the Free Software Foundation. 
    1348 + * 
    1349 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. 
    1350 + */ 
    1351 + 
    1352 + /* 
    1353 +  * This code implements the ECC algorithm used in SmartMedia. 
    1354 +  * 
    1355 +  * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.  
    1356 +  * The two unused bit are set to 1. 
    1357 +  * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC  
    1358 +  * blocks are used on a 512-byte NAND page. 
    1359 +  * 
    1360 +  */ 
    1361 + 
    1362 +#ifndef __YAFFS_ECC_H__ 
    1363 +#define __YAFFS_ECC_H__ 
    1364 + 
    1365 +typedef struct { 
    1366 +       unsigned char colParity; 
    1367 +       unsigned lineParity; 
    1368 +       unsigned lineParityPrime; 
    1369 +} yaffs_ECCOther; 
    1370 + 
    1371 +void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc); 
    1372 +int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc, 
    1373 +                    const unsigned char *test_ecc); 
    1374 + 
    1375 +void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes, 
    1376 +                            yaffs_ECCOther * ecc); 
    1377 +int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes, 
    1378 +                         yaffs_ECCOther * read_ecc, 
    1379 +                         const yaffs_ECCOther * test_ecc); 
    1380 +#endif 
    1381 diff -urN linux-2.6.21.1/fs/yaffs2/yaffs_fs.c linux-2.6.21.1.new/fs/yaffs2/yaffs_fs.c 
    1382 --- linux-2.6.21.1/fs/yaffs2/yaffs_fs.c 1970-01-01 01:00:00.000000000 +0100 
    1383 +++ linux-2.6.21.1.new/fs/yaffs2/yaffs_fs.c     2007-06-08 14:07:26.000000000 +0200 
    1384 @@ -0,0 +1,2278 @@ 
    1385 +/* 
    1386 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. 
    1387 + * 
    1388 + * Copyright (C) 2002-2007 Aleph One Ltd. 
    1389 + *   for Toby Churchill Ltd and Brightstar Engineering 
    1390 + * 
    1391 + * Created by Charles Manning <charles@aleph1.co.uk> 
    1392 + * Acknowledgements: 
    1393 + * Luc van OostenRyck for numerous patches. 
    1394 + * Nick Bane for numerous patches. 
    1395 + * Nick Bane for 2.5/2.6 integration. 
    1396 + * Andras Toth for mknod rdev issue. 
    1397 + * Michael Fischer for finding the problem with inode inconsistency. 
    1398 + * Some code bodily lifted from JFFS 
    1399 + * 
    1400 + * This program is free software; you can redistribute it and/or modify 
    1401 + * it under the terms of the GNU General Public License version 2 as 
    1402 + * published by the Free Software Foundation. 
    1403 + */ 
    1404 + 
    1405 +/* 
    1406 + * 
    1407 + * This is the file system front-end to YAFFS that hooks it up to 
    1408 + * the VFS. 
    1409 + * 
    1410 + * Special notes:  
    1411 + * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with 
    1412 + *         this superblock 
    1413 + * >> 2.6: sb->s_fs_info  points to the yaffs_Device associated with this 
    1414 + *         superblock 
    1415 + * >> inode->u.generic_ip points to the associated yaffs_Object. 
    1416 + */ 
    1417 + 
    1418 +const char *yaffs_fs_c_version = 
    1419 +    "$Id: yaffs_fs.c,v 1.60 2007-05-15 20:07:40 charles Exp $"; 
    1420 +extern const char *yaffs_guts_c_version; 
    1421 + 
    1422 +#include <linux/version.h> 
    1423 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) 
    1424 +#include <linux/config.h> 
    1425 +#endif 
    1426 +#include <linux/kernel.h> 
    1427 +#include <linux/module.h> 
    1428 +#include <linux/slab.h> 
    1429 +#include <linux/init.h> 
    1430 +#include <linux/list.h> 
    1431 +#include <linux/fs.h> 
    1432 +#include <linux/proc_fs.h> 
    1433 +#include <linux/smp_lock.h> 
    1434 +#include <linux/pagemap.h> 
    1435 +#include <linux/mtd/mtd.h> 
    1436 +#include <linux/interrupt.h> 
    1437 +#include <linux/string.h> 
    1438 +#include <linux/ctype.h> 
    1439 + 
    1440 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) 
    1441 + 
    1442 +#include <linux/statfs.h>      /* Added NCB 15-8-2003 */ 
    1443 +#include <asm/statfs.h> 
    1444 +#define UnlockPage(p) unlock_page(p) 
    1445 +#define Page_Uptodate(page)    test_bit(PG_uptodate, &(page)->flags) 
    1446 + 
    1447 +/* FIXME: use sb->s_id instead ? */ 
    1448 +#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf) 
    1449 + 
    1450 +#else 
    1451 + 
    1452 +#include <linux/locks.h> 
    1453 +#define        BDEVNAME_SIZE           0 
    1454 +#define        yaffs_devname(sb, buf)  kdevname(sb->s_dev) 
    1455 + 
    1456 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) 
    1457 +/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */ 
    1458 +#define __user 
    1459 +#endif 
    1460 + 
    1461 +#endif 
    1462 + 
    1463 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 
    1464 +#define WRITE_SIZE_STR "writesize" 
    1465 +#define WRITE_SIZE(mtd) (mtd)->writesize 
    1466 +#else 
    1467 +#define WRITE_SIZE_STR "oobblock" 
    1468 +#define WRITE_SIZE(mtd) (mtd)->oobblock 
    1469 +#endif 
    1470 + 
    1471 +#include <asm/uaccess.h> 
    1472 + 
    1473 +#include "yportenv.h" 
    1474 +#include "yaffs_guts.h" 
    1475 + 
    1476 +#include <linux/mtd/mtd.h> 
    1477 +#include "yaffs_mtdif.h" 
    1478 +#include "yaffs_mtdif1.h" 
    1479 +#include "yaffs_mtdif2.h" 
    1480 + 
    1481 +unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS; 
    1482 +unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS; 
    1483 + 
    1484 +/* Module Parameters */ 
    1485 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) 
    1486 +module_param(yaffs_traceMask,uint,0644); 
    1487 +module_param(yaffs_wr_attempts,uint,0644); 
    1488 +#else 
    1489 +MODULE_PARM(yaffs_traceMask,"i"); 
    1490 +MODULE_PARM(yaffs_wr_attempts,"i"); 
    1491 +#endif 
    1492 + 
    1493 +/*#define T(x) printk x */ 
    1494 + 
    1495 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) 
    1496 +#define yaffs_InodeToObjectLV(iptr) (iptr)->i_private 
    1497 +#else 
    1498 +#define yaffs_InodeToObjectLV(iptr) (iptr)->u.generic_ip 
    1499 +#endif 
    1500 + 
    1501 +#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr))) 
    1502 +#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode) 
    1503 + 
    1504 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) 
    1505 +#define yaffs_SuperToDevice(sb)        ((yaffs_Device *)sb->s_fs_info) 
    1506 +#else 
    1507 +#define yaffs_SuperToDevice(sb)        ((yaffs_Device *)sb->u.generic_sbp) 
    1508 +#endif 
    1509 + 
    1510 +static void yaffs_put_super(struct super_block *sb); 
    1511 + 
    1512 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, 
    1513 +                               loff_t * pos); 
    1514 + 
    1515 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 
    1516 +static int yaffs_file_flush(struct file *file, fl_owner_t id); 
    1517 +#else 
    1518 +static int yaffs_file_flush(struct file *file); 
    1519 +#endif 
    1520 + 
    1521 +static int yaffs_sync_object(struct file *file, struct dentry *dentry, 
    1522 +                            int datasync); 
    1523 + 
    1524 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir); 
    1525 + 
    1526 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) 
    1527 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, 
    1528 +                       struct nameidata *n); 
    1529 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, 
    1530 +                                  struct nameidata *n); 
    1531 +#else 
    1532 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode); 
    1533 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry); 
    1534 +#endif 
    1535 +static int yaffs_link(struct dentry *old_dentry, struct inode *dir, 
    1536 +                     struct dentry *dentry); 
    1537 +static int yaffs_unlink(struct inode *dir, struct dentry *dentry); 
    1538 +static int yaffs_symlink(struct inode *dir, struct dentry *dentry, 
    1539 +                        const char *symname); 
    1540 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode); 
    1541 + 
    1542 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) 
    1543 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, 
    1544 +                      dev_t dev); 
    1545 +#else 
    1546 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, 
    1547 +                      int dev); 
    1548 +#endif 
    1549 +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, 
    1550 +                       struct inode *new_dir, struct dentry *new_dentry); 
    1551 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr); 
    1552 + 
    1553 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 
    1554 +static int yaffs_sync_fs(struct super_block *sb, int wait); 
    1555 +static void yaffs_write_super(struct super_block *sb); 
    1556 +#else 
    1557 +static int yaffs_sync_fs(struct super_block *sb); 
    1558 +static int yaffs_write_super(struct super_block *sb); 
    1559 +#endif 
    1560 + 
    1561 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 
    1562 +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf); 
    1563 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) 
    1564 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf); 
    1565 +#else 
    1566 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf); 
    1567 +#endif 
    1568 +static void yaffs_read_inode(struct inode *inode); 
    1569 + 
    1570 +static void yaffs_put_inode(struct inode *inode); 
    1571 +static void yaffs_delete_inode(struct inode *); 
    1572 +static void yaffs_clear_inode(struct inode *); 
    1573 + 
    1574 +static int yaffs_readpage(struct file *file, struct page *page); 
    1575 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) 
    1576 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc); 
    1577 +#else 
    1578 +static int yaffs_writepage(struct page *page); 
    1579 +#endif 
    1580 +static int yaffs_prepare_write(struct file *f, struct page *pg, 
    1581 +                              unsigned offset, unsigned to); 
    1582 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, 
    1583 +                             unsigned to); 
    1584 + 
    1585 +static int yaffs_readlink(struct dentry *dentry, char __user * buffer, 
    1586 +                         int buflen); 
    1587 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)) 
    1588 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd); 
    1589 +#else 
    1590 +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd); 
    1591 +#endif 
    1592 + 
    1593 +static struct address_space_operations yaffs_file_address_operations = { 
    1594 +       .readpage = yaffs_readpage, 
    1595 +       .writepage = yaffs_writepage, 
    1596 +       .prepare_write = yaffs_prepare_write, 
    1597 +       .commit_write = yaffs_commit_write, 
    1598 +}; 
    1599 + 
    1600 +static struct file_operations yaffs_file_operations = { 
    1601 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) 
    1602 +       .read = do_sync_read, 
    1603 +       .write = do_sync_write, 
    1604 +       .aio_read = generic_file_aio_read, 
    1605 +       .aio_write = generic_file_aio_write, 
    1606 +#else 
    1607 +       .read = generic_file_read, 
    1608 +       .write = generic_file_write, 
    1609 +#endif 
    1610 +       .mmap = generic_file_mmap, 
    1611 +       .flush = yaffs_file_flush, 
    1612 +       .fsync = yaffs_sync_object, 
    1613 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) 
    1614 +       .sendfile = generic_file_sendfile, 
    1615 +#endif 
    1616 + 
    1617 +}; 
    1618 + 
    1619 +static struct inode_operations yaffs_file_inode_operations = { 
    1620 +       .setattr = yaffs_setattr, 
    1621 +}; 
    1622 + 
    1623 +static struct inode_operations yaffs_symlink_inode_operations = { 
    1624 +       .readlink = yaffs_readlink, 
    1625 +       .follow_link = yaffs_follow_link, 
    1626 +       .setattr = yaffs_setattr, 
    1627 +}; 
    1628 + 
    1629 +static struct inode_operations yaffs_dir_inode_operations = { 
    1630 +       .create = yaffs_create, 
    1631 +       .lookup = yaffs_lookup, 
    1632 +       .link = yaffs_link, 
    1633 +       .unlink = yaffs_unlink, 
    1634 +       .symlink = yaffs_symlink, 
    1635 +       .mkdir = yaffs_mkdir, 
    1636 +       .rmdir = yaffs_unlink, 
    1637 +       .mknod = yaffs_mknod, 
    1638 +       .rename = yaffs_rename, 
    1639 +       .setattr = yaffs_setattr, 
    1640 +}; 
    1641 + 
    1642 +static struct file_operations yaffs_dir_operations = { 
    1643 +       .read = generic_read_dir, 
    1644 +       .readdir = yaffs_readdir, 
    1645 +       .fsync = yaffs_sync_object, 
    1646 +}; 
    1647 + 
    1648 +static struct super_operations yaffs_super_ops = { 
    1649 +       .statfs = yaffs_statfs, 
    1650 +       .read_inode = yaffs_read_inode, 
    1651 +       .put_inode = yaffs_put_inode, 
    1652 +       .put_super = yaffs_put_super, 
    1653 +       .delete_inode = yaffs_delete_inode, 
    1654 +       .clear_inode = yaffs_clear_inode, 
    1655 +       .sync_fs = yaffs_sync_fs, 
    1656 +       .write_super = yaffs_write_super, 
    1657 +}; 
    1658 + 
    1659 +static void yaffs_GrossLock(yaffs_Device * dev) 
    1660 +{ 
    1661 +       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs locking\n")); 
    1662 + 
    1663 +       down(&dev->grossLock); 
    1664 +} 
    1665 + 
    1666 +static void yaffs_GrossUnlock(yaffs_Device * dev) 
    1667 +{ 
    1668 +       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs unlocking\n")); 
    1669 +       up(&dev->grossLock); 
    1670 + 
    1671 +} 
    1672 + 
    1673 +static int yaffs_readlink(struct dentry *dentry, char __user * buffer, 
    1674 +                         int buflen) 
    1675 +{ 
    1676 +       unsigned char *alias; 
    1677 +       int ret; 
    1678 + 
    1679 +       yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev; 
    1680 + 
    1681 +       yaffs_GrossLock(dev); 
    1682 + 
    1683 +       alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry)); 
    1684 + 
    1685 +       yaffs_GrossUnlock(dev); 
    1686 + 
    1687 +       if (!alias) 
    1688 +               return -ENOMEM; 
    1689 + 
    1690 +       ret = vfs_readlink(dentry, buffer, buflen, alias); 
    1691 +       kfree(alias); 
    1692 +       return ret; 
    1693 +} 
    1694 + 
    1695 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)) 
    1696 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) 
    1697 +#else 
    1698 +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) 
    1699 +#endif 
    1700 +{ 
    1701 +       unsigned char *alias; 
    1702 +       int ret; 
    1703 +       yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev; 
    1704 + 
    1705 +       yaffs_GrossLock(dev); 
    1706 + 
    1707 +       alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry)); 
    1708 + 
    1709 +       yaffs_GrossUnlock(dev); 
    1710 + 
    1711 +       if (!alias) 
    1712 +        { 
    1713 +               ret = -ENOMEM; 
    1714 +               goto out; 
    1715 +        } 
    1716 + 
    1717 +       ret = vfs_follow_link(nd, alias); 
    1718 +       kfree(alias); 
    1719 +out: 
    1720 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)) 
    1721 +       return ERR_PTR (ret); 
    1722 +#else 
    1723 +       return ret; 
    1724 +#endif 
    1725 +} 
    1726 + 
    1727 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev, 
    1728 +                             yaffs_Object * obj); 
    1729 + 
    1730 +/* 
    1731 + * Lookup is used to find objects in the fs 
    1732 + */ 
    1733 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) 
    1734 + 
    1735 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, 
    1736 +                                  struct nameidata *n) 
    1737 +#else 
    1738 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry) 
    1739 +#endif 
    1740 +{ 
    1741 +       yaffs_Object *obj; 
    1742 +       struct inode *inode = NULL;     /* NCB 2.5/2.6 needs NULL here */ 
    1743 + 
    1744 +       yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev; 
    1745 + 
    1746 +       yaffs_GrossLock(dev); 
    1747 + 
    1748 +       T(YAFFS_TRACE_OS, 
    1749 +         (KERN_DEBUG "yaffs_lookup for %d:%s\n", 
    1750 +          yaffs_InodeToObject(dir)->objectId, dentry->d_name.name)); 
    1751 + 
    1752 +       obj = 
    1753 +           yaffs_FindObjectByName(yaffs_InodeToObject(dir), 
    1754 +                                  dentry->d_name.name); 
    1755 + 
    1756 +       obj = yaffs_GetEquivalentObject(obj);   /* in case it was a hardlink */ 
    1757 +        
    1758 +       /* Can't hold gross lock when calling yaffs_get_inode() */ 
    1759 +       yaffs_GrossUnlock(dev); 
    1760 + 
    1761 +       if (obj) { 
    1762 +               T(YAFFS_TRACE_OS, 
    1763 +                 (KERN_DEBUG "yaffs_lookup found %d\n", obj->objectId)); 
    1764 + 
    1765 +               inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); 
    1766 + 
    1767 +               if (inode) { 
    1768 +                       T(YAFFS_TRACE_OS, 
    1769 +                         (KERN_DEBUG "yaffs_loookup dentry \n")); 
    1770 +/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to 
    1771 + * d_add even if NULL inode */ 
    1772 +#if 0 
    1773 +                       /*dget(dentry); // try to solve directory bug */ 
    1774 +                       d_add(dentry, inode); 
    1775 + 
    1776 +                       /* return dentry; */ 
    1777 +                       return NULL; 
    1778 +#endif 
    1779 +               } 
    1780 + 
    1781 +       } else { 
    1782 +               T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_lookup not found\n")); 
    1783 + 
    1784 +       } 
    1785 + 
    1786 +/* added NCB for 2.5/6 compatability - forces add even if inode is 
    1787 + * NULL which creates dentry hash */ 
    1788 +       d_add(dentry, inode); 
    1789 + 
    1790 +       return NULL; 
    1791 +       /*      return (ERR_PTR(-EIO)); */ 
    1792 + 
    1793 +} 
    1794 + 
    1795 +/* For now put inode is just for debugging 
    1796 + * Put inode is called when the inode **structure** is put. 
    1797 + */ 
    1798 +static void yaffs_put_inode(struct inode *inode) 
    1799 +{ 
    1800 +       T(YAFFS_TRACE_OS, 
    1801 +         ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino, 
    1802 +          atomic_read(&inode->i_count))); 
    1803 + 
    1804 +} 
    1805 + 
    1806 +/* clear is called to tell the fs to release any per-inode data it holds */ 
    1807 +static void yaffs_clear_inode(struct inode *inode) 
    1808 +{ 
    1809 +       yaffs_Object *obj; 
    1810 +       yaffs_Device *dev; 
    1811 + 
    1812 +       obj = yaffs_InodeToObject(inode); 
    1813 + 
    1814 +       T(YAFFS_TRACE_OS, 
    1815 +         ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino, 
    1816 +          atomic_read(&inode->i_count), 
    1817 +          obj ? "object exists" : "null object")); 
    1818 + 
    1819 +       if (obj) { 
    1820 +               dev = obj->myDev; 
    1821 +               yaffs_GrossLock(dev); 
    1822 + 
    1823 +               /* Clear the association between the inode and 
    1824 +                * the yaffs_Object. 
    1825 +                */ 
    1826 +               obj->myInode = NULL; 
    1827 +               yaffs_InodeToObjectLV(inode) = NULL; 
    1828 + 
    1829 +               /* If the object freeing was deferred, then the real 
    1830 +                * free happens now. 
    1831 +                * This should fix the inode inconsistency problem. 
    1832 +                */ 
    1833 + 
    1834 +               yaffs_HandleDeferedFree(obj); 
    1835 + 
    1836 +               yaffs_GrossUnlock(dev); 
    1837 +       } 
    1838 + 
    1839 +} 
    1840 + 
    1841 +/* delete is called when the link count is zero and the inode 
    1842 + * is put (ie. nobody wants to know about it anymore, time to 
    1843 + * delete the file). 
    1844 + * NB Must call clear_inode() 
    1845 + */ 
    1846 +static void yaffs_delete_inode(struct inode *inode) 
    1847 +{ 
    1848 +       yaffs_Object *obj = yaffs_InodeToObject(inode); 
    1849 +       yaffs_Device *dev; 
    1850 + 
    1851 +       T(YAFFS_TRACE_OS, 
    1852 +         ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino, 
    1853 +          atomic_read(&inode->i_count), 
    1854 +          obj ? "object exists" : "null object")); 
    1855 + 
    1856 +       if (obj) { 
    1857 +               dev = obj->myDev; 
    1858 +               yaffs_GrossLock(dev); 
    1859 +               yaffs_DeleteFile(obj); 
    1860 +               yaffs_GrossUnlock(dev); 
    1861 +       } 
    1862 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)) 
    1863 +        truncate_inode_pages (&inode->i_data, 0); 
    1864 +#endif 
    1865 +       clear_inode(inode); 
    1866 +} 
    1867 + 
    1868 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 
    1869 +static int yaffs_file_flush(struct file *file, fl_owner_t id) 
    1870 +#else 
    1871 +static int yaffs_file_flush(struct file *file) 
    1872 +#endif 
    1873 +{ 
    1874 +       yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry); 
    1875 + 
    1876 +       yaffs_Device *dev = obj->myDev; 
    1877 + 
    1878 +       T(YAFFS_TRACE_OS, 
    1879 +         (KERN_DEBUG "yaffs_file_flush object %d (%s)\n", obj->objectId, 
    1880 +          obj->dirty ? "dirty" : "clean")); 
    1881 + 
    1882 +       yaffs_GrossLock(dev); 
    1883 + 
    1884 +       yaffs_FlushFile(obj, 1); 
    1885 + 
    1886 +       yaffs_GrossUnlock(dev); 
    1887 + 
    1888 +       return 0; 
    1889 +} 
    1890 + 
    1891 +static int yaffs_readpage_nolock(struct file *f, struct page *pg) 
    1892 +{ 
    1893 +       /* Lifted from jffs2 */ 
    1894 + 
    1895 +       yaffs_Object *obj; 
    1896 +       unsigned char *pg_buf; 
    1897 +       int ret; 
    1898 + 
    1899 +       yaffs_Device *dev; 
    1900 + 
    1901 +       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_readpage at %08x, size %08x\n", 
    1902 +                          (unsigned)(pg->index << PAGE_CACHE_SHIFT), 
    1903 +                          (unsigned)PAGE_CACHE_SIZE)); 
    1904 + 
    1905 +       obj = yaffs_DentryToObject(f->f_dentry); 
    1906 + 
    1907 +       dev = obj->myDev; 
    1908 + 
    1909 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) 
    1910 +       BUG_ON(!PageLocked(pg)); 
    1911 +#else 
    1912 +       if (!PageLocked(pg)) 
    1913 +               PAGE_BUG(pg); 
    1914 +#endif 
    1915 + 
    1916 +       pg_buf = kmap(pg); 
    1917 +       /* FIXME: Can kmap fail? */ 
    1918 + 
    1919 +       yaffs_GrossLock(dev); 
    1920 + 
    1921 +       ret = 
    1922 +           yaffs_ReadDataFromFile(obj, pg_buf, pg->index << PAGE_CACHE_SHIFT, 
    1923 +                                  PAGE_CACHE_SIZE); 
    1924 + 
    1925 +       yaffs_GrossUnlock(dev); 
    1926 + 
    1927 +       if (ret >= 0) 
    1928 +               ret = 0; 
    1929 + 
    1930 +       if (ret) { 
    1931 +               ClearPageUptodate(pg); 
    1932 +               SetPageError(pg); 
    1933 +       } else { 
    1934 +               SetPageUptodate(pg); 
    1935 +               ClearPageError(pg); 
    1936 +       } 
    1937 + 
    1938 +       flush_dcache_page(pg); 
    1939 +       kunmap(pg); 
    1940 + 
    1941 +       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_readpage done\n")); 
    1942 +       return ret; 
    1943 +} 
    1944 + 
    1945 +static int yaffs_readpage_unlock(struct file *f, struct page *pg) 
    1946 +{ 
    1947 +       int ret = yaffs_readpage_nolock(f, pg); 
    1948 +       UnlockPage(pg); 
    1949 +       return ret; 
    1950 +} 
    1951 + 
    1952 +static int yaffs_readpage(struct file *f, struct page *pg) 
    1953 +{ 
    1954 +       return yaffs_readpage_unlock(f, pg); 
    1955 +} 
    1956 + 
    1957 +/* writepage inspired by/stolen from smbfs */ 
    1958 + 
    1959 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) 
    1960 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc) 
    1961 +#else 
    1962 +static int yaffs_writepage(struct page *page) 
    1963 +#endif 
    1964 +{ 
    1965 +       struct address_space *mapping = page->mapping; 
    1966 +       loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT; 
    1967 +       struct inode *inode; 
    1968 +       unsigned long end_index; 
    1969 +       char *buffer; 
    1970 +       yaffs_Object *obj; 
    1971 +       int nWritten = 0; 
    1972 +       unsigned nBytes; 
    1973 + 
    1974 +       if (!mapping) 
    1975 +               BUG(); 
    1976 +       inode = mapping->host; 
    1977 +       if (!inode) 
    1978 +               BUG(); 
    1979 + 
    1980 +       if (offset > inode->i_size) { 
    1981 +               T(YAFFS_TRACE_OS, 
    1982 +                 (KERN_DEBUG 
    1983 +                  "yaffs_writepage at %08x, inode size = %08x!!!\n", 
    1984 +                  (unsigned)(page->index << PAGE_CACHE_SHIFT), 
    1985 +                  (unsigned)inode->i_size)); 
    1986 +               T(YAFFS_TRACE_OS, 
    1987 +                 (KERN_DEBUG "                -> don't care!!\n")); 
    1988 +               unlock_page(page); 
    1989 +               return 0; 
    1990 +       } 
    1991 + 
    1992 +       end_index = inode->i_size >> PAGE_CACHE_SHIFT; 
    1993 + 
    1994 +       /* easy case */ 
    1995 +       if (page->index < end_index) { 
    1996 +               nBytes = PAGE_CACHE_SIZE; 
    1997 +       } else { 
    1998 +               nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1); 
    1999 +       } 
    2000 + 
    2001 +       get_page(page); 
    2002 + 
    2003 +       buffer = kmap(page); 
    2004 + 
    2005 +       obj = yaffs_InodeToObject(inode); 
    2006 +       yaffs_GrossLock(obj->myDev); 
    2007 + 
    2008 +       T(YAFFS_TRACE_OS, 
    2009 +         (KERN_DEBUG "yaffs_writepage at %08x, size %08x\n", 
    2010 +          (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes)); 
    2011 +       T(YAFFS_TRACE_OS, 
    2012 +         (KERN_DEBUG "writepag0: obj = %05x, ino = %05x\n", 
    2013 +          (int)obj->variant.fileVariant.fileSize, (int)inode->i_size)); 
    2014 + 
    2015 +       nWritten = 
    2016 +           yaffs_WriteDataToFile(obj, buffer, page->index << PAGE_CACHE_SHIFT, 
    2017 +                                 nBytes, 0); 
    2018 + 
    2019 +       T(YAFFS_TRACE_OS, 
    2020 +         (KERN_DEBUG "writepag1: obj = %05x, ino = %05x\n", 
    2021 +          (int)obj->variant.fileVariant.fileSize, (int)inode->i_size)); 
    2022 + 
    2023 +       yaffs_GrossUnlock(obj->myDev); 
    2024 + 
    2025 +       kunmap(page); 
    2026 +       SetPageUptodate(page); 
    2027 +       UnlockPage(page); 
    2028 +       put_page(page); 
    2029 + 
    2030 +       return (nWritten == nBytes) ? 0 : -ENOSPC; 
    2031 +} 
    2032 + 
    2033 +static int yaffs_prepare_write(struct file *f, struct page *pg, 
    2034 +                              unsigned offset, unsigned to) 
    2035 +{ 
    2036 + 
    2037 +       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_prepair_write\n")); 
    2038 +       if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE)) 
    2039 +               return yaffs_readpage_nolock(f, pg); 
    2040 + 
    2041 +       return 0; 
    2042 + 
    2043 +} 
    2044 + 
    2045 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, 
    2046 +                             unsigned to) 
    2047 +{ 
    2048 + 
    2049 +       void *addr = page_address(pg) + offset; 
    2050 +       loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset; 
    2051 +       int nBytes = to - offset; 
    2052 +       int nWritten; 
    2053 + 
    2054 +       unsigned spos = pos; 
    2055 +       unsigned saddr = (unsigned)addr; 
    2056 + 
    2057 +       T(YAFFS_TRACE_OS, 
    2058 +         (KERN_DEBUG "yaffs_commit_write addr %x pos %x nBytes %d\n", saddr, 
    2059 +          spos, nBytes)); 
    2060 + 
    2061 +       nWritten = yaffs_file_write(f, addr, nBytes, &pos); 
    2062 + 
    2063 +       if (nWritten != nBytes) { 
    2064 +               T(YAFFS_TRACE_OS, 
    2065 +                 (KERN_DEBUG 
    2066 +                  "yaffs_commit_write not same size nWritten %d  nBytes %d\n", 
    2067 +                  nWritten, nBytes)); 
    2068 +               SetPageError(pg); 
    2069 +               ClearPageUptodate(pg); 
    2070 +       } else { 
    2071 +               SetPageUptodate(pg); 
    2072 +       } 
    2073 + 
    2074 +       T(YAFFS_TRACE_OS, 
    2075 +         (KERN_DEBUG "yaffs_commit_write returning %d\n", 
    2076 +          nWritten == nBytes ? 0 : nWritten)); 
    2077 + 
    2078 +       return nWritten == nBytes ? 0 : nWritten; 
    2079 + 
    2080 +} 
    2081 + 
    2082 +static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * obj) 
    2083 +{ 
    2084 +       if (inode && obj) { 
    2085 + 
    2086 + 
    2087 +               /* Check mode against the variant type and attempt to repair if broken. */ 
    2088 +               __u32 mode = obj->yst_mode; 
    2089 +               switch( obj->variantType ){ 
    2090 +               case YAFFS_OBJECT_TYPE_FILE : 
    2091 +                       if( ! S_ISREG(mode) ){ 
    2092 +                               obj->yst_mode &= ~S_IFMT; 
    2093 +                               obj->yst_mode |= S_IFREG; 
    2094 +                       } 
    2095 +  
    2096 +                       break; 
    2097 +               case YAFFS_OBJECT_TYPE_SYMLINK : 
    2098 +                       if( ! S_ISLNK(mode) ){ 
    2099 +                               obj->yst_mode &= ~S_IFMT; 
    2100 +                               obj->yst_mode |= S_IFLNK; 
    2101 +                       } 
    2102 +  
    2103 +                       break; 
    2104 +               case YAFFS_OBJECT_TYPE_DIRECTORY : 
    2105 +                       if( ! S_ISDIR(mode) ){ 
    2106 +                               obj->yst_mode &= ~S_IFMT; 
    2107 +                               obj->yst_mode |= S_IFDIR; 
    2108 +                       } 
    2109 +  
    2110 +                       break; 
    2111 +               case YAFFS_OBJECT_TYPE_UNKNOWN : 
    2112 +               case YAFFS_OBJECT_TYPE_HARDLINK : 
    2113 +               case YAFFS_OBJECT_TYPE_SPECIAL : 
    2114 +               default: 
    2115 +                       /* TODO? */ 
    2116 +                       break; 
    2117 +               } 
    2118 + 
    2119 +               inode->i_ino = obj->objectId; 
    2120 +               inode->i_mode = obj->yst_mode; 
    2121 +               inode->i_uid = obj->yst_uid; 
    2122 +               inode->i_gid = obj->yst_gid; 
    2123 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) 
    2124 +               inode->i_blksize = inode->i_sb->s_blocksize; 
    2125 +#endif 
    2126 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) 
    2127 + 
    2128 +               inode->i_rdev = old_decode_dev(obj->yst_rdev); 
    2129 +               inode->i_atime.tv_sec = (time_t) (obj->yst_atime); 
    2130 +               inode->i_atime.tv_nsec = 0; 
    2131 +               inode->i_mtime.tv_sec = (time_t) obj->yst_mtime; 
    2132 +               inode->i_mtime.tv_nsec = 0; 
    2133 +               inode->i_ctime.tv_sec = (time_t) obj->yst_ctime; 
    2134 +               inode->i_ctime.tv_nsec = 0; 
    2135 +#else 
    2136 +               inode->i_rdev = obj->yst_rdev; 
    2137 +               inode->i_atime = obj->yst_atime; 
    2138 +               inode->i_mtime = obj->yst_mtime; 
    2139 +               inode->i_ctime = obj->yst_ctime; 
    2140 +#endif 
    2141 +               inode->i_size = yaffs_GetObjectFileLength(obj); 
    2142 +               inode->i_blocks = (inode->i_size + 511) >> 9; 
    2143 + 
    2144 +               inode->i_nlink = yaffs_GetObjectLinkCount(obj); 
    2145 + 
    2146 +               T(YAFFS_TRACE_OS, 
    2147 +                 (KERN_DEBUG 
    2148 +                  "yaffs_FillInode mode %x uid %d gid %d size %d count %d\n", 
    2149 +                  inode->i_mode, inode->i_uid, inode->i_gid, 
    2150 +                  (int)inode->i_size, atomic_read(&inode->i_count))); 
    2151 + 
    2152 +               switch (obj->yst_mode & S_IFMT) { 
    2153 +               default:        /* fifo, device or socket */ 
    2154 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) 
    2155 +                       init_special_inode(inode, obj->yst_mode, 
    2156 +                                          old_decode_dev(obj->yst_rdev)); 
    2157 +#else 
    2158 +                       init_special_inode(inode, obj->yst_mode, 
    2159 +                                          (dev_t) (obj->yst_rdev)); 
    2160 +#endif 
    2161 +                       break; 
    2162 +               case S_IFREG:   /* file */ 
    2163 +                       inode->i_op = &yaffs_file_inode_operations; 
    2164 +                       inode->i_fop = &yaffs_file_operations; 
    2165 +                       inode->i_mapping->a_ops = 
    2166 +                           &yaffs_file_address_operations; 
    2167 +                       break; 
    2168 +               case S_IFDIR:   /* directory */ 
    2169 +                       inode->i_op = &yaffs_dir_inode_operations; 
    2170 +                       inode->i_fop = &yaffs_dir_operations; 
    2171 +                       break; 
    2172 +               case S_IFLNK:   /* symlink */ 
    2173 +                       inode->i_op = &yaffs_symlink_inode_operations; 
    2174 +                       break; 
    2175 +               } 
    2176 + 
    2177 +               yaffs_InodeToObjectLV(inode) = obj; 
    2178 + 
    2179 +               obj->myInode = inode; 
    2180 + 
    2181 +       } else { 
    2182 +               T(YAFFS_TRACE_OS, 
    2183 +                 (KERN_DEBUG "yaffs_FileInode invalid parameters\n")); 
    2184 +       } 
    2185 + 
    2186 +} 
    2187 + 
    2188 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev, 
    2189 +                             yaffs_Object * obj) 
    2190 +{ 
    2191 +       struct inode *inode; 
    2192 + 
    2193 +       if (!sb) { 
    2194 +               T(YAFFS_TRACE_OS, 
    2195 +                 (KERN_DEBUG "yaffs_get_inode for NULL super_block!!\n")); 
    2196 +               return NULL; 
    2197 + 
    2198 +       } 
    2199 + 
    2200 +       if (!obj) { 
    2201 +               T(YAFFS_TRACE_OS, 
    2202 +                 (KERN_DEBUG "yaffs_get_inode for NULL object!!\n")); 
    2203 +               return NULL; 
    2204 + 
    2205 +       } 
    2206 + 
    2207 +       T(YAFFS_TRACE_OS, 
    2208 +         (KERN_DEBUG "yaffs_get_inode for object %d\n", obj->objectId)); 
    2209 + 
    2210 +       inode = iget(sb, obj->objectId); 
    2211 + 
    2212 +       /* NB Side effect: iget calls back to yaffs_read_inode(). */ 
    2213 +       /* iget also increments the inode's i_count */ 
    2214 +       /* NB You can't be holding grossLock or deadlock will happen! */ 
    2215 + 
    2216 +       return inode; 
    2217 +} 
    2218 + 
    2219 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, 
    2220 +                               loff_t * pos) 
    2221 +{ 
    2222 +       yaffs_Object *obj; 
    2223 +       int nWritten, ipos; 
    2224 +       struct inode *inode; 
    2225 +       yaffs_Device *dev; 
    2226 + 
    2227 +       obj = yaffs_DentryToObject(f->f_dentry); 
    2228 + 
    2229 +       dev = obj->myDev; 
    2230 + 
    2231 +       yaffs_GrossLock(dev); 
    2232 + 
    2233 +       inode = f->f_dentry->d_inode; 
    2234 + 
    2235 +       if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) { 
    2236 +               ipos = inode->i_size; 
    2237 +       } else { 
    2238 +               ipos = *pos; 
    2239 +       } 
    2240 + 
    2241 +       if (!obj) { 
    2242 +               T(YAFFS_TRACE_OS, 
    2243 +                 (KERN_DEBUG "yaffs_file_write: hey obj is null!\n")); 
    2244 +       } else { 
    2245 +               T(YAFFS_TRACE_OS, 
    2246 +                 (KERN_DEBUG 
    2247 +                  "yaffs_file_write about to write writing %d bytes" 
    2248 +                  "to object %d at %d\n", 
    2249 +                  n, obj->objectId, ipos)); 
    2250 +       } 
    2251 + 
    2252 +       nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0); 
    2253 + 
    2254 +       T(YAFFS_TRACE_OS, 
    2255 +         (KERN_DEBUG "yaffs_file_write writing %d bytes, %d written at %d\n", 
    2256 +          n, nWritten, ipos)); 
    2257 +       if (nWritten > 0) { 
    2258 +               ipos += nWritten; 
    2259 +               *pos = ipos; 
    2260 +               if (ipos > inode->i_size) { 
    2261 +                       inode->i_size = ipos; 
    2262 +                       inode->i_blocks = (ipos + 511) >> 9; 
    2263 + 
    2264 +                       T(YAFFS_TRACE_OS, 
    2265 +                         (KERN_DEBUG 
    2266 +                          "yaffs_file_write size updated to %d bytes, " 
    2267 +                          "%d blocks\n", 
    2268 +                          ipos, (int)(inode->i_blocks))); 
    2269 +               } 
    2270 + 
    2271 +       } 
    2272 +       yaffs_GrossUnlock(dev); 
    2273 +       return nWritten == 0 ? -ENOSPC : nWritten; 
    2274 +} 
    2275 + 
    2276 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) 
    2277 +{ 
    2278 +       yaffs_Object *obj; 
    2279 +       yaffs_Device *dev; 
    2280 +       struct inode *inode = f->f_dentry->d_inode; 
    2281 +       unsigned long offset, curoffs; 
    2282 +       struct list_head *i; 
    2283 +       yaffs_Object *l; 
    2284 + 
    2285 +       char name[YAFFS_MAX_NAME_LENGTH + 1]; 
    2286 + 
    2287 +       obj = yaffs_DentryToObject(f->f_dentry); 
    2288 +       dev = obj->myDev; 
    2289 + 
    2290 +       yaffs_GrossLock(dev); 
    2291 + 
    2292 +       offset = f->f_pos; 
    2293 + 
    2294 +       T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset)); 
    2295 + 
    2296 +       if (offset == 0) { 
    2297 +               T(YAFFS_TRACE_OS, 
    2298 +                 (KERN_DEBUG "yaffs_readdir: entry . ino %d \n", 
    2299 +                  (int)inode->i_ino)); 
    2300 +               if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) 
    2301 +                   < 0) { 
    2302 +                       goto out; 
    2303 +               } 
    2304 +               offset++; 
    2305 +               f->f_pos++; 
    2306 +       } 
    2307 +       if (offset == 1) { 
    2308 +               T(YAFFS_TRACE_OS, 
    2309 +                 (KERN_DEBUG "yaffs_readdir: entry .. ino %d \n", 
    2310 +                  (int)f->f_dentry->d_parent->d_inode->i_ino)); 
    2311 +               if (filldir 
    2312 +                   (dirent, "..", 2, offset, 
    2313 +                    f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { 
    2314 +                       goto out; 
    2315 +               } 
    2316 +               offset++; 
    2317 +               f->f_pos++; 
    2318 +       } 
    2319 + 
    2320 +       curoffs = 1; 
    2321 + 
    2322 +       /* If the directory has changed since the open or last call to 
    2323 +          readdir, rewind to after the 2 canned entries. */ 
    2324 + 
    2325 +       if (f->f_version != inode->i_version) { 
    2326 +               offset = 2; 
    2327 +               f->f_pos = offset; 
    2328 +               f->f_version = inode->i_version; 
    2329 +       } 
    2330 + 
    2331 +       list_for_each(i, &obj->variant.directoryVariant.children) { 
    2332 +               curoffs++; 
    2333 +               if (curoffs >= offset) { 
    2334 +                       l = list_entry(i, yaffs_Object, siblings); 
    2335 + 
    2336 +                       yaffs_GetObjectName(l, name, 
    2337 +                                           YAFFS_MAX_NAME_LENGTH + 1); 
    2338 +                       T(YAFFS_TRACE_OS, 
    2339 +                         (KERN_DEBUG "yaffs_readdir: %s inode %d\n", name, 
    2340 +                          yaffs_GetObjectInode(l))); 
    2341 + 
    2342 +                       if (filldir(dirent, 
    2343 +                                   name, 
    2344 +                                   strlen(name), 
    2345 +                                   offset, 
    2346 +                                   yaffs_GetObjectInode(l), 
    2347 +                                   yaffs_GetObjectType(l)) 
    2348 +                           < 0) { 
    2349 +                               goto up_and_out; 
    2350 +                       } 
    2351 + 
    2352 +                       offset++; 
    2353 +                       f->f_pos++; 
    2354 +               } 
    2355 +       } 
    2356 + 
    2357 +      up_and_out: 
    2358 +      out: 
    2359 + 
    2360 +       yaffs_GrossUnlock(dev); 
    2361 + 
    2362 +       return 0; 
    2363 +} 
    2364 + 
    2365 +/* 
    2366 + * File creation. Allocate an inode, and we're done.. 
    2367 + */ 
    2368 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) 
    2369 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, 
    2370 +                      dev_t rdev) 
    2371 +#else 
    2372 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, 
    2373 +                      int rdev) 
    2374 +#endif 
    2375 +{ 
    2376 +       struct inode *inode; 
    2377 + 
    2378 +       yaffs_Object *obj = NULL; 
    2379 +       yaffs_Device *dev; 
    2380 + 
    2381 +       yaffs_Object *parent = yaffs_InodeToObject(dir); 
    2382 + 
    2383 +       int error = -ENOSPC; 
    2384 +       uid_t uid = current->fsuid; 
    2385 +       gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; 
    2386 +        
    2387 +       if((dir->i_mode & S_ISGID) && S_ISDIR(mode)) 
    2388 +               mode |= S_ISGID; 
    2389 + 
    2390 +       if (parent) { 
    2391 +               T(YAFFS_TRACE_OS, 
    2392 +                 (KERN_DEBUG "yaffs_mknod: parent object %d type %d\n", 
    2393 +                  parent->objectId, parent->variantType)); 
    2394 +       } else { 
    2395 +               T(YAFFS_TRACE_OS, 
    2396 +                 (KERN_DEBUG "yaffs_mknod: could not get parent object\n")); 
    2397 +               return -EPERM; 
    2398 +       } 
    2399 + 
    2400 +       T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, " 
    2401 +                          "mode %x dev %x\n", 
    2402 +                          dentry->d_name.name, mode, rdev)); 
    2403 + 
    2404 +       dev = parent->myDev; 
    2405 + 
    2406 +       yaffs_GrossLock(dev); 
    2407 + 
    2408 +       switch (mode & S_IFMT) { 
    2409 +       default: 
    2410 +               /* Special (socket, fifo, device...) */ 
    2411 +               T(YAFFS_TRACE_OS, (KERN_DEBUG 
    2412 +                                  "yaffs_mknod: making special\n")); 
    2413 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) 
    2414 +               obj = 
    2415 +                   yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid, 
    2416 +                                      gid, old_encode_dev(rdev)); 
    2417 +#else 
    2418 +               obj = 
    2419 +                   yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid, 
    2420 +                                      gid, rdev); 
    2421 +#endif 
    2422 +               break; 
    2423 +       case S_IFREG:           /* file          */ 
    2424 +               T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_mknod: making file\n")); 
    2425 +               obj = 
    2426 +                   yaffs_MknodFile(parent, dentry->d_name.name, mode, uid, 
    2427 +                                   gid); 
    2428 +               break; 
    2429 +       case S_IFDIR:           /* directory */ 
    2430 +               T(YAFFS_TRACE_OS, 
    2431 +                 (KERN_DEBUG "yaffs_mknod: making directory\n")); 
    2432 +               obj = 
    2433 +                   yaffs_MknodDirectory(parent, dentry->d_name.name, mode, 
    2434 +                                        uid, gid); 
    2435 +               break; 
    2436 +       case S_IFLNK:           /* symlink */ 
    2437 +               T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_mknod: making file\n")); 
    2438 +               obj = NULL;     /* Do we ever get here? */ 
    2439 +               break; 
    2440 +       } 
    2441 +        
    2442 +       /* Can not call yaffs_get_inode() with gross lock held */ 
    2443 +       yaffs_GrossUnlock(dev); 
    2444 + 
    2445 +       if (obj) { 
    2446 +               inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj); 
    2447 +               d_instantiate(dentry, inode); 
    2448 +               T(YAFFS_TRACE_OS, 
    2449 +                 (KERN_DEBUG "yaffs_mknod created object %d count = %d\n", 
    2450 +                  obj->objectId, atomic_read(&inode->i_count))); 
    2451 +               error = 0; 
    2452 +       } else { 
    2453 +               T(YAFFS_TRACE_OS, 
    2454 +                 (KERN_DEBUG "yaffs_mknod failed making object\n")); 
    2455 +               error = -ENOMEM; 
    2456 +       } 
    2457 + 
    2458 +       return error; 
    2459 +} 
    2460 + 
    2461 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) 
    2462 +{ 
    2463 +       int retVal; 
    2464 +       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_mkdir\n")); 
    2465 +       retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0); 
    2466 +#if 0 
    2467 +       /* attempt to fix dir bug - didn't work */ 
    2468 +       if (!retVal) { 
    2469 +               dget(dentry); 
    2470 +       } 
    2471 +#endif 
    2472 +       return retVal; 
    2473 +} 
    2474 + 
    2475 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) 
    2476 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, 
    2477 +                       struct nameidata *n) 
    2478 +#else 
    2479 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode) 
    2480 +#endif 
    2481 +{ 
    2482 +       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_create\n")); 
    2483 +       return yaffs_mknod(dir, dentry, mode | S_IFREG, 0); 
    2484 +} 
    2485 + 
    2486 +static int yaffs_unlink(struct inode *dir, struct dentry *dentry) 
    2487 +{ 
    2488 +       int retVal; 
    2489 + 
    2490 +       yaffs_Device *dev; 
    2491 + 
    2492 +       T(YAFFS_TRACE_OS, 
    2493 +         (KERN_DEBUG "yaffs_unlink %d:%s\n", (int)(dir->i_ino), 
    2494 +          dentry->d_name.name)); 
    2495 + 
    2496 +       dev = yaffs_InodeToObject(dir)->myDev; 
    2497 + 
    2498 +       yaffs_GrossLock(dev); 
    2499 + 
    2500 +       retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name); 
    2501 + 
    2502 +       if (retVal == YAFFS_OK) { 
    2503 +               dentry->d_inode->i_nlink--; 
    2504 +               dir->i_version++; 
    2505 +               yaffs_GrossUnlock(dev); 
    2506 +               mark_inode_dirty(dentry->d_inode); 
    2507 +               return 0; 
    2508 +       } 
    2509 +       yaffs_GrossUnlock(dev); 
    2510 +       return -ENOTEMPTY; 
    2511 +} 
    2512 + 
    2513 +/* 
    2514 + * Create a link... 
    2515 + */ 
    2516 +static int yaffs_link(struct dentry *old_dentry, struct inode *dir, 
    2517 +                     struct dentry *dentry) 
    2518 +{ 
    2519 +       struct inode *inode = old_dentry->d_inode; 
    2520 +       yaffs_Object *obj = NULL; 
    2521 +       yaffs_Object *link = NULL; 
    2522 +       yaffs_Device *dev; 
    2523 + 
    2524 +       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_link\n")); 
    2525 + 
    2526 +       obj = yaffs_InodeToObject(inode); 
    2527 +       dev = obj->myDev; 
    2528 + 
    2529 +       yaffs_GrossLock(dev); 
    2530 + 
    2531 +       if (!S_ISDIR(inode->i_mode))    /* Don't link directories */ 
    2532 +       { 
    2533 +               link = 
    2534 +                   yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name, 
    2535 +                              obj); 
    2536 +       } 
    2537 + 
    2538 +       if (link) { 
    2539 +               old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj); 
    2540 +               d_instantiate(dentry, old_dentry->d_inode); 
    2541 +               atomic_inc(&old_dentry->d_inode->i_count); 
    2542 +               T(YAFFS_TRACE_OS, 
    2543 +                 (KERN_DEBUG "yaffs_link link count %d i_count %d\n", 
    2544 +                  old_dentry->d_inode->i_nlink, 
    2545 +                  atomic_read(&old_dentry->d_inode->i_count))); 
    2546 + 
    2547 +       } 
    2548 + 
    2549 +       yaffs_GrossUnlock(dev); 
    2550 + 
    2551 +       if (link) { 
    2552 + 
    2553 +               return 0; 
    2554 +       } 
    2555 + 
    2556 +       return -EPERM; 
    2557 +} 
    2558 + 
    2559 +static int yaffs_symlink(struct inode *dir, struct dentry *dentry, 
    2560 +                        const char *symname) 
    2561 +{ 
    2562 +       yaffs_Object *obj; 
    2563 +       yaffs_Device *dev; 
    2564 +       uid_t uid = current->fsuid; 
    2565 +       gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; 
    2566 + 
    2567 +       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_symlink\n")); 
    2568 + 
    2569 +       dev = yaffs_InodeToObject(dir)->myDev; 
    2570 +       yaffs_GrossLock(dev); 
    2571 +       obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name, 
    2572 +                                S_IFLNK | S_IRWXUGO, uid, gid, symname); 
    2573 +       yaffs_GrossUnlock(dev); 
    2574 + 
    2575 +       if (obj) { 
    2576 + 
    2577 +               struct inode *inode; 
    2578 + 
    2579 +               inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); 
    2580 +               d_instantiate(dentry, inode); 
    2581 +               T(YAFFS_TRACE_OS, (KERN_DEBUG "symlink created OK\n")); 
    2582 +               return 0; 
    2583 +       } else { 
    2584 +               T(YAFFS_TRACE_OS, (KERN_DEBUG "symlink not created\n")); 
    2585 + 
    2586 +       } 
    2587 + 
    2588 +       return -ENOMEM; 
    2589 +} 
    2590 + 
    2591 +static int yaffs_sync_object(struct file *file, struct dentry *dentry, 
    2592 +                            int datasync) 
    2593 +{ 
    2594 + 
    2595 +       yaffs_Object *obj; 
    2596 +       yaffs_Device *dev; 
    2597 + 
    2598 +       obj = yaffs_DentryToObject(dentry); 
    2599 + 
    2600 +       dev = obj->myDev; 
    2601 + 
    2602 +       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_object\n")); 
    2603 +       yaffs_GrossLock(dev); 
    2604 +       yaffs_FlushFile(obj, 1); 
    2605 +       yaffs_GrossUnlock(dev); 
    2606 +       return 0; 
    2607 +} 
    2608 + 
    2609 +/* 
    2610 + * The VFS layer already does all the dentry stuff for rename. 
    2611 + * 
    2612 + * NB: POSIX says you can rename an object over an old object of the same name 
    2613 + */ 
    2614 +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, 
    2615 +                       struct inode *new_dir, struct dentry *new_dentry) 
    2616 +{ 
    2617 +       yaffs_Device *dev; 
    2618 +       int retVal = YAFFS_FAIL; 
    2619 +       yaffs_Object *target; 
    2620 + 
    2621 +        T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_rename\n")); 
    2622 +       dev = yaffs_InodeToObject(old_dir)->myDev; 
    2623 + 
    2624 +       yaffs_GrossLock(dev); 
    2625 + 
    2626 +       /* Check if the target is an existing directory that is not empty. */ 
    2627 +       target = 
    2628 +           yaffs_FindObjectByName(yaffs_InodeToObject(new_dir), 
    2629 +                                  new_dentry->d_name.name); 
    2630 +        
    2631 +        
    2632 + 
    2633 +       if (target && 
    2634 +           target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && 
    2635 +           !list_empty(&target->variant.directoryVariant.children)) { 
    2636 +            
    2637 +               T(YAFFS_TRACE_OS, (KERN_DEBUG "target is non-empty dir\n")); 
    2638 + 
    2639 +               retVal = YAFFS_FAIL; 
    2640 +       } else { 
    2641 + 
    2642 +               /* Now does unlinking internally using shadowing mechanism */ 
    2643 +               T(YAFFS_TRACE_OS, (KERN_DEBUG "calling yaffs_RenameObject\n")); 
    2644 +                
    2645 +               retVal = 
    2646 +                   yaffs_RenameObject(yaffs_InodeToObject(old_dir), 
    2647 +                                      old_dentry->d_name.name, 
    2648 +                                      yaffs_InodeToObject(new_dir), 
    2649 +                                      new_dentry->d_name.name); 
    2650 + 
    2651 +       } 
    2652 +       yaffs_GrossUnlock(dev); 
    2653 + 
    2654 +       if (retVal == YAFFS_OK) { 
    2655 +               if(target) { 
    2656 +                       new_dentry->d_inode->i_nlink--; 
    2657 +                       mark_inode_dirty(new_dentry->d_inode); 
    2658 +               } 
    2659 + 
    2660 +               return 0; 
    2661 +       } else { 
    2662 +               return -ENOTEMPTY; 
    2663 +       } 
    2664 + 
    2665 +} 
    2666 + 
    2667 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr) 
    2668 +{ 
    2669 +       struct inode *inode = dentry->d_inode; 
    2670 +       int error; 
    2671 +       yaffs_Device *dev; 
    2672 + 
    2673 +       T(YAFFS_TRACE_OS, 
    2674 +         (KERN_DEBUG "yaffs_setattr of object %d\n", 
    2675 +          yaffs_InodeToObject(inode)->objectId)); 
    2676 + 
    2677 +       if ((error = inode_change_ok(inode, attr)) == 0) { 
    2678 + 
    2679 +               dev = yaffs_InodeToObject(inode)->myDev; 
    2680 +               yaffs_GrossLock(dev); 
    2681 +               if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) == 
    2682 +                   YAFFS_OK) { 
    2683 +                       error = 0; 
    2684 +               } else { 
    2685 +                       error = -EPERM; 
    2686 +               } 
    2687 +               yaffs_GrossUnlock(dev); 
    2688 +               if (!error) 
    2689 +                       error = inode_setattr(inode, attr); 
    2690 +       } 
    2691 +       return error; 
    2692 +} 
    2693 + 
    2694 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 
    2695 +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf) 
    2696 +{ 
    2697 +       yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev; 
    2698 +       struct super_block *sb = dentry->d_sb; 
    2699 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) 
    2700 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf) 
    2701 +{ 
    2702 +       yaffs_Device *dev = yaffs_SuperToDevice(sb); 
    2703 +#else 
    2704 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf) 
    2705 +{ 
    2706 +       yaffs_Device *dev = yaffs_SuperToDevice(sb); 
    2707 +#endif 
    2708 + 
    2709 +       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_statfs\n")); 
    2710 + 
    2711 +       yaffs_GrossLock(dev); 
    2712 + 
    2713 +       buf->f_type = YAFFS_MAGIC; 
    2714 +       buf->f_bsize = sb->s_blocksize; 
    2715 +       buf->f_namelen = 255; 
    2716 +       if (sb->s_blocksize > dev->nDataBytesPerChunk) { 
    2717 + 
    2718 +               buf->f_blocks = 
    2719 +                   (dev->endBlock - dev->startBlock + 
    2720 +                    1) * dev->nChunksPerBlock / (sb->s_blocksize / 
    2721 +                                                 dev->nDataBytesPerChunk); 
    2722 +               buf->f_bfree = 
    2723 +                   yaffs_GetNumberOfFreeChunks(dev) / (sb->s_blocksize / 
    2724 +                                                       dev->nDataBytesPerChunk); 
    2725 +       } else { 
    2726 + 
    2727 +               buf->f_blocks = 
    2728 +                   (dev->endBlock - dev->startBlock + 
    2729 +                    1) * dev->nChunksPerBlock * (dev->nDataBytesPerChunk / 
    2730 +                                                 sb->s_blocksize); 
    2731 +               buf->f_bfree = 
    2732 +                   yaffs_GetNumberOfFreeChunks(dev) * (dev->nDataBytesPerChunk / 
    2733 +                                                       sb->s_blocksize); 
    2734 +       } 
    2735 +       buf->f_files = 0; 
    2736 +       buf->f_ffree = 0; 
    2737 +       buf->f_bavail = buf->f_bfree; 
    2738 + 
    2739 +       yaffs_GrossUnlock(dev); 
    2740 +       return 0; 
    2741 +} 
    2742 + 
    2743 + 
    2744 +/** 
    2745 +static int yaffs_do_sync_fs(struct super_block *sb) 
    2746 +{ 
    2747 + 
    2748 +       yaffs_Device *dev = yaffs_SuperToDevice(sb); 
    2749 +       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_do_sync_fs\n")); 
    2750 + 
    2751 +       if(sb->s_dirt) { 
    2752 +               yaffs_GrossLock(dev); 
    2753 + 
    2754 +               if(dev) 
    2755 +                       yaffs_CheckpointSave(dev); 
    2756 +                
    2757 +               yaffs_GrossUnlock(dev); 
    2758 + 
    2759 +               sb->s_dirt = 0; 
    2760 +       } 
    2761 +       return 0; 
    2762 +} 
    2763 +**/ 
    2764 + 
    2765 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 
    2766 +static void yaffs_write_super(struct super_block *sb) 
    2767 +#else 
    2768 +static int yaffs_write_super(struct super_block *sb) 
    2769 +#endif 
    2770 +{ 
    2771 + 
    2772 +       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_write_super\n")); 
    2773 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)) 
    2774 +       return 0; /* yaffs_do_sync_fs(sb);*/ 
    2775 +#endif 
    2776 +} 
    2777 + 
    2778 + 
    2779 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 
    2780 +static int yaffs_sync_fs(struct super_block *sb, int wait) 
    2781 +#else 
    2782 +static int yaffs_sync_fs(struct super_block *sb) 
    2783 +#endif 
    2784 +{ 
    2785 + 
    2786 +       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_fs\n")); 
    2787 +        
    2788 +       return 0; /* yaffs_do_sync_fs(sb);*/ 
    2789 +        
    2790 +} 
    2791 + 
    2792 + 
    2793 +static void yaffs_read_inode(struct inode *inode) 
    2794 +{ 
    2795 +       /* NB This is called as a side effect of other functions, but 
    2796 +        * we had to release the lock to prevent deadlocks, so  
    2797 +        * need to lock again. 
    2798 +        */ 
    2799 + 
    2800 +       yaffs_Object *obj; 
    2801 +       yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb); 
    2802 + 
    2803 +       T(YAFFS_TRACE_OS, 
    2804 +         (KERN_DEBUG "yaffs_read_inode for %d\n", (int)inode->i_ino)); 
    2805 + 
    2806 +       yaffs_GrossLock(dev); 
    2807 +        
    2808 +       obj = yaffs_FindObjectByNumber(dev, inode->i_ino); 
    2809 + 
    2810 +       yaffs_FillInodeFromObject(inode, obj); 
    2811 + 
    2812 +       yaffs_GrossUnlock(dev); 
    2813 +} 
    2814 + 
    2815 +static LIST_HEAD(yaffs_dev_list); 
    2816 + 
    2817 +static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data) 
    2818 +{ 
    2819 +       yaffs_Device    *dev = yaffs_SuperToDevice(sb); 
    2820 + 
    2821 +       if( *flags & MS_RDONLY ) { 
    2822 +               struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice; 
    2823 +            
    2824 +               T(YAFFS_TRACE_OS, 
    2825 +                       (KERN_DEBUG "yaffs_remount_fs: %s: RO\n", dev->name )); 
    2826 + 
    2827 +               yaffs_GrossLock(dev); 
    2828 +         
    2829 +               yaffs_FlushEntireDeviceCache(dev); 
    2830 +        
    2831 +               yaffs_CheckpointSave(dev); 
    2832 +  
    2833 +               if (mtd->sync) 
    2834 +                       mtd->sync(mtd); 
    2835 + 
    2836 +               yaffs_GrossUnlock(dev); 
    2837 +       } 
    2838 +       else { 
    2839 +               T(YAFFS_TRACE_OS,  
    2840 +                       (KERN_DEBUG "yaffs_remount_fs: %s: RW\n", dev->name )); 
    2841 +       } 
    2842 +  
    2843 +       return 0; 
    2844 +} 
    2845 + 
    2846 +static void yaffs_put_super(struct super_block *sb) 
    2847 +{ 
    2848 +       yaffs_Device *dev = yaffs_SuperToDevice(sb); 
    2849 + 
    2850 +       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_put_super\n")); 
    2851 + 
    2852 +       yaffs_GrossLock(dev); 
    2853 +        
    2854 +       yaffs_FlushEntireDeviceCache(dev); 
    2855 + 
    2856 +       yaffs_CheckpointSave(dev); 
    2857 + 
    2858 +       if (dev->putSuperFunc) { 
    2859 +               dev->putSuperFunc(sb); 
    2860 +       } 
    2861 + 
    2862 +       yaffs_Deinitialise(dev); 
    2863 +        
    2864 +       yaffs_GrossUnlock(dev); 
    2865 + 
    2866 +       /* we assume this is protected by lock_kernel() in mount/umount */ 
    2867 +       list_del(&dev->devList); 
    2868 +        
    2869 +       if(dev->spareBuffer){ 
    2870 +               YFREE(dev->spareBuffer); 
    2871 +               dev->spareBuffer = NULL; 
    2872 +       } 
    2873 + 
    2874 +       kfree(dev); 
    2875 +} 
    2876 + 
    2877 + 
    2878 +static void yaffs_MTDPutSuper(struct super_block *sb) 
    2879 +{ 
    2880 + 
    2881 +       struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice; 
    2882 + 
    2883 +       if (mtd->sync) { 
    2884 +               mtd->sync(mtd); 
    2885 +       } 
    2886 + 
    2887 +       put_mtd_device(mtd); 
    2888 +} 
    2889 + 
    2890 + 
    2891 +static void yaffs_MarkSuperBlockDirty(void *vsb) 
    2892 +{ 
    2893 +       struct super_block *sb = (struct super_block *)vsb; 
    2894 +        
    2895 +       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_MarkSuperBlockDirty() sb = %p\n",sb)); 
    2896 +//     if(sb) 
    2897 +//             sb->s_dirt = 1; 
    2898 +} 
    2899 + 
    2900 +typedef struct { 
    2901 +       int inband_tags; 
    2902 +       int skip_checkpoint_read; 
    2903 +       int skip_checkpoint_write; 
    2904 +       int no_cache; 
    2905 +} yaffs_options; 
    2906 + 
    2907 +#define MAX_OPT_LEN 20 
    2908 +static int yaffs_parse_options(yaffs_options *options, const char *options_str) 
    2909 +{ 
    2910 +       char cur_opt[MAX_OPT_LEN+1]; 
    2911 +       int p; 
    2912 +       int error = 0; 
    2913 +        
    2914 +       /* Parse through the options which is a comma seperated list */ 
    2915 +        
    2916 +       while(options_str && *options_str && !error){ 
    2917 +               memset(cur_opt,0,MAX_OPT_LEN+1); 
    2918 +               p = 0; 
    2919 +                
    2920 +               while(*options_str && *options_str != ','){ 
    2921 +                       if(p < MAX_OPT_LEN){ 
    2922 +                               cur_opt[p] = *options_str; 
    2923 +                               p++; 
    2924 +                       } 
    2925 +                       options_str++; 
    2926 +               } 
    2927 +                
    2928 +               if(!strcmp(cur_opt,"inband-tags")) 
    2929 +                       options->inband_tags = 1; 
    2930 +               else if(!strcmp(cur_opt,"no-cache")) 
    2931 +                       options->no_cache = 1; 
    2932 +               else if(!strcmp(cur_opt,"no-checkpoint-read")) 
    2933 +                       options->skip_checkpoint_read = 1; 
    2934 +               else if(!strcmp(cur_opt,"no-checkpoint-write")) 
    2935 +                       options->skip_checkpoint_write = 1; 
    2936 +               else if(!strcmp(cur_opt,"no-checkpoint")){ 
    2937 +                       options->skip_checkpoint_read = 1; 
    2938 +                       options->skip_checkpoint_write = 1; 
    2939 +               } else { 
    2940 +                       printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",cur_opt); 
    2941 +                       error = 1; 
    2942 +               } 
    2943 +                
    2944 +       } 
    2945 + 
    2946 +       return error; 
    2947 +} 
    2948 + 
    2949 +static struct super_block *yaffs_internal_read_super(int yaffsVersion, 
    2950 +                                                    struct super_block *sb, 
    2951 +                                                    void *data, int silent) 
    2952 +{ 
    2953 +       int nBlocks; 
    2954 +       struct inode *inode = NULL; 
    2955 +       struct dentry *root; 
    2956 +       yaffs_Device *dev = 0; 
    2957 +       char devname_buf[BDEVNAME_SIZE + 1]; 
    2958 +       struct mtd_info *mtd; 
    2959 +       int err; 
    2960 +       char *data_str = (char *)data; 
    2961 +        
    2962 +       yaffs_options options; 
    2963 + 
    2964 +       sb->s_magic = YAFFS_MAGIC; 
    2965 +       sb->s_op = &yaffs_super_ops; 
    2966 + 
    2967 +       if (!sb) 
    2968 +               printk(KERN_INFO "yaffs: sb is NULL\n"); 
    2969 +       else if (!sb->s_dev) 
    2970 +               printk(KERN_INFO "yaffs: sb->s_dev is NULL\n"); 
    2971 +       else if (!yaffs_devname(sb, devname_buf)) 
    2972 +               printk(KERN_INFO "yaffs: devname is NULL\n"); 
    2973 +       else 
    2974 +               printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n", 
    2975 +                      sb->s_dev, 
    2976 +                      yaffs_devname(sb, devname_buf)); 
    2977 +                    
    2978 +       if(!data_str) 
    2979 +               data_str = ""; 
    2980 +    
    2981 +       printk(KERN_INFO "yaffs: passed flags \"%s\"\n",data_str); 
    2982 +        
    2983 +       memset(&options,0,sizeof(options)); 
    2984 +        
    2985 +       if(yaffs_parse_options(&options,data_str)){ 
    2986 +               /* Option parsing failed */ 
    2987 +               return NULL; 
    2988 +       } 
    2989 + 
    2990 + 
    2991 +       sb->s_blocksize = PAGE_CACHE_SIZE; 
    2992 +       sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 
    2993 +       T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion)); 
    2994 +       T(YAFFS_TRACE_OS, 
    2995 +         ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize))); 
    2996 + 
    2997 +#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY 
    2998 +       T(YAFFS_TRACE_OS, 
    2999 +         ("yaffs: Write verification disabled. All guarantees " 
    3000 +          "null and void\n")); 
    3001 +#endif 
    3002 + 
    3003 +       T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, " 
    3004 +                              "\"%s\"\n", 
    3005 +                              MAJOR(sb->s_dev), MINOR(sb->s_dev), 
    3006 +                              yaffs_devname(sb, devname_buf))); 
    3007 + 
    3008 +       /* Check it's an mtd device..... */ 
    3009 +       if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) { 
    3010 +               return NULL;    /* This isn't an mtd device */ 
    3011 +       } 
    3012 +       /* Get the device */ 
    3013 +       mtd = get_mtd_device(NULL, MINOR(sb->s_dev)); 
    3014 +       if (!mtd) { 
    3015 +               T(YAFFS_TRACE_ALWAYS, 
    3016 +                 ("yaffs: MTD device #%u doesn't appear to exist\n", 
    3017 +                  MINOR(sb->s_dev))); 
    3018 +               return NULL; 
    3019 +       } 
    3020 +       /* Check it's NAND */ 
    3021 +       if (mtd->type != MTD_NANDFLASH) { 
    3022 +               T(YAFFS_TRACE_ALWAYS, 
    3023 +                 ("yaffs: MTD device is not NAND it's type %d\n", mtd->type)); 
    3024 +               return NULL; 
    3025 +       } 
    3026 + 
    3027 +       T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase)); 
    3028 +       T(YAFFS_TRACE_OS, (" read %p\n", mtd->read)); 
    3029 +       T(YAFFS_TRACE_OS, (" write %p\n", mtd->write)); 
    3030 +       T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob)); 
    3031 +       T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob)); 
    3032 +       T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad)); 
    3033 +       T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad)); 
    3034 +       T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd))); 
    3035 +       T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize)); 
    3036 +       T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize)); 
    3037 +       T(YAFFS_TRACE_OS, (" size %d\n", mtd->size)); 
    3038 +        
    3039 +#ifdef CONFIG_YAFFS_AUTO_YAFFS2 
    3040 + 
    3041 +       if (yaffsVersion == 1 &&  
    3042 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 
    3043 +           mtd->writesize >= 2048) { 
    3044 +#else 
    3045 +           mtd->oobblock >= 2048) { 
    3046 +#endif 
    3047 +           T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n")); 
    3048 +           yaffsVersion = 2; 
    3049 +       }        
    3050 +        
    3051 +       /* Added NCB 26/5/2006 for completeness */ 
    3052 +       if (yaffsVersion == 2 &&  
    3053 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 
    3054 +           mtd->writesize == 512) { 
    3055 +#else 
    3056 +           mtd->oobblock == 512) { 
    3057 +#endif 
    3058 +           T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n")); 
    3059 +           yaffsVersion = 1; 
    3060 +       }        
    3061 + 
    3062 +#endif 
    3063 + 
    3064 +       if (yaffsVersion == 2) { 
    3065 +               /* Check for version 2 style functions */ 
    3066 +               if (!mtd->erase || 
    3067 +                   !mtd->block_isbad || 
    3068 +                   !mtd->block_markbad || 
    3069 +                   !mtd->read || 
    3070 +                   !mtd->write || 
    3071 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 
    3072 +                   !mtd->read_oob || !mtd->write_oob) { 
    3073 +#else 
    3074 +                   !mtd->write_ecc || 
    3075 +                   !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) { 
    3076 +#endif 
    3077 +                       T(YAFFS_TRACE_ALWAYS, 
    3078 +                         ("yaffs: MTD device does not support required " 
    3079 +                          "functions\n"));; 
    3080 +                       return NULL; 
    3081 +               } 
    3082 + 
    3083 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 
    3084 +               if (mtd->writesize < YAFFS_MIN_YAFFS2_CHUNK_SIZE || 
    3085 +#else 
    3086 +               if (mtd->oobblock < YAFFS_MIN_YAFFS2_CHUNK_SIZE || 
    3087 +#endif 
    3088 +                   mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) { 
    3089 +                       T(YAFFS_TRACE_ALWAYS, 
    3090 +                         ("yaffs: MTD device does not have the " 
    3091 +                          "right page sizes\n")); 
    3092 +                       return NULL; 
    3093 +               } 
    3094 +       } else { 
    3095 +               /* Check for V1 style functions */ 
    3096 +               if (!mtd->erase || 
    3097 +                   !mtd->read || 
    3098 +                   !mtd->write || 
    3099 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 
    3100 +                   !mtd->read_oob || !mtd->write_oob) { 
    3101 +#else 
    3102 +                   !mtd->write_ecc || 
    3103 +                   !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) { 
    3104 +#endif 
    3105 +                       T(YAFFS_TRACE_ALWAYS, 
    3106 +                         ("yaffs: MTD device does not support required " 
    3107 +                          "functions\n"));; 
    3108 +                       return NULL; 
    3109 +               } 
    3110 + 
    3111 +               if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK || 
    3112 +                   mtd->oobsize != YAFFS_BYTES_PER_SPARE) { 
    3113 +                       T(YAFFS_TRACE_ALWAYS, 
    3114 +                         ("yaffs: MTD device does not support have the " 
    3115 +                          "right page sizes\n")); 
    3116 +                       return NULL; 
    3117 +               } 
    3118 +       } 
    3119 + 
    3120 +       /* OK, so if we got here, we have an MTD that's NAND and looks 
    3121 +        * like it has the right capabilities 
    3122 +        * Set the yaffs_Device up for mtd 
    3123 +        */ 
    3124 + 
    3125 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) 
    3126 +       sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL); 
    3127 +#else 
    3128 +       sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL); 
    3129 +#endif 
    3130 +       if (!dev) { 
    3131 +               /* Deep shit could not allocate device structure */ 
    3132 +               T(YAFFS_TRACE_ALWAYS, 
    3133 +                 ("yaffs_read_super: Failed trying to allocate " 
    3134 +                  "yaffs_Device. \n")); 
    3135 +               return NULL; 
    3136 +       } 
    3137 + 
    3138 +       memset(dev, 0, sizeof(yaffs_Device)); 
    3139 +       dev->genericDevice = mtd; 
    3140 +       dev->name = mtd->name; 
    3141 + 
    3142 +       /* Set up the memory size parameters.... */ 
    3143 + 
    3144 +       nBlocks = mtd->size / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK); 
    3145 +       dev->startBlock = 0; 
    3146 +       dev->endBlock = nBlocks - 1; 
    3147 +       dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; 
    3148 +       dev->nDataBytesPerChunk = YAFFS_BYTES_PER_CHUNK; 
    3149 +       dev->nReservedBlocks = 5; 
    3150 +       dev->nShortOpCaches = (options.no_cache) ? 0 : 10; 
    3151 + 
    3152 +       /* ... and the functions. */ 
    3153 +       if (yaffsVersion == 2) { 
    3154 +               dev->writeChunkWithTagsToNAND = 
    3155 +                   nandmtd2_WriteChunkWithTagsToNAND; 
    3156 +               dev->readChunkWithTagsFromNAND = 
    3157 +                   nandmtd2_ReadChunkWithTagsFromNAND; 
    3158 +               dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad; 
    3159 +               dev->queryNANDBlock = nandmtd2_QueryNANDBlock; 
    3160 +               dev->spareBuffer = YMALLOC(mtd->oobsize); 
    3161 +               dev->isYaffs2 = 1; 
    3162 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 
    3163 +               dev->nDataBytesPerChunk = mtd->writesize; 
    3164 +               dev->nChunksPerBlock = mtd->erasesize / mtd->writesize; 
    3165 +#else 
    3166 +               dev->nDataBytesPerChunk = mtd->oobblock; 
    3167 +               dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock; 
    3168 +#endif 
    3169 +               nBlocks = mtd->size / mtd->erasesize; 
    3170 + 
    3171 +               dev->nCheckpointReservedBlocks = CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS; 
    3172 +               dev->startBlock = 0; 
    3173 +               dev->endBlock = nBlocks - 1; 
    3174 +       } else { 
    3175 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 
    3176 +               /* use the MTD interface in yaffs_mtdif1.c */ 
    3177 +               dev->writeChunkWithTagsToNAND = 
    3178 +                       nandmtd1_WriteChunkWithTagsToNAND; 
    3179 +               dev->readChunkWithTagsFromNAND = 
    3180 +                       nandmtd1_ReadChunkWithTagsFromNAND; 
    3181 +               dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad; 
    3182 +               dev->queryNANDBlock = nandmtd1_QueryNANDBlock; 
    3183 +#else 
    3184 +               dev->writeChunkToNAND = nandmtd_WriteChunkToNAND; 
    3185 +               dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND; 
    3186 +#endif 
    3187 +               dev->isYaffs2 = 0; 
    3188 +       } 
    3189 +       /* ... and common functions */ 
    3190 +       dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND; 
    3191 +       dev->initialiseNAND = nandmtd_InitialiseNAND; 
    3192 + 
    3193 +       dev->putSuperFunc = yaffs_MTDPutSuper; 
    3194 +        
    3195 +       dev->superBlock = (void *)sb; 
    3196 +       dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty; 
    3197 +        
    3198 + 
    3199 +#ifndef CONFIG_YAFFS_DOES_ECC 
    3200 +       dev->useNANDECC = 1; 
    3201 +#endif 
    3202 + 
    3203 +#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES 
    3204 +       dev->wideTnodesDisabled = 1; 
    3205 +#endif 
    3206 + 
    3207 +       dev->skipCheckpointRead = options.skip_checkpoint_read; 
    3208 +       dev->skipCheckpointWrite = options.skip_checkpoint_write; 
    3209 +        
    3210 +       /* we assume this is protected by lock_kernel() in mount/umount */ 
    3211 +       list_add_tail(&dev->devList, &yaffs_dev_list); 
    3212 + 
    3213 +       init_MUTEX(&dev->grossLock); 
    3214 + 
    3215 +       yaffs_GrossLock(dev); 
    3216 + 
    3217 +       err = yaffs_GutsInitialise(dev); 
    3218 + 
    3219 +       T(YAFFS_TRACE_OS, 
    3220 +         ("yaffs_read_super: guts initialised %s\n", 
    3221 +          (err == YAFFS_OK) ? "OK" : "FAILED")); 
    3222 +        
    3223 +       /* Release lock before yaffs_get_inode() */ 
    3224 +       yaffs_GrossUnlock(dev); 
    3225 + 
    3226 +       /* Create root inode */ 
    3227 +       if (err == YAFFS_OK) 
    3228 +               inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0, 
    3229 +                                       yaffs_Root(dev)); 
    3230 + 
    3231 +       if (!inode) 
    3232 +               return NULL; 
    3233 + 
    3234 +       inode->i_op = &yaffs_dir_inode_operations; 
    3235 +       inode->i_fop = &yaffs_dir_operations; 
    3236 + 
    3237 +       T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n")); 
    3238 + 
    3239 +       root = d_alloc_root(inode); 
    3240 + 
    3241 +       T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n")); 
    3242 + 
    3243 +       if (!root) { 
    3244 +               iput(inode); 
    3245 +               return NULL; 
    3246 +       } 
    3247 +       sb->s_root = root; 
    3248 + 
    3249 +       T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n")); 
    3250 +       return sb; 
    3251 +} 
    3252 + 
    3253 + 
    3254 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) 
    3255 +static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data, 
    3256 +                                        int silent) 
    3257 +{ 
    3258 +       return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL; 
    3259 +} 
    3260 + 
    3261 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 
    3262 +static int yaffs_read_super(struct file_system_type *fs, 
    3263 +                           int flags, const char *dev_name, 
    3264 +                           void *data, struct vfsmount *mnt) 
    3265 +{ 
    3266 + 
    3267 +       return get_sb_bdev(fs, flags, dev_name, data, 
    3268 +                          yaffs_internal_read_super_mtd, mnt); 
    3269 +} 
    3270 +#else 
    3271 +static struct super_block *yaffs_read_super(struct file_system_type *fs, 
    3272 +                                           int flags, const char *dev_name, 
    3273 +                                           void *data) 
    3274 +{ 
    3275 + 
    3276 +       return get_sb_bdev(fs, flags, dev_name, data, 
    3277 +                          yaffs_internal_read_super_mtd); 
    3278 +} 
    3279 +#endif 
    3280 + 
    3281 +static struct file_system_type yaffs_fs_type = { 
    3282 +       .owner = THIS_MODULE, 
    3283 +       .name = "yaffs", 
    3284 +       .get_sb = yaffs_read_super, 
    3285 +       .kill_sb = kill_block_super, 
    3286 +       .fs_flags = FS_REQUIRES_DEV, 
    3287 +}; 
    3288 +#else 
    3289 +static struct super_block *yaffs_read_super(struct super_block *sb, void *data, 
    3290 +                                           int silent) 
    3291 +{ 
    3292 +       return yaffs_internal_read_super(1, sb, data, silent); 
    3293 +} 
    3294 + 
    3295 +static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super, 
    3296 +                     FS_REQUIRES_DEV); 
    3297 +#endif 
    3298 + 
    3299 + 
    3300 +#ifdef CONFIG_YAFFS_YAFFS2 
    3301 + 
    3302 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) 
    3303 +static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data, 
    3304 +                                         int silent) 
    3305 +{ 
    3306 +       return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL; 
    3307 +} 
    3308 + 
    3309 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) 
    3310 +static int yaffs2_read_super(struct file_system_type *fs, 
    3311 +                       int flags, const char *dev_name, void *data, 
    3312 +                       struct vfsmount *mnt) 
    3313 +{ 
    3314 +       return get_sb_bdev(fs, flags, dev_name, data, 
    3315 +                       yaffs2_internal_read_super_mtd, mnt); 
    3316 +} 
    3317 +#else 
    3318 +static struct super_block *yaffs2_read_super(struct file_system_type *fs, 
    3319 +                                            int flags, const char *dev_name, 
    3320 +                                            void *data) 
    3321 +{ 
    3322 + 
    3323 +       return get_sb_bdev(fs, flags, dev_name, data, 
    3324 +                          yaffs2_internal_read_super_mtd); 
    3325 +} 
    3326 +#endif 
    3327 + 
    3328 +static struct file_system_type yaffs2_fs_type = { 
    3329 +       .owner = THIS_MODULE, 
    3330 +       .name = "yaffs2", 
    3331 +       .get_sb = yaffs2_read_super, 
    3332 +       .kill_sb = kill_block_super, 
    3333 +       .fs_flags = FS_REQUIRES_DEV, 
    3334 +}; 
    3335 +#else 
    3336 +static struct super_block *yaffs2_read_super(struct super_block *sb, 
    3337 +                                            void *data, int silent) 
    3338 +{ 
    3339 +       return yaffs_internal_read_super(2, sb, data, silent); 
    3340 +} 
    3341 + 
    3342 +static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super, 
    3343 +                     FS_REQUIRES_DEV); 
    3344 +#endif 
    3345 + 
    3346 +#endif                         /* CONFIG_YAFFS_YAFFS2 */ 
    3347 + 
    3348 +static struct proc_dir_entry *my_proc_entry; 
    3349 + 
    3350 +static char *yaffs_dump_dev(char *buf, yaffs_Device * dev) 
    3351 +{ 
    3352 +       buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock); 
    3353 +       buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock); 
    3354 +       buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk); 
    3355 +       buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits); 
    3356 +       buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize); 
    3357 +       buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks); 
    3358 +       buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks); 
    3359 +       buf += sprintf(buf, "nCheckptResBlocks.. %d\n", dev->nCheckpointReservedBlocks); 
    3360 +       buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint); 
    3361 +       buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated); 
    3362 +       buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes); 
    3363 +       buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated); 
    3364 +       buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects); 
    3365 +       buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks); 
    3366 +       buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites); 
    3367 +       buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads); 
    3368 +       buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures); 
    3369 +       buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies); 
    3370 +       buf += 
    3371 +           sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections); 
    3372 +       buf += 
    3373 +           sprintf(buf, "passiveGCs......... %d\n", 
    3374 +                   dev->passiveGarbageCollections); 
    3375 +       buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites); 
    3376 +       buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches); 
    3377 +       buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks); 
    3378 +       buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed); 
    3379 +       buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed); 
    3380 +       buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed); 
    3381 +       buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed); 
    3382 +       buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits); 
    3383 +       buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles); 
    3384 +       buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles); 
    3385 +       buf += 
    3386 +           sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions); 
    3387 +       buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC); 
    3388 +       buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2); 
    3389 + 
    3390 +       return buf; 
    3391 +} 
    3392 + 
    3393 +static int yaffs_proc_read(char *page, 
    3394 +                          char **start, 
    3395 +                          off_t offset, int count, int *eof, void *data) 
    3396 +{ 
    3397 +       struct list_head *item; 
    3398 +       char *buf = page; 
    3399 +       int step = offset; 
    3400 +       int n = 0; 
    3401 + 
    3402 +       /* Get proc_file_read() to step 'offset' by one on each sucessive call. 
    3403 +        * We use 'offset' (*ppos) to indicate where we are in devList. 
    3404 +        * This also assumes the user has posted a read buffer large 
    3405 +        * enough to hold the complete output; but that's life in /proc. 
    3406 +        */ 
    3407 + 
    3408 +       *(int *)start = 1; 
    3409 + 
    3410 +       /* Print header first */ 
    3411 +       if (step == 0) { 
    3412 +               buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__ 
    3413 +                              "\n%s\n%s\n", yaffs_fs_c_version, 
    3414 +                              yaffs_guts_c_version); 
    3415 +       } 
    3416 + 
    3417 +       /* hold lock_kernel while traversing yaffs_dev_list */ 
    3418 +       lock_kernel(); 
    3419 + 
    3420 +       /* Locate and print the Nth entry.  Order N-squared but N is small. */ 
    3421 +       list_for_each(item, &yaffs_dev_list) { 
    3422 +               yaffs_Device *dev = list_entry(item, yaffs_Device, devList); 
    3423 +               if (n < step) { 
    3424 +                       n++; 
    3425 +                       continue; 
    3426 +               } 
    3427 +               buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name); 
    3428 +               buf = yaffs_dump_dev(buf, dev); 
    3429 +               break; 
    3430 +       } 
    3431 +       unlock_kernel(); 
    3432 + 
    3433 +       return buf - page < count ? buf - page : count; 
    3434 +} 
    3435 + 
    3436 +/** 
    3437 + * Set the verbosity of the warnings and error messages. 
    3438 + * 
    3439 + * Note that the names can only be a..z or _ with the current code. 
    3440 + */ 
    3441 + 
    3442 +static struct { 
    3443 +       char *mask_name; 
    3444 +       unsigned mask_bitfield; 
    3445 +} mask_flags[] = { 
    3446 +       {"allocate", YAFFS_TRACE_ALLOCATE}, 
    3447 +       {"always", YAFFS_TRACE_ALWAYS}, 
    3448 +       {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS}, 
    3449 +       {"buffers", YAFFS_TRACE_BUFFERS}, 
    3450 +       {"bug", YAFFS_TRACE_BUG}, 
    3451 +       {"checkpt", YAFFS_TRACE_CHECKPOINT}, 
    3452 +       {"deletion", YAFFS_TRACE_DELETION}, 
    3453 +       {"erase", YAFFS_TRACE_ERASE}, 
    3454 +       {"error", YAFFS_TRACE_ERROR}, 
    3455 +       {"gc_detail", YAFFS_TRACE_GC_DETAIL}, 
    3456 +       {"gc", YAFFS_TRACE_GC}, 
    3457 +       {"mtd", YAFFS_TRACE_MTD}, 
    3458 +       {"nandaccess", YAFFS_TRACE_NANDACCESS}, 
    3459 +       {"os", YAFFS_TRACE_OS}, 
    3460 +       {"scan_debug", YAFFS_TRACE_SCAN_DEBUG}, 
    3461 +       {"scan", YAFFS_TRACE_SCAN}, 
    3462 +       {"tracing", YAFFS_TRACE_TRACING}, 
    3463 + 
    3464 +       {"verify", YAFFS_TRACE_VERIFY}, 
    3465 +       {"verify_nand", YAFFS_TRACE_VERIFY_NAND}, 
    3466 +       {"verify_full", YAFFS_TRACE_VERIFY_FULL}, 
    3467 +       {"verify_all", YAFFS_TRACE_VERIFY_ALL}, 
    3468 + 
    3469 +       {"write", YAFFS_TRACE_WRITE}, 
    3470 +       {"all", 0xffffffff}, 
    3471 +       {"none", 0}, 
    3472 +       {NULL, 0}, 
    3473 +}; 
    3474 + 
    3475 +#define MAX_MASK_NAME_LENGTH 40 
    3476 +static int yaffs_proc_write(struct file *file, const char *buf, 
    3477 +                                        unsigned long count, void *data) 
    3478 +{ 
    3479 +       unsigned rg = 0, mask_bitfield; 
    3480 +       char *end; 
    3481 +       char *mask_name; 
    3482 +       char *x;  
    3483 +       char substring[MAX_MASK_NAME_LENGTH+1]; 
    3484 +       int i; 
    3485 +       int done = 0; 
    3486 +       int add, len = 0; 
    3487 +       int pos = 0; 
    3488 + 
    3489 +       rg = yaffs_traceMask; 
    3490 + 
    3491 +       while (!done && (pos < count)) { 
    3492 +               done = 1; 
    3493 +               while ((pos < count) && isspace(buf[pos])) { 
    3494 +                       pos++; 
    3495 +               } 
    3496 + 
    3497 +               switch (buf[pos]) { 
    3498 +               case '+': 
    3499 +               case '-': 
    3500 +               case '=': 
    3501 +                       add = buf[pos]; 
    3502 +                       pos++; 
    3503 +                       break; 
    3504 + 
    3505 +               default: 
    3506 +                       add = ' '; 
    3507 +                       break; 
    3508 +               } 
    3509 +               mask_name = NULL; 
    3510 +                
    3511 +               mask_bitfield = simple_strtoul(buf + pos, &end, 0); 
    3512 +               if (end > buf + pos) { 
    3513 +                       mask_name = "numeral"; 
    3514 +                       len = end - (buf + pos); 
    3515 +                       done = 0; 
    3516 +               } else { 
    3517 +                       for(x = buf + pos, i = 0;  
    3518 +                           (*x == '_' || (*x >='a' && *x <= 'z')) && 
    3519 +                           i <MAX_MASK_NAME_LENGTH; x++, i++, pos++) 
    3520 +                           substring[i] = *x; 
    3521 +                       substring[i] = '\0'; 
    3522 +                        
    3523 +                       for (i = 0; mask_flags[i].mask_name != NULL; i++) { 
    3524 +                               //len = strlen(mask_flags[i].mask_name); 
    3525 +                               //if (strncmp(buf + pos, mask_flags[i].mask_name, len) == 0) { 
    3526 +                               if(strcmp(substring,mask_flags[i].mask_name) == 0){ 
    3527 +                                       mask_name = mask_flags[i].mask_name; 
    3528 +                                       mask_bitfield = mask_flags[i].mask_bitfield; 
    3529 +                                       done = 0; 
    3530 +                                       break; 
    3531 +                               } 
    3532 +                       } 
    3533 +               } 
    3534 + 
    3535 +               if (mask_name != NULL) { 
    3536 +                       // pos += len; 
    3537 +                       done = 0; 
    3538 +                       switch(add) { 
    3539 +                       case '-': 
    3540 +                               rg &= ~mask_bitfield; 
    3541 +                               break; 
    3542 +                       case '+': 
    3543 +                               rg |= mask_bitfield; 
    3544 +                               break; 
    3545 +                       case '=': 
    3546 +                               rg = mask_bitfield; 
    3547 +                               break; 
    3548 +                       default: 
    3549 +                               rg |= mask_bitfield; 
    3550 +                               break; 
    3551 +                       } 
    3552 +               } 
    3553 +       } 
    3554 + 
    3555 +       yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS; 
    3556 +        
    3557 +       printk("new trace = 0x%08X\n",yaffs_traceMask); 
    3558 +        
    3559 +       if (rg & YAFFS_TRACE_ALWAYS) { 
    3560 +               for (i = 0; mask_flags[i].mask_name != NULL; i++) { 
    3561 +                       char flag; 
    3562 +                       flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-'; 
    3563 +                       printk("%c%s\n", flag, mask_flags[i].mask_name); 
    3564 +               } 
    3565 +       } 
    3566 + 
    3567 +       return count; 
    3568 +} 
    3569 + 
    3570 +/* Stuff to handle installation of file systems */ 
    3571 +struct file_system_to_install { 
    3572 +       struct file_system_type *fst; 
    3573 +       int installed; 
    3574 +}; 
    3575 + 
    3576 +static struct file_system_to_install fs_to_install[] = { 
    3577 +//#ifdef CONFIG_YAFFS_YAFFS1 
    3578 +       {&yaffs_fs_type, 0}, 
    3579 +//#endif 
    3580 +//#ifdef CONFIG_YAFFS_YAFFS2 
    3581 +       {&yaffs2_fs_type, 0}, 
    3582 +//#endif 
    3583 +       {NULL, 0} 
    3584 +}; 
    3585 + 
    3586 +static int __init init_yaffs_fs(void) 
    3587 +{ 
    3588 +       int error = 0; 
    3589 +       struct file_system_to_install *fsinst; 
    3590 + 
    3591 +       T(YAFFS_TRACE_ALWAYS, 
    3592 +         ("yaffs " __DATE__ " " __TIME__ " Installing. \n")); 
    3593 + 
    3594 +       /* Install the proc_fs entry */ 
    3595 +       my_proc_entry = create_proc_entry("yaffs", 
    3596 +                                              S_IRUGO | S_IFREG, 
    3597 +                                              &proc_root); 
    3598 + 
    3599 +       if (my_proc_entry) { 
    3600 +               my_proc_entry->write_proc = yaffs_proc_write; 
    3601 +               my_proc_entry->read_proc = yaffs_proc_read; 
    3602 +               my_proc_entry->data = NULL; 
    3603 +       } else { 
    3604 +               return -ENOMEM; 
    3605 +       } 
    3606 + 
    3607 +       /* Now add the file system entries */ 
    3608 + 
    3609 +       fsinst = fs_to_install; 
    3610 + 
    3611 +       while (fsinst->fst && !error) { 
    3612 +               error = register_filesystem(fsinst->fst); 
    3613 +               if (!error) { 
    3614 +                       fsinst->installed = 1; 
    3615 +               } 
    3616 +               fsinst++; 
    3617 +       } 
    3618 + 
    3619 +       /* Any errors? uninstall  */ 
    3620 +       if (error) { 
    3621 +               fsinst = fs_to_install; 
    3622 + 
    3623 +               while (fsinst->fst) { 
    3624 +                       if (fsinst->installed) { 
    3625 +                               unregister_filesystem(fsinst->fst); 
    3626 +                               fsinst->installed = 0; 
    3627 +                       } 
    3628 +                       fsinst++; 
    3629 +               } 
    3630 +       } 
    3631 + 
    3632 +       return error; 
    3633 +} 
    3634 + 
    3635 +static void __exit exit_yaffs_fs(void) 
    3636 +{ 
    3637 + 
    3638 +       struct file_system_to_install *fsinst; 
    3639 + 
    3640 +       T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__ 
    3641 +                              " removing. \n")); 
    3642 + 
    3643 +       remove_proc_entry("yaffs", &proc_root); 
    3644 + 
    3645 +       fsinst = fs_to_install; 
    3646 + 
    3647 +       while (fsinst->fst) { 
    3648 +               if (fsinst->installed) { 
    3649 +                       unregister_filesystem(fsinst->fst); 
    3650 +                       fsinst->installed = 0; 
    3651 +               } 
    3652 +               fsinst++; 
    3653 +       } 
    3654 + 
    3655 +} 
    3656 + 
    3657 +module_init(init_yaffs_fs) 
    3658 +module_exit(exit_yaffs_fs) 
    3659 + 
    3660 +MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system"); 
    3661 +MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006"); 
    3662 +MODULE_LICENSE("GPL"); 
    3663 diff -urN linux-2.6.21.1/fs/yaffs2/yaffs_guts.c linux-2.6.21.1.new/fs/yaffs2/yaffs_guts.c 
    3664 --- linux-2.6.21.1/fs/yaffs2/yaffs_guts.c       1970-01-01 01:00:00.000000000 +0100 
    3665 +++ linux-2.6.21.1.new/fs/yaffs2/yaffs_guts.c   2007-06-08 14:07:26.000000000 +0200 
    3666 @@ -0,0 +1,7469 @@ 
    3667 +/* 
    3668 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. 
    3669 + * 
    3670 + * Copyright (C) 2002-2007 Aleph One Ltd. 
    3671 + *   for Toby Churchill Ltd and Brightstar Engineering 
    3672 + * 
    3673 + * Created by Charles Manning <charles@aleph1.co.uk> 
    3674 + * 
    3675 + * This program is free software; you can redistribute it and/or modify 
    3676 + * it under the terms of the GNU General Public License version 2 as 
    3677 + * published by the Free Software Foundation. 
    3678 + */ 
    3679 + 
    3680 +const char *yaffs_guts_c_version = 
    3681 +    "$Id: yaffs_guts.c,v 1.49 2007-05-15 20:07:40 charles Exp $"; 
    3682 + 
    3683 +#include "yportenv.h" 
    3684 + 
    3685 +#include "yaffsinterface.h" 
    3686 +#include "yaffs_guts.h" 
    3687 +#include "yaffs_tagsvalidity.h" 
    3688 + 
    3689 +#include "yaffs_tagscompat.h" 
    3690 +#ifndef  CONFIG_YAFFS_USE_OWN_SORT 
    3691 +#include "yaffs_qsort.h" 
    3692 +#endif 
    3693 +#include "yaffs_nand.h" 
    3694 + 
    3695 +#include "yaffs_checkptrw.h" 
    3696 + 
    3697 +#include "yaffs_nand.h" 
    3698 +#include "yaffs_packedtags2.h" 
    3699 + 
    3700 + 
    3701 +#ifdef CONFIG_YAFFS_WINCE 
    3702 +void yfsd_LockYAFFS(BOOL fsLockOnly); 
    3703 +void yfsd_UnlockYAFFS(BOOL fsLockOnly); 
    3704 +#endif 
    3705 + 
    3706 +#define YAFFS_PASSIVE_GC_CHUNKS 2 
    3707 + 
    3708 +#include "yaffs_ecc.h" 
    3709 + 
    3710 + 
    3711 +/* Robustification (if it ever comes about...) */ 
    3712 +static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND); 
    3713 +static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int erasedOk); 
    3714 +static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND, 
    3715 +                                    const __u8 * data, 
    3716 +                                    const yaffs_ExtendedTags * tags); 
    3717 +static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND, 
    3718 +                                   const yaffs_ExtendedTags * tags); 
    3719 + 
    3720 +/* Other local prototypes */ 
    3721 +static int yaffs_UnlinkObject( yaffs_Object *obj); 
    3722 +static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj); 
    3723 + 
    3724 +static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList); 
    3725 + 
    3726 +static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device * dev, 
    3727 +                                            const __u8 * buffer, 
    3728 +                                            yaffs_ExtendedTags * tags, 
    3729 +                                            int useReserve); 
    3730 +static int yaffs_PutChunkIntoFile(yaffs_Object * in, int chunkInInode, 
    3731 +                                 int chunkInNAND, int inScan); 
    3732 + 
    3733 +static yaffs_Object *yaffs_CreateNewObject(yaffs_Device * dev, int number, 
    3734 +                                          yaffs_ObjectType type); 
    3735 +static void yaffs_AddObjectToDirectory(yaffs_Object * directory, 
    3736 +                                      yaffs_Object * obj); 
    3737 +static int yaffs_UpdateObjectHeader(yaffs_Object * in, const YCHAR * name, 
    3738 +                                   int force, int isShrink, int shadows); 
    3739 +static void yaffs_RemoveObjectFromDirectory(yaffs_Object * obj); 
    3740 +static int yaffs_CheckStructures(void); 
    3741 +static int yaffs_DeleteWorker(yaffs_Object * in, yaffs_Tnode * tn, __u32 level, 
    3742 +                             int chunkOffset, int *limit); 
    3743 +static int yaffs_DoGenericObjectDeletion(yaffs_Object * in); 
    3744 + 
    3745 +static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blockNo); 
    3746 + 
    3747 +static __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo); 
    3748 +static void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer, 
    3749 +                                   int lineNo); 
    3750 + 
    3751 +static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, 
    3752 +                                 int chunkInNAND); 
    3753 + 
    3754 +static int yaffs_UnlinkWorker(yaffs_Object * obj); 
    3755 +static void yaffs_DestroyObject(yaffs_Object * obj); 
    3756 + 
    3757 +static int yaffs_TagsMatch(const yaffs_ExtendedTags * tags, int objectId, 
    3758 +                          int chunkInObject); 
    3759 + 
    3760 +loff_t yaffs_GetFileSize(yaffs_Object * obj); 
    3761 + 
    3762 +static int yaffs_AllocateChunk(yaffs_Device * dev, int useReserve, yaffs_BlockInfo **blockUsedPtr); 
    3763 + 
    3764 +static void yaffs_VerifyFreeChunks(yaffs_Device * dev); 
    3765 + 
    3766 +static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in); 
    3767 + 
    3768 +#ifdef YAFFS_PARANOID 
    3769 +static int yaffs_CheckFileSanity(yaffs_Object * in); 
    3770 +#else 
    3771 +#define yaffs_CheckFileSanity(in) 
    3772 +#endif 
    3773 + 
    3774 +static void yaffs_InvalidateWholeChunkCache(yaffs_Object * in); 
    3775 +static void yaffs_InvalidateChunkCache(yaffs_Object * object, int chunkId); 
    3776 + 
    3777 +static void yaffs_InvalidateCheckpoint(yaffs_Device *dev); 
    3778 + 
    3779 +static int yaffs_FindChunkInFile(yaffs_Object * in, int chunkInInode, 
    3780 +                                yaffs_ExtendedTags * tags); 
    3781 + 
    3782 +static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos); 
    3783 +static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device * dev, 
    3784 +                                         yaffs_FileStructure * fStruct, 
    3785 +                                         __u32 chunkId); 
    3786 + 
    3787 + 
    3788 +/* Function to calculate chunk and offset */ 
    3789 + 
    3790 +static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, __u32 *chunk, __u32 *offset) 
    3791 +{ 
    3792 +       if(dev->chunkShift){ 
    3793 +               /* Easy-peasy power of 2 case */ 
    3794 +               *chunk  = (__u32)(addr >> dev->chunkShift); 
    3795 +               *offset = (__u32)(addr & dev->chunkMask); 
    3796 +       } 
    3797 +       else if(dev->crumbsPerChunk) 
    3798 +       { 
    3799 +               /* Case where we're using "crumbs" */ 
    3800 +               *offset = (__u32)(addr & dev->crumbMask); 
    3801 +               addr >>= dev->crumbShift; 
    3802 +               *chunk = ((__u32)addr)/dev->crumbsPerChunk; 
    3803 +               *offset += ((addr - (*chunk * dev->crumbsPerChunk)) << dev->crumbShift); 
    3804 +       } 
    3805 +       else 
    3806 +               YBUG(); 
    3807 +} 
    3808 + 
    3809 +/* Function to return the number of shifts for a power of 2 greater than or equal  
    3810 + * to the given number 
    3811 + * Note we don't try to cater for all possible numbers and this does not have to 
    3812 + * be hellishly efficient. 
    3813 + */ 
    3814 +  
    3815 +static __u32 ShiftsGE(__u32 x) 
    3816 +{ 
    3817 +       int extraBits; 
    3818 +       int nShifts; 
    3819 +        
    3820 +       nShifts = extraBits = 0; 
    3821 +        
    3822 +       while(x>1){ 
    3823 +               if(x & 1) extraBits++; 
    3824 +               x>>=1; 
    3825 +               nShifts++; 
    3826 +       } 
    3827 + 
    3828 +       if(extraBits)  
    3829 +               nShifts++; 
    3830 +                
    3831 +       return nShifts; 
    3832 +} 
    3833 + 
    3834 +/* Function to return the number of shifts to get a 1 in bit 0 
    3835 + */ 
    3836 +  
    3837 +static __u32 ShiftDiv(__u32 x) 
    3838 +{ 
    3839 +       int nShifts; 
    3840 +        
    3841 +       nShifts =  0; 
    3842 +        
    3843 +       if(!x) return 0; 
    3844 +        
    3845 +       while( !(x&1)){ 
    3846 +               x>>=1; 
    3847 +               nShifts++; 
    3848 +       } 
    3849 +                
    3850 +       return nShifts; 
    3851 +} 
    3852 + 
    3853 + 
    3854 + 
    3855 +/*  
    3856 + * Temporary buffer manipulations. 
    3857 + */ 
    3858 + 
    3859 +static int yaffs_InitialiseTempBuffers(yaffs_Device *dev)       
    3860 +{ 
    3861 +       int i; 
    3862 +       __u8 *buf = (__u8 *)1; 
    3863 +                
    3864 +       memset(dev->tempBuffer,0,sizeof(dev->tempBuffer)); 
    3865 +                
    3866 +       for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) { 
    3867 +               dev->tempBuffer[i].line = 0;    /* not in use */ 
    3868 +               dev->tempBuffer[i].buffer = buf = 
    3869 +                   YMALLOC_DMA(dev->nDataBytesPerChunk); 
    3870 +       } 
    3871 +                
    3872 +       return buf ? YAFFS_OK : YAFFS_FAIL; 
    3873 +        
    3874 +} 
    3875 + 
    3876 +static __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo) 
    3877 +{ 
    3878 +       int i, j; 
    3879 +       for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { 
    3880 +               if (dev->tempBuffer[i].line == 0) { 
    3881 +                       dev->tempBuffer[i].line = lineNo; 
    3882 +                       if ((i + 1) > dev->maxTemp) { 
    3883 +                               dev->maxTemp = i + 1; 
    3884 +                               for (j = 0; j <= i; j++) 
    3885 +                                       dev->tempBuffer[j].maxLine = 
    3886 +                                           dev->tempBuffer[j].line; 
    3887 +                       } 
    3888 + 
    3889 +                       return dev->tempBuffer[i].buffer; 
    3890 +               } 
    3891 +       } 
    3892 + 
    3893 +       T(YAFFS_TRACE_BUFFERS, 
    3894 +         (TSTR("Out of temp buffers at line %d, other held by lines:"), 
    3895 +          lineNo)); 
    3896 +       for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { 
    3897 +               T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->tempBuffer[i].line)); 
    3898 +       } 
    3899 +       T(YAFFS_TRACE_BUFFERS, (TSTR(" " TENDSTR))); 
    3900 + 
    3901 +       /* 
    3902 +        * If we got here then we have to allocate an unmanaged one 
    3903 +        * This is not good. 
    3904 +        */ 
    3905 + 
    3906 +       dev->unmanagedTempAllocations++; 
    3907 +       return YMALLOC(dev->nDataBytesPerChunk); 
    3908 + 
    3909 +} 
    3910 + 
    3911 +static void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer, 
    3912 +                                   int lineNo) 
    3913 +{ 
    3914 +       int i; 
    3915 +       for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { 
    3916 +               if (dev->tempBuffer[i].buffer == buffer) { 
    3917 +                       dev->tempBuffer[i].line = 0; 
    3918 +                       return; 
    3919 +               } 
    3920 +       } 
    3921 + 
    3922 +       if (buffer) { 
    3923 +               /* assume it is an unmanaged one. */ 
    3924 +               T(YAFFS_TRACE_BUFFERS, 
    3925 +                 (TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR), 
    3926 +                  lineNo)); 
    3927 +               YFREE(buffer); 
    3928 +               dev->unmanagedTempDeallocations++; 
    3929 +       } 
    3930 + 
    3931 +} 
    3932 + 
    3933 +/* 
    3934 + * Determine if we have a managed buffer. 
    3935 + */ 
    3936 +int yaffs_IsManagedTempBuffer(yaffs_Device * dev, const __u8 * buffer) 
    3937 +{ 
    3938 +       int i; 
    3939 +       for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { 
    3940 +               if (dev->tempBuffer[i].buffer == buffer) 
    3941 +                       return 1; 
    3942 + 
    3943 +       } 
    3944 + 
    3945 +    for (i = 0; i < dev->nShortOpCaches; i++) { 
    3946 +        if( dev->srCache[i].data == buffer ) 
    3947 +            return 1; 
    3948 + 
    3949 +    } 
    3950 + 
    3951 +    if (buffer == dev->checkpointBuffer) 
    3952 +      return 1; 
    3953 + 
    3954 +    T(YAFFS_TRACE_ALWAYS, 
    3955 +         (TSTR("yaffs: unmaged buffer detected.\n" TENDSTR))); 
    3956 +    return 0; 
    3957 +} 
    3958 + 
    3959 + 
    3960 + 
    3961 +/* 
    3962 + * Chunk bitmap manipulations 
    3963 + */ 
    3964 + 
    3965 +static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device * dev, int blk) 
    3966 +{ 
    3967 +       if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) { 
    3968 +               T(YAFFS_TRACE_ERROR, 
    3969 +                 (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR), 
    3970 +                  blk)); 
    3971 +               YBUG(); 
    3972 +       } 
    3973 +       return dev->chunkBits + 
    3974 +           (dev->chunkBitmapStride * (blk - dev->internalStartBlock)); 
    3975 +} 
    3976 + 
    3977 +static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk) 
    3978 +{ 
    3979 +       if(blk < dev->internalStartBlock || blk > dev->internalEndBlock || 
    3980 +          chunk < 0 || chunk >= dev->nChunksPerBlock) { 
    3981 +          T(YAFFS_TRACE_ERROR, 
    3982 +           (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),blk,chunk)); 
    3983 +           YBUG(); 
    3984 +       } 
    3985 +} 
    3986 + 
    3987 +static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device * dev, int blk) 
    3988 +{ 
    3989 +       __u8 *blkBits = yaffs_BlockBits(dev, blk); 
    3990 + 
    3991 +       memset(blkBits, 0, dev->chunkBitmapStride); 
    3992 +} 
    3993 + 
    3994 +static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device * dev, int blk, int chunk) 
    3995 +{ 
    3996 +       __u8 *blkBits = yaffs_BlockBits(dev, blk); 
    3997 + 
    3998 +       yaffs_VerifyChunkBitId(dev,blk,chunk); 
    3999 + 
    4000 +       blkBits[chunk / 8] &= ~(1 << (chunk & 7)); 
    4001 +} 
    4002 + 
    4003 +static Y_INLINE void yaffs_SetChunkBit(yaffs_Device * dev, int blk, int chunk) 
    4004 +{ 
    4005 +       __u8 *blkBits = yaffs_BlockBits(dev, blk); 
    4006 +        
    4007 +       yaffs_VerifyChunkBitId(dev,blk,chunk); 
    4008 + 
    4009 +       blkBits[chunk / 8] |= (1 << (chunk & 7)); 
    4010 +} 
    4011 + 
    4012 +static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device * dev, int blk, int chunk) 
    4013 +{ 
    4014 +       __u8 *blkBits = yaffs_BlockBits(dev, blk); 
    4015 +       yaffs_VerifyChunkBitId(dev,blk,chunk); 
    4016 + 
    4017 +       return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0; 
    4018 +} 
    4019 + 
    4020 +static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device * dev, int blk) 
    4021 +{ 
    4022 +       __u8 *blkBits = yaffs_BlockBits(dev, blk); 
    4023 +       int i; 
    4024 +       for (i = 0; i < dev->chunkBitmapStride; i++) { 
    4025 +               if (*blkBits) 
    4026 +                       return 1; 
    4027 +               blkBits++; 
    4028 +       } 
    4029 +       return 0; 
    4030 +} 
    4031 + 
    4032 +static int yaffs_CountChunkBits(yaffs_Device * dev, int blk) 
    4033 +{ 
    4034 +       __u8 *blkBits = yaffs_BlockBits(dev, blk); 
    4035 +       int i; 
    4036 +       int n = 0; 
    4037 +       for (i = 0; i < dev->chunkBitmapStride; i++) { 
    4038 +               __u8 x = *blkBits; 
    4039 +               while(x){ 
    4040 +                       if(x & 1) 
    4041 +                               n++; 
    4042 +                       x >>=1; 
    4043 +               } 
    4044 +                        
    4045 +               blkBits++; 
    4046 +       } 
    4047 +       return n; 
    4048 +} 
    4049 + 
    4050 +/*  
    4051 + * Verification code 
    4052 + */ 
    4053 +  
    4054 +static int yaffs_SkipVerification(yaffs_Device *dev) 
    4055 +{ 
    4056 +       return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); 
    4057 +} 
    4058 + 
    4059 +static int yaffs_SkipFullVerification(yaffs_Device *dev) 
    4060 +{ 
    4061 +       return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL)); 
    4062 +} 
    4063 + 
    4064 +static int yaffs_SkipNANDVerification(yaffs_Device *dev) 
    4065 +{ 
    4066 +       return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND)); 
    4067 +} 
    4068 + 
    4069 +static const char * blockStateName[] = { 
    4070 +"Unknown", 
    4071 +"Needs scanning", 
    4072 +"Scanning", 
    4073 +"Empty", 
    4074 +"Allocating", 
    4075 +"Full", 
    4076 +"Dirty", 
    4077 +"Checkpoint", 
    4078 +"Collecting", 
    4079 +"Dead" 
    4080 +}; 
    4081 + 
    4082 +static void yaffs_VerifyBlock(yaffs_Device *dev,yaffs_BlockInfo *bi,int n) 
    4083 +{ 
    4084 +       int actuallyUsed; 
    4085 +       int inUse; 
    4086 +        
    4087 +       if(yaffs_SkipVerification(dev)) 
    4088 +               return; 
    4089 +                
    4090 +       /* Report illegal runtime states */ 
    4091 +       if(bi->blockState <0 || bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES) 
    4092 +               T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has undefined state %d"TENDSTR),n,bi->blockState)); 
    4093 +                
    4094 +       switch(bi->blockState){ 
    4095 +        case YAFFS_BLOCK_STATE_UNKNOWN: 
    4096 +        case YAFFS_BLOCK_STATE_SCANNING: 
    4097 +        case YAFFS_BLOCK_STATE_NEEDS_SCANNING: 
    4098 +               T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has bad run-state %s"TENDSTR), 
    4099 +               n,blockStateName[bi->blockState])); 
    4100 +       } 
    4101 +        
    4102 +       /* Check pages in use and soft deletions are legal */ 
    4103 +        
    4104 +       actuallyUsed = bi->pagesInUse - bi->softDeletions; 
    4105 +        
    4106 +       if(bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock || 
    4107 +          bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock || 
    4108 +          actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock) 
    4109 +               T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR), 
    4110 +               n,bi->pagesInUse,bi->softDeletions)); 
    4111 +        
    4112 +                
    4113 +       /* Check chunk bitmap legal */ 
    4114 +       inUse = yaffs_CountChunkBits(dev,n); 
    4115 +       if(inUse != bi->pagesInUse) 
    4116 +               T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR), 
    4117 +                       n,bi->pagesInUse,inUse)); 
    4118 +        
    4119 +       /* Check that the sequence number is valid. 
    4120 +        * Ten million is legal, but is very unlikely  
    4121 +        */ 
    4122 +       if(dev->isYaffs2 &&  
    4123 +          (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) && 
    4124 +          (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000 )) 
    4125 +               T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has suspect sequence number of %d"TENDSTR), 
    4126 +               n,bi->sequenceNumber)); 
    4127 +                
    4128 +} 
    4129 + 
    4130 +static void yaffs_VerifyCollectedBlock(yaffs_Device *dev,yaffs_BlockInfo *bi,int n) 
    4131 +{ 
    4132 +       yaffs_VerifyBlock(dev,bi,n); 
    4133 +        
    4134 +       /* After collection the block should be in the erased state */ 
    4135 +       /* TODO: This will need to change if we do partial gc */ 
    4136 +        
    4137 +       if(bi->blockState != YAFFS_BLOCK_STATE_EMPTY){ 
    4138 +               T(YAFFS_TRACE_ERROR,(TSTR("Block %d is in state %d after gc, should be erased"TENDSTR), 
    4139 +                       n,bi->blockState)); 
    4140 +       } 
    4141 +} 
    4142 + 
    4143 +static void yaffs_VerifyBlocks(yaffs_Device *dev) 
    4144 +{ 
    4145 +       int i; 
    4146 +       int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES]; 
    4147 +       int nIllegalBlockStates = 0; 
    4148 +        
    4149 + 
    4150 +       if(yaffs_SkipVerification(dev)) 
    4151 +               return; 
    4152 + 
    4153 +       memset(nBlocksPerState,0,sizeof(nBlocksPerState)); 
    4154 + 
    4155 +                
    4156 +       for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++){ 
    4157 +               yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); 
    4158 +               yaffs_VerifyBlock(dev,bi,i); 
    4159 + 
    4160 +               if(bi->blockState >=0 && bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES) 
    4161 +                       nBlocksPerState[bi->blockState]++; 
    4162 +               else 
    4163 +                       nIllegalBlockStates++; 
    4164 +                                        
    4165 +       } 
    4166 +        
    4167 +       T(YAFFS_TRACE_VERIFY,(TSTR(""TENDSTR))); 
    4168 +       T(YAFFS_TRACE_VERIFY,(TSTR("Block summary"TENDSTR))); 
    4169 +        
    4170 +       T(YAFFS_TRACE_VERIFY,(TSTR("%d blocks have illegal states"TENDSTR),nIllegalBlockStates)); 
    4171 +       if(nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1) 
    4172 +               T(YAFFS_TRACE_VERIFY,(TSTR("Too many allocating blocks"TENDSTR))); 
    4173 + 
    4174 +       for(i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) 
    4175 +               T(YAFFS_TRACE_VERIFY, 
    4176 +                 (TSTR("%s %d blocks"TENDSTR), 
    4177 +                 blockStateName[i],nBlocksPerState[i])); 
    4178 +        
    4179 +       if(dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]) 
    4180 +               T(YAFFS_TRACE_VERIFY, 
    4181 +                (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR), 
    4182 +                dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])); 
    4183 +                 
    4184 +       if(dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]) 
    4185 +               T(YAFFS_TRACE_VERIFY, 
    4186 +                (TSTR("Erased block count wrong dev %d count %d"TENDSTR), 
    4187 +                dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])); 
    4188 +                 
    4189 +       if(nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1) 
    4190 +               T(YAFFS_TRACE_VERIFY, 
    4191 +                (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR), 
    4192 +                nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING])); 
    4193 + 
    4194 +       T(YAFFS_TRACE_VERIFY,(TSTR(""TENDSTR))); 
    4195 + 
    4196 +} 
    4197 + 
    4198 +/* 
    4199 + * Verify the object header. oh must be valid, but obj and tags may be NULL in which 
    4200 + * case those tests will not be performed. 
    4201 + */ 
    4202 +static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck) 
    4203 +{ 
    4204 +       if(yaffs_SkipVerification(obj->myDev)) 
    4205 +               return; 
    4206 +                
    4207 +       if(!(tags && obj && oh)){ 
    4208 +               T(YAFFS_TRACE_VERIFY, 
    4209 +                               (TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR), 
    4210 +                               (__u32)tags,(__u32)obj,(__u32)oh)); 
    4211 +               return; 
    4212 +       } 
    4213 +        
    4214 +       if(oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN || 
    4215 +          oh->type > YAFFS_OBJECT_TYPE_MAX) 
    4216 +               T(YAFFS_TRACE_VERIFY, 
    4217 +                (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR), 
    4218 +                tags->objectId, oh->type)); 
    4219 + 
    4220 +       if(tags->objectId != obj->objectId) 
    4221 +               T(YAFFS_TRACE_VERIFY, 
    4222 +                (TSTR("Obj %d header mismatch objectId %d"TENDSTR), 
    4223 +                tags->objectId, obj->objectId)); 
    4224 + 
    4225 + 
    4226 +       /* 
    4227 +        * Check that the object's parent ids match if parentCheck requested. 
    4228 +        *  
    4229 +        * Tests do not apply to the root object. 
    4230 +        */ 
    4231 +        
    4232 +       if(parentCheck && tags->objectId > 1 && !obj->parent) 
    4233 +               T(YAFFS_TRACE_VERIFY, 
    4234 +                (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR), 
    4235 +                tags->objectId, oh->parentObjectId)); 
    4236 +                
    4237 +        
    4238 +       if(parentCheck && obj->parent && 
    4239 +          oh->parentObjectId != obj->parent->objectId &&  
    4240 +          (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED || 
    4241 +           obj->parent->objectId != YAFFS_OBJECTID_DELETED)) 
    4242 +               T(YAFFS_TRACE_VERIFY, 
    4243 +                (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR), 
    4244 +                tags->objectId, oh->parentObjectId, obj->parent->objectId)); 
    4245 +                
    4246 +        
    4247 +       if(tags->objectId > 1 && oh->name[0] == 0) /* Null name */ 
    4248 +               T(YAFFS_TRACE_VERIFY, 
    4249 +               (TSTR("Obj %d header name is NULL"TENDSTR), 
    4250 +                obj->objectId)); 
    4251 + 
    4252 +       if(tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */ 
    4253 +               T(YAFFS_TRACE_VERIFY, 
    4254 +               (TSTR("Obj %d header name is 0xFF"TENDSTR), 
    4255 +                obj->objectId)); 
    4256 +} 
    4257 + 
    4258 + 
    4259 + 
    4260 +static int yaffs_VerifyTnodeWorker(yaffs_Object * obj, yaffs_Tnode * tn, 
    4261 +                                       __u32 level, int chunkOffset) 
    4262 +{ 
    4263 +       int i; 
    4264 +       yaffs_Device *dev = obj->myDev; 
    4265 +       int ok = 1; 
    4266 +       int nTnodeBytes = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; 
    4267 + 
    4268 +       if (tn) { 
    4269 +               if (level > 0) { 
    4270 + 
    4271 +                       for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++){ 
    4272 +                               if (tn->internal[i]) { 
    4273 +                                       ok = yaffs_VerifyTnodeWorker(obj, 
    4274 +                                                       tn->internal[i], 
    4275 +                                                       level - 1, 
    4276 +                                                       (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i); 
    4277 +                               } 
    4278 +                       } 
    4279 +               } else if (level == 0) { 
    4280 +                       int i; 
    4281 +                       yaffs_ExtendedTags tags; 
    4282 +                       __u32 objectId = obj->objectId; 
    4283 +                        
    4284 +                       chunkOffset <<=  YAFFS_TNODES_LEVEL0_BITS; 
    4285 +                        
    4286 +                       for(i = 0; i < YAFFS_NTNODES_LEVEL0; i++){ 
    4287 +                               __u32 theChunk = yaffs_GetChunkGroupBase(dev,tn,i); 
    4288 +                                
    4289 +                               if(theChunk > 0){ 
    4290 +                                       /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */ 
    4291 +                                       yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL, &tags); 
    4292 +                                       if(tags.objectId != objectId || tags.chunkId != chunkOffset){ 
    4293 +                                               T(~0,(TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), 
    4294 +                                                       objectId, chunkOffset, theChunk, 
    4295 +                                                       tags.objectId, tags.chunkId)); 
    4296 +                                       } 
    4297 +                               } 
    4298 +                               chunkOffset++; 
    4299 +                       } 
    4300 +               } 
    4301 +       } 
    4302 + 
    4303 +       return ok; 
    4304 + 
    4305 +} 
    4306 + 
    4307 + 
    4308 +static void yaffs_VerifyFile(yaffs_Object *obj) 
    4309 +{ 
    4310 +       int requiredTallness; 
    4311 +       int actualTallness; 
    4312 +       __u32 lastChunk; 
    4313 +       __u32 x; 
    4314 +       __u32 i; 
    4315 +       int ok; 
    4316 +       yaffs_Device *dev; 
    4317 +       yaffs_ExtendedTags tags; 
    4318 +       yaffs_Tnode *tn; 
    4319 +       __u32 objectId; 
    4320 +        
    4321 +       if(obj && yaffs_SkipVerification(obj->myDev)) 
    4322 +               return; 
    4323 +        
    4324 +       dev = obj->myDev; 
    4325 +       objectId = obj->objectId; 
    4326 +        
    4327 +       /* Check file size is consistent with tnode depth */ 
    4328 +       lastChunk =  obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1; 
    4329 +       x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS; 
    4330 +       requiredTallness = 0; 
    4331 +       while (x> 0) { 
    4332 +               x >>= YAFFS_TNODES_INTERNAL_BITS; 
    4333 +               requiredTallness++; 
    4334 +       } 
    4335 +        
    4336 +       actualTallness = obj->variant.fileVariant.topLevel; 
    4337 +        
    4338 +       if(requiredTallness > actualTallness ) 
    4339 +               T(YAFFS_TRACE_VERIFY, 
    4340 +               (TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR), 
    4341 +                obj->objectId,actualTallness, requiredTallness)); 
    4342 +        
    4343 +        
    4344 +       /* Check that the chunks in the tnode tree are all correct.  
    4345 +        * We do this by scanning through the tnode tree and 
    4346 +        * checking the tags for every chunk match. 
    4347 +        */ 
    4348 + 
    4349 +       if(yaffs_SkipNANDVerification(dev)) 
    4350 +               return; 
    4351 +                
    4352 +       for(i = 1; i <= lastChunk; i++){ 
    4353 +               tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant,i); 
    4354 + 
    4355 +               if (tn) { 
    4356 +                       __u32 theChunk = yaffs_GetChunkGroupBase(dev,tn,i); 
    4357 +                       if(theChunk > 0){ 
    4358 +                               /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */ 
    4359 +                               yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL, &tags); 
    4360 +                               if(tags.objectId != objectId || tags.chunkId != i){ 
    4361 +                                       T(~0,(TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), 
    4362 +                                               objectId, i, theChunk, 
    4363 +                                               tags.objectId, tags.chunkId)); 
    4364 +                               } 
    4365 +                       } 
    4366 +               } 
    4367 + 
    4368 +       } 
    4369 + 
    4370 +} 
    4371 + 
    4372 +static void yaffs_VerifyDirectory(yaffs_Object *obj) 
    4373 +{ 
    4374 +       if(obj && yaffs_SkipVerification(obj->myDev)) 
    4375 +               return; 
    4376 +        
    4377 +} 
    4378 + 
    4379 +static void yaffs_VerifyHardLink(yaffs_Object *obj) 
    4380 +{ 
    4381 +       if(obj && yaffs_SkipVerification(obj->myDev)) 
    4382 +               return; 
    4383 +                
    4384 +       /* Verify sane equivalent object */ 
    4385 +} 
    4386 + 
    4387 +static void yaffs_VerifySymlink(yaffs_Object *obj) 
    4388 +{ 
    4389 +       if(obj && yaffs_SkipVerification(obj->myDev)) 
    4390 +               return; 
    4391 +                
    4392 +       /* Verify symlink string */ 
    4393 +} 
    4394 + 
    4395 +static void yaffs_VerifySpecial(yaffs_Object *obj) 
    4396 +{ 
    4397 +       if(obj && yaffs_SkipVerification(obj->myDev)) 
    4398 +               return; 
    4399 +} 
    4400 + 
    4401 +static void yaffs_VerifyObject(yaffs_Object *obj) 
    4402 +{ 
    4403 +       yaffs_Device *dev; 
    4404 +        
    4405 +       __u32 chunkMin; 
    4406 +       __u32 chunkMax; 
    4407 +        
    4408 +       __u32 chunkIdOk; 
    4409 +       __u32 chunkIsLive; 
    4410 +        
    4411 +       if(!obj) 
    4412 +               return; 
    4413 +        
    4414 +       dev = obj->myDev; 
    4415 +        
    4416 +       if(yaffs_SkipVerification(dev)) 
    4417 +               return; 
    4418 +                
    4419 +       /* Check sane object header chunk */ 
    4420 +        
    4421 +       chunkMin = dev->internalStartBlock * dev->nChunksPerBlock; 
    4422 +       chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1; 
    4423 +        
    4424 +       chunkIdOk = (obj->chunkId >= chunkMin && obj->chunkId <= chunkMax); 
    4425 +       chunkIsLive = chunkIdOk &&  
    4426 +                       yaffs_CheckChunkBit(dev,  
    4427 +                                           obj->chunkId / dev->nChunksPerBlock, 
    4428 +                                           obj->chunkId % dev->nChunksPerBlock); 
    4429 +       if(!obj->fake &&  
    4430 +           (!chunkIdOk || !chunkIsLive)) { 
    4431 +          T(YAFFS_TRACE_VERIFY, 
    4432 +          (TSTR("Obj %d has chunkId %d %s %s"TENDSTR), 
    4433 +          obj->objectId,obj->chunkId, 
    4434 +          chunkIdOk ? "" : ",out of range", 
    4435 +          chunkIsLive || !chunkIdOk ? "" : ",marked as deleted")); 
    4436 +       } 
    4437 +        
    4438 +       if(chunkIdOk && chunkIsLive &&!yaffs_SkipNANDVerification(dev)) { 
    4439 +               yaffs_ExtendedTags tags; 
    4440 +               yaffs_ObjectHeader *oh; 
    4441 +               __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__); 
    4442 +                
    4443 +               oh = (yaffs_ObjectHeader *)buffer; 
    4444 +                
    4445 +               yaffs_ReadChunkWithTagsFromNAND(dev, obj->chunkId,buffer, &tags); 
    4446 +                
    4447 +               yaffs_VerifyObjectHeader(obj,oh,&tags,1); 
    4448 +                
    4449 +               yaffs_ReleaseTempBuffer(dev,buffer,__LINE__); 
    4450 +       } 
    4451 +        
    4452 +       /* Verify it has a parent */ 
    4453 +       if(obj && !obj->fake && 
    4454 +          (!obj->parent || obj->parent->myDev != dev)){ 
    4455 +          T(YAFFS_TRACE_VERIFY, 
    4456 +          (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR), 
    4457 +          obj->objectId,obj->parent));     
    4458 +       } 
    4459 +        
    4460 +       /* Verify parent is a directory */ 
    4461 +       if(obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY){ 
    4462 +          T(YAFFS_TRACE_VERIFY, 
    4463 +          (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR), 
    4464 +          obj->objectId,obj->parent->variantType));        
    4465 +       } 
    4466 +        
    4467 +       switch(obj->variantType){ 
    4468 +       case YAFFS_OBJECT_TYPE_FILE: 
    4469 +               yaffs_VerifyFile(obj); 
    4470 +               break; 
    4471 +       case YAFFS_OBJECT_TYPE_SYMLINK: 
    4472 +               yaffs_VerifySymlink(obj); 
    4473 +               break; 
    4474 +       case YAFFS_OBJECT_TYPE_DIRECTORY: 
    4475 +               yaffs_VerifyDirectory(obj); 
    4476 +               break; 
    4477 +       case YAFFS_OBJECT_TYPE_HARDLINK: 
    4478 +               yaffs_VerifyHardLink(obj); 
    4479 +               break; 
    4480 +       case YAFFS_OBJECT_TYPE_SPECIAL: 
    4481 +               yaffs_VerifySpecial(obj); 
    4482 +               break; 
    4483 +       case YAFFS_OBJECT_TYPE_UNKNOWN: 
    4484 +       default: 
    4485 +               T(YAFFS_TRACE_VERIFY, 
    4486 +               (TSTR("Obj %d has illegaltype %d"TENDSTR), 
    4487 +               obj->objectId,obj->variantType));           
    4488 +               break; 
    4489 +       } 
    4490 +        
    4491 +        
    4492 +} 
    4493 + 
    4494 +static void yaffs_VerifyObjects(yaffs_Device *dev) 
    4495 +{ 
    4496 +       yaffs_Object *obj; 
    4497 +       int i; 
    4498 +       struct list_head *lh; 
    4499 + 
    4500 +       if(yaffs_SkipVerification(dev)) 
    4501 +               return; 
    4502 +        
    4503 +       /* Iterate through the objects in each hash entry */ 
    4504 +         
    4505 +        for(i = 0; i <  YAFFS_NOBJECT_BUCKETS; i++){ 
    4506 +               list_for_each(lh, &dev->objectBucket[i].list) { 
    4507 +                       if (lh) { 
    4508 +                               obj = list_entry(lh, yaffs_Object, hashLink); 
    4509 +                               yaffs_VerifyObject(obj); 
    4510 +                       } 
    4511 +               } 
    4512 +        } 
    4513 + 
    4514 +} 
    4515 + 
    4516 + 
    4517 +/* 
    4518 + *  Simple hash function. Needs to have a reasonable spread 
    4519 + */ 
    4520 +  
    4521 +static Y_INLINE int yaffs_HashFunction(int n) 
    4522 +{ 
    4523 +       n = abs(n); 
    4524 +       return (n % YAFFS_NOBJECT_BUCKETS); 
    4525 +} 
    4526 + 
    4527 +/* 
    4528 + * Access functions to useful fake objects 
    4529 + */ 
    4530 +  
    4531 +yaffs_Object *yaffs_Root(yaffs_Device * dev) 
    4532 +{ 
    4533 +       return dev->rootDir; 
    4534 +} 
    4535 + 
    4536 +yaffs_Object *yaffs_LostNFound(yaffs_Device * dev) 
    4537 +{ 
    4538 +       return dev->lostNFoundDir; 
    4539 +} 
    4540 + 
    4541 + 
    4542 +/* 
    4543 + *  Erased NAND checking functions 
    4544 + */ 
    4545 +  
    4546 +int yaffs_CheckFF(__u8 * buffer, int nBytes) 
    4547 +{ 
    4548 +       /* Horrible, slow implementation */ 
    4549 +       while (nBytes--) { 
    4550 +               if (*buffer != 0xFF) 
    4551 +                       return 0; 
    4552 +               buffer++; 
    4553 +       } 
    4554 +       return 1; 
    4555 +} 
    4556 + 
    4557 +static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, 
    4558 +                                 int chunkInNAND) 
    4559 +{ 
    4560 + 
    4561 +       int retval = YAFFS_OK; 
    4562 +       __u8 *data = yaffs_GetTempBuffer(dev, __LINE__); 
    4563 +       yaffs_ExtendedTags tags; 
    4564 +       int result; 
    4565 + 
    4566 +       result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags); 
    4567 +        
    4568 +       if(tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR) 
    4569 +               retval = YAFFS_FAIL; 
    4570 +                
    4571 + 
    4572 +       if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) { 
    4573 +               T(YAFFS_TRACE_NANDACCESS, 
    4574 +                 (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND)); 
    4575 +               retval = YAFFS_FAIL; 
    4576 +       } 
    4577 + 
    4578 +       yaffs_ReleaseTempBuffer(dev, data, __LINE__); 
    4579 + 
    4580 +       return retval; 
    4581 + 
    4582 +} 
    4583 + 
    4584 + 
    4585 +static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, 
    4586 +                                            const __u8 * data, 
    4587 +                                            yaffs_ExtendedTags * tags, 
    4588 +                                            int useReserve) 
    4589 +{ 
    4590 +       int attempts = 0; 
    4591 +       int writeOk = 0; 
    4592 +       int chunk; 
    4593 + 
    4594 +       yaffs_InvalidateCheckpoint(dev); 
    4595 + 
    4596 +       do { 
    4597 +               yaffs_BlockInfo *bi = 0; 
    4598 +               int erasedOk = 0; 
    4599 + 
    4600 +               chunk = yaffs_AllocateChunk(dev, useReserve, &bi); 
    4601 +               if (chunk < 0) { 
    4602 +                       /* no space */ 
    4603 +                       break; 
    4604 +               } 
    4605 + 
    4606 +               /* First check this chunk is erased, if it needs 
    4607 +                * checking.  The checking policy (unless forced 
    4608 +                * always on) is as follows: 
    4609 +                * 
    4610 +                * Check the first page we try to write in a block. 
    4611 +                * If the check passes then we don't need to check any 
    4612 +                * more.        If the check fails, we check again... 
    4613 +                * If the block has been erased, we don't need to check. 
    4614 +                * 
    4615 +                * However, if the block has been prioritised for gc, 
    4616 +                * then we think there might be something odd about 
    4617 +                * this block and stop using it. 
    4618 +                * 
    4619 +                * Rationale: We should only ever see chunks that have 
    4620 +                * not been erased if there was a partially written 
    4621 +                * chunk due to power loss.  This checking policy should 
    4622 +                * catch that case with very few checks and thus save a 
    4623 +                * lot of checks that are most likely not needed. 
    4624 +                */ 
    4625 +               if (bi->gcPrioritise) { 
    4626 +                       yaffs_DeleteChunk(dev, chunk, 1, __LINE__); 
    4627 +                       /* try another chunk */ 
    4628 +                       continue; 
    4629 +               } 
    4630 + 
    4631 +               /* let's give it a try */ 
    4632 +               attempts++; 
    4633 + 
    4634 +#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED 
    4635 +               bi->skipErasedCheck = 0; 
    4636 +#endif 
    4637 +               if (!bi->skipErasedCheck) { 
    4638 +                       erasedOk = yaffs_CheckChunkErased(dev, chunk); 
    4639 +                       if (erasedOk != YAFFS_OK) { 
    4640 +                               T(YAFFS_TRACE_ERROR, 
    4641 +                               (TSTR ("**>> yaffs chunk %d was not erased" 
    4642 +                               TENDSTR), chunk)); 
    4643 + 
    4644 +                               /* try another chunk */ 
    4645 +                               continue; 
    4646 +                       } 
    4647 +                       bi->skipErasedCheck = 1; 
    4648 +               } 
    4649 + 
    4650 +               writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk, 
    4651 +                               data, tags); 
    4652 +               if (writeOk != YAFFS_OK) { 
    4653 +                       yaffs_HandleWriteChunkError(dev, chunk, erasedOk); 
    4654 +                       /* try another chunk */ 
    4655 +                       continue; 
    4656 +               } 
    4657 + 
    4658 +               /* Copy the data into the robustification buffer */ 
    4659 +               yaffs_HandleWriteChunkOk(dev, chunk, data, tags); 
    4660 + 
    4661 +       } while (writeOk != YAFFS_OK && attempts < yaffs_wr_attempts); 
    4662 + 
    4663 +       if (attempts > 1) { 
    4664 +               T(YAFFS_TRACE_ERROR, 
    4665 +                       (TSTR("**>> yaffs write required %d attempts" TENDSTR), 
    4666 +                       attempts)); 
    4667 + 
    4668 +               dev->nRetriedWrites += (attempts - 1); 
    4669 +       } 
    4670 + 
    4671 +       return chunk; 
    4672 +} 
    4673 + 
    4674 +/* 
    4675 + * Block retiring for handling a broken block. 
    4676 + */ 
    4677 +  
    4678 +static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND) 
    4679 +{ 
    4680 +       yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); 
    4681 + 
    4682 +       yaffs_InvalidateCheckpoint(dev); 
    4683 +        
    4684 +       yaffs_MarkBlockBad(dev, blockInNAND); 
    4685 + 
    4686 +       bi->blockState = YAFFS_BLOCK_STATE_DEAD; 
    4687 +       bi->gcPrioritise = 0; 
    4688 +       bi->needsRetiring = 0; 
    4689 + 
    4690 +       dev->nRetiredBlocks++; 
    4691 +} 
    4692 + 
    4693 +/* 
    4694 + * Functions for robustisizing TODO 
    4695 + * 
    4696 + */ 
    4697 +  
    4698 +static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND, 
    4699 +                                    const __u8 * data, 
    4700 +                                    const yaffs_ExtendedTags * tags) 
    4701 +{ 
    4702 +} 
    4703 + 
    4704 +static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND, 
    4705 +                                   const yaffs_ExtendedTags * tags) 
    4706 +{ 
    4707 +} 
    4708 + 
    4709 +void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi) 
    4710 +{ 
    4711 +       if(!bi->gcPrioritise){ 
    4712 +               bi->gcPrioritise = 1; 
    4713 +               dev->hasPendingPrioritisedGCs = 1; 
    4714 +               bi->chunkErrorStrikes ++; 
    4715 +                
    4716 +               if(bi->chunkErrorStrikes > 3){ 
    4717 +                       bi->needsRetiring = 1; /* Too many stikes, so retire this */ 
    4718 +                       T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR))); 
    4719 + 
    4720 +               } 
    4721 +                
    4722 +       } 
    4723 +} 
    4724 + 
    4725 +static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int erasedOk) 
    4726 +{ 
    4727 + 
    4728 +       int blockInNAND = chunkInNAND / dev->nChunksPerBlock; 
    4729 +       yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); 
    4730 + 
    4731 +       yaffs_HandleChunkError(dev,bi); 
    4732 +                
    4733 +        
    4734 +       if(erasedOk ) { 
    4735 +               /* Was an actual write failure, so mark the block for retirement  */ 
    4736 +               bi->needsRetiring = 1; 
    4737 +               T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, 
    4738 +                 (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND)); 
    4739 + 
    4740 +                
    4741 +       } 
    4742 +        
    4743 +       /* Delete the chunk */ 
    4744 +       yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); 
    4745 +} 
    4746 + 
    4747 + 
    4748 +/*---------------- Name handling functions ------------*/  
    4749 + 
    4750 +static __u16 yaffs_CalcNameSum(const YCHAR * name) 
    4751 +{ 
    4752 +       __u16 sum = 0; 
    4753 +       __u16 i = 1; 
    4754 + 
    4755 +       YUCHAR *bname = (YUCHAR *) name; 
    4756 +       if (bname) { 
    4757 +               while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) { 
    4758 + 
    4759 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE 
    4760 +                       sum += yaffs_toupper(*bname) * i; 
    4761 +#else 
    4762 +                       sum += (*bname) * i; 
    4763 +#endif 
    4764 +                       i++; 
    4765 +                       bname++; 
    4766 +               } 
    4767 +       } 
    4768 +       return sum; 
    4769 +} 
    4770 + 
    4771 +static void yaffs_SetObjectName(yaffs_Object * obj, const YCHAR * name) 
    4772 +{ 
    4773 +#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM 
    4774 +       if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH) { 
    4775 +               yaffs_strcpy(obj->shortName, name); 
    4776 +       } else { 
    4777 +               obj->shortName[0] = _Y('\0'); 
    4778 +       } 
    4779 +#endif 
    4780 +       obj->sum = yaffs_CalcNameSum(name); 
    4781 +} 
    4782 + 
    4783 +/*-------------------- TNODES ------------------- 
    4784 + 
    4785 + * List of spare tnodes 
    4786 + * The list is hooked together using the first pointer 
    4787 + * in the tnode. 
    4788 + */ 
    4789 +  
    4790 +/* yaffs_CreateTnodes creates a bunch more tnodes and 
    4791 + * adds them to the tnode free list. 
    4792 + * Don't use this function directly 
    4793 + */ 
    4794 + 
    4795 +static int yaffs_CreateTnodes(yaffs_Device * dev, int nTnodes) 
    4796 +{ 
    4797 +       int i; 
    4798 +       int tnodeSize; 
    4799 +       yaffs_Tnode *newTnodes; 
    4800 +       __u8 *mem; 
    4801 +       yaffs_Tnode *curr; 
    4802 +       yaffs_Tnode *next; 
    4803 +       yaffs_TnodeList *tnl; 
    4804 + 
    4805 +       if (nTnodes < 1) 
    4806 +               return YAFFS_OK; 
    4807 +                
    4808 +       /* Calculate the tnode size in bytes for variable width tnode support. 
    4809 +        * Must be a multiple of 32-bits  */ 
    4810 +       tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; 
    4811 + 
    4812 +       /* make these things */ 
    4813 + 
    4814 +       newTnodes = YMALLOC(nTnodes * tnodeSize); 
    4815 +       mem = (__u8 *)newTnodes; 
    4816 + 
    4817 +       if (!newTnodes) { 
    4818 +               T(YAFFS_TRACE_ERROR, 
    4819 +                 (TSTR("yaffs: Could not allocate Tnodes" TENDSTR))); 
    4820 +               return YAFFS_FAIL; 
    4821 +       } 
    4822 + 
    4823 +       /* Hook them into the free list */ 
    4824 +#if 0 
    4825 +       for (i = 0; i < nTnodes - 1; i++) { 
    4826 +               newTnodes[i].internal[0] = &newTnodes[i + 1]; 
    4827 +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG 
    4828 +               newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1; 
    4829 +#endif 
    4830 +       } 
    4831 + 
    4832 +       newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes; 
    4833 +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG 
    4834 +       newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1; 
    4835 +#endif 
    4836 +       dev->freeTnodes = newTnodes; 
    4837 +#else 
    4838 +       /* New hookup for wide tnodes */ 
    4839 +       for(i = 0; i < nTnodes -1; i++) { 
    4840 +               curr = (yaffs_Tnode *) &mem[i * tnodeSize]; 
    4841 +               next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize]; 
    4842 +               curr->internal[0] = next; 
    4843 +       } 
    4844 +        
    4845 +       curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize]; 
    4846 +       curr->internal[0] = dev->freeTnodes; 
    4847 +       dev->freeTnodes = (yaffs_Tnode *)mem; 
    4848 + 
    4849 +#endif 
    4850 + 
    4851 + 
    4852 +       dev->nFreeTnodes += nTnodes; 
    4853 +       dev->nTnodesCreated += nTnodes; 
    4854 + 
    4855 +       /* Now add this bunch of tnodes to a list for freeing up. 
    4856 +        * NB If we can't add this to the management list it isn't fatal 
    4857 +        * but it just means we can't free this bunch of tnodes later. 
    4858 +        */ 
    4859 +         
    4860 +       tnl = YMALLOC(sizeof(yaffs_TnodeList)); 
    4861 +       if (!tnl) { 
    4862 +               T(YAFFS_TRACE_ERROR, 
    4863 +                 (TSTR 
    4864 +                  ("yaffs: Could not add tnodes to management list" TENDSTR))); 
    4865 +                  return YAFFS_FAIL; 
    4866 + 
    4867 +       } else { 
    4868 +               tnl->tnodes = newTnodes; 
    4869 +               tnl->next = dev->allocatedTnodeList; 
    4870 +               dev->allocatedTnodeList = tnl; 
    4871 +       } 
    4872 + 
    4873 +       T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR))); 
    4874 + 
    4875 +       return YAFFS_OK; 
    4876 +} 
    4877 + 
    4878 +/* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */ 
    4879 + 
    4880 +static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device * dev) 
    4881 +{ 
    4882 +       yaffs_Tnode *tn = NULL; 
    4883 + 
    4884 +       /* If there are none left make more */ 
    4885 +       if (!dev->freeTnodes) { 
    4886 +               yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES); 
    4887 +       } 
    4888 + 
    4889 +       if (dev->freeTnodes) { 
    4890 +               tn = dev->freeTnodes; 
    4891 +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG 
    4892 +               if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) { 
    4893 +                       /* Hoosterman, this thing looks like it isn't in the list */ 
    4894 +                       T(YAFFS_TRACE_ALWAYS, 
    4895 +                         (TSTR("yaffs: Tnode list bug 1" TENDSTR))); 
    4896 +               } 
    4897 +#endif 
    4898 +               dev->freeTnodes = dev->freeTnodes->internal[0]; 
    4899 +               dev->nFreeTnodes--; 
    4900 +       } 
    4901 + 
    4902 +       return tn; 
    4903 +} 
    4904 + 
    4905 +static yaffs_Tnode *yaffs_GetTnode(yaffs_Device * dev) 
    4906 +{ 
    4907 +       yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev); 
    4908 +        
    4909 +       if(tn) 
    4910 +               memset(tn, 0, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); 
    4911 + 
    4912 +       return tn;       
    4913 +} 
    4914 + 
    4915 +/* FreeTnode frees up a tnode and puts it back on the free list */ 
    4916 +static void yaffs_FreeTnode(yaffs_Device * dev, yaffs_Tnode * tn) 
    4917 +{ 
    4918 +       if (tn) { 
    4919 +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG 
    4920 +               if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) { 
    4921 +                       /* Hoosterman, this thing looks like it is already in the list */ 
    4922 +                       T(YAFFS_TRACE_ALWAYS, 
    4923 +                         (TSTR("yaffs: Tnode list bug 2" TENDSTR))); 
    4924 +               } 
    4925 +               tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1; 
    4926 +#endif 
    4927 +               tn->internal[0] = dev->freeTnodes; 
    4928 +               dev->freeTnodes = tn; 
    4929 +               dev->nFreeTnodes++; 
    4930 +       } 
    4931 +} 
    4932 + 
    4933 +static void yaffs_DeinitialiseTnodes(yaffs_Device * dev) 
    4934 +{ 
    4935 +       /* Free the list of allocated tnodes */ 
    4936 +       yaffs_TnodeList *tmp; 
    4937 + 
    4938 +       while (dev->allocatedTnodeList) { 
    4939 +               tmp = dev->allocatedTnodeList->next; 
    4940 + 
    4941 +               YFREE(dev->allocatedTnodeList->tnodes); 
    4942 +               YFREE(dev->allocatedTnodeList); 
    4943 +               dev->allocatedTnodeList = tmp; 
    4944 + 
    4945 +       } 
    4946 + 
    4947 +       dev->freeTnodes = NULL; 
    4948 +       dev->nFreeTnodes = 0; 
    4949 +} 
    4950 + 
    4951 +static void yaffs_InitialiseTnodes(yaffs_Device * dev) 
    4952 +{ 
    4953 +       dev->allocatedTnodeList = NULL; 
    4954 +       dev->freeTnodes = NULL; 
    4955 +       dev->nFreeTnodes = 0; 
    4956 +       dev->nTnodesCreated = 0; 
    4957 + 
    4958 +} 
    4959 + 
    4960 + 
    4961 +void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos, unsigned val) 
    4962 +{ 
    4963 +  __u32 *map = (__u32 *)tn; 
    4964 +  __u32 bitInMap; 
    4965 +  __u32 bitInWord; 
    4966 +  __u32 wordInMap; 
    4967 +  __u32 mask; 
    4968  
    4969 +  pos &= YAFFS_TNODES_LEVEL0_MASK; 
    4970 +  val >>= dev->chunkGroupBits; 
    4971  
    4972 +  bitInMap = pos * dev->tnodeWidth; 
    4973 +  wordInMap = bitInMap /32; 
    4974 +  bitInWord = bitInMap & (32 -1); 
    4975  
    4976 +  mask = dev->tnodeMask << bitInWord; 
    4977  
    4978 +  map[wordInMap] &= ~mask; 
    4979 +  map[wordInMap] |= (mask & (val << bitInWord)); 
    4980  
    4981 +  if(dev->tnodeWidth > (32-bitInWord)) { 
    4982 +    bitInWord = (32 - bitInWord); 
    4983 +    wordInMap++;; 
    4984 +    mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord); 
    4985 +    map[wordInMap] &= ~mask; 
    4986 +    map[wordInMap] |= (mask & (val >> bitInWord)); 
    4987 +  } 
    4988 +} 
    4989 + 
    4990 +static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos) 
    4991 +{ 
    4992 +  __u32 *map = (__u32 *)tn; 
    4993 +  __u32 bitInMap; 
    4994 +  __u32 bitInWord; 
    4995 +  __u32 wordInMap; 
    4996 +  __u32 val; 
    4997  
    4998 +  pos &= YAFFS_TNODES_LEVEL0_MASK; 
    4999  
    5000 +  bitInMap = pos * dev->tnodeWidth; 
    5001 +  wordInMap = bitInMap /32; 
    5002 +  bitInWord = bitInMap & (32 -1); 
    5003  
    5004 +  val = map[wordInMap] >> bitInWord; 
    5005  
    5006 +  if(dev->tnodeWidth > (32-bitInWord)) { 
    5007 +    bitInWord = (32 - bitInWord); 
    5008 +    wordInMap++;; 
    5009 +    val |= (map[wordInMap] << bitInWord); 
    5010 +  } 
    5011  
    5012 +  val &= dev->tnodeMask; 
    5013 +  val <<= dev->chunkGroupBits; 
    5014  
    5015 +  return val; 
    5016 +} 
    5017 + 
    5018 +/* ------------------- End of individual tnode manipulation -----------------*/ 
    5019 + 
    5020 +/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------ 
    5021 + * The look up tree is represented by the top tnode and the number of topLevel 
    5022 + * in the tree. 0 means only the level 0 tnode is in the tree. 
    5023 + */ 
    5024 + 
    5025 +/* FindLevel0Tnode finds the level 0 tnode, if one exists. */ 
    5026 +static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device * dev, 
    5027 +                                         yaffs_FileStructure * fStruct, 
    5028 +                                         __u32 chunkId) 
    5029 +{ 
    5030 + 
    5031 +       yaffs_Tnode *tn = fStruct->top; 
    5032 +       __u32 i; 
    5033 +       int requiredTallness; 
    5034 +       int level = fStruct->topLevel; 
    5035 + 
    5036 +       /* Check sane level and chunk Id */ 
    5037 +       if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL) { 
    5038 +               return NULL; 
    5039 +       } 
    5040 + 
    5041 +       if (chunkId > YAFFS_MAX_CHUNK_ID) { 
    5042 +               return NULL; 
    5043 +       } 
    5044 + 
    5045 +       /* First check we're tall enough (ie enough topLevel) */ 
    5046 + 
    5047 +       i = chunkId >> YAFFS_TNODES_LEVEL0_BITS; 
    5048 +       requiredTallness = 0; 
    5049 +       while (i) { 
    5050 +               i >>= YAFFS_TNODES_INTERNAL_BITS; 
    5051 +               requiredTallness++; 
    5052 +       } 
    5053 + 
    5054 +       if (requiredTallness > fStruct->topLevel) { 
    5055 +               /* Not tall enough, so we can't find it, return NULL. */ 
    5056 +               return NULL; 
    5057 +       } 
    5058 + 
    5059 +       /* Traverse down to level 0 */ 
    5060 +       while (level > 0 && tn) { 
    5061 +               tn = tn-> 
    5062 +                   internal[(chunkId >> 
    5063 +                              ( YAFFS_TNODES_LEVEL0_BITS +  
    5064 +                                (level - 1) * 
    5065 +                                YAFFS_TNODES_INTERNAL_BITS) 
    5066 +                             ) & 
    5067 +                            YAFFS_TNODES_INTERNAL_MASK]; 
    5068 +               level--; 
    5069 + 
    5070 +       } 
    5071 + 
    5072 +       return tn; 
    5073 +} 
    5074 + 
    5075 +/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree. 
    5076 + * This happens in two steps: 
    5077 + *  1. If the tree isn't tall enough, then make it taller. 
    5078 + *  2. Scan down the tree towards the level 0 tnode adding tnodes if required. 
    5079 + * 
    5080 + * Used when modifying the tree. 
    5081 + * 
    5082 + *  If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will 
    5083 + *  be plugged into the ttree. 
    5084 + */ 
    5085 +  
    5086 +static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device * dev, 
    5087 +                                              yaffs_FileStructure * fStruct, 
    5088 +                                              __u32 chunkId, 
    5089 +                                              yaffs_Tnode *passedTn) 
    5090 +{ 
    5091 + 
    5092 +       int requiredTallness; 
    5093 +       int i; 
    5094 +       int l; 
    5095 +       yaffs_Tnode *tn; 
    5096 + 
    5097 +       __u32 x; 
    5098 + 
    5099 + 
    5100 +       /* Check sane level and page Id */ 
    5101 +       if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL) { 
    5102 +               return NULL; 
    5103 +       } 
    5104 + 
    5105 +       if (chunkId > YAFFS_MAX_CHUNK_ID) { 
    5106 +               return NULL; 
    5107 +       } 
    5108 + 
    5109 +       /* First check we're tall enough (ie enough topLevel) */ 
    5110 + 
    5111 +       x = chunkId >> YAFFS_TNODES_LEVEL0_BITS; 
    5112 +       requiredTallness = 0; 
    5113 +       while (x) { 
    5114 +               x >>= YAFFS_TNODES_INTERNAL_BITS; 
    5115 +               requiredTallness++; 
    5116 +       } 
    5117 + 
    5118 + 
    5119 +       if (requiredTallness > fStruct->topLevel) { 
    5120 +               /* Not tall enough,gotta make the tree taller */ 
    5121 +               for (i = fStruct->topLevel; i < requiredTallness; i++) { 
    5122 +                
    5123 +                       tn = yaffs_GetTnode(dev); 
    5124 + 
    5125 +                       if (tn) { 
    5126 +                               tn->internal[0] = fStruct->top; 
    5127 +                               fStruct->top = tn; 
    5128 +                       } else { 
    5129 +                               T(YAFFS_TRACE_ERROR, 
    5130 +                                 (TSTR("yaffs: no more tnodes" TENDSTR))); 
    5131 +                       } 
    5132 +               } 
    5133 + 
    5134 +               fStruct->topLevel = requiredTallness; 
    5135 +       } 
    5136 + 
    5137 +       /* Traverse down to level 0, adding anything we need */ 
    5138 + 
    5139 +       l = fStruct->topLevel; 
    5140 +       tn = fStruct->top; 
    5141 +        
    5142 +       if(l > 0) { 
    5143 +               while (l > 0 && tn) { 
    5144 +                       x = (chunkId >> 
    5145 +                            ( YAFFS_TNODES_LEVEL0_BITS + 
    5146 +                             (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) & 
    5147 +                           YAFFS_TNODES_INTERNAL_MASK; 
    5148 + 
    5149 + 
    5150 +                       if((l>1) && !tn->internal[x]){ 
    5151 +                               /* Add missing non-level-zero tnode */ 
    5152 +                               tn->internal[x] = yaffs_GetTnode(dev); 
    5153 + 
    5154 +                       } else if(l == 1) { 
    5155 +                               /* Looking from level 1 at level 0 */ 
    5156 +                               if (passedTn) { 
    5157 +                                       /* If we already have one, then release it.*/ 
    5158 +                                       if(tn->internal[x]) 
    5159 +                                               yaffs_FreeTnode(dev,tn->internal[x]); 
    5160 +                                       tn->internal[x] = passedTn; 
    5161 +                        
    5162 +                               } else if(!tn->internal[x]) { 
    5163 +                                       /* Don't have one, none passed in */ 
    5164 +                                       tn->internal[x] = yaffs_GetTnode(dev); 
    5165 +                               } 
    5166 +                       } 
    5167 +                
    5168 +                       tn = tn->internal[x]; 
    5169 +                       l--; 
    5170 +               } 
    5171 +       } else { 
    5172 +               /* top is level 0 */ 
    5173 +               if(passedTn) { 
    5174 +                       memcpy(tn,passedTn,(dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); 
    5175 +                       yaffs_FreeTnode(dev,passedTn); 
    5176 +               } 
    5177 +       } 
    5178 + 
    5179 +       return tn; 
    5180 +} 
    5181 + 
    5182 +static int yaffs_FindChunkInGroup(yaffs_Device * dev, int theChunk, 
    5183 +                                 yaffs_ExtendedTags * tags, int objectId, 
    5184 +                                 int chunkInInode) 
    5185 +{ 
    5186 +       int j; 
    5187 + 
    5188 +       for (j = 0; theChunk && j < dev->chunkGroupSize; j++) { 
    5189 +               if (yaffs_CheckChunkBit 
    5190 +                   (dev, theChunk / dev->nChunksPerBlock, 
    5191 +                    theChunk % dev->nChunksPerBlock)) { 
    5192 +                       yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, 
    5193 +                                                       tags); 
    5194 +                       if (yaffs_TagsMatch(tags, objectId, chunkInInode)) { 
    5195 +                               /* found it; */ 
    5196 +                               return theChunk; 
    5197 + 
    5198 +                       } 
    5199 +               } 
    5200 +               theChunk++; 
    5201 +       } 
    5202 +       return -1; 
    5203 +} 
    5204 + 
    5205 + 
    5206 +/* DeleteWorker scans backwards through the tnode tree and deletes all the 
    5207 + * chunks and tnodes in the file 
    5208 + * Returns 1 if the tree was deleted.  
    5209 + * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete. 
    5210 + */ 
    5211 + 
    5212 +static int yaffs_DeleteWorker(yaffs_Object * in, yaffs_Tnode * tn, __u32 level, 
    5213 +                             int chunkOffset, int *limit) 
    5214 +{ 
    5215 +       int i; 
    5216 +       int chunkInInode; 
    5217 +       int theChunk; 
    5218 +       yaffs_ExtendedTags tags; 
    5219 +       int foundChunk; 
    5220 +       yaffs_Device *dev = in->myDev; 
    5221 + 
    5222 +       int allDone = 1; 
    5223 + 
    5224 +       if (tn) { 
    5225 +               if (level > 0) { 
    5226 + 
    5227 +                       for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0; 
    5228 +                            i--) { 
    5229 +                               if (tn->internal[i]) { 
    5230 +                                       if (limit && (*limit) < 0) { 
    5231 +                                               allDone = 0; 
    5232 +                                       } else { 
    5233 +                                               allDone = 
    5234 +                                                   yaffs_DeleteWorker(in, 
    5235 +                                                                      tn-> 
    5236 +                                                                      internal 
    5237 +                                                                      [i], 
    5238 +                                                                      level - 
    5239 +                                                                      1, 
    5240 +                                                                      (chunkOffset 
    5241 +                                                                       << 
    5242 +                                                                       YAFFS_TNODES_INTERNAL_BITS) 
    5243 +                                                                      + i, 
    5244 +                                                                      limit); 
    5245 +                                       } 
    5246 +                                       if (allDone) { 
    5247 +                                               yaffs_FreeTnode(dev, 
    5248 +                                                               tn-> 
    5249 +                                                               internal[i]); 
    5250 +                                               tn->internal[i] = NULL; 
    5251 +                                       } 
    5252 +                               } 
    5253 + 
    5254 +                       } 
    5255 +                       return (allDone) ? 1 : 0; 
    5256 +               } else if (level == 0) { 
    5257 +                       int hitLimit = 0; 
    5258 + 
    5259 +                       for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit; 
    5260 +                            i--) { 
    5261 +                               theChunk = yaffs_GetChunkGroupBase(dev,tn,i); 
    5262 +                               if (theChunk) { 
    5263 + 
    5264 +                                       chunkInInode = 
    5265 +                                           (chunkOffset << 
    5266 +                                            YAFFS_TNODES_LEVEL0_BITS) + i; 
    5267 + 
    5268 +                                       foundChunk = 
    5269 +                                           yaffs_FindChunkInGroup(dev, 
    5270 +                                                                  theChunk, 
    5271 +                                                                  &tags, 
    5272 +                                                                  in->objectId, 
    5273 +                                                                  chunkInInode); 
    5274 + 
    5275 +                                       if (foundChunk > 0) { 
    5276 +                                               yaffs_DeleteChunk(dev, 
    5277 +                                                                 foundChunk, 1, 
    5278 +                                                                 __LINE__); 
    5279 +                                               in->nDataChunks--; 
    5280 +                                               if (limit) { 
    5281 +                                                       *limit = *limit - 1; 
    5282 +                                                       if (*limit <= 0) { 
    5283 +                                                               hitLimit = 1; 
    5284 +                                                       } 
    5285 +                                               } 
    5286 + 
    5287 +                                       } 
    5288 + 
    5289 +                                       yaffs_PutLevel0Tnode(dev,tn,i,0); 
    5290 +                               } 
    5291 + 
    5292 +                       } 
    5293 +                       return (i < 0) ? 1 : 0; 
    5294 + 
    5295 +               } 
    5296 + 
    5297 +       } 
    5298 + 
    5299 +       return 1; 
    5300 + 
    5301 +} 
    5302 + 
    5303 +static void yaffs_SoftDeleteChunk(yaffs_Device * dev, int chunk) 
    5304 +{ 
    5305 + 
    5306 +       yaffs_BlockInfo *theBlock; 
    5307 + 
    5308 +       T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk)); 
    5309 + 
    5310 +       theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock); 
    5311 +       if (theBlock) { 
    5312 +               theBlock->softDeletions++; 
    5313 +               dev->nFreeChunks++; 
    5314 +       } 
    5315 +} 
    5316 + 
    5317 +/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file. 
    5318 + * All soft deleting does is increment the block's softdelete count and pulls the chunk out 
    5319 + * of the tnode. 
    5320 + * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted. 
    5321 + */ 
    5322 +  
    5323 +static int yaffs_SoftDeleteWorker(yaffs_Object * in, yaffs_Tnode * tn, 
    5324 +                                 __u32 level, int chunkOffset) 
    5325 +{ 
    5326 +       int i; 
    5327 +       int theChunk; 
    5328 +       int allDone = 1; 
    5329 +       yaffs_Device *dev = in->myDev; 
    5330 + 
    5331 +       if (tn) { 
    5332 +               if (level > 0) { 
    5333 + 
    5334 +                       for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0; 
    5335 +                            i--) { 
    5336 +                               if (tn->internal[i]) { 
    5337 +                                       allDone = 
    5338 +                                           yaffs_SoftDeleteWorker(in, 
    5339 +                                                                  tn-> 
    5340 +                                                                  internal[i], 
    5341 +                                                                  level - 1, 
    5342 +                                                                  (chunkOffset 
    5343 +                                                                   << 
    5344 +                                                                   YAFFS_TNODES_INTERNAL_BITS) 
    5345 +                                                                  + i); 
    5346 +                                       if (allDone) { 
    5347 +                                               yaffs_FreeTnode(dev, 
    5348 +                                                               tn-> 
    5349 +                                                               internal[i]); 
    5350 +                                               tn->internal[i] = NULL; 
    5351 +                                       } else { 
    5352 +                                               /* Hoosterman... how could this happen? */ 
    5353 +                                       } 
    5354 +                               } 
    5355 +                       } 
    5356 +                       return (allDone) ? 1 : 0; 
    5357 +               } else if (level == 0) { 
    5358 + 
    5359 +                       for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) { 
    5360 +                               theChunk = yaffs_GetChunkGroupBase(dev,tn,i); 
    5361 +                               if (theChunk) { 
    5362 +                                       /* Note this does not find the real chunk, only the chunk group. 
    5363 +                                        * We make an assumption that a chunk group is not larger than  
    5364 +                                        * a block. 
    5365 +                                        */ 
    5366 +                                       yaffs_SoftDeleteChunk(dev, theChunk); 
    5367 +                                       yaffs_PutLevel0Tnode(dev,tn,i,0); 
    5368 +                               } 
    5369 + 
    5370 +                       } 
    5371 +                       return 1; 
    5372 + 
    5373 +               } 
    5374 + 
    5375 +       } 
    5376 + 
    5377 +       return 1; 
    5378 + 
    5379 +} 
    5380 + 
    5381 +static void yaffs_SoftDeleteFile(yaffs_Object * obj) 
    5382 +{ 
    5383 +       if (obj->deleted && 
    5384 +           obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) { 
    5385 +               if (obj->nDataChunks <= 0) { 
    5386 +                       /* Empty file with no duplicate object headers, just delete it immediately */ 
    5387 +                       yaffs_FreeTnode(obj->myDev, 
    5388 +                                       obj->variant.fileVariant.top); 
    5389 +                       obj->variant.fileVariant.top = NULL; 
    5390 +                       T(YAFFS_TRACE_TRACING, 
    5391 +                         (TSTR("yaffs: Deleting empty file %d" TENDSTR), 
    5392 +                          obj->objectId)); 
    5393 +                       yaffs_DoGenericObjectDeletion(obj); 
    5394 +               } else { 
    5395 +                       yaffs_SoftDeleteWorker(obj, 
    5396 +                                              obj->variant.fileVariant.top, 
    5397 +                                              obj->variant.fileVariant. 
    5398 +                                              topLevel, 0); 
    5399 +                       obj->softDeleted = 1; 
    5400 +               } 
    5401 +       } 
    5402 +} 
    5403 + 
    5404 +/* Pruning removes any part of the file structure tree that is beyond the 
    5405 + * bounds of the file (ie that does not point to chunks). 
    5406 + * 
    5407 + * A file should only get pruned when its size is reduced. 
    5408 + * 
    5409 + * Before pruning, the chunks must be pulled from the tree and the 
    5410 + * level 0 tnode entries must be zeroed out. 
    5411 + * Could also use this for file deletion, but that's probably better handled 
    5412 + * by a special case. 
    5413 + */ 
    5414 + 
    5415 +static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device * dev, yaffs_Tnode * tn, 
    5416 +                                     __u32 level, int del0) 
    5417 +{ 
    5418 +       int i; 
    5419 +       int hasData; 
    5420 + 
    5421 +       if (tn) { 
    5422 +               hasData = 0; 
    5423 + 
    5424 +               for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) { 
    5425 +                       if (tn->internal[i] && level > 0) { 
    5426 +                               tn->internal[i] = 
    5427 +                                   yaffs_PruneWorker(dev, tn->internal[i], 
    5428 +                                                     level - 1, 
    5429 +                                                     (i == 0) ? del0 : 1); 
    5430 +                       } 
    5431 + 
    5432 +                       if (tn->internal[i]) { 
    5433 +                               hasData++; 
    5434 +                       } 
    5435 +               } 
    5436 + 
    5437 +               if (hasData == 0 && del0) { 
    5438 +                       /* Free and return NULL */ 
    5439 + 
    5440 +                       yaffs_FreeTnode(dev, tn); 
    5441 +                       tn = NULL; 
    5442 +               } 
    5443 + 
    5444 +       } 
    5445 + 
    5446 +       return tn; 
    5447 + 
    5448 +} 
    5449 + 
    5450 +static int yaffs_PruneFileStructure(yaffs_Device * dev, 
    5451 +                                   yaffs_FileStructure * fStruct) 
    5452 +{ 
    5453 +       int i; 
    5454 +       int hasData; 
    5455 +       int done = 0; 
    5456 +       yaffs_Tnode *tn; 
    5457 + 
    5458 +       if (fStruct->topLevel > 0) { 
    5459 +               fStruct->top = 
    5460 +                   yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0); 
    5461 + 
    5462 +               /* Now we have a tree with all the non-zero branches NULL but the height 
    5463 +                * is the same as it was. 
    5464 +                * Let's see if we can trim internal tnodes to shorten the tree. 
    5465 +                * We can do this if only the 0th element in the tnode is in use  
    5466 +                * (ie all the non-zero are NULL) 
    5467 +                */ 
    5468 + 
    5469 +               while (fStruct->topLevel && !done) { 
    5470 +                       tn = fStruct->top; 
    5471 + 
    5472 +                       hasData = 0; 
    5473 +                       for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) { 
    5474 +                               if (tn->internal[i]) { 
    5475 +                                       hasData++; 
    5476 +                               } 
    5477 +                       } 
    5478 + 
    5479 +                       if (!hasData) { 
    5480 +                               fStruct->top = tn->internal[0]; 
    5481 +                               fStruct->topLevel--; 
    5482 +                               yaffs_FreeTnode(dev, tn); 
    5483 +                       } else { 
    5484 +                               done = 1; 
    5485 +                       } 
    5486 +               } 
    5487 +       } 
    5488 + 
    5489 +       return YAFFS_OK; 
    5490 +} 
    5491 + 
    5492 +/*-------------------- End of File Structure functions.-------------------*/ 
    5493 + 
    5494 +/* yaffs_CreateFreeObjects creates a bunch more objects and 
    5495 + * adds them to the object free list. 
    5496 + */ 
    5497 +static int yaffs_CreateFreeObjects(yaffs_Device * dev, int nObjects) 
    5498 +{ 
    5499 +       int i; 
    5500 +       yaffs_Object *newObjects; 
    5501 +       yaffs_ObjectList *list; 
    5502 + 
    5503 +       if (nObjects < 1) 
    5504 +               return YAFFS_OK; 
    5505 + 
    5506 +       /* make these things */ 
    5507 +       newObjects = YMALLOC(nObjects * sizeof(yaffs_Object)); 
    5508 +       list = YMALLOC(sizeof(yaffs_ObjectList)); 
    5509 + 
    5510 +       if (!newObjects || !list) { 
    5511 +               if(newObjects) 
    5512 +                       YFREE(newObjects); 
    5513 +               if(list) 
    5514 +                       YFREE(list); 
    5515 +               T(YAFFS_TRACE_ALLOCATE, 
    5516 +                 (TSTR("yaffs: Could not allocate more objects" TENDSTR))); 
    5517 +               return YAFFS_FAIL; 
    5518 +       } 
    5519 +        
    5520 +       /* Hook them into the free list */ 
    5521 +       for (i = 0; i < nObjects - 1; i++) { 
    5522 +               newObjects[i].siblings.next = 
    5523 +                   (struct list_head *)(&newObjects[i + 1]); 
    5524 +       } 
    5525 + 
    5526 +       newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects; 
    5527 +       dev->freeObjects = newObjects; 
    5528 +       dev->nFreeObjects += nObjects; 
    5529 +       dev->nObjectsCreated += nObjects; 
    5530 + 
    5531 +       /* Now add this bunch of Objects to a list for freeing up. */ 
    5532 + 
    5533 +       list->objects = newObjects; 
    5534 +       list->next = dev->allocatedObjectList; 
    5535 +       dev->allocatedObjectList = list; 
    5536 + 
    5537 +       return YAFFS_OK; 
    5538 +} 
    5539 + 
    5540 + 
    5541 +/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */ 
    5542 +static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device * dev) 
    5543 +{ 
    5544 +       yaffs_Object *tn = NULL; 
    5545 + 
    5546 +       /* If there are none left make more */ 
    5547 +       if (!dev->freeObjects) { 
    5548 +               yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS); 
    5549 +       } 
    5550 + 
    5551 +       if (dev->freeObjects) { 
    5552 +               tn = dev->freeObjects; 
    5553 +               dev->freeObjects = 
    5554 +                   (yaffs_Object *) (dev->freeObjects->siblings.next); 
    5555 +               dev->nFreeObjects--; 
    5556 + 
    5557 +               /* Now sweeten it up... */ 
    5558 + 
    5559 +               memset(tn, 0, sizeof(yaffs_Object)); 
    5560 +               tn->myDev = dev; 
    5561 +               tn->chunkId = -1; 
    5562 +               tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN; 
    5563 +               INIT_LIST_HEAD(&(tn->hardLinks)); 
    5564 +               INIT_LIST_HEAD(&(tn->hashLink)); 
    5565 +               INIT_LIST_HEAD(&tn->siblings); 
    5566 + 
    5567 +               /* Add it to the lost and found directory. 
    5568 +                * NB Can't put root or lostNFound in lostNFound so 
    5569 +                * check if lostNFound exists first 
    5570 +                */ 
    5571 +               if (dev->lostNFoundDir) { 
    5572 +                       yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn); 
    5573 +               } 
    5574 +       } 
    5575 + 
    5576 +       return tn; 
    5577 +} 
    5578 + 
    5579 +static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device * dev, int number, 
    5580 +                                              __u32 mode) 
    5581 +{ 
    5582 + 
    5583 +       yaffs_Object *obj = 
    5584 +           yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY); 
    5585 +       if (obj) { 
    5586 +               obj->fake = 1;          /* it is fake so it has no NAND presence... */ 
    5587 +               obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */ 
    5588 +               obj->unlinkAllowed = 0; /* ... or unlink it */ 
    5589 +               obj->deleted = 0; 
    5590 +               obj->unlinked = 0; 
    5591 +               obj->yst_mode = mode; 
    5592 +               obj->myDev = dev; 
    5593 +               obj->chunkId = 0;       /* Not a valid chunk. */ 
    5594 +       } 
    5595 + 
    5596 +       return obj; 
    5597 + 
    5598 +} 
    5599 + 
    5600 +static void yaffs_UnhashObject(yaffs_Object * tn) 
    5601 +{ 
    5602 +       int bucket; 
    5603 +       yaffs_Device *dev = tn->myDev; 
    5604 + 
    5605 +       /* If it is still linked into the bucket list, free from the list */ 
    5606 +       if (!list_empty(&tn->hashLink)) { 
    5607 +               list_del_init(&tn->hashLink); 
    5608 +               bucket = yaffs_HashFunction(tn->objectId); 
    5609 +               dev->objectBucket[bucket].count--; 
    5610 +       } 
    5611 + 
    5612 +} 
    5613 + 
    5614 +/*  FreeObject frees up a Object and puts it back on the free list */ 
    5615 +static void yaffs_FreeObject(yaffs_Object * tn) 
    5616 +{ 
    5617 + 
    5618 +       yaffs_Device *dev = tn->myDev; 
    5619 + 
    5620 +#ifdef  __KERNEL__ 
    5621 +       if (tn->myInode) { 
    5622 +               /* We're still hooked up to a cached inode. 
    5623 +                * Don't delete now, but mark for later deletion 
    5624 +                */ 
    5625 +               tn->deferedFree = 1; 
    5626 +               return; 
    5627 +       } 
    5628 +#endif 
    5629 + 
    5630 +       yaffs_UnhashObject(tn); 
    5631 + 
    5632 +       /* Link into the free list. */ 
    5633 +       tn->siblings.next = (struct list_head *)(dev->freeObjects); 
    5634 +       dev->freeObjects = tn; 
    5635 +       dev->nFreeObjects++; 
    5636 +} 
    5637 + 
    5638 +#ifdef __KERNEL__ 
    5639 + 
    5640 +void yaffs_HandleDeferedFree(yaffs_Object * obj) 
    5641 +{ 
    5642 +       if (obj->deferedFree) { 
    5643 +               yaffs_FreeObject(obj); 
    5644 +       } 
    5645 +} 
    5646 + 
    5647 +#endif 
    5648 + 
    5649 +static void yaffs_DeinitialiseObjects(yaffs_Device * dev) 
    5650 +{ 
    5651 +       /* Free the list of allocated Objects */ 
    5652 + 
    5653 +       yaffs_ObjectList *tmp; 
    5654 + 
    5655 +       while (dev->allocatedObjectList) { 
    5656 +               tmp = dev->allocatedObjectList->next; 
    5657 +               YFREE(dev->allocatedObjectList->objects); 
    5658 +               YFREE(dev->allocatedObjectList); 
    5659 + 
    5660 +               dev->allocatedObjectList = tmp; 
    5661 +       } 
    5662 + 
    5663 +       dev->freeObjects = NULL; 
    5664 +       dev->nFreeObjects = 0; 
    5665 +} 
    5666 + 
    5667 +static void yaffs_InitialiseObjects(yaffs_Device * dev) 
    5668 +{ 
    5669 +       int i; 
    5670 + 
    5671 +       dev->allocatedObjectList = NULL; 
    5672 +       dev->freeObjects = NULL; 
    5673 +       dev->nFreeObjects = 0; 
    5674 + 
    5675 +       for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { 
    5676 +               INIT_LIST_HEAD(&dev->objectBucket[i].list); 
    5677 +               dev->objectBucket[i].count = 0; 
    5678 +       } 
    5679 + 
    5680 +} 
    5681 + 
    5682 +static int yaffs_FindNiceObjectBucket(yaffs_Device * dev) 
    5683 +{ 
    5684 +       static int x = 0; 
    5685 +       int i; 
    5686 +       int l = 999; 
    5687 +       int lowest = 999999; 
    5688 + 
    5689 +       /* First let's see if we can find one that's empty. */ 
    5690 + 
    5691 +       for (i = 0; i < 10 && lowest > 0; i++) { 
    5692 +               x++; 
    5693 +               x %= YAFFS_NOBJECT_BUCKETS; 
    5694 +               if (dev->objectBucket[x].count < lowest) { 
    5695 +                       lowest = dev->objectBucket[x].count; 
    5696 +                       l = x; 
    5697 +               } 
    5698 + 
    5699 +       } 
    5700 + 
    5701 +       /* If we didn't find an empty list, then try 
    5702 +        * looking a bit further for a short one 
    5703 +        */ 
    5704 + 
    5705 +       for (i = 0; i < 10 && lowest > 3; i++) { 
    5706 +               x++; 
    5707 +               x %= YAFFS_NOBJECT_BUCKETS; 
    5708 +               if (dev->objectBucket[x].count < lowest) { 
    5709 +                       lowest = dev->objectBucket[x].count; 
    5710 +                       l = x; 
    5711 +               } 
    5712 + 
    5713 +       } 
    5714 + 
    5715 +       return l; 
    5716 +} 
    5717 + 
    5718 +static int yaffs_CreateNewObjectNumber(yaffs_Device * dev) 
    5719 +{ 
    5720 +       int bucket = yaffs_FindNiceObjectBucket(dev); 
    5721 + 
    5722 +       /* Now find an object value that has not already been taken 
    5723 +        * by scanning the list. 
    5724 +        */ 
    5725 + 
    5726 +       int found = 0; 
    5727 +       struct list_head *i; 
    5728 + 
    5729 +       __u32 n = (__u32) bucket; 
    5730 + 
    5731 +       /* yaffs_CheckObjectHashSanity();  */ 
    5732 + 
    5733 +       while (!found) { 
    5734 +               found = 1; 
    5735 +               n += YAFFS_NOBJECT_BUCKETS; 
    5736 +               if (1 || dev->objectBucket[bucket].count > 0) { 
    5737 +                       list_for_each(i, &dev->objectBucket[bucket].list) { 
    5738 +                               /* If there is already one in the list */ 
    5739 +                               if (i 
    5740 +                                   && list_entry(i, yaffs_Object, 
    5741 +                                                 hashLink)->objectId == n) { 
    5742 +                                       found = 0; 
    5743 +                               } 
    5744 +                       } 
    5745 +               } 
    5746 +       } 
    5747 + 
    5748 + 
    5749 +       return n; 
    5750 +} 
    5751 + 
    5752 +static void yaffs_HashObject(yaffs_Object * in) 
    5753 +{ 
    5754 +       int bucket = yaffs_HashFunction(in->objectId); 
    5755 +       yaffs_Device *dev = in->myDev; 
    5756 + 
    5757 +       list_add(&in->hashLink, &dev->objectBucket[bucket].list); 
    5758 +       dev->objectBucket[bucket].count++; 
    5759 + 
    5760 +} 
    5761 + 
    5762 +yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device * dev, __u32 number) 
    5763 +{ 
    5764 +       int bucket = yaffs_HashFunction(number); 
    5765 +       struct list_head *i; 
    5766 +       yaffs_Object *in; 
    5767 + 
    5768 +       list_for_each(i, &dev->objectBucket[bucket].list) { 
    5769 +               /* Look if it is in the list */ 
    5770 +               if (i) { 
    5771 +                       in = list_entry(i, yaffs_Object, hashLink); 
    5772 +                       if (in->objectId == number) { 
    5773 +#ifdef __KERNEL__ 
    5774 +                               /* Don't tell the VFS about this one if it is defered free */ 
    5775 +                               if (in->deferedFree) 
    5776 +                                       return NULL; 
    5777 +#endif 
    5778 + 
    5779 +                               return in; 
    5780 +                       } 
    5781 +               } 
    5782 +       } 
    5783 + 
    5784 +       return NULL; 
    5785 +} 
    5786 + 
    5787 +yaffs_Object *yaffs_CreateNewObject(yaffs_Device * dev, int number, 
    5788 +                                   yaffs_ObjectType type) 
    5789 +{ 
    5790 + 
    5791 +       yaffs_Object *theObject; 
    5792 +       yaffs_Tnode *tn; 
    5793 + 
    5794 +       if (number < 0) { 
    5795 +               number = yaffs_CreateNewObjectNumber(dev); 
    5796 +       } 
    5797 + 
    5798 +       theObject = yaffs_AllocateEmptyObject(dev); 
    5799 +       if(!theObject) 
    5800 +               return NULL; 
    5801 +                
    5802 +       if(type == YAFFS_OBJECT_TYPE_FILE){ 
    5803 +               tn = yaffs_GetTnode(dev); 
    5804 +               if(!tn){ 
    5805 +                       yaffs_FreeObject(theObject); 
    5806 +                       return NULL; 
    5807 +               } 
    5808 +       } 
    5809 +                
    5810 +        
    5811 + 
    5812 +       if (theObject) { 
    5813 +               theObject->fake = 0; 
    5814 +               theObject->renameAllowed = 1; 
    5815 +               theObject->unlinkAllowed = 1; 
    5816 +               theObject->objectId = number; 
    5817 +               yaffs_HashObject(theObject); 
    5818 +               theObject->variantType = type; 
    5819 +#ifdef CONFIG_YAFFS_WINCE 
    5820 +               yfsd_WinFileTimeNow(theObject->win_atime); 
    5821 +               theObject->win_ctime[0] = theObject->win_mtime[0] = 
    5822 +                   theObject->win_atime[0]; 
    5823 +               theObject->win_ctime[1] = theObject->win_mtime[1] = 
    5824 +                   theObject->win_atime[1]; 
    5825 + 
    5826 +#else 
    5827 + 
    5828 +               theObject->yst_atime = theObject->yst_mtime = 
    5829 +                   theObject->yst_ctime = Y_CURRENT_TIME; 
    5830 +#endif 
    5831 +               switch (type) { 
    5832 +               case YAFFS_OBJECT_TYPE_FILE: 
    5833 +                       theObject->variant.fileVariant.fileSize = 0; 
    5834 +                       theObject->variant.fileVariant.scannedFileSize = 0; 
    5835 +                       theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */ 
    5836 +                       theObject->variant.fileVariant.topLevel = 0; 
    5837 +                       theObject->variant.fileVariant.top = tn; 
    5838 +                       break; 
    5839 +               case YAFFS_OBJECT_TYPE_DIRECTORY: 
    5840 +                       INIT_LIST_HEAD(&theObject->variant.directoryVariant. 
    5841 +                                      children); 
    5842 +                       break; 
    5843 +               case YAFFS_OBJECT_TYPE_SYMLINK: 
    5844 +               case YAFFS_OBJECT_TYPE_HARDLINK: 
    5845 +               case YAFFS_OBJECT_TYPE_SPECIAL: 
    5846 +                       /* No action required */ 
    5847 +                       break; 
    5848 +               case YAFFS_OBJECT_TYPE_UNKNOWN: 
    5849 +                       /* todo this should not happen */ 
    5850 +                       break; 
    5851 +               } 
    5852 +       } 
    5853 + 
    5854 +       return theObject; 
    5855 +} 
    5856 + 
    5857 +static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device * dev, 
    5858 +                                                     int number, 
    5859 +                                                     yaffs_ObjectType type) 
    5860 +{ 
    5861 +       yaffs_Object *theObject = NULL; 
    5862 + 
    5863 +       if (number > 0) { 
    5864 +               theObject = yaffs_FindObjectByNumber(dev, number); 
    5865 +       } 
    5866 + 
    5867 +       if (!theObject) { 
    5868 +               theObject = yaffs_CreateNewObject(dev, number, type); 
    5869 +       } 
    5870 + 
    5871 +       return theObject; 
    5872 + 
    5873 +} 
    5874 +                        
    5875 + 
    5876 +static YCHAR *yaffs_CloneString(const YCHAR * str) 
    5877 +{ 
    5878 +       YCHAR *newStr = NULL; 
    5879 + 
    5880 +       if (str && *str) { 
    5881 +               newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR)); 
    5882 +               if(newStr) 
    5883 +                       yaffs_strcpy(newStr, str); 
    5884 +       } 
    5885 + 
    5886 +       return newStr; 
    5887 + 
    5888 +} 
    5889 + 
    5890 +/* 
    5891 + * Mknod (create) a new object. 
    5892 + * equivalentObject only has meaning for a hard link; 
    5893 + * aliasString only has meaning for a sumlink. 
    5894 + * rdev only has meaning for devices (a subset of special objects) 
    5895 + */ 
    5896 +  
    5897 +static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type, 
    5898 +                                      yaffs_Object * parent, 
    5899 +                                      const YCHAR * name, 
    5900 +                                      __u32 mode, 
    5901 +                                      __u32 uid, 
    5902 +                                      __u32 gid, 
    5903 +                                      yaffs_Object * equivalentObject, 
    5904 +                                      const YCHAR * aliasString, __u32 rdev) 
    5905 +{ 
    5906 +       yaffs_Object *in; 
    5907 +       YCHAR *str; 
    5908 + 
    5909 +       yaffs_Device *dev = parent->myDev; 
    5910 + 
    5911 +       /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/ 
    5912 +       if (yaffs_FindObjectByName(parent, name)) { 
    5913 +               return NULL; 
    5914 +       } 
    5915 + 
    5916 +       in = yaffs_CreateNewObject(dev, -1, type); 
    5917 +        
    5918 +       if(type == YAFFS_OBJECT_TYPE_SYMLINK){ 
    5919 +               str = yaffs_CloneString(aliasString); 
    5920 +               if(!str){ 
    5921 +                       yaffs_FreeObject(in); 
    5922 +                       return NULL; 
    5923 +               } 
    5924 +       } 
    5925 +        
    5926 +        
    5927 + 
    5928 +       if (in) { 
    5929 +               in->chunkId = -1; 
    5930 +               in->valid = 1; 
    5931 +               in->variantType = type; 
    5932 + 
    5933 +               in->yst_mode = mode; 
    5934 + 
    5935 +#ifdef CONFIG_YAFFS_WINCE 
    5936 +               yfsd_WinFileTimeNow(in->win_atime); 
    5937 +               in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0]; 
    5938 +               in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1]; 
    5939 + 
    5940 +#else 
    5941 +               in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME; 
    5942 + 
    5943 +               in->yst_rdev = rdev; 
    5944 +               in->yst_uid = uid; 
    5945 +               in->yst_gid = gid; 
    5946 +#endif 
    5947 +               in->nDataChunks = 0; 
    5948 + 
    5949 +               yaffs_SetObjectName(in, name); 
    5950 +               in->dirty = 1; 
    5951 + 
    5952 +               yaffs_AddObjectToDirectory(parent, in); 
    5953 + 
    5954 +               in->myDev = parent->myDev; 
    5955 + 
    5956 +               switch (type) { 
    5957 +               case YAFFS_OBJECT_TYPE_SYMLINK: 
    5958 +                       in->variant.symLinkVariant.alias = str; 
    5959 +                       break; 
    5960 +               case YAFFS_OBJECT_TYPE_HARDLINK: 
    5961 +                       in->variant.hardLinkVariant.equivalentObject = 
    5962 +                           equivalentObject; 
    5963 +                       in->variant.hardLinkVariant.equivalentObjectId = 
    5964 +                           equivalentObject->objectId; 
    5965 +                       list_add(&in->hardLinks, &equivalentObject->hardLinks); 
    5966 +                       break; 
    5967 +               case YAFFS_OBJECT_TYPE_FILE:     
    5968 +               case YAFFS_OBJECT_TYPE_DIRECTORY: 
    5969 +               case YAFFS_OBJECT_TYPE_SPECIAL: 
    5970 +               case YAFFS_OBJECT_TYPE_UNKNOWN: 
    5971 +                       /* do nothing */ 
    5972 +                       break; 
    5973 +               } 
    5974 + 
    5975 +               if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) { 
    5976 +                       /* Could not create the object header, fail the creation */ 
    5977 +                       yaffs_DestroyObject(in); 
    5978 +                       in = NULL; 
    5979 +               } 
    5980 + 
    5981 +       } 
    5982 + 
    5983 +       return in; 
    5984 +} 
    5985 + 
    5986 +yaffs_Object *yaffs_MknodFile(yaffs_Object * parent, const YCHAR * name, 
    5987 +                             __u32 mode, __u32 uid, __u32 gid) 
    5988 +{ 
    5989 +       return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode, 
    5990 +                                uid, gid, NULL, NULL, 0); 
    5991 +} 
    5992 + 
    5993 +yaffs_Object *yaffs_MknodDirectory(yaffs_Object * parent, const YCHAR * name, 
    5994 +                                  __u32 mode, __u32 uid, __u32 gid) 
    5995 +{ 
    5996 +       return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name, 
    5997 +                                mode, uid, gid, NULL, NULL, 0); 
    5998 +} 
    5999 + 
    6000 +yaffs_Object *yaffs_MknodSpecial(yaffs_Object * parent, const YCHAR * name, 
    6001 +                                __u32 mode, __u32 uid, __u32 gid, __u32 rdev) 
    6002 +{ 
    6003 +       return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode, 
    6004 +                                uid, gid, NULL, NULL, rdev); 
    6005 +} 
    6006 + 
    6007 +yaffs_Object *yaffs_MknodSymLink(yaffs_Object * parent, const YCHAR * name, 
    6008 +                                __u32 mode, __u32 uid, __u32 gid, 
    6009 +                                const YCHAR * alias) 
    6010 +{ 
    6011 +       return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode, 
    6012 +                                uid, gid, NULL, alias, 0); 
    6013 +} 
    6014 + 
    6015 +/* yaffs_Link returns the object id of the equivalent object.*/ 
    6016 +yaffs_Object *yaffs_Link(yaffs_Object * parent, const YCHAR * name, 
    6017 +                        yaffs_Object * equivalentObject) 
    6018 +{ 
    6019 +       /* Get the real object in case we were fed a hard link as an equivalent object */ 
    6020 +       equivalentObject = yaffs_GetEquivalentObject(equivalentObject); 
    6021 + 
    6022 +       if (yaffs_MknodObject 
    6023 +           (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0, 
    6024 +            equivalentObject, NULL, 0)) { 
    6025 +               return equivalentObject; 
    6026 +       } else { 
    6027 +               return NULL; 
    6028 +       } 
    6029 + 
    6030 +} 
    6031 + 
    6032 +static int yaffs_ChangeObjectName(yaffs_Object * obj, yaffs_Object * newDir, 
    6033 +                                 const YCHAR * newName, int force, int shadows) 
    6034 +{ 
    6035 +       int unlinkOp; 
    6036 +       int deleteOp; 
    6037 + 
    6038 +       yaffs_Object *existingTarget; 
    6039 + 
    6040 +       if (newDir == NULL) { 
    6041 +               newDir = obj->parent;   /* use the old directory */ 
    6042 +       } 
    6043 + 
    6044 +       if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { 
    6045 +               T(YAFFS_TRACE_ALWAYS, 
    6046 +                 (TSTR 
    6047 +                  ("tragendy: yaffs_ChangeObjectName: newDir is not a directory" 
    6048 +                   TENDSTR))); 
    6049 +               YBUG(); 
    6050 +       } 
    6051 +        
    6052 +       /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */ 
    6053 +       if (obj->myDev->isYaffs2) { 
    6054 +               unlinkOp = (newDir == obj->myDev->unlinkedDir); 
    6055 +       } else { 
    6056 +               unlinkOp = (newDir == obj->myDev->unlinkedDir 
    6057 +                           && obj->variantType == YAFFS_OBJECT_TYPE_FILE); 
    6058 +       } 
    6059 + 
    6060 +       deleteOp = (newDir == obj->myDev->deletedDir); 
    6061 + 
    6062 +       existingTarget = yaffs_FindObjectByName(newDir, newName); 
    6063 + 
    6064 +       /* If the object is a file going into the unlinked directory,  
    6065 +        *   then it is OK to just stuff it in since duplicate names are allowed. 
    6066 +        *   else only proceed if the new name does not exist and if we're putting  
    6067 +        *   it into a directory. 
    6068 +        */ 
    6069 +       if ((unlinkOp || 
    6070 +            deleteOp || 
    6071 +            force || 
    6072 +            (shadows > 0) || 
    6073 +            !existingTarget) && 
    6074 +           newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) { 
    6075 +               yaffs_SetObjectName(obj, newName); 
    6076 +               obj->dirty = 1; 
    6077 + 
    6078 +               yaffs_AddObjectToDirectory(newDir, obj); 
    6079 + 
    6080 +               if (unlinkOp) 
    6081 +                       obj->unlinked = 1; 
    6082 + 
    6083 +               /* If it is a deletion then we mark it as a shrink for gc purposes. */ 
    6084 +               if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows)>= 0) 
    6085 +                       return YAFFS_OK; 
    6086 +       } 
    6087 + 
    6088 +       return YAFFS_FAIL; 
    6089 +} 
    6090 + 
    6091 +int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName, 
    6092 +                      yaffs_Object * newDir, const YCHAR * newName) 
    6093 +{ 
    6094 +       yaffs_Object *obj; 
    6095 +       yaffs_Object *existingTarget; 
    6096 +       int force = 0; 
    6097 + 
    6098 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE 
    6099 +       /* Special case for case insemsitive systems (eg. WinCE). 
    6100 +        * While look-up is case insensitive, the name isn't. 
    6101 +        * Therefore we might want to change x.txt to X.txt 
    6102 +       */ 
    6103 +       if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0) { 
    6104 +               force = 1; 
    6105 +       } 
    6106 +#endif 
    6107 + 
    6108 +       obj = yaffs_FindObjectByName(oldDir, oldName); 
    6109 +       /* Check new name to long. */ 
    6110 +       if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK && 
    6111 +           yaffs_strlen(newName) > YAFFS_MAX_ALIAS_LENGTH) 
    6112 +         /* ENAMETOOLONG */ 
    6113 +         return YAFFS_FAIL; 
    6114 +       else if (obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK && 
    6115 +                yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH) 
    6116 +         /* ENAMETOOLONG */ 
    6117 +         return YAFFS_FAIL; 
    6118 + 
    6119 +       if (obj && obj->renameAllowed) { 
    6120 + 
    6121 +               /* Now do the handling for an existing target, if there is one */ 
    6122 + 
    6123 +               existingTarget = yaffs_FindObjectByName(newDir, newName); 
    6124 +               if (existingTarget && 
    6125 +                   existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && 
    6126 +                   !list_empty(&existingTarget->variant.directoryVariant.children)) { 
    6127 +                       /* There is a target that is a non-empty directory, so we fail */ 
    6128 +                       return YAFFS_FAIL;      /* EEXIST or ENOTEMPTY */ 
    6129 +               } else if (existingTarget && existingTarget != obj) { 
    6130 +                       /* Nuke the target first, using shadowing,  
    6131 +                        * but only if it isn't the same object 
    6132 +                        */