Add NAND flash/YAFFS2 patches for RB532 by David Goodenough
[openwrt.git] / target / linux / rb532-2.6 / patches / 510-Yaffs.patch
1 diff --git a/fs/Kconfig b/fs/Kconfig
2 index f9b5842..556f12a 100644
3 --- a/fs/Kconfig
4 +++ b/fs/Kconfig
5 @@ -1022,6 +1022,15 @@ config EFS_FS
6           To compile the EFS file system support as a module, choose M here: the
7           module will be called efs.
8  
9 +config YAFFS_FS
10 +       tristate "Yet Another Flash File System (YAFFS) support"
11 +       depends on MTD
12 +       help
13 +         JFFS is the Journaling Flash File System developed by Axis
14 +         Communications in Sweden, aimed at providing a crash/powerdown-safe
15 +         file system for disk-less embedded devices. Further information is
16 +         available at (<http://developer.axis.com/software/jffs/>).
17 +
18  config JFFS_FS
19         tristate "Journalling Flash File System (JFFS) support"
20         depends on MTD
21 diff --git a/fs/Makefile b/fs/Makefile
22 index 078d3d1..2062d2f 100644
23 --- a/fs/Makefile
24 +++ b/fs/Makefile
25 @@ -84,6 +85,7 @@ obj-$(CONFIG_UFS_FS)          += ufs/
26  obj-$(CONFIG_EFS_FS)           += efs/
27  obj-$(CONFIG_JFFS_FS)          += jffs/
28  obj-$(CONFIG_JFFS2_FS)         += jffs2/
29 +obj-$(CONFIG_YAFFS_FS)         += yaffs/
30  obj-$(CONFIG_AFFS_FS)          += affs/
31  obj-$(CONFIG_ROMFS_FS)         += romfs/
32  obj-$(CONFIG_QNX4FS_FS)                += qnx4/
33 diff --git a/fs/yaffs/Makefile b/fs/yaffs/Makefile
34 new file mode 100644
35 index 0000000..615c2b2
36 --- /dev/null
37 +++ b/fs/yaffs/Makefile
38 @@ -0,0 +1,18 @@
39 +#
40 +# Makefile for the Linux msdos filesystem routines.
41 +#
42 +# Note! Dependencies are done automagically by 'make dep', which also
43 +# removes any old dependencies. DON'T put your own dependencies here
44 +# unless it's something special (ie not a .c file).
45 +#
46 +# Note 2! The CFLAGS definitions are now in the main makefile.
47 +
48 +
49 +EXTRA_CFLAGS += -DCONFIG_YAFFS_YAFFS1 -DCONFIG_YAFFS_YAFFS2
50 +
51 +
52 +obj-$(CONFIG_YAFFS_FS) += yaffs.o
53 +
54 +yaffs-y = yaffs_fs.o yaffs_guts.o yaffs_mtdif.o yaffs_tagscompat.o \
55 +        yaffs_packedtags2.o yaffs_mtdif2.o yaffs_tagsvalidity.o \
56 +       yaffs_ecc.o
57 diff --git a/fs/yaffs/devextras.h b/fs/yaffs/devextras.h
58 new file mode 100644
59 index 0000000..752c2cc
60 --- /dev/null
61 +++ b/fs/yaffs/devextras.h
62 @@ -0,0 +1,271 @@
63 +/*
64 + * YAFFS: Yet another FFS. A NAND-flash specific file system. 
65 + * devextras.h
66 + *
67 + * Copyright (C) 2002 Aleph One Ltd.
68 + *   for Toby Churchill Ltd and Brightstar Engineering
69 + *
70 + * Created by Charles Manning <charles@aleph1.co.uk>
71 + *
72 + * This program is free software; you can redistribute it and/or modify
73 + * it under the terms of the GNU Lesser General Public License version 2.1 as
74 + * published by the Free Software Foundation.
75 + *
76 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
77 + *
78 + * This file is just holds extra declarations used during development.
79 + * Most of these are from kernel includes placed here so we can use them in 
80 + * applications.
81 + *
82 + * $Id: devextras.h,v 1.1 2004/11/03 08:14:07 charles Exp $
83 + *
84 + */
85
86 +#ifndef __EXTRAS_H__
87 +#define __EXTRAS_H__
88 +
89 +#if defined WIN32
90 +#define __inline__ __inline
91 +#define new newHack
92 +#endif
93 +
94 +#if !(defined __KERNEL__) || (defined WIN32)
95 +
96 +// User space defines
97 +
98 +typedef unsigned char   __u8;
99 +typedef unsigned short  __u16;
100 +typedef unsigned        __u32;
101 +
102 +
103 +/*
104 + * Simple doubly linked list implementation.
105 + *
106 + * Some of the internal functions ("__xxx") are useful when
107 + * manipulating whole lists rather than single entries, as
108 + * sometimes we already know the next/prev entries and we can
109 + * generate better code by using them directly rather than
110 + * using the generic single-entry routines.
111 + */
112
113 + #define prefetch(x) 1
114
115 +
116 +struct list_head {
117 +       struct list_head *next, *prev;
118 +};
119 +
120 +#define LIST_HEAD_INIT(name) { &(name), &(name) }
121 +
122 +#define LIST_HEAD(name) \
123 +       struct list_head name = LIST_HEAD_INIT(name)
124 +
125 +#define INIT_LIST_HEAD(ptr) do { \
126 +       (ptr)->next = (ptr); (ptr)->prev = (ptr); \
127 +} while (0)
128 +
129 +/*
130 + * Insert a new entry between two known consecutive entries.
131 + *
132 + * This is only for internal list manipulation where we know
133 + * the prev/next entries already!
134 + */
135 +static __inline__ void __list_add(struct list_head * new,
136 +       struct list_head * prev,
137 +       struct list_head * next)
138 +{
139 +       next->prev = new;
140 +       new->next = next;
141 +       new->prev = prev;
142 +       prev->next = new;
143 +}
144 +
145 +/**
146 + * list_add - add a new entry
147 + * @new: new entry to be added
148 + * @head: list head to add it after
149 + *
150 + * Insert a new entry after the specified head.
151 + * This is good for implementing stacks.
152 + */
153 +static __inline__ void list_add(struct list_head *new, struct list_head *head)
154 +{
155 +       __list_add(new, head, head->next);
156 +}
157 +
158 +/**
159 + * list_add_tail - add a new entry
160 + * @new: new entry to be added
161 + * @head: list head to add it before
162 + *
163 + * Insert a new entry before the specified head.
164 + * This is useful for implementing queues.
165 + */
166 +static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
167 +{
168 +       __list_add(new, head->prev, head);
169 +}
170 +
171 +/*
172 + * Delete a list entry by making the prev/next entries
173 + * point to each other.
174 + *
175 + * This is only for internal list manipulation where we know
176 + * the prev/next entries already!
177 + */
178 +static __inline__ void __list_del(struct list_head * prev,
179 +                                 struct list_head * next)
180 +{
181 +       next->prev = prev;
182 +       prev->next = next;
183 +}
184 +
185 +/**
186 + * list_del - deletes entry from list.
187 + * @entry: the element to delete from the list.
188 + * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
189 + */
190 +static __inline__ void list_del(struct list_head *entry)
191 +{
192 +       __list_del(entry->prev, entry->next);
193 +}
194 +
195 +/**
196 + * list_del_init - deletes entry from list and reinitialize it.
197 + * @entry: the element to delete from the list.
198 + */
199 +static __inline__ void list_del_init(struct list_head *entry)
200 +{
201 +       __list_del(entry->prev, entry->next);
202 +       INIT_LIST_HEAD(entry);
203 +}
204 +
205 +/**
206 + * list_empty - tests whether a list is empty
207 + * @head: the list to test.
208 + */
209 +static __inline__ int list_empty(struct list_head *head)
210 +{
211 +       return head->next == head;
212 +}
213 +
214 +/**
215 + * list_splice - join two lists
216 + * @list: the new list to add.
217 + * @head: the place to add it in the first list.
218 + */
219 +static __inline__ void list_splice(struct list_head *list, struct list_head *head)
220 +{
221 +       struct list_head *first = list->next;
222 +
223 +       if (first != list) {
224 +               struct list_head *last = list->prev;
225 +               struct list_head *at = head->next;
226 +
227 +               first->prev = head;
228 +               head->next = first;
229 +
230 +               last->next = at;
231 +               at->prev = last;
232 +       }
233 +}
234 +
235 +/**
236 + * list_entry - get the struct for this entry
237 + * @ptr:       the &struct list_head pointer.
238 + * @type:      the type of the struct this is embedded in.
239 + * @member:    the name of the list_struct within the struct.
240 + */
241 +#define list_entry(ptr, type, member) \
242 +       ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
243 +
244 +/**
245 + * list_for_each       -       iterate over a list
246 + * @pos:       the &struct list_head to use as a loop counter.
247 + * @head:      the head for your list.
248 + */
249 +#define list_for_each(pos, head) \
250 +       for (pos = (head)->next, prefetch(pos->next); pos != (head); \
251 +               pos = pos->next, prefetch(pos->next))
252 +
253 +/**
254 + * list_for_each_safe  -       iterate over a list safe against removal of list entry
255 + * @pos:       the &struct list_head to use as a loop counter.
256 + * @n:         another &struct list_head to use as temporary storage
257 + * @head:      the head for your list.
258 + */
259 +#define list_for_each_safe(pos, n, head) \
260 +       for (pos = (head)->next, n = pos->next; pos != (head); \
261 +               pos = n, n = pos->next)
262 +
263 +
264 +
265 +
266 +/*
267 + * File types
268 + */
269 +#define DT_UNKNOWN     0
270 +#define DT_FIFO                1
271 +#define DT_CHR         2
272 +#define DT_DIR         4
273 +#define DT_BLK         6
274 +#define DT_REG         8
275 +#define DT_LNK         10
276 +#define DT_SOCK                12
277 +#define DT_WHT         14
278 +
279 +#ifndef WIN32
280 +#include <sys/stat.h>
281 +#endif
282 +
283 +/*
284 + * Attribute flags.  These should be or-ed together to figure out what
285 + * has been changed!
286 + */
287 +#define ATTR_MODE      1
288 +#define ATTR_UID       2
289 +#define ATTR_GID       4
290 +#define ATTR_SIZE      8
291 +#define ATTR_ATIME     16
292 +#define ATTR_MTIME     32
293 +#define ATTR_CTIME     64
294 +#define ATTR_ATIME_SET 128
295 +#define ATTR_MTIME_SET 256
296 +#define ATTR_FORCE     512     /* Not a change, but a change it */
297 +#define ATTR_ATTR_FLAG 1024
298 +
299 +
300 +struct iattr {
301 +       unsigned int    ia_valid;
302 +       unsigned                ia_mode;
303 +       unsigned                ia_uid;
304 +       unsigned                ia_gid;
305 +       unsigned                ia_size;
306 +       unsigned                ia_atime;
307 +       unsigned        ia_mtime;
308 +       unsigned        ia_ctime;
309 +       unsigned int    ia_attr_flags;
310 +};
311 +
312 +#define KERN_DEBUG
313 +
314 +
315 +#else
316 +
317 +#ifndef WIN32
318 +#include <linux/types.h>
319 +#include <linux/list.h>
320 +#include <linux/fs.h>
321 +#include <linux/stat.h>
322 +#endif
323 +
324 +#endif
325 +
326 +
327 +
328 +#if defined WIN32
329 +#undef new
330 +#endif 
331 +
332 +#endif
333 +
334 diff --git a/fs/yaffs/yaffs_ecc.c b/fs/yaffs/yaffs_ecc.c
335 new file mode 100644
336 index 0000000..166bcad
337 --- /dev/null
338 +++ b/fs/yaffs/yaffs_ecc.c
339 @@ -0,0 +1,287 @@
340 +/*
341 + * YAFFS: Yet another FFS. A NAND-flash specific file system. 
342 + *
343 + * yaffs_ecc.c: ECC generation/correction algorithms.
344 + *
345 + * Copyright (C) 2002 Aleph One Ltd.
346 + *
347 + * Created by Charles Manning <charles@aleph1.co.uk>
348 + *
349 + *
350 + * This program is free software; you can redistribute it and/or
351 + * modify it under the terms of the GNU Lesser General Public License
352 + * version 2.1 as published by the Free Software Foundation.
353 + */
354
355 + /*
356 + * This code implements the ECC algorithm used in SmartMedia.
357 + *
358 + * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. 
359 + * The two unused bit are set to 1.
360 + * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC 
361 + * blocks are used on a 512-byte NAND page.
362 + *
363 + */
364 +
365 +// Table generated by gen-ecc.c
366 +// Using a table means we do not have to calculate p1..p4 and p1'..p4'
367 +// for each byte of data. These are instead provided in a table in bits7..2.
368 +// Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore
369 +// this bytes influence on the line parity.
370 +
371 +const char *yaffs_ecc_c_version = "$Id: yaffs_ecc.c,v 1.4 2005/07/31 00:28:04 charles Exp $";
372 +
373 +#include "yportenv.h"
374 +
375 +#include "yaffs_ecc.h"
376 +
377 +static const unsigned char column_parity_table[] = {
378 +0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, 
379 +0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, 
380 +0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, 
381 +0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, 
382 +0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, 
383 +0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, 
384 +0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, 
385 +0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, 
386 +0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, 
387 +0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, 
388 +0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, 
389 +0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, 
390 +0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, 
391 +0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, 
392 +0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, 
393 +0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, 
394 +};
395 +
396 +
397 +static int yaffs_CountBits(unsigned char x)
398 +{
399 +       int r = 0;
400 +       while(x)
401 +       {
402 +               if(x & 1) r++;
403 +               x >>= 1;
404 +       }
405 +       return r;
406 +}
407 +
408 +static int yaffs_CountBits32(unsigned  x)
409 +{
410 +       int r = 0;
411 +       while(x)
412 +       {
413 +               if(x & 1) r++;
414 +               x >>= 1;
415 +       }
416 +       return r;
417 +}
418 +
419 +
420 +void yaffs_ECCCalculate(const unsigned char *data,unsigned char *ecc)
421 +{
422 +       unsigned int i;
423 +       
424 +       unsigned char col_parity = 0;
425 +       unsigned char line_parity = 0;
426 +       unsigned char line_parity_prime = 0;
427 +       unsigned char t;
428 +       unsigned char b;
429 +       
430 +       for(i = 0; i < 256; i++)
431 +       {
432 +               b = column_parity_table[*data++];
433 +               col_parity ^= b;
434 +
435 +               if(b & 0x01) // odd number of bits in the byte
436 +               {
437 +                       line_parity ^= i;
438 +                       line_parity_prime ^= ~i;
439 +               }
440 +               
441 +       }
442 +       
443 +       ecc[2] = (~col_parity) | 0x03;
444 +       
445 +       t = 0;
446 +       if(line_parity       & 0x80) t |= 0x80;
447 +       if(line_parity_prime & 0x80) t |= 0x40;
448 +       if(line_parity       & 0x40) t |= 0x20;
449 +       if(line_parity_prime & 0x40) t |= 0x10;
450 +       if(line_parity       & 0x20) t |= 0x08;
451 +       if(line_parity_prime & 0x20) t |= 0x04;
452 +       if(line_parity       & 0x10) t |= 0x02;
453 +       if(line_parity_prime & 0x10) t |= 0x01;
454 +       ecc[1] = ~t;
455 +       
456 +       t = 0;
457 +       if(line_parity       & 0x08) t |= 0x80;
458 +       if(line_parity_prime & 0x08) t |= 0x40;
459 +       if(line_parity       & 0x04) t |= 0x20;
460 +       if(line_parity_prime & 0x04) t |= 0x10;
461 +       if(line_parity       & 0x02) t |= 0x08;
462 +       if(line_parity_prime & 0x02) t |= 0x04;
463 +       if(line_parity       & 0x01) t |= 0x02;
464 +       if(line_parity_prime & 0x01) t |= 0x01;
465 +       ecc[0] = ~t;
466 +
467 +#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
468 +       // Swap the bytes into the wrong order
469 +       t = ecc[0];
470 +       ecc[0] = ecc[1];
471 +       ecc[1] = t;
472 +#endif 
473 +}
474 +
475 +int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc, const unsigned char *test_ecc)
476 +{
477 +       unsigned char d0, d1, d2; // deltas 
478 +
479 +       d0 = read_ecc[0] ^ test_ecc[0];
480 +       d1 = read_ecc[1] ^ test_ecc[1];
481 +       d2 = read_ecc[2] ^ test_ecc[2];
482 +       
483 +       
484 +       
485 +       if((d0 | d1 | d2) == 0)
486 +       {
487 +               // no error
488 +               return 0;
489 +       }
490 +       
491 +       if( ((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
492 +           ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
493 +           ((d2 ^ (d2 >> 1)) & 0x54) == 0x54)
494 +       {
495 +               // Single bit (recoverable) error in data
496 +
497 +               unsigned byte;
498 +               unsigned bit;
499 +
500 +#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
501 +               // swap the bytes to correct for the wrong order
502 +               unsigned char t;
503 +               
504 +               t = d0;
505 +               d0 = d1;
506 +               d1 = t;
507 +#endif
508 +               
509 +               bit = byte = 0;
510 +               
511 +               
512 +               if(d1 & 0x80) byte |= 0x80;
513 +               if(d1 & 0x20) byte |= 0x40;
514 +               if(d1 & 0x08) byte |= 0x20;
515 +               if(d1 & 0x02) byte |= 0x10;
516 +               if(d0 & 0x80) byte |= 0x08;
517 +               if(d0 & 0x20) byte |= 0x04;
518 +               if(d0 & 0x08) byte |= 0x02;
519 +               if(d0 & 0x02) byte |= 0x01;
520 +
521 +               if(d2 & 0x80) bit |= 0x04;
522 +               if(d2 & 0x20) bit |= 0x02;
523 +               if(d2 & 0x08) bit |= 0x01;
524 +
525 +               data[byte] ^= (1 << bit);
526 +               
527 +               return 1;
528 +       }
529 +       
530 +       if((yaffs_CountBits(d0)+yaffs_CountBits(d1)+yaffs_CountBits(d2)) == 1)
531 +       {
532 +               // Reccoverable error in ecc
533 +               
534 +               read_ecc[0] = test_ecc[0];
535 +               read_ecc[1] = test_ecc[1];
536 +               read_ecc[2] = test_ecc[2];
537 +               
538 +               return 1;
539 +       }
540 +       
541 +       // Unrecoverable error
542 +       
543 +       return -1;
544 +           
545 +
546 +}
547 +
548 +
549 +
550 +void yaffs_ECCCalculateOther(const unsigned char *data,unsigned nBytes, yaffs_ECCOther *eccOther)
551 +{
552 +       unsigned int i;
553 +       
554 +       unsigned char col_parity = 0;
555 +       unsigned line_parity = 0;
556 +       unsigned line_parity_prime = 0;
557 +       unsigned char b;
558 +       
559 +       for(i = 0; i < nBytes; i++)
560 +       {
561 +               b = column_parity_table[*data++];
562 +               col_parity ^= b;
563 +
564 +               if(b & 0x01) // odd number of bits in the byte
565 +               {
566 +                       line_parity ^= i;
567 +                       line_parity_prime ^= ~i;
568 +               }
569 +               
570 +       }
571 +       
572 +       eccOther->colParity = (col_parity >> 2) & 0x3f;
573 +       eccOther->lineParity = line_parity;
574 +       eccOther->lineParityPrime = line_parity_prime;
575 +}
576 +
577 +int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes, yaffs_ECCOther *read_ecc, const yaffs_ECCOther  *test_ecc)
578 +{
579 +       unsigned char cDelta; // column parity delta
580 +       unsigned lDelta; // line parity delta
581 +       unsigned lDeltaPrime; // line parity delta
582 +       unsigned bit;
583 +
584 +       cDelta = read_ecc->colParity ^ test_ecc->colParity;
585 +       lDelta = read_ecc->lineParity ^ test_ecc->lineParity;   
586 +       lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime;
587 +       
588 +       if((cDelta | lDelta | lDeltaPrime) == 0)
589 +       {
590 +               // no error
591 +               return 0;
592 +       }
593 +       
594 +       if( lDelta == ~lDeltaPrime &&
595 +            (((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15)) // Not correct 
596 +       {
597 +               // Single bit (recoverable) error in data
598 +
599 +               bit = 0;
600 +
601 +               if(cDelta & 0x20) bit |= 0x04;
602 +               if(cDelta & 0x08) bit |= 0x02;
603 +               if(cDelta & 0x02) bit |= 0x01;
604 +
605 +               data[lDelta] ^= (1 << bit);
606 +               
607 +               return 1;
608 +       }
609 +       
610 +       if((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) + yaffs_CountBits(cDelta)) == 1)
611 +       {
612 +               // Reccoverable error in ecc
613 +               
614 +               *read_ecc  = *test_ecc;         
615 +               return 1;
616 +       }
617 +       
618 +       // Unrecoverable error
619 +       
620 +       return -1;
621 +           
622 +
623 +}
624 +
625 +
626 +
627 diff --git a/fs/yaffs/yaffs_ecc.h b/fs/yaffs/yaffs_ecc.h
628 new file mode 100644
629 index 0000000..f96d707
630 --- /dev/null
631 +++ b/fs/yaffs/yaffs_ecc.h
632 @@ -0,0 +1,41 @@
633 +/*
634 + * YAFFS: Yet another FFS. A NAND-flash specific file system. 
635 + *
636 + * yaffs_ecc.c: ECC generation/correction algorithms.
637 + *
638 + * Copyright (C) 2002 Aleph One Ltd.
639 + *
640 + * Created by Charles Manning <charles@aleph1.co.uk>
641 + *
642 + * This program is free software; you can redistribute it and/or modify
643 + * it under the terms of the GNU General Public License version 2 as
644 + * published by the Free Software Foundation.
645 + *
646 + */
647
648 + /*
649 + * This code implements the ECC algorithm used in SmartMedia.
650 + *
651 + * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. 
652 + * The two unused bit are set to 1.
653 + * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC 
654 + * blocks are used on a 512-byte NAND page.
655 + *
656 + */
657 +
658 +#ifndef __YAFFS_ECC_H__
659 +#define __YAFFS_ECC_H__
660 +
661 +typedef struct
662 +{
663 +       unsigned char colParity;
664 +       unsigned lineParity;
665 +       unsigned lineParityPrime;
666 +} yaffs_ECCOther;
667 +
668 +void yaffs_ECCCalculate(const unsigned char *data,unsigned char *ecc);
669 +int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc, const unsigned char *test_ecc);
670 +
671 +void yaffs_ECCCalculateOther(const unsigned char *data,unsigned nBytes, yaffs_ECCOther *ecc);
672 +int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes, yaffs_ECCOther *read_ecc, const yaffs_ECCOther *test_ecc);
673 +#endif
674 diff --git a/fs/yaffs/yaffs_fs.c b/fs/yaffs/yaffs_fs.c
675 new file mode 100644
676 index 0000000..717f41a
677 --- /dev/null
678 +++ b/fs/yaffs/yaffs_fs.c
679 @@ -0,0 +1,1727 @@
680 +/*
681 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
682 + * yaffs_fs.c
683 + *
684 + * Copyright (C) 2002 Aleph One Ltd.
685 + *   for Toby Churchill Ltd and Brightstar Engineering
686 + *
687 + * Created by Charles Manning <charles@aleph1.co.uk>
688 + *
689 + * This program is free software; you can redistribute it and/or modify
690 + * it under the terms of the GNU General Public License version 2 as
691 + * published by the Free Software Foundation.
692 + *
693 + * This is the file system front-end to YAFFS that hooks it up to
694 + * the VFS.
695 + *
696 + * Special notes: 
697 + * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with this superblock
698 + * >> 2.6: sb->s_fs_info  points to the yaffs_Device associated with this superblock
699 + * >> inode->u.generic_ip points to the associated yaffs_Object.
700 + *
701 + *
702 + * Acknowledgements:
703 + * * Luc van OostenRyck for numerous patches.
704 + * * Nick Bane for numerous patches.
705 + * * Nick Bane for 2.5/2.6 integration.
706 + * * Andras Toth for mknod rdev issue.
707 + * * Michael Fischer for finding the problem with inode inconsistency.
708 + * * Some code bodily lifted from JFFS2.
709 + */
710 +
711 +
712 +const char *yaffs_fs_c_version = "$Id: yaffs_fs.c,v 1.27 2005/08/04 22:47:36 luc Exp $";
713 +extern const char *yaffs_guts_c_version;
714 +
715 +
716 +#include <linux/config.h>
717 +#include <linux/kernel.h>
718 +#include <linux/module.h>
719 +#include <linux/version.h>
720 +#include <linux/slab.h>
721 +#include <linux/init.h>
722 +#include <linux/list.h>
723 +#include <linux/fs.h>
724 +#include <linux/proc_fs.h>
725 +#include <linux/smp_lock.h>
726 +#include <linux/pagemap.h>
727 +#include <linux/mtd/mtd.h>
728 +#include <linux/interrupt.h>
729 +#include <linux/string.h>
730 +
731 +
732 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
733 +
734 +#include <linux/statfs.h>      /* Added NCB 15-8-2003 */
735 +#include <asm/statfs.h>
736 +#define UnlockPage(p) unlock_page(p)
737 +#define Page_Uptodate(page)    test_bit(PG_uptodate, &(page)->flags)
738 +#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)       // FIXME: use sb->s_id instead ?
739 +
740 +#else
741 +
742 +#include <linux/locks.h>
743 +#define        BDEVNAME_SIZE           0
744 +#define        yaffs_devname(sb, buf)  kdevname(sb->s_dev)
745 +
746 +#endif
747 +
748 +#include <asm/uaccess.h>
749 +
750 +#include "yportenv.h"
751 +#include "yaffs_guts.h"
752 +
753 +
754 +
755 +
756 +unsigned yaffs_traceMask = YAFFS_TRACE_ALWAYS | YAFFS_TRACE_BAD_BLOCKS;
757 +//unsigned yaffs_traceMask = 0xFFFFFFFF;
758 +
759 +
760 +#ifdef CONFIG_YAFFS_YAFFS1
761 +#include <linux/mtd/mtd.h>
762 +#include "yaffs_mtdif.h"
763 +#include "yaffs_mtdif2.h"
764 +#endif //CONFIG_YAFFS_YAFFS1
765 +
766 +//#define T(x) printk x
767 +
768 +
769 +
770 +#define yaffs_InodeToObject(iptr) ((yaffs_Object *)((iptr)->u.generic_ip))
771 +#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
772 +
773 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
774 +#define yaffs_SuperToDevice(sb)        ((yaffs_Device *)sb->s_fs_info)
775 +#else
776 +#define yaffs_SuperToDevice(sb)        ((yaffs_Device *)sb->u.generic_sbp)
777 +#endif
778 +
779 +
780 +static void yaffs_put_super(struct super_block *sb);
781 +
782 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, loff_t *pos);
783 +
784 +static int yaffs_file_flush(struct file* file);
785 +
786 +static int yaffs_sync_object(struct file * file, struct dentry *dentry, int datasync);
787 +
788 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
789 +
790 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
791 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *n);
792 +static struct dentry * yaffs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *n);
793 +#else
794 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
795 +static struct dentry * yaffs_lookup(struct inode *dir, struct dentry *dentry);
796 +#endif
797 +static int yaffs_link(struct dentry *old_dentry, struct inode * dir, struct dentry * dentry);
798 +static int yaffs_unlink(struct inode * dir, struct dentry *dentry);
799 +static int yaffs_symlink(struct inode * dir, struct dentry *dentry, const char * symname);
800 +static int yaffs_mkdir(struct inode * dir, struct dentry * dentry, int mode);
801 +
802 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
803 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev);
804 +#else
805 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev);
806 +#endif
807 +static int yaffs_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir,struct dentry *new_dentry);
808 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
809 +
810 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
811 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
812 +#else
813 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
814 +#endif
815 +static void yaffs_read_inode (struct inode *inode);
816 +
817 +static void yaffs_put_inode (struct inode *inode);
818 +static void yaffs_delete_inode(struct inode *);
819 +static void yaffs_clear_inode(struct inode *);
820 +
821 +static int yaffs_readpage(struct file *file, struct page * page);
822 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
823 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
824 +#else
825 +static int yaffs_writepage(struct page *page);
826 +#endif
827 +static int yaffs_prepare_write(struct file *f, struct page *pg, unsigned offset, unsigned to);
828 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, unsigned to);
829 +
830 +static int yaffs_readlink(struct dentry *dentry, char __user *buffer, int buflen);
831 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
832 +
833 +
834 +
835 +static struct address_space_operations yaffs_file_address_operations = {
836 +       .readpage       = yaffs_readpage,
837 +       .writepage      = yaffs_writepage,
838 +       .prepare_write  = yaffs_prepare_write,
839 +       .commit_write   = yaffs_commit_write,
840 +};
841 +
842 +static struct file_operations yaffs_file_operations = {
843 +       .read           = generic_file_read,
844 +       .write          = generic_file_write,
845 +       .mmap           = generic_file_mmap,
846 +       .flush          = yaffs_file_flush,
847 +       .fsync          = yaffs_sync_object,
848 +};
849 +
850 +static struct inode_operations yaffs_file_inode_operations = {
851 +       .setattr        = yaffs_setattr,
852 +};
853 +
854 +static struct inode_operations yaffs_symlink_inode_operations = {      
855 +       .readlink       = yaffs_readlink,
856 +       .follow_link    = yaffs_follow_link,
857 +       .setattr        = yaffs_setattr,
858 +};
859 +
860 +static struct inode_operations yaffs_dir_inode_operations = {
861 +       .create         = yaffs_create,
862 +       .lookup         = yaffs_lookup,
863 +       .link           = yaffs_link,
864 +       .unlink         = yaffs_unlink, 
865 +       .symlink        = yaffs_symlink,
866 +       .mkdir          = yaffs_mkdir,
867 +       .rmdir          = yaffs_unlink,
868 +       .mknod          = yaffs_mknod,
869 +       .rename         = yaffs_rename,
870 +       .setattr        = yaffs_setattr,
871 +};
872 +
873 +static struct file_operations yaffs_dir_operations = {
874 +       .read           = generic_read_dir,
875 +       .readdir        = yaffs_readdir,
876 +       .fsync          = yaffs_sync_object,
877 +};
878 +
879 +static struct super_operations yaffs_super_ops = {
880 +       .statfs         = yaffs_statfs,
881 +       .read_inode     = yaffs_read_inode,
882 +       .put_inode      = yaffs_put_inode,
883 +       .put_super      = yaffs_put_super,
884 +       .delete_inode   = yaffs_delete_inode,
885 +       .clear_inode    = yaffs_clear_inode,
886 +};
887 +
888 +
889 +
890 +static void yaffs_GrossLock(yaffs_Device *dev)
891 +{
892 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs locking\n"));
893 +
894 +       down(&dev->grossLock);
895 +}
896 +
897 +static void yaffs_GrossUnlock(yaffs_Device *dev)
898 +{
899 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs unlocking\n"));
900 +       up(&dev->grossLock);
901 +
902 +}
903 +
904 +static int yaffs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
905 +{
906 +       unsigned char *alias;
907 +       int ret;
908 +
909 +       yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
910 +
911 +
912 +       yaffs_GrossLock(dev);
913 +       
914 +       alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
915 +       
916 +       yaffs_GrossUnlock(dev);
917 +       
918 +       if(!alias)
919 +               return -ENOMEM;
920 +
921 +       ret = vfs_readlink(dentry, buffer, buflen, alias);
922 +       kfree(alias);
923 +       return ret;
924 +}
925 +
926 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
927 +{
928 +       unsigned char *alias;
929 +       int ret;
930 +       yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
931 +
932 +
933 +       yaffs_GrossLock(dev);
934 +
935 +       alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
936 +       
937 +       yaffs_GrossUnlock(dev);
938 +       
939 +       if(!alias)
940 +               ret = -ENOMEM;
941 +       else {
942 +               ret = vfs_follow_link(nd,alias);
943 +               kfree(alias);
944 +       }
945 +       return ERR_PTR (ret);
946 +}
947 +
948 +
949 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,yaffs_Object *obj);
950 +
951 +/*
952 + * Lookup is used to find objects in the fs
953 + */
954 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
955 +
956 +static struct dentry * yaffs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *n)
957 +#else
958 +static struct dentry * yaffs_lookup(struct inode *dir, struct dentry *dentry)
959 +#endif
960 +{
961 +       yaffs_Object *obj;
962 +       struct inode *inode = NULL; // NCB 2.5/2.6 needs NULL here
963 +       
964 +       yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
965 +
966 +
967 +       yaffs_GrossLock(dev);
968 +
969 +       
970 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_lookup for %d:%s\n",yaffs_InodeToObject(dir)->objectId,dentry->d_name.name));
971 +       
972 +       obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir),dentry->d_name.name);
973 +       
974 +       obj = yaffs_GetEquivalentObject(obj); // in case it was a hardlink
975 +       
976 +
977 +       
978 +       if(obj)
979 +       {
980 +               T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_lookup found %d\n",obj->objectId));
981 +               
982 +               inode = yaffs_get_inode(dir->i_sb, obj->yst_mode,0,obj);
983 +               
984 +               if(inode)
985 +               {
986 +                       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_loookup dentry \n"));
987 +/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to d_add even if NULL inode */        
988 +#if 0
989 +                       //dget(dentry); // try to solve directory bug
990 +                       d_add(dentry,inode);
991 +                       
992 +                       yaffs_GrossUnlock(dev);
993 +
994 +                       // return dentry;
995 +                       return NULL;
996 +#endif
997 +               }
998 +
999 +       }
1000 +       else
1001 +       {
1002 +               T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_lookup not found\n"));
1003 +               
1004 +       }
1005 +       yaffs_GrossUnlock(dev);
1006 +
1007 +/* added NCB for 2.5/6 compatability - forces add even if inode is NULL which creates dentry hash*/    
1008 +       d_add(dentry,inode);
1009 +       
1010 +       return NULL;
1011 +       //      return (ERR_PTR(-EIO));
1012 +       
1013 +}
1014 +
1015 +// For now put inode is just for debugging
1016 +// Put inode is called when the inode **structure** is put.
1017 +static void yaffs_put_inode(struct inode *inode)
1018 +{
1019 +       T(YAFFS_TRACE_OS,("yaffs_put_inode: ino %d, count %d\n",(int)inode->i_ino, atomic_read(&inode->i_count)));
1020 +       
1021 +}
1022 +
1023 +// clear is called to tell the fs to release any per-inode data it holds
1024 +static void yaffs_clear_inode(struct inode *inode)
1025 +{
1026 +       yaffs_Object *obj;
1027 +       yaffs_Device *dev;
1028 +       
1029 +       obj = yaffs_InodeToObject(inode);
1030 +       
1031 +       T(YAFFS_TRACE_OS,("yaffs_clear_inode: ino %d, count %d %s\n",(int)inode->i_ino, atomic_read(&inode->i_count),
1032 +               obj ? "object exists" : "null object"));        
1033 +
1034 +       if(obj)
1035 +       {
1036 +               dev = obj->myDev;
1037 +               yaffs_GrossLock(dev);
1038 +               
1039 +               // Clear the association between the inode ant the yaffs_Object.
1040 +               obj->myInode = NULL;
1041 +               inode->u.generic_ip = NULL;
1042 +               
1043 +               // If the object freeing was deferred, then the real free happens now.
1044 +               // This should fix the inode inconsistency problem.
1045 +               
1046 +               yaffs_HandleDeferedFree(obj);
1047 +               
1048 +               yaffs_GrossUnlock(dev);
1049 +       }
1050 +       
1051 +       
1052 +}
1053 +
1054 +// delete is called when the link count is zero and the inode
1055 +// is put (ie. nobody wants to know about it anymore, time to
1056 +// delete the file).
1057 +// NB Must call clear_inode()
1058 +static void yaffs_delete_inode(struct inode *inode)
1059 +{
1060 +       yaffs_Object *obj = yaffs_InodeToObject(inode);
1061 +       yaffs_Device *dev;
1062 +
1063 +       T(YAFFS_TRACE_OS,("yaffs_delete_inode: ino %d, count %d %s\n",(int)inode->i_ino, atomic_read(&inode->i_count),
1064 +               obj ? "object exists" : "null object"));
1065 +       
1066 +       if(obj)
1067 +       {
1068 +               dev = obj->myDev;
1069 +               yaffs_GrossLock(dev);
1070 +               yaffs_DeleteFile(obj);
1071 +               yaffs_GrossUnlock(dev);
1072 +       }
1073 +       clear_inode(inode);
1074 +}
1075 +
1076 +
1077 +static int yaffs_file_flush(struct file* file)
1078 +{
1079 +       yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
1080 +       
1081 +       yaffs_Device *dev = obj->myDev;
1082 +       
1083 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_file_flush object %d (%s)\n",obj->objectId,
1084 +                               obj->dirty ? "dirty" : "clean"));
1085 +
1086 +       yaffs_GrossLock(dev);
1087 +       
1088 +    yaffs_FlushFile(obj,1);
1089 +
1090 +       yaffs_GrossUnlock(dev);
1091 +
1092 +    return 0;
1093 +}
1094 +
1095 +
1096 +
1097 +static int yaffs_readpage_nolock(struct file *f, struct page * pg)
1098 +{
1099 +       // Lifted from jffs2
1100 +       
1101 +       yaffs_Object *obj;
1102 +       unsigned char *pg_buf;
1103 +       int ret;
1104 +
1105 +       yaffs_Device *dev;
1106 +
1107 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_readpage at %08x, size %08x\n",
1108 +                     (unsigned)(pg->index << PAGE_CACHE_SHIFT), (unsigned)PAGE_CACHE_SIZE));
1109 +
1110 +       obj  = yaffs_DentryToObject(f->f_dentry);
1111 +
1112 +       dev = obj->myDev;
1113 +       
1114 +       
1115 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1116 +        BUG_ON(!PageLocked(pg));
1117 +#else
1118 +       if (!PageLocked(pg))
1119 +                PAGE_BUG(pg);
1120 +#endif
1121 +
1122 +       pg_buf = kmap(pg);
1123 +       /* FIXME: Can kmap fail? */
1124 +
1125 +       yaffs_GrossLock(dev);
1126 +       
1127 +       ret = yaffs_ReadDataFromFile(obj, pg_buf, pg->index << PAGE_CACHE_SHIFT, PAGE_CACHE_SIZE);
1128 +
1129 +       yaffs_GrossUnlock(dev);
1130 +       
1131 +       if(ret >= 0) ret = 0;
1132 +
1133 +       if (ret) {
1134 +               ClearPageUptodate(pg);
1135 +               SetPageError(pg);
1136 +       } else {
1137 +               SetPageUptodate(pg);
1138 +               ClearPageError(pg);
1139 +       }
1140 +
1141 +       flush_dcache_page(pg);
1142 +       kunmap(pg);
1143 +
1144 +
1145 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_readpage done\n"));
1146 +       return ret;
1147 +}
1148 +
1149 +static int yaffs_readpage_unlock(struct file *f, struct page *pg)
1150 +{
1151 +       int ret = yaffs_readpage_nolock(f,pg);
1152 +       UnlockPage(pg);
1153 +       return ret;
1154 +}
1155 +
1156 +static int yaffs_readpage(struct file *f, struct page * pg)
1157 +{
1158 +       return yaffs_readpage_unlock(f,pg);
1159 +}
1160 +
1161 +// writepage inspired by/stolen from smbfs
1162 +//
1163 +
1164 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1165 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
1166 +#else
1167 +static int yaffs_writepage(struct page *page)
1168 +#endif
1169 +{
1170 +       struct address_space *mapping = page->mapping;
1171 +       loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1172 +       struct inode *inode;
1173 +       unsigned long end_index;
1174 +       char *buffer;
1175 +       yaffs_Object *obj;
1176 +       int nWritten = 0;
1177 +       unsigned nBytes;
1178 +
1179 +       if (!mapping)
1180 +               BUG();
1181 +       inode = mapping->host;
1182 +       if (!inode)
1183 +               BUG();
1184 +
1185 +       if (offset > inode->i_size)
1186 +       {
1187 +               T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_writepage at %08x, inode size = %08x!!!\n", (unsigned)(page->index << PAGE_CACHE_SHIFT), (unsigned) inode->i_size));
1188 +               T(YAFFS_TRACE_OS,(KERN_DEBUG"                -> don't care!!\n"));
1189 +               unlock_page(page);
1190 +               return 0;
1191 +       }
1192 +
1193 +       end_index = inode->i_size >> PAGE_CACHE_SHIFT;
1194 +
1195 +       /* easy case */
1196 +       if (page->index < end_index)
1197 +       {
1198 +               nBytes = PAGE_CACHE_SIZE;
1199 +       }
1200 +       else
1201 +       {
1202 +               nBytes = inode->i_size & (PAGE_CACHE_SIZE-1);
1203 +       }
1204 +       //  What's happening here?
1205 +       ///* OK, are we completely out? */
1206 +       //if (page->index >= end_index+1 || !offset)
1207 +       //      return -EIO;
1208 +
1209 +       get_page(page);
1210 +
1211 +
1212 +       buffer = kmap(page);
1213 +
1214 +       obj = yaffs_InodeToObject(inode);
1215 +       yaffs_GrossLock(obj->myDev);
1216 +
1217 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_writepage at %08x, size %08x\n", (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
1218 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"writepag0: obj = %05x, ino = %05x\n", (int) obj->variant.fileVariant.fileSize, (int) inode->i_size));
1219 +
1220 +       nWritten = yaffs_WriteDataToFile(obj,buffer,page->index << PAGE_CACHE_SHIFT,nBytes,0);
1221 +
1222 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"writepag1: obj = %05x, ino = %05x\n", (int) obj->variant.fileVariant.fileSize, (int) inode->i_size));
1223 +
1224 +       yaffs_GrossUnlock(obj->myDev);
1225 +       
1226 +       kunmap(page);
1227 +       SetPageUptodate(page);
1228 +       UnlockPage(page);
1229 +       put_page(page);
1230 +
1231 +       return (nWritten == nBytes) ? 0  : -ENOSPC;
1232 +}
1233 +
1234 +
1235 +
1236 +static int yaffs_prepare_write(struct file *f, struct page *pg, unsigned offset, unsigned to)
1237 +{
1238 +
1239 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_prepair_write\n"));
1240 +       if(!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
1241 +               return  yaffs_readpage_nolock(f,pg);    
1242 +
1243 +       return 0;
1244 +       
1245 +}
1246 +
1247 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, unsigned to)
1248 +{
1249 +
1250 +       void *addr = page_address(pg) + offset;
1251 +       loff_t pos = (((loff_t)pg->index) << PAGE_CACHE_SHIFT) + offset;
1252 +       int nBytes = to - offset;
1253 +       int nWritten;
1254 +       
1255 +       unsigned spos = pos;
1256 +       unsigned saddr = (unsigned)addr;
1257 +
1258 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_commit_write addr %x pos %x nBytes %d\n",saddr,spos,nBytes));
1259 +       
1260 +       nWritten = yaffs_file_write(f,addr, nBytes, &pos);
1261 +       
1262 +       if(nWritten != nBytes)
1263 +       {
1264 +               T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_commit_write not same size nWritten %d  nBytes %d\n",nWritten,nBytes));
1265 +               SetPageError(pg);
1266 +               ClearPageUptodate(pg);
1267 +       }
1268 +       else
1269 +       {
1270 +               SetPageUptodate(pg);
1271 +       }
1272 +
1273 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_commit_write returning %d\n",nWritten));
1274 +       
1275 +       return nWritten;
1276 +
1277 +}
1278 +
1279 +
1280 +
1281 +static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
1282 +{
1283 +       if (inode && obj) 
1284 +       {
1285 +               inode->i_ino = obj->objectId;
1286 +               inode->i_mode = obj->yst_mode;
1287 +               inode->i_uid = obj->yst_uid;
1288 +               inode->i_gid = obj->yst_gid;
1289 +               inode->i_blksize = inode->i_sb->s_blocksize;
1290 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1291 +
1292 +               inode->i_rdev = old_decode_dev(obj->yst_rdev);
1293 +               inode->i_atime.tv_sec = (time_t)(obj->yst_atime);
1294 +               inode->i_atime.tv_nsec = 0;
1295 +               inode->i_mtime.tv_sec = (time_t)obj->yst_mtime;
1296 +               inode->i_mtime.tv_nsec =0;
1297 +               inode->i_ctime.tv_sec = (time_t)obj->yst_ctime;
1298 +               inode->i_ctime.tv_nsec = 0;
1299 +#else
1300 +               inode->i_rdev = obj->yst_rdev;
1301 +               inode->i_atime = obj->yst_atime;
1302 +               inode->i_mtime = obj->yst_mtime;
1303 +               inode->i_ctime = obj->yst_ctime;
1304 +#endif
1305 +               inode->i_size = yaffs_GetObjectFileLength(obj);
1306 +               inode->i_blocks = (inode->i_size + 511) >> 9;
1307 +
1308 +               inode->i_nlink = yaffs_GetObjectLinkCount(obj);
1309 +               
1310 +               T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",
1311 +                               inode->i_mode, inode->i_uid, inode->i_gid, (int)inode->i_size, atomic_read(&inode->i_count)));
1312 +               
1313 +               switch (obj->yst_mode & S_IFMT) 
1314 +               {
1315 +                       default: // fifo, device or socket
1316 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1317 +                               init_special_inode(inode, obj->yst_mode,old_decode_dev(obj->yst_rdev));
1318 +#else
1319 +                                 init_special_inode(inode, obj->yst_mode,(dev_t)(obj->yst_rdev));
1320 +#endif                         
1321 +                        break;
1322 +                       case S_IFREG:   // file         
1323 +                               inode->i_op = &yaffs_file_inode_operations;
1324 +                               inode->i_fop = &yaffs_file_operations;
1325 +                               inode->i_mapping->a_ops = &yaffs_file_address_operations;
1326 +                               break;
1327 +                       case S_IFDIR:   // directory
1328 +                               inode->i_op = &yaffs_dir_inode_operations;
1329 +                               inode->i_fop = &yaffs_dir_operations;
1330 +                               break;
1331 +                       case S_IFLNK:   // symlink
1332 +                               inode->i_op = &yaffs_symlink_inode_operations;
1333 +                               break;
1334 +               }
1335 +               
1336 +               
1337 +               inode->u.generic_ip = obj;
1338 +               obj->myInode = inode;
1339 +               
1340 +       }
1341 +       else
1342 +       {
1343 +               T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_FileInode invalid parameters\n"));
1344 +       }
1345 +
1346 +}
1347 +
1348 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,yaffs_Object *obj)
1349 +{
1350 +       struct inode * inode;
1351 +       
1352 +       if(!sb)
1353 +       {
1354 +         T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_get_inode for NULL super_block!!\n"));
1355 +         return NULL;
1356 +         
1357 +       }
1358 +       
1359 +       if(!obj)
1360 +       {
1361 +         T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_get_inode for NULL object!!\n"));
1362 +         return NULL;
1363 +         
1364 +       }
1365 +       
1366 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_get_inode for object %d\n",obj->objectId));
1367 +
1368 +       inode = iget(sb,obj->objectId);
1369 +
1370 +       // NB Side effect: iget calls back to yaffs_read_inode().
1371 +       // iget also increments the inode's i_count
1372 +       
1373 +       return inode;
1374 +}
1375 +
1376 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, loff_t *pos)
1377 +{
1378 +       yaffs_Object *obj;
1379 +       int nWritten,ipos;
1380 +       struct inode *inode;
1381 +       yaffs_Device *dev;
1382 +       
1383 +       
1384 +       obj  = yaffs_DentryToObject(f->f_dentry);
1385 +       
1386 +       dev = obj->myDev;
1387 +       
1388 +       yaffs_GrossLock(dev);
1389 +
1390 +       inode = f->f_dentry->d_inode;
1391 +
1392 +       if(!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
1393 +       {
1394 +               ipos = inode->i_size;
1395 +       }
1396 +       else
1397 +       {
1398 +               ipos = *pos;
1399 +       }
1400 +       
1401 +       
1402 +       if(!obj)
1403 +       {
1404 +               T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_file_write: hey obj is null!\n"));
1405 +       }
1406 +       else
1407 +       {
1408 +               T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_file_write about to write writing %d bytes to object %d at %d\n",n,obj->objectId,ipos));
1409 +       }
1410 +
1411 +       nWritten = yaffs_WriteDataToFile(obj,buf,ipos,n,0);
1412 +
1413 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_file_write writing %d bytes, %d written at %d\n",n,nWritten,ipos));
1414 +       if(nWritten > 0)
1415 +       {
1416 +               ipos += nWritten;
1417 +               *pos = ipos;
1418 +               if(ipos > inode->i_size)
1419 +               {
1420 +                       inode->i_size = ipos;
1421 +                       inode->i_blocks = (ipos + 511)>>9;
1422 +                       
1423 +                       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_file_write size updated to %d bytes, %d blocks\n",ipos,(int)(inode->i_blocks)));
1424 +               }
1425 +               
1426 +       }
1427 +       yaffs_GrossUnlock(dev);
1428 +       
1429 +       return nWritten != n ? -ENOSPC : nWritten;
1430 +}
1431 +
1432 +
1433 +
1434 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
1435 +{
1436 +       yaffs_Object *obj;
1437 +       yaffs_Device *dev;
1438 +       struct inode *inode = f->f_dentry->d_inode;
1439 +       unsigned long offset, curoffs;
1440 +       struct list_head *i;    
1441 +       yaffs_Object *l;
1442 +       
1443 +       char name[YAFFS_MAX_NAME_LENGTH +1];
1444 +               
1445 +       obj =  yaffs_DentryToObject(f->f_dentry);
1446 +       dev = obj->myDev;
1447 +       
1448 +       yaffs_GrossLock(dev);
1449 +       
1450 +       offset = f->f_pos;
1451 +       
1452 +       T(YAFFS_TRACE_OS,("yaffs_readdir: starting at %d\n",(int)offset));
1453 +       
1454 +       if(offset == 0)
1455 +       {
1456 +        T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_readdir: entry . ino %d \n",(int)inode->i_ino));
1457 +               if(filldir(dirent,".",1,offset,inode->i_ino,DT_DIR) < 0)
1458 +               {
1459 +                       goto out;
1460 +               }
1461 +               offset++;
1462 +               f->f_pos++;
1463 +       }
1464 +       if(offset == 1)
1465 +       {
1466 +               T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_readdir: entry .. ino %d \n",(int)f->f_dentry->d_parent->d_inode->i_ino));
1467 +               if(filldir(dirent,"..",2,offset,f->f_dentry->d_parent->d_inode->i_ino,DT_DIR) < 0)
1468 +               {
1469 +                       goto out;
1470 +               }
1471 +               offset++;
1472 +               f->f_pos++;
1473 +       }
1474 +       
1475 +       curoffs = 1;
1476 +       
1477 +       list_for_each(i,&obj->variant.directoryVariant.children)
1478 +       {
1479 +               curoffs++;
1480 +               if(curoffs >= offset)
1481 +               {               
1482 +                       l = list_entry(i, yaffs_Object,siblings);
1483 +                       
1484 +                       yaffs_GetObjectName(l,name,YAFFS_MAX_NAME_LENGTH+1); 
1485 +                       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_readdir: %s inode %d\n",name,yaffs_GetObjectInode(l)));
1486 +                       
1487 +                       if(filldir(dirent,
1488 +                                          name,
1489 +                                          strlen(name),
1490 +                                          offset,
1491 +                                          yaffs_GetObjectInode(l),
1492 +                                          yaffs_GetObjectType(l))
1493 +                                          < 0)
1494 +                       {
1495 +                               goto up_and_out;
1496 +                       }
1497 +                       
1498 +                       offset++;
1499 +                       f->f_pos++;        
1500 +               }
1501 +       }
1502 +
1503 +  up_and_out:
1504 +  out:
1505 +  
1506 +    yaffs_GrossUnlock(dev);
1507 +    
1508 +       return 0;
1509 +}
1510 +
1511 +
1512 +/*
1513 + * File creation. Allocate an inode, and we're done..
1514 + */
1515 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1516 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
1517 +#else
1518 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
1519 +#endif
1520 +{
1521 +       struct inode *inode;
1522 +       
1523 +       yaffs_Object *obj = NULL;
1524 +       yaffs_Device *dev;
1525 +       
1526 +       yaffs_Object *parent = yaffs_InodeToObject(dir);
1527 +       
1528 +       int error = -ENOSPC;
1529 +       uid_t uid = current->fsuid;
1530 +       gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
1531 +
1532 +       if(parent)
1533 +       {
1534 +               T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_mknod: parent object %d type %d\n",
1535 +                                        parent->objectId,parent->variantType));
1536 +       }
1537 +       else
1538 +       {
1539 +               T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_mknod: could not get parent object\n"));
1540 +               return -EPERM;
1541 +       }
1542 +       
1543 +       T(YAFFS_TRACE_OS,("yaffs_mknod: making oject for %s, mode %x dev %x\n",
1544 +                                       dentry->d_name.name, mode,rdev));
1545 +
1546 +       dev = parent->myDev;
1547 +       
1548 +       yaffs_GrossLock(dev);
1549 +
1550 +       switch (mode & S_IFMT) 
1551 +       {
1552 +               default:
1553 +                       // Special (socket, fifo, device...)
1554 +                       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_mknod: making special\n"));
1555 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1556 +                        obj = yaffs_MknodSpecial(parent,dentry->d_name.name,mode,uid, gid,old_encode_dev(rdev));
1557 +#else
1558 +                        obj = yaffs_MknodSpecial(parent,dentry->d_name.name,mode,uid, gid,rdev);
1559 +#endif                 
1560 +                break;
1561 +               case S_IFREG:   // file         
1562 +                       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_mknod: making file\n"));
1563 +                       obj = yaffs_MknodFile(parent,dentry->d_name.name,mode,uid, gid);
1564 +                       break;
1565 +               case S_IFDIR:   // directory
1566 +                       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_mknod: making directory\n"));
1567 +                       obj = yaffs_MknodDirectory(parent,dentry->d_name.name,mode,uid, gid);
1568 +                       break;
1569 +               case S_IFLNK:   // symlink
1570 +                       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_mknod: making file\n"));
1571 +                       obj = NULL; // Do we ever get here?
1572 +                       break;
1573 +       }
1574 +       
1575 +       if(obj)
1576 +       {
1577 +               inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
1578 +               d_instantiate(dentry, inode);
1579 +               T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_mknod created object %d count = %d\n",obj->objectId,atomic_read(&inode->i_count)));
1580 +               error = 0;
1581 +       }
1582 +       else
1583 +       {
1584 +               T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_mknod failed making object\n"));
1585 +               error = -ENOMEM;
1586 +       }
1587 +
1588 +       yaffs_GrossUnlock(dev);
1589 +
1590 +       return error;
1591 +}
1592 +
1593 +static int yaffs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
1594 +{
1595 +       int retVal;
1596 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_mkdir\n"));
1597 +       retVal =  yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
1598 +#if 0
1599 + // attempt to fix dir bug - didn't work
1600 +       if(!retVal)
1601 +       {
1602 +               dget(dentry);
1603 +       }
1604 +#endif
1605 +       return retVal;
1606 +}
1607 +
1608 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1609 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *n)
1610 +#else
1611 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
1612 +#endif
1613 +{
1614 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_create\n"));
1615 +       return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
1616 +}
1617 +
1618 +
1619 +static int yaffs_unlink(struct inode * dir, struct dentry *dentry)
1620 +{
1621 +       int retVal;
1622 +       
1623 +       yaffs_Device *dev;
1624 +       
1625 +       
1626 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_unlink %d:%s\n",(int)(dir->i_ino),dentry->d_name.name));
1627 +       
1628 +       dev = yaffs_InodeToObject(dir)->myDev;
1629 +       
1630 +       yaffs_GrossLock(dev);
1631 +       
1632 +       
1633 +       retVal = yaffs_Unlink(yaffs_InodeToObject(dir),dentry->d_name.name);
1634 +       
1635 +       
1636 +       yaffs_GrossUnlock(dev);
1637 +       
1638 +       if( retVal == YAFFS_OK)
1639 +       {
1640 +               dentry->d_inode->i_nlink--;
1641 +               mark_inode_dirty(dentry->d_inode);
1642 +               return 0;
1643 +       }
1644 +       else
1645 +       {
1646 +               return -ENOTEMPTY;
1647 +       }
1648 +}
1649 +
1650 +
1651 +/*
1652 + * Create a link...
1653 + */
1654 +static int yaffs_link(struct dentry *old_dentry, struct inode * dir, struct dentry * dentry)
1655 +{
1656 +       struct inode *inode = old_dentry->d_inode;
1657 +       yaffs_Object *obj = NULL;
1658 +       yaffs_Object *link=NULL;
1659 +       yaffs_Device *dev;
1660 +       
1661 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_link\n"));
1662 +       
1663 +       obj = yaffs_InodeToObject(inode);
1664 +       dev = obj->myDev;
1665 +       
1666 +       yaffs_GrossLock(dev);
1667 +
1668 +       if (!S_ISDIR(inode->i_mode))    // Don't link directories
1669 +       {
1670 +               link = yaffs_Link(yaffs_InodeToObject(dir),dentry->d_name.name,obj);
1671 +       }
1672 +       
1673 +
1674 +       if(link)
1675 +       {
1676 +               old_dentry->d_inode->i_nlink =  yaffs_GetObjectLinkCount(obj);
1677 +               d_instantiate(dentry, old_dentry->d_inode);
1678 +               atomic_inc(&old_dentry->d_inode->i_count);
1679 +               T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_link link count %d i_count %d\n",    
1680 +                       old_dentry->d_inode->i_nlink,atomic_read(&old_dentry->d_inode->i_count)));
1681 +       
1682 +       }
1683 +       
1684 +       yaffs_GrossUnlock(dev);
1685 +       
1686 +
1687 +       if(link)
1688 +       {
1689 +       
1690 +               return 0;
1691 +       }
1692 +       
1693 +       
1694 +       return -EPERM; 
1695 +}
1696 +
1697 +
1698 +static int yaffs_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
1699 +{
1700 +       yaffs_Object *obj;
1701 +       yaffs_Device *dev;
1702 +       uid_t uid = current->fsuid;
1703 +       gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
1704 +       
1705 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_symlink\n"));
1706 +       
1707 +       dev = yaffs_InodeToObject(dir)->myDev;
1708 +       yaffs_GrossLock(dev);
1709 +       obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name, 
1710 +                                                        S_IFLNK | S_IRWXUGO, uid, gid,
1711 +                                                        symname);
1712 +       yaffs_GrossUnlock(dev);
1713 +
1714 +       if(obj)
1715 +       {
1716 +
1717 +               struct inode* inode;
1718 +       
1719 +               inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
1720 +               d_instantiate(dentry, inode);
1721 +               T(YAFFS_TRACE_OS,(KERN_DEBUG"symlink created OK\n"));
1722 +               return 0;
1723 +       }
1724 +       else
1725 +       {
1726 +               T(YAFFS_TRACE_OS,(KERN_DEBUG"symlink not created\n"));
1727 +
1728 +       }
1729 +       
1730 +       return -ENOMEM;
1731 +}
1732 +
1733 +static int yaffs_sync_object(struct file * file, struct dentry *dentry, int datasync)
1734 +{
1735 +
1736 +       yaffs_Object *obj;
1737 +       yaffs_Device *dev;
1738 +       
1739 +       obj = yaffs_DentryToObject(dentry);
1740 +
1741 +       dev = obj->myDev;
1742 +       
1743 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_sync_object\n"));
1744 +       yaffs_GrossLock(dev);
1745 +       yaffs_FlushFile(obj,1);
1746 +       yaffs_GrossUnlock(dev);
1747 +       return 0;
1748 +}
1749 +
1750 +/*
1751 + * The VFS layer already does all the dentry stuff for rename.
1752 + *
1753 + * NB: POSIX says you can rename an object over an old object of the same name
1754 + */
1755 +static int yaffs_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir,struct dentry *new_dentry)
1756 +{
1757 +       yaffs_Device *dev;
1758 +       int retVal = YAFFS_FAIL;
1759 +       int removed = 0;
1760 +       yaffs_Object *target;
1761 +       
1762 +       dev = yaffs_InodeToObject(old_dir)->myDev;
1763 +
1764 +       yaffs_GrossLock(dev);
1765 +       
1766 +       // Check if the target is an existing directory that is not empty.
1767 +       target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),new_dentry->d_name.name);
1768 +       
1769 +       if(target &&
1770 +          target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
1771 +          !list_empty(&target->variant.directoryVariant.children))
1772 +       {
1773 +               retVal = YAFFS_FAIL;
1774 +       }
1775 +       else
1776 +       {
1777 +          
1778 +               // Unlink the target if it exists
1779 +               removed = yaffs_Unlink(yaffs_InodeToObject(new_dir),new_dentry->d_name.name);
1780 +
1781 +       
1782 +               retVal =  yaffs_RenameObject(yaffs_InodeToObject(old_dir),old_dentry->d_name.name,
1783 +                                                                       yaffs_InodeToObject(new_dir),new_dentry->d_name.name);
1784 +                                                                       
1785 +       }
1786 +       yaffs_GrossUnlock(dev);
1787 +       
1788 +       if(retVal == YAFFS_OK)
1789 +       {
1790 +               if(removed == YAFFS_OK)
1791 +               {
1792 +                       new_dentry->d_inode->i_nlink--;
1793 +                       mark_inode_dirty(new_dentry->d_inode);
1794 +               }
1795 +               
1796 +               return 0;
1797 +       }
1798 +       else
1799 +       {
1800 +               return -ENOTEMPTY;
1801 +       }
1802 +       
1803 +
1804 +}
1805 +
1806 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
1807 +{
1808 +       struct inode *inode = dentry->d_inode;
1809 +       int error;
1810 +       yaffs_Device *dev;
1811 +       
1812 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_setattr of object %d\n",yaffs_InodeToObject(inode)->objectId));
1813 +       
1814 +       if((error = inode_change_ok(inode,attr)) == 0)
1815 +       {
1816 +       
1817 +               dev = yaffs_InodeToObject(inode)->myDev;
1818 +               yaffs_GrossLock(dev);
1819 +               if(yaffs_SetAttributes(yaffs_InodeToObject(inode),attr) == YAFFS_OK)
1820 +               {
1821 +                       error = 0;
1822 +               }
1823 +               else
1824 +               {
1825 +                       error = -EPERM;
1826 +               }
1827 +               yaffs_GrossUnlock(dev);
1828 +               if (!error)
1829 +                       error = inode_setattr(inode,attr);
1830 +       }
1831 +       return error;
1832 +}
1833 +
1834 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1835 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
1836 +#else
1837 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
1838 +#endif
1839 +{
1840 +
1841 +       
1842 +       yaffs_Device *dev = yaffs_SuperToDevice(sb);
1843 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_statfs\n"));
1844 +
1845 +       yaffs_GrossLock(dev);
1846 +       
1847 +       
1848 +       buf->f_type = YAFFS_MAGIC;
1849 +       buf->f_bsize = sb->s_blocksize;
1850 +       buf->f_namelen = 255;
1851 +       if(sb->s_blocksize > dev->nBytesPerChunk)
1852 +       {
1853 +               
1854 +               buf->f_blocks = (dev->endBlock - dev->startBlock + 1) * dev->nChunksPerBlock/
1855 +                                               (sb->s_blocksize/dev->nBytesPerChunk);
1856 +               buf->f_bfree = yaffs_GetNumberOfFreeChunks(dev)/
1857 +                                               (sb->s_blocksize/dev->nBytesPerChunk);
1858 +       }
1859 +       else
1860 +       {
1861 +               
1862 +               buf->f_blocks = (dev->endBlock - dev->startBlock + 1) * dev->nChunksPerBlock *
1863 +                                               (dev->nBytesPerChunk/sb->s_blocksize);
1864 +               buf->f_bfree = yaffs_GetNumberOfFreeChunks(dev) *
1865 +                                               (dev->nBytesPerChunk/sb->s_blocksize);
1866 +       }
1867 +       buf->f_files = 0;
1868 +       buf->f_ffree = 0;
1869 +       buf->f_bavail =  buf->f_bfree;
1870 +       
1871 +       yaffs_GrossUnlock(dev);
1872 +       return 0;
1873 +}
1874 +
1875 +static void yaffs_read_inode (struct inode *inode)
1876 +{
1877 +       // NB This is called as a side effect of other functions and
1878 +       // thus gross locking should always be in place already.
1879 +       
1880 +       yaffs_Object *obj ; 
1881 +       yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
1882 +       
1883 +       T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_read_inode for %d\n",(int)inode->i_ino));
1884 +
1885 +       obj  = yaffs_FindObjectByNumber(dev,inode->i_ino);
1886 +       
1887 +       yaffs_FillInodeFromObject(inode,obj);
1888 +
1889 +}
1890 +
1891 +static LIST_HEAD(yaffs_dev_list);
1892 +
1893 +static void yaffs_put_super(struct super_block *sb)
1894 +{
1895 +       yaffs_Device *dev = yaffs_SuperToDevice(sb);
1896 +       
1897 +       yaffs_GrossLock(dev);
1898 +       if(dev->putSuperFunc)
1899 +       {
1900 +                dev->putSuperFunc(sb);
1901 +       }
1902 +       yaffs_Deinitialise(dev);
1903 +       yaffs_GrossUnlock(dev);
1904 +
1905 +       /* we assume this is protected by lock_kernel() in mount/umount */
1906 +       list_del(&dev->devList);
1907 +
1908 +       kfree(dev);
1909 +}
1910 +
1911 +
1912 +#ifdef CONFIG_YAFFS_YAFFS1
1913 +
1914 +static void  yaffs_MTDPutSuper(struct super_block *sb)
1915 +{
1916 +       
1917 +       struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
1918 +       
1919 +       if(mtd->sync)
1920 +       {
1921 +               mtd->sync(mtd);
1922 +       }
1923 +       
1924 +       put_mtd_device(mtd);
1925 +}
1926 +
1927 +#endif
1928 +
1929 +
1930 +static struct super_block *yaffs_internal_read_super(int yaffsVersion, struct super_block * sb, void * data, int silent)
1931 +{
1932 +       int nBlocks;
1933 +       struct inode * inode = NULL;
1934 +       struct dentry * root;
1935 +       yaffs_Device *dev = 0;
1936 +       char devname_buf[BDEVNAME_SIZE+1];
1937 +       struct mtd_info *mtd;
1938 +       int err;
1939 +       
1940 +       sb->s_magic = YAFFS_MAGIC;
1941 +       sb->s_op = &yaffs_super_ops;
1942 +       
1943 +       if(!sb)
1944 +               printk(KERN_INFO"yaffs: sb is NULL\n");
1945 +       else if(!sb->s_dev)
1946 +               printk(KERN_INFO"yaffs: sb->s_dev is NULL\n");
1947 +       else if(!yaffs_devname(sb, devname_buf))
1948 +               printk(KERN_INFO"yaffs: devname is NULL\n");
1949 +       else
1950 +               printk(KERN_INFO"yaffs: dev is %d name is \"%s\"\n", sb->s_dev, yaffs_devname(sb, devname_buf));
1951 +
1952 +       
1953 +
1954 +       sb->s_blocksize = PAGE_CACHE_SIZE;
1955 +       sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
1956 +       T(YAFFS_TRACE_OS,("yaffs_read_super: Using yaffs%d\n",yaffsVersion));
1957 +       T(YAFFS_TRACE_OS,("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize)));
1958 +
1959 +#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
1960 +       T(YAFFS_TRACE_OS,("yaffs: Write verification disabled. All guarantees null and void\n"));
1961 +#endif
1962 +
1963 +
1964 +       T(YAFFS_TRACE_ALWAYS,("yaffs: Attempting MTD mount on %u.%u, \"%s\"\n",
1965 +        MAJOR(sb->s_dev),MINOR(sb->s_dev), yaffs_devname(sb, devname_buf)));
1966 +               
1967 +       // Check it's an mtd device.....
1968 +       if(MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
1969 +       {
1970 +               return NULL; // This isn't an mtd device
1971 +       } 
1972 +       
1973 +       // Get the device
1974 +       mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
1975 +       if (!mtd) 
1976 +       {
1977 +               T(YAFFS_TRACE_ALWAYS,("yaffs: MTD device #%u doesn't appear to exist\n", MINOR(sb->s_dev)));
1978 +               return NULL;
1979 +       }
1980 +       
1981 +       // Check it's NAND
1982 +       if(mtd->type != MTD_NANDFLASH)
1983 +       {
1984 +               T(YAFFS_TRACE_ALWAYS,("yaffs: MTD device is not NAND it's type %d\n", mtd->type));
1985 +               return NULL;
1986 +       }
1987 +
1988 +       T(YAFFS_TRACE_OS,(" erase %p\n",mtd->erase));
1989 +       T(YAFFS_TRACE_OS,(" read %p\n",mtd->read));
1990 +       T(YAFFS_TRACE_OS,(" write %p\n",mtd->write));
1991 +       T(YAFFS_TRACE_OS,(" readoob %p\n",mtd->read_oob));
1992 +       T(YAFFS_TRACE_OS,(" writeoob %p\n",mtd->write_oob));
1993 +//     T(YAFFS_TRACE_OS,(" block_isbad %p\n",mtd->block_isbad));
1994 +//     T(YAFFS_TRACE_OS,(" block_markbad %p\n",mtd->block_markbad));
1995 +       T(YAFFS_TRACE_OS,(" oobblock %d\n",mtd->oobblock));
1996 +       T(YAFFS_TRACE_OS,(" oobsize %d\n",mtd->oobsize));
1997 +       T(YAFFS_TRACE_OS,(" erasesize %d\n",mtd->erasesize));
1998 +       T(YAFFS_TRACE_OS,(" size %d\n",mtd->size));
1999 +
2000 +       if(yaffsVersion == 2)
2001 +       {
2002 +               // Check for version 2 style functions
2003 +               if(!mtd->erase ||
2004 +//                !mtd->block_isbad ||
2005 +//                !mtd->block_markbad ||
2006 +                  !mtd->read  ||
2007 +                  !mtd->write ||
2008 +                  !mtd->write_ecc ||
2009 +                  !mtd->read_ecc ||
2010 +                  !mtd->read_oob ||
2011 +                  !mtd->write_oob )
2012 +               {
2013 +                       T(YAFFS_TRACE_ALWAYS,("yaffs: MTD device does not support required functions\n"));;
2014 +                       return NULL;
2015 +               }
2016 +       
2017 +               if(mtd->oobblock < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
2018 +                  mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE)
2019 +               {
2020 +                       T(YAFFS_TRACE_ALWAYS,("yaffs: MTD device does not support have the right page sizes\n"));
2021 +                       return NULL;
2022 +               }               }
2023 +       else
2024 +       {
2025 +               // Check for V1 style functions
2026 +               if(!mtd->erase ||
2027 +                  !mtd->read  ||
2028 +                  !mtd->write ||
2029 +                  !mtd->write_ecc ||
2030 +                  !mtd->read_ecc ||
2031 +                  !mtd->read_oob ||
2032 +                  !mtd->write_oob )
2033 +               {
2034 +                       T(YAFFS_TRACE_ALWAYS,("yaffs: MTD device does not support required functions\n"));;
2035 +                       return NULL;
2036 +               }
2037 +       
2038 +               if(mtd->oobblock != YAFFS_BYTES_PER_CHUNK ||
2039 +                  mtd->oobsize != YAFFS_BYTES_PER_SPARE)
2040 +               {
2041 +                       T(YAFFS_TRACE_ALWAYS,("yaffs: MTD device does not support have the right page sizes\n"));
2042 +                       return NULL;
2043 +               }
2044 +       }
2045 +          
2046 +
2047 +               // OK, so if we got here, we have an MTD that's NAND and looks 
2048 +               // like it has the right capabilities
2049 +               // Set the yaffs_Device up for mtd
2050 +
2051 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
2052 +       sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device),GFP_KERNEL);
2053 +#else
2054 +       sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device),GFP_KERNEL);
2055 +#endif
2056 +       if(!dev)
2057 +       {
2058 +               // Deep shit could not allocate device structure
2059 +               T(YAFFS_TRACE_ALWAYS,("yaffs_read_super: Failed trying to allocate yaffs_Device. \n"));
2060 +               return NULL;
2061 +       }
2062 +
2063 +       memset(dev,0,sizeof(yaffs_Device));
2064 +       dev->genericDevice = mtd; 
2065 +       dev->name = mtd->name;
2066 +
2067 +       // Set up the memory size parameters....
2068 +       
2069 +       nBlocks = mtd->size / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
2070 +       dev->startBlock = 0;
2071 +       dev->endBlock = nBlocks - 1;
2072 +       dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
2073 +       dev->nBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
2074 +       dev->nReservedBlocks = 5;
2075 +       dev->nShortOpCaches = 10; // Enable short op caching
2076 +       
2077 +
2078 +       // ... and the functions.
2079 +       if(yaffsVersion == 2)
2080 +       {
2081 +               dev->writeChunkWithTagsToNAND = nandmtd2_WriteChunkWithTagsToNAND;
2082 +               dev->readChunkWithTagsFromNAND = nandmtd2_ReadChunkWithTagsFromNAND;
2083 +               dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
2084 +               dev->queryNANDBlock = nandmtd2_QueryNANDBlock;
2085 +               dev->spareBuffer = YMALLOC(mtd->oobsize);
2086 +               dev->isYaffs2 = 1;
2087 +               dev->nBytesPerChunk = mtd->oobblock;
2088 +               dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
2089 +               nBlocks = mtd->size / mtd->erasesize;
2090 +               dev->startBlock = 0;
2091 +               dev->endBlock = nBlocks - 1;
2092 +       }
2093 +       else
2094 +       {
2095 +               dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
2096 +               dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
2097 +               dev->isYaffs2 = 0;
2098 +       }
2099 +       // ... and common functions
2100 +       dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
2101 +       dev->initialiseNAND = nandmtd_InitialiseNAND;
2102 +       
2103 +       dev->putSuperFunc = yaffs_MTDPutSuper;
2104 +       
2105 +#ifndef CONFIG_YAFFS_DOES_ECC
2106 +       dev->useNANDECC = 1;
2107 +#endif
2108 +
2109 +       /* we assume this is protected by lock_kernel() in mount/umount */
2110 +       list_add_tail(&dev->devList, &yaffs_dev_list);
2111 +
2112 +       init_MUTEX(&dev->grossLock);
2113 +       
2114 +       
2115 +       yaffs_GrossLock(dev);
2116 +       
2117 +       err = yaffs_GutsInitialise(dev);
2118 +
2119 +       T(YAFFS_TRACE_OS,("yaffs_read_super: guts initialised %s\n", (err == YAFFS_OK) ? "OK" : "FAILED"));
2120 +
2121 +       // Create root inode
2122 +       if(err == YAFFS_OK)
2123 +         inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,yaffs_Root(dev));
2124 +
2125 +       yaffs_GrossUnlock(dev);
2126 +
2127 +       if (!inode)
2128 +               return NULL;
2129 +               
2130 +// added NCB
2131 +       inode->i_op = & yaffs_dir_inode_operations;
2132 +       inode->i_fop = & yaffs_dir_operations;
2133 +
2134 +       T(YAFFS_TRACE_OS,("yaffs_read_super: got root inode\n"));
2135 +               
2136 +
2137 +       root = d_alloc_root(inode);
2138 +
2139 +       T(YAFFS_TRACE_OS,("yaffs_read_super: d_alloc_root done\n"));
2140 +
2141 +       if (!root) {
2142 +               iput(inode);
2143 +               return NULL;
2144 +       }
2145 +       sb->s_root = root;
2146 +
2147 +       T(YAFFS_TRACE_OS,("yaffs_read_super: done\n"));
2148 +       return sb;
2149 +}
2150 +
2151 +
2152 +
2153 +#ifdef CONFIG_YAFFS_YAFFS1
2154 +
2155 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
2156 +static int yaffs_internal_read_super_mtd(struct super_block * sb, void * data, int silent)
2157 +{
2158 +        return yaffs_internal_read_super(1,sb,data,silent) ? 0 : -1;
2159 +}
2160 +
2161 +static struct super_block *yaffs_read_super(struct file_system_type * fs, int flags, const char *dev_name, void *data)
2162 +{
2163 +
2164 +    return get_sb_bdev(fs, flags, dev_name, data, yaffs_internal_read_super_mtd);
2165 +}
2166 +
2167 +static struct file_system_type yaffs_fs_type = {
2168 +       .owner          = THIS_MODULE,
2169 +       .name           = "yaffs",
2170 +       .get_sb         = yaffs_read_super,
2171 +       .kill_sb        = kill_block_super,
2172 +       .fs_flags       = FS_REQUIRES_DEV,
2173 +};
2174 +#else
2175 +static struct super_block *yaffs_read_super(struct super_block * sb, void * data, int silent)
2176 +{
2177 +       return yaffs_internal_read_super(1,sb,data,silent);
2178 +}
2179 +
2180 +static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super, FS_REQUIRES_DEV);
2181 +#endif
2182 +
2183 +#endif // CONFIG_YAFFS_YAFFS1
2184 +
2185 +#ifdef CONFIG_YAFFS_YAFFS2
2186 +
2187 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
2188 +static int yaffs2_internal_read_super_mtd(struct super_block * sb, void * data, int silent)
2189 +{
2190 +        return yaffs_internal_read_super(2,sb,data,silent) ? 0 : -1;
2191 +}
2192 +
2193 +static struct super_block *yaffs2_read_super(struct file_system_type * fs, int flags, const char *dev_name, void *data)
2194 +{
2195 +
2196 +    return get_sb_bdev(fs, flags, dev_name, data, yaffs2_internal_read_super_mtd);
2197 +}
2198 +
2199 +static struct file_system_type yaffs2_fs_type = {
2200 +       .owner          = THIS_MODULE,
2201 +       .name           = "yaffs2",
2202 +       .get_sb         = yaffs2_read_super,
2203 +       .kill_sb        = kill_block_super,
2204 +       .fs_flags       = FS_REQUIRES_DEV,
2205 +};
2206 +#else
2207 +static struct super_block *yaffs2_read_super(struct super_block * sb, void * data, int silent)
2208 +{
2209 +       return yaffs_internal_read_super(2,sb,data,silent);
2210 +}
2211 +
2212 +static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super, FS_REQUIRES_DEV);
2213 +#endif
2214 +
2215 +#endif // CONFIG_YAFFS_YAFFS2
2216 +
2217 +
2218 +
2219 +
2220 +static struct proc_dir_entry *my_proc_entry;
2221 +
2222 +static char * yaffs_dump_dev(char *buf,yaffs_Device *dev)
2223 +{
2224 +       buf +=sprintf(buf,"startBlock......... %d\n",dev->startBlock);
2225 +       buf +=sprintf(buf,"endBlock........... %d\n",dev->endBlock);
2226 +       buf +=sprintf(buf,"chunkGroupBits..... %d\n",dev->chunkGroupBits);
2227 +       buf +=sprintf(buf,"chunkGroupSize..... %d\n",dev->chunkGroupSize);
2228 +       buf +=sprintf(buf,"nErasedBlocks...... %d\n",dev->nErasedBlocks);
2229 +       buf +=sprintf(buf,"nTnodesCreated..... %d\n",dev->nTnodesCreated);
2230 +       buf +=sprintf(buf,"nFreeTnodes........ %d\n",dev->nFreeTnodes);
2231 +       buf +=sprintf(buf,"nObjectsCreated.... %d\n",dev->nObjectsCreated);
2232 +       buf +=sprintf(buf,"nFreeObjects....... %d\n",dev->nFreeObjects);
2233 +       buf +=sprintf(buf,"nFreeChunks........ %d\n",dev->nFreeChunks);
2234 +       buf +=sprintf(buf,"nPageWrites........ %d\n",dev->nPageWrites);
2235 +       buf +=sprintf(buf,"nPageReads......... %d\n",dev->nPageReads);
2236 +       buf +=sprintf(buf,"nBlockErasures..... %d\n",dev->nBlockErasures);
2237 +       buf +=sprintf(buf,"nGCCopies.......... %d\n",dev->nGCCopies);
2238 +       buf +=sprintf(buf,"garbageCollections. %d\n",dev->garbageCollections);
2239 +       buf +=sprintf(buf,"passiveGCs......... %d\n",dev->passiveGarbageCollections);
2240 +       buf +=sprintf(buf,"nRetriedWrites..... %d\n",dev->nRetriedWrites);
2241 +       buf +=sprintf(buf,"nRetireBlocks...... %d\n",dev->nRetiredBlocks);
2242 +       buf +=sprintf(buf,"eccFixed........... %d\n",dev->eccFixed);
2243 +       buf +=sprintf(buf,"eccUnfixed......... %d\n",dev->eccUnfixed);
2244 +       buf +=sprintf(buf,"tagsEccFixed....... %d\n",dev->tagsEccFixed);
2245 +       buf +=sprintf(buf,"tagsEccUnfixed..... %d\n",dev->tagsEccUnfixed);
2246 +       buf +=sprintf(buf,"cacheHits.......... %d\n",dev->cacheHits);
2247 +       buf +=sprintf(buf,"nDeletedFiles...... %d\n",dev->nDeletedFiles);
2248 +       buf +=sprintf(buf,"nUnlinkedFiles..... %d\n",dev->nUnlinkedFiles);
2249 +       buf +=sprintf(buf,"nBackgroudDeletions %d\n",dev->nBackgroundDeletions);
2250 +       buf +=sprintf(buf,"useNANDECC......... %d\n",dev->useNANDECC);
2251 +       buf +=sprintf(buf,"isYaffs2........... %d\n",dev->isYaffs2);
2252 +
2253 +       return buf;     
2254 +}
2255 +
2256 +static int  yaffs_proc_read(
2257 +        char *page,
2258 +       char **start,
2259 +       off_t offset,
2260 +       int count,
2261 +       int *eof,
2262 +       void *data
2263 +       )
2264 +{
2265 +       struct list_head *item;
2266 +       char *buf = page;
2267 +       int step = offset;
2268 +       int n = 0;
2269 +
2270 +       /* Get proc_file_read() to step 'offset' by one on each sucessive call.
2271 +        * We use 'offset' (*ppos) to indicate where we are in devList.
2272 +        * This also assumes the user has posted a read buffer large
2273 +        * enough to hold the complete output; but that's life in /proc.
2274 +        */
2275 +
2276 +       *(int *)start = 1;
2277 +
2278 +       /* Print header first */
2279 +       if (step == 0) {
2280 +               buf += sprintf(buf, "YAFFS built:" __DATE__ " "__TIME__
2281 +               "\n%s\n%s\n", yaffs_fs_c_version, yaffs_guts_c_version);
2282 +       }
2283 +
2284 +       /* hold lock_kernel while traversing yaffs_dev_list */
2285 +       lock_kernel();
2286 +
2287 +       /* Locate and print the Nth entry.  Order N-squared but N is small. */
2288 +       list_for_each(item, &yaffs_dev_list) {
2289 +               yaffs_Device *dev = list_entry(item, yaffs_Device, devList);
2290 +               if (n < step) {
2291 +                       n++;
2292 +                       continue;
2293 +               }
2294 +               buf += sprintf(buf,"\nDevice %d \"%s\"\n", n, dev->name);
2295 +               buf = yaffs_dump_dev(buf, dev);
2296 +               break;
2297 +       }
2298 +       unlock_kernel();
2299 +
2300 +       return buf-page < count ? buf-page : count;
2301 +}
2302 +
2303 +// Stuff to handle installation of file systems
2304 +struct file_system_to_install
2305 +{
2306 +   struct file_system_type *fst;
2307 +   int installed;
2308 +};
2309 +
2310 +static struct file_system_to_install fs_to_install[] =
2311 +{
2312 +#ifdef CONFIG_YAFFS_YAFFS1
2313 +     { &yaffs_fs_type,0},
2314 +#endif
2315 +#ifdef CONFIG_YAFFS_YAFFS2
2316 +     { &yaffs2_fs_type,0},
2317 +#endif
2318 +     { NULL,0}
2319 +};
2320 +
2321 +static int __init init_yaffs_fs(void)
2322 +{
2323 +       int error = 0;
2324 +       struct file_system_to_install *fsinst;  
2325 +       
2326 +   T(YAFFS_TRACE_ALWAYS,("yaffs " __DATE__ " " __TIME__ " Installing. \n"));
2327 +
2328 +
2329 +
2330 +    /* Install the proc_fs entry */
2331 +    my_proc_entry = create_proc_read_entry("yaffs",
2332 +                                           S_IRUGO | S_IFREG,
2333 +                                          &proc_root,
2334 +                                          yaffs_proc_read,
2335 +                                          NULL);
2336 +    if(!my_proc_entry)
2337 +    {
2338 +       return -ENOMEM;
2339 +    }
2340 +    
2341 +    
2342 +
2343 +    // Now add the file system entries
2344 +    
2345 +    fsinst = fs_to_install;
2346 +    
2347 +    while(fsinst->fst && !error)
2348 +    {
2349 +      error = register_filesystem(fsinst->fst);
2350 +      if(!error)
2351 +      {
2352 +          fsinst->installed = 1;
2353 +      }
2354 +      fsinst++;
2355 +    }
2356 +   
2357 +    // Any errors? uninstall 
2358 +    if(error)
2359 +    {
2360 +           fsinst = fs_to_install;
2361 +           
2362 +           while(fsinst->fst)
2363 +           {
2364 +             if(fsinst->installed)
2365 +             {
2366 +               unregister_filesystem(fsinst->fst);
2367 +               fsinst->installed = 0;
2368 +             }
2369 +             fsinst++;
2370 +           }
2371 +    }
2372 +    
2373 +    return error;
2374 +}
2375 +
2376 +static void __exit exit_yaffs_fs(void)
2377 +{
2378 +
2379 +   struct file_system_to_install *fsinst;
2380 +   
2381 +   T(YAFFS_TRACE_ALWAYS,("yaffs " __DATE__ " " __TIME__ " removing. \n"));
2382 +
2383 +   remove_proc_entry("yaffs",&proc_root);
2384 +    
2385 +    fsinst = fs_to_install;
2386 +    
2387 +    while(fsinst->fst)
2388 +    {
2389 +      if(fsinst->installed)
2390 +      {
2391 +        unregister_filesystem(fsinst->fst);
2392 +        fsinst->installed = 0;
2393 +      }
2394 +      fsinst++;
2395 +    }
2396 +
2397 +}
2398 +
2399 +module_init(init_yaffs_fs)
2400 +module_exit(exit_yaffs_fs)
2401 +
2402 +MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
2403 +MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002,2003,2004");
2404 +MODULE_LICENSE("GPL");
2405 +
2406 +
2407 diff --git a/fs/yaffs/yaffs_guts.c b/fs/yaffs/yaffs_guts.c
2408 new file mode 100644
2409 index 0000000..bf13f91
2410 --- /dev/null
2411 +++ b/fs/yaffs/yaffs_guts.c
2412 @@ -0,0 +1,6346 @@
2413 +/*
2414 + * YAFFS: Yet another FFS. A NAND-flash specific file system. 
2415 + *
2416 + * Copyright (C) 2002 Aleph One Ltd.
2417 + *   for Toby Churchill Ltd and Brightstar Engineering
2418 + *
2419 + * Created by Charles Manning <charles@aleph1.co.uk>
2420 + *
2421 + * This program is free software; you can redistribute it and/or modify
2422 + * it under the terms of the GNU General Public License version 2 as
2423 + * published by the Free Software Foundation.
2424 + *
2425 + */
2426 + //yaffs_guts.c
2427 +
2428 +const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.15 2005/08/02 04:24:22 charles Exp $";
2429 +
2430 +#include "yportenv.h"
2431 +
2432 +#include "yaffsinterface.h"
2433 +#include "yaffs_guts.h"
2434 +#include "yaffs_tagsvalidity.h"
2435 +
2436 +
2437 +#include "yaffs_tagscompat.h"
2438 +
2439 +#ifdef CONFIG_YAFFS_WINCE
2440 +void yfsd_LockYAFFS(BOOL fsLockOnly);
2441 +void yfsd_UnlockYAFFS(BOOL fsLockOnly);
2442 +#endif
2443 +
2444 +#define YAFFS_PASSIVE_GC_CHUNKS 2
2445 +
2446 +#if 0
2447 +// Use Steven Hill's ECC struff instead
2448 +// External functions for ECC on data
2449 +void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);
2450 +int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
2451 +#define yaffs_ECCCalculate(data,ecc) nand_calculate_ecc(data,ecc)
2452 +#define yaffs_ECCCorrect(data,read_ecc,calc_ecc) nand_correct_ecc(data,read_ecc,calc_ecc)
2453 +#else
2454 +#include "yaffs_ecc.h"
2455 +#endif
2456 +
2457 +#if 0
2458 +// countBits is a quick way of counting the number of bits in a byte.
2459 +// ie. countBits[n] holds the number of 1 bits in a byte with the value n.
2460 +
2461 +static const char yaffs_countBitsTable[256] =
2462 +{
2463 +0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
2464 +1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2465 +1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2466 +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2467 +1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2468 +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2469 +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2470 +3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
2471 +1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2472 +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2473 +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2474 +3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
2475 +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2476 +3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
2477 +3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
2478 +4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
2479 +};
2480 +
2481 +static int yaffs_CountBits(__u8 x)
2482 +{
2483 +       int retVal;
2484 +       retVal = yaffs_countBitsTable[x];
2485 +       return retVal;
2486 +}
2487 +
2488 +#endif
2489 +
2490 +
2491 +#if 0
2492 +// Stuff using yea olde tags
2493 +static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr);
2494 +static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr);
2495 +
2496 +static int yaffs_ReadChunkTagsFromNAND(yaffs_Device *dev,int chunkInNAND, yaffs_Tags *tags, int *chunkDeleted);
2497 +static int yaffs_TagsMatch(const yaffs_Tags *tags, int objectId, int chunkInObject, int chunkDeleted);
2498 +#else
2499 +#endif
2500 +
2501 +// NAND access
2502 +
2503 +
2504 +static Y_INLINE int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *buffer, yaffs_ExtendedTags *tags);
2505 +static Y_INLINE int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, const __u8 *data, yaffs_ExtendedTags *tags);
2506 +static Y_INLINE int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo);
2507 +static Y_INLINE int yaffs_QueryInitialBlockState(yaffs_Device *dev,int blockNo, yaffs_BlockState *state,unsigned *sequenceNumber);
2508 +// Local prototypes
2509 +static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_ExtendedTags *tags, int useReserve);
2510 +#if 0
2511 +static int yaffs_CheckObjectHashSanity(yaffs_Device *dev);
2512 +#endif
2513 +static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan);
2514 +
2515 +static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type);
2516 +static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj);
2517 +static int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink, int shadows);
2518 +static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
2519 +static int yaffs_CheckStructures(void);
2520 +static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit);
2521 +static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);
2522 +
2523 +static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev,int blockNo);
2524 +
2525 +static __u8 *yaffs_GetTempBuffer(yaffs_Device *dev,int lineNo);
2526 +static void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo);
2527 +
2528 +
2529 +// Robustification (if it ever comes about...)
2530 +static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND);
2531 +#if 0
2532 +static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND);
2533 +#endif
2534 +static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND);
2535 +static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags);
2536 +static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND,  const yaffs_ExtendedTags *tags);
2537 +
2538 +static int  yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND);
2539 +
2540 +static int yaffs_UnlinkWorker(yaffs_Object *obj);
2541 +static void yaffs_DestroyObject(yaffs_Object *obj);
2542 +
2543 +#if 0
2544 +static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1,int dataSize);
2545 +#endif
2546 +
2547 +static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, int chunkInObject);
2548 +
2549 +
2550 +loff_t yaffs_GetFileSize(yaffs_Object *obj);
2551 +
2552 +
2553 +static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve);
2554 +
2555 +static void yaffs_VerifyFreeChunks(yaffs_Device *dev);
2556 +
2557 +#ifdef YAFFS_PARANOID
2558 +static int yaffs_CheckFileSanity(yaffs_Object *in);
2559 +#else
2560 +#define yaffs_CheckFileSanity(in)
2561 +#endif
2562 +
2563 +static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);
2564 +static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
2565 +
2566 +static int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *buffer, yaffs_ExtendedTags *tags)
2567 +{
2568 +       chunkInNAND -= dev->chunkOffset;
2569 +       
2570 +       if(dev->readChunkWithTagsFromNAND)
2571 +               return dev->readChunkWithTagsFromNAND(dev,chunkInNAND,buffer,tags);
2572 +       else
2573 +               return yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,chunkInNAND,buffer,tags);
2574 +}
2575 +
2576 +static Y_INLINE int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, const __u8 *buffer, yaffs_ExtendedTags *tags)
2577 +{
2578 +       chunkInNAND -= dev->chunkOffset;
2579 +       
2580 +       if(tags)
2581 +       {
2582 +               tags->sequenceNumber = dev->sequenceNumber;
2583 +               tags->chunkUsed = 1;
2584 +               if(!yaffs_ValidateTags(tags))
2585 +               {
2586 +                       T(YAFFS_TRACE_ERROR,(TSTR("Writing uninitialised tags" TENDSTR)));
2587 +                       YBUG();
2588 +               }
2589 +               T(YAFFS_TRACE_WRITE,(TSTR("Writing chunk %d tags %d %d"TENDSTR),chunkInNAND,tags->objectId,tags->chunkId));
2590 +       }
2591 +       else
2592 +       {
2593 +                       T(YAFFS_TRACE_ERROR,(TSTR("Writing with no tags" TENDSTR)));
2594 +                       YBUG();
2595 +       }
2596 +
2597 +       if(dev->writeChunkWithTagsToNAND)
2598 +               return dev->writeChunkWithTagsToNAND(dev,chunkInNAND,buffer,tags);
2599 +       else
2600 +               return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,chunkInNAND,buffer,tags);
2601 +}
2602 +
2603 +static Y_INLINE int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo)
2604 +{
2605 +       blockNo -= dev->blockOffset;
2606 +       
2607 +       if(dev->markNANDBlockBad)
2608 +               return dev->markNANDBlockBad(dev,blockNo);
2609 +       else
2610 +               return yaffs_TagsCompatabilityMarkNANDBlockBad(dev,blockNo);
2611 +}
2612 +static Y_INLINE int yaffs_QueryInitialBlockState(yaffs_Device *dev,int blockNo, yaffs_BlockState *state, unsigned *sequenceNumber)
2613 +{
2614 +       blockNo -= dev->blockOffset;
2615 +       
2616 +       if(dev->queryNANDBlock)
2617 +               return dev->queryNANDBlock(dev,blockNo,state,sequenceNumber);
2618 +       else
2619 +               return yaffs_TagsCompatabilityQueryNANDBlock(dev,blockNo,state,sequenceNumber);
2620 +}
2621 +
2622 +static int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
2623 +{
2624 +       int result;
2625 +       
2626 +       blockInNAND -= dev->blockOffset;
2627 +
2628 +       dev->nBlockErasures++;
2629 +       result = dev->eraseBlockInNAND(dev,blockInNAND);
2630 +
2631 +       if(!result)result = dev->eraseBlockInNAND(dev,blockInNAND); // If at first we don't succeed, try again *once*.
2632 +       return result;
2633 +}
2634 +
2635 +static int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
2636 +{
2637 +       return dev->initialiseNAND(dev);
2638 +}
2639 +
2640 +
2641 +
2642 +
2643 +// Temporary buffer manipulations
2644 +
2645 +static __u8 *yaffs_GetTempBuffer(yaffs_Device *dev,int lineNo)
2646 +{
2647 +       int i,j;
2648 +       for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
2649 +       {
2650 +               if(dev->tempBuffer[i].line == 0)
2651 +               {
2652 +                       dev->tempBuffer[i].line = lineNo;
2653 +                       if((i+1) > dev->maxTemp)
2654 +                       {
2655 +                               dev->maxTemp = i + 1;
2656 +                               for(j = 0; j <= i; j++)
2657 +                                       dev->tempBuffer[j].maxLine = dev->tempBuffer[j].line;
2658 +                       }       
2659 +                       
2660 +                       return dev->tempBuffer[i].buffer;
2661 +               }
2662 +       }
2663 +
2664 +       T(YAFFS_TRACE_BUFFERS,(TSTR("Out of temp buffers at line %d, other held by lines:"),lineNo));
2665 +       for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
2666 +       {
2667 +               T(YAFFS_TRACE_BUFFERS,(TSTR(" %d "),dev->tempBuffer[i].line));
2668 +       }
2669 +       T(YAFFS_TRACE_BUFFERS,(TSTR(" "TENDSTR)));
2670 +       
2671 +       dev->unmanagedTempAllocations++;
2672 +       // Get an unmanaged one
2673 +       return YMALLOC(dev->nBytesPerChunk);    
2674 +       
2675 +       
2676 +}
2677 +
2678 +static void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo)
2679 +{
2680 +       int i;
2681 +       for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
2682 +       {
2683 +               if(dev->tempBuffer[i].buffer == buffer)
2684 +               {
2685 +                       dev->tempBuffer[i].line = 0;
2686 +                       return;
2687 +               }
2688 +       }
2689 +       
2690 +       if(buffer)
2691 +       {
2692 +               // assume it is an unmanaged one.
2693 +               T(YAFFS_TRACE_BUFFERS,(TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR),lineNo));
2694 +               YFREE(buffer);
2695 +               dev->unmanagedTempDeallocations++;
2696 +       }
2697 +
2698 +}
2699 +
2700 +
2701 +// Chunk bitmap manipulations
2702 +
2703 +static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
2704 +{
2705 +       if(blk < dev->internalStartBlock || blk > dev->internalEndBlock)
2706 +       {
2707 +               T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),blk));
2708 +               YBUG();
2709 +       }
2710 +       return dev->chunkBits + (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
2711 +}
2712 +
2713 +static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev,int blk)
2714 +{
2715 +       __u8 *blkBits = yaffs_BlockBits(dev,blk);
2716 +
2717 +        memset(blkBits,0,dev->chunkBitmapStride);
2718 +}
2719 +
2720 +static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device *dev,int blk,int chunk)
2721 +{
2722 +       __u8 *blkBits = yaffs_BlockBits(dev,blk);
2723 +       
2724 +       blkBits[chunk/8] &=  ~ (1<<(chunk & 7));
2725 +}
2726 +
2727 +static Y_INLINE void yaffs_SetChunkBit(yaffs_Device *dev,int blk,int chunk)
2728 +{
2729 +       __u8 *blkBits = yaffs_BlockBits(dev,blk);
2730 +
2731 +       blkBits[chunk/8] |=   (1<<(chunk & 7));
2732 +}
2733 +
2734 +static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device *dev,int blk,int chunk)
2735 +{
2736 +       __u8 *blkBits = yaffs_BlockBits(dev,blk);
2737 +       return (blkBits[chunk/8] &  (1<<(chunk & 7))) ? 1 :0;
2738 +}
2739 +
2740 +static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev,int blk)
2741 +{
2742 +       __u8 *blkBits = yaffs_BlockBits(dev,blk);
2743 +       int i;
2744 +       for(i = 0; i < dev->chunkBitmapStride; i++)
2745 +       {
2746 +               if(*blkBits) return 1;
2747 +               blkBits++;
2748 +       }
2749 +       return 0;
2750 +}
2751 +
2752 +
2753 +static  Y_INLINE int yaffs_HashFunction(int n)
2754 +{
2755 +       return (n % YAFFS_NOBJECT_BUCKETS);
2756 +}
2757 +
2758 +
2759 +yaffs_Object *yaffs_Root(yaffs_Device *dev)
2760 +{
2761 +       return dev->rootDir;
2762 +}
2763 +
2764 +yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
2765 +{
2766 +       return dev->lostNFoundDir;
2767 +}
2768 +
2769 +
2770 +
2771 +
2772 +int yaffs_CheckFF(__u8 *buffer,int nBytes)
2773 +{
2774 +       //Horrible, slow implementation
2775 +       while(nBytes--)
2776 +       {
2777 +               if(*buffer != 0xFF) return 0;
2778 +               buffer++;
2779 +       }
2780 +       return 1;
2781 +}
2782 +
2783 +static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND)
2784 +{
2785 +
2786 +       int retval = YAFFS_OK;
2787 +       __u8 *data = yaffs_GetTempBuffer(dev,__LINE__);
2788 +       yaffs_ExtendedTags tags;
2789 +
2790 +// NCB         dev->readChunkWithTagsFromNAND(dev,chunkInNAND,data,&tags);
2791 +       yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND,data,&tags);
2792 +       
2793 +       if(!yaffs_CheckFF(data,dev->nBytesPerChunk) || tags.chunkUsed)
2794 +       {
2795 +               T(YAFFS_TRACE_NANDACCESS,(TSTR("Chunk %d not erased" TENDSTR),chunkInNAND));
2796 +               retval = YAFFS_FAIL;
2797 +       }
2798 +
2799 +       yaffs_ReleaseTempBuffer(dev,data,__LINE__);
2800 +       
2801 +       return retval;
2802 +       
2803 +}
2804 +
2805 +
2806 +
2807 +#if 1
2808 +static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, const __u8 *data, yaffs_ExtendedTags *tags,int useReserve)
2809 +{
2810 +       int chunk;
2811 +       
2812 +       int writeOk = 1;
2813 +       int attempts = 0;
2814 +       
2815 +
2816 +       
2817 +       do{
2818 +               chunk = yaffs_AllocateChunk(dev,useReserve);
2819 +       
2820 +               if(chunk >= 0)
2821 +               {
2822 +
2823 +                       // First check this chunk is erased...
2824 +#ifndef CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
2825 +                       writeOk = yaffs_CheckChunkErased(dev,chunk);
2826 +#endif         
2827 +                       if(!writeOk)
2828 +                       {
2829 +                               T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d was not erased" TENDSTR),chunk));
2830 +                       }
2831 +                       else
2832 +                       {
2833 +                               writeOk =  yaffs_WriteChunkWithTagsToNAND(dev,chunk,data,tags);
2834 +                       }
2835 +                       attempts++;
2836 +
2837 +                       if(writeOk)
2838 +                       {
2839 +                               // Copy the data into the robustification buffer.
2840 +                               // NB We do this at the end to prevent duplicates in the case of a write error.
2841 +                               //Todo
2842 +                               yaffs_HandleWriteChunkOk(dev,chunk,data,tags);
2843 +                       }
2844 +                       else
2845 +                       {
2846 +                               yaffs_HandleWriteChunkError(dev,chunk);
2847 +                       }
2848 +               }
2849 +               
2850 +       } while(chunk >= 0 && ! writeOk);
2851 +       
2852 +       if(attempts > 1)
2853 +       {
2854 +               T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs write required %d attempts" TENDSTR),attempts));
2855 +               dev->nRetriedWrites+= (attempts - 1);   
2856 +       }
2857 +       
2858 +
2859 +       
2860 +       return chunk;
2861 +}
2862 +#endif
2863 +
2864 +
2865 +///
2866 +// Functions for robustisizing
2867 +//
2868 +//
2869 +
2870 +static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND)
2871 +{
2872 +       
2873 +       yaffs_MarkBlockBad(dev,blockInNAND);
2874 +       
2875 +       yaffs_GetBlockInfo(dev,blockInNAND)->blockState = YAFFS_BLOCK_STATE_DEAD;
2876 +
2877 +       dev->nRetiredBlocks++;
2878 +}
2879 +
2880 +
2881 +#if 0
2882 +static int yaffs_RewriteBufferedBlock(yaffs_Device *dev)
2883 +{
2884 +       dev->doingBufferedBlockRewrite = 1;
2885 +       //
2886 +       //      Remove erased chunks
2887 +       //  Rewrite existing chunks to a new block
2888 +       //      Set current write block to the new block
2889 +       
2890 +       dev->doingBufferedBlockRewrite = 0;
2891 +       
2892 +       return 1;
2893 +}
2894 +
2895 +
2896 +static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND)
2897 +{
2898 +       int blockInNAND = chunkInNAND/dev->nChunksPerBlock;
2899 +
2900 +       // Mark the block for retirement
2901 +       yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
2902 +       T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>>Block %d marked for retirement" TENDSTR),blockInNAND));
2903 +
2904 +
2905 +       //TODO  
2906 +       // Just do a garbage collection on the affected block then retire the block
2907 +       // NB recursion
2908 +}
2909 +
2910 +
2911 +static void yaffs_CheckWrittenBlock(yaffs_Device *dev,int chunkInNAND)
2912 +{
2913 +}
2914 +
2915 +#endif
2916 +
2917 +static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags)
2918 +{
2919 +}
2920 +
2921 +static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_ExtendedTags *tags)
2922 +{
2923 +}
2924 +
2925 +static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND)
2926 +{
2927 +       int blockInNAND = chunkInNAND/dev->nChunksPerBlock;
2928 +
2929 +       // Mark the block for retirement
2930 +       yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
2931 +       // Delete the chunk
2932 +       yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__);
2933 +}
2934 +
2935 +
2936 +
2937 +#if 0
2938 +static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1,int dataSize)
2939 +{
2940 +
2941 +
2942 +       if( memcmp(d0,d1,dataSize) != 0 ||
2943 +               s0->tagByte0 != s1->tagByte0 ||
2944 +               s0->tagByte1 != s1->tagByte1 ||
2945 +               s0->tagByte2 != s1->tagByte2 ||
2946 +               s0->tagByte3 != s1->tagByte3 ||
2947 +               s0->tagByte4 != s1->tagByte4 ||
2948 +               s0->tagByte5 != s1->tagByte5 ||
2949 +               s0->tagByte6 != s1->tagByte6 ||
2950 +               s0->tagByte7 != s1->tagByte7 ||
2951 +               s0->ecc1[0]  != s1->ecc1[0]  ||
2952 +               s0->ecc1[1]  != s1->ecc1[1]  ||
2953 +               s0->ecc1[2]  != s1->ecc1[2]  ||
2954 +               s0->ecc2[0]  != s1->ecc2[0]  ||
2955 +               s0->ecc2[1]  != s1->ecc2[1]  ||
2956 +               s0->ecc2[2]  != s1->ecc2[2] )
2957 +               {
2958 +                       return 0;
2959 +               }
2960 +       
2961 +       return 1;
2962 +}
2963 +#endif
2964 +
2965 +
2966 +///////////////////////// Object management //////////////////
2967 +// List of spare objects
2968 +// The list is hooked together using the first pointer
2969 +// in the object
2970 +
2971 +// static yaffs_Object *yaffs_freeObjects = NULL;
2972 +
2973 +// static int yaffs_nFreeObjects;
2974 +
2975 +// static yaffs_ObjectList *yaffs_allocatedObjectList = NULL;
2976 +
2977 +// static yaffs_ObjectBucket yaffs_objectBucket[YAFFS_NOBJECT_BUCKETS];
2978 +
2979 +
2980 +static __u16 yaffs_CalcNameSum(const YCHAR *name)
2981 +{
2982 +       __u16 sum = 0;
2983 +       __u16 i = 1;
2984 +       
2985 +       YUCHAR *bname = (YUCHAR *)name;
2986 +       if(bname)
2987 +       {
2988 +               while ((*bname) && (i <=YAFFS_MAX_NAME_LENGTH))
2989 +               {
2990 +
2991 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
2992 +                       sum += yaffs_toupper(*bname) * i;
2993 +#else
2994 +                       sum += (*bname) * i;
2995 +#endif
2996 +                       i++;
2997 +                       bname++;
2998 +               }
2999 +       }
3000 +       return sum;
3001 +}
3002 +
3003 +static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
3004 +{
3005 +#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
3006 +                                       if(name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH)
3007 +                                       {
3008 +                                               yaffs_strcpy(obj->shortName,name);
3009 +                                       }
3010 +                                       else
3011 +                                       {
3012 +                                               obj->shortName[0]=_Y('\0');
3013 +                                       }
3014 +#endif
3015 +                                       obj->sum = yaffs_CalcNameSum(name);
3016 +}
3017 +
3018 +#if 0
3019 +void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
3020 +{
3021 +       yaffs_ECCCalculate(data , spare->ecc1);
3022 +       yaffs_ECCCalculate(&data[256] , spare->ecc2);
3023 +}
3024 +#endif
3025 +
3026 +
3027 +///////////////////////// TNODES ///////////////////////
3028 +
3029 +// List of spare tnodes
3030 +// The list is hooked together using the first pointer
3031 +// in the tnode.
3032 +
3033 +//static yaffs_Tnode *yaffs_freeTnodes = NULL;
3034 +
3035 +// static int yaffs_nFreeTnodes;
3036 +
3037 +//static yaffs_TnodeList *yaffs_allocatedTnodeList = NULL;
3038 +
3039 +
3040 +
3041 +// yaffs_CreateTnodes creates a bunch more tnodes and
3042 +// adds them to the tnode free list.
3043 +// Don't use this function directly
3044 +
3045 +static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes)
3046 +{
3047 +    int i;
3048 +    yaffs_Tnode *newTnodes;
3049 +    yaffs_TnodeList *tnl;
3050 +    
3051 +    if(nTnodes < 1) return YAFFS_OK;
3052 +   
3053 +       // make these things
3054 +       
3055 +    newTnodes = YMALLOC(nTnodes * sizeof(yaffs_Tnode));
3056 +   
3057 +    if (!newTnodes)
3058 +    {
3059 +               T(YAFFS_TRACE_ERROR,(TSTR("yaffs: Could not allocate Tnodes"TENDSTR)));
3060 +               return YAFFS_FAIL;
3061 +    }
3062 +    
3063 +    // Hook them into the free list
3064 +    for(i = 0; i < nTnodes - 1; i++)
3065 +    {
3066 +       newTnodes[i].internal[0] = &newTnodes[i+1];
3067 +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
3068 +       newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
3069 +#endif
3070 +    }
3071 +       
3072 +       newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
3073 +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
3074 +       newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
3075 +#endif
3076 +       dev->freeTnodes = newTnodes;
3077 +       dev->nFreeTnodes+= nTnodes;
3078 +       dev->nTnodesCreated += nTnodes;
3079 +
3080 +       // Now add this bunch of tnodes to a list for freeing up.
3081 +       // NB If we can't add this to the management list it isn't fatal
3082 +       // but it just means we can't free this bunch of tnodes later.
3083 +       tnl = YMALLOC(sizeof(yaffs_TnodeList));
3084 +       if(!tnl)
3085 +       {
3086 +               T(YAFFS_TRACE_ERROR,(TSTR("yaffs: Could not add tnodes to management list" TENDSTR)));
3087 +               
3088 +       }
3089 +       else
3090 +       {
3091 +               tnl->tnodes = newTnodes;
3092 +               tnl->next = dev->allocatedTnodeList;
3093 +               dev->allocatedTnodeList = tnl;
3094 +       }
3095 +
3096 +
3097 +       T(YAFFS_TRACE_ALLOCATE,(TSTR("yaffs: Tnodes added" TENDSTR)));
3098 +
3099 +
3100 +       return YAFFS_OK;
3101 +}
3102 +
3103 +
3104 +// GetTnode gets us a clean tnode. Tries to make allocate more if we run out
3105 +static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
3106 +{
3107 +       yaffs_Tnode *tn = NULL;
3108 +       
3109 +       // If there are none left make more
3110 +       if(!dev->freeTnodes)
3111 +       {
3112 +               yaffs_CreateTnodes(dev,YAFFS_ALLOCATION_NTNODES);
3113 +       }
3114 +       
3115 +       if(dev->freeTnodes)
3116 +       {
3117 +               tn = dev->freeTnodes;
3118 +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
3119 +       if(tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1)
3120 +               {
3121 +                       // Hoosterman, this thing looks like it isn't in the list
3122 +                               T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 1" TENDSTR)));
3123 +               }
3124 +#endif
3125 +               dev->freeTnodes = dev->freeTnodes->internal[0];
3126 +               dev->nFreeTnodes--;
3127 +               // zero out
3128 +               memset(tn,0,sizeof(yaffs_Tnode));
3129 +       }
3130 +       
3131 +
3132 +       return tn;
3133 +}
3134 +
3135 +
3136 +// FreeTnode frees up a tnode and puts it back on the free list
3137 +static void yaffs_FreeTnode(yaffs_Device*dev, yaffs_Tnode *tn)
3138 +{
3139 +       if(tn)
3140 +       {
3141 +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
3142 +       if(tn->internal[YAFFS_NTNODES_INTERNAL] != 0)
3143 +               {
3144 +                       // Hoosterman, this thing looks like it is already in the list
3145 +                               T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 2" TENDSTR)));
3146 +               }
3147 +               tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
3148 +#endif
3149 +               tn->internal[0] = dev->freeTnodes;
3150 +               dev->freeTnodes = tn;
3151 +               dev->nFreeTnodes++;
3152 +       }
3153 +}
3154 +
3155 +
3156 +static void yaffs_DeinitialiseTnodes(yaffs_Device*dev)
3157 +{
3158 +       // Free the list of allocated tnodes
3159 +       yaffs_TnodeList *tmp;
3160 +               
3161 +       while(dev->allocatedTnodeList)
3162 +       {
3163 +               tmp =  dev->allocatedTnodeList->next;
3164 +
3165 +               YFREE(dev->allocatedTnodeList->tnodes);
3166 +               YFREE(dev->allocatedTnodeList);
3167 +               dev->allocatedTnodeList = tmp;
3168 +               
3169 +       }
3170 +       
3171 +       dev->freeTnodes = NULL;
3172 +       dev->nFreeTnodes = 0;
3173 +}
3174 +
3175 +static void yaffs_InitialiseTnodes(yaffs_Device*dev)
3176 +{
3177 +       dev->allocatedTnodeList = NULL;
3178 +       dev->freeTnodes = NULL;
3179 +       dev->nFreeTnodes = 0;
3180 +       dev->nTnodesCreated = 0;
3181 +
3182 +}
3183 +
3184 +#if 0
3185 +void yaffs_TnodeTest(yaffs_Device *dev)
3186 +{
3187 +
3188 +       int i;
3189 +       int j;
3190 +       yaffs_Tnode *tn[1000];
3191 +       
3192 +       YINFO("Testing TNodes");
3193 +       
3194 +       for(j = 0; j < 50; j++)
3195 +       {
3196 +               for(i = 0; i < 1000; i++)
3197 +               {
3198 +                       tn[i] = yaffs_GetTnode(dev);
3199 +                       if(!tn[i])
3200 +                       {
3201 +                               YALERT("Getting tnode failed");
3202 +                       }
3203 +               }
3204 +               for(i = 0; i < 1000; i+=3)
3205 +               {
3206 +                       yaffs_FreeTnode(dev,tn[i]);
3207 +                       tn[i] = NULL;
3208 +               }
3209 +               
3210 +       }
3211 +}
3212 +#endif
3213 +
3214 +
3215 +////////////////// END OF TNODE MANIPULATION ///////////////////////////
3216 +
3217 +/////////////// Functions to manipulate the look-up tree (made up of tnodes)
3218 +// The look up tree is represented by the top tnode and the number of topLevel
3219 +// in the tree. 0 means only the level 0 tnode is in the tree.
3220 +
3221 +
3222 +// FindLevel0Tnode finds the level 0 tnode, if one exists.
3223 +// Used when reading.....
3224 +static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,yaffs_FileStructure *fStruct, __u32 chunkId)
3225 +{
3226 +       
3227 +       yaffs_Tnode *tn = fStruct->top;
3228 +       __u32 i;
3229 +       int requiredTallness;   
3230 +       int level = fStruct->topLevel;
3231 +       
3232 +       // Check sane level and chunk Id
3233 +       if(level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
3234 +       {
3235 +//             char str[50];
3236 +//             sprintf(str,"Bad level %d",level);
3237 +//             YALERT(str);
3238 +               return NULL;
3239 +       }
3240 +       
3241 +       if(chunkId > YAFFS_MAX_CHUNK_ID)
3242 +       {
3243 +//             char str[50];
3244 +//             sprintf(str,"Bad chunkId %d",chunkId);
3245 +//             YALERT(str);
3246 +               return NULL;
3247 +       }
3248 +
3249 +       // First check we're tall enough (ie enough topLevel)
3250 +       
3251 +       i = chunkId >> (/*dev->chunkGroupBits  + */YAFFS_TNODES_LEVEL0_BITS);
3252 +       requiredTallness = 0;
3253 +       while(i)
3254 +       {
3255 +               i >>= YAFFS_TNODES_INTERNAL_BITS;
3256 +               requiredTallness++;
3257 +       }
3258 +       
3259 +       
3260 +       if(requiredTallness > fStruct->topLevel)
3261 +       {
3262 +               // Not tall enough, so we can't find it, return NULL.
3263 +               return NULL;
3264 +       }
3265 +               
3266 +       
3267 +       // Traverse down to level 0
3268 +       while (level > 0 && tn)
3269 +       {
3270 +           tn = tn->internal[(chunkId >>(/* dev->chunkGroupBits + */ YAFFS_TNODES_LEVEL0_BITS + (level-1) * YAFFS_TNODES_INTERNAL_BITS)) & 
3271 +                              YAFFS_TNODES_INTERNAL_MASK]; 
3272 +               level--;
3273 +       
3274 +       }
3275 +       
3276 +       return tn;              
3277 +}
3278 +
3279 +// AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
3280 +// This happens in two steps:
3281 +//  1. If the tree isn't tall enough, then make it taller.
3282 +//  2. Scan down the tree towards the level 0 tnode adding tnodes if required.
3283 +//
3284 +// Used when modifying the tree.
3285 +//
3286 +static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStructure *fStruct, __u32 chunkId)
3287 +{
3288 +       
3289 +       yaffs_Tnode *tn; 
3290 +       
3291 +       int requiredTallness;
3292 +       int i;
3293 +       int l;
3294 +       
3295 +       __u32 x;
3296 +               
3297 +       
3298 +       //T((TSTR("AddOrFind topLevel=%d, chunk=%d"),fStruct->topLevel,chunkId));
3299 +       
3300 +       // Check sane level and page Id
3301 +       if(fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
3302 +       {
3303 +//             char str[50];
3304 +//             sprintf(str,"Bad level %d",fStruct->topLevel);
3305 +//             YALERT(str);
3306 +               return NULL;
3307 +       }
3308 +       
3309 +       if(chunkId > YAFFS_MAX_CHUNK_ID)
3310 +       {
3311 +//             char str[50];
3312 +//             sprintf(str,"Bad chunkId %d",chunkId);
3313 +//             YALERT(str);
3314 +               return NULL;
3315 +       }
3316 +       
3317 +       // First check we're tall enough (ie enough topLevel)
3318 +       
3319 +       x = chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS);
3320 +       requiredTallness = 0;
3321 +       while(x)
3322 +       {
3323 +               x >>= YAFFS_TNODES_INTERNAL_BITS;
3324 +               requiredTallness++;
3325 +       }
3326 +       
3327 +       //T((TSTR(" required=%d"),requiredTallness));
3328 +       
3329 +       
3330 +       if(requiredTallness > fStruct->topLevel)
3331 +       {
3332 +               // Not tall enough,gotta make the tree taller
3333 +               for(i = fStruct->topLevel; i < requiredTallness; i++)
3334 +               {
3335 +                       //T((TSTR(" add new top")));
3336 +                       
3337 +                       tn = yaffs_GetTnode(dev);
3338 +                       
3339 +                       if(tn)
3340 +                       {
3341 +                               tn->internal[0] = fStruct->top;
3342 +                               fStruct->top = tn;
3343 +                       }
3344 +                       else
3345 +                       {
3346 +                                       T(YAFFS_TRACE_ERROR,(TSTR("yaffs: no more tnodes" TENDSTR)));
3347 +                       }
3348 +               }
3349 +               
3350 +               fStruct->topLevel = requiredTallness;
3351 +       }
3352 +       
3353 +       
3354 +       // Traverse down to level 0, adding anything we need
3355 +       
3356 +       l = fStruct->topLevel;
3357 +       tn = fStruct->top;
3358 +       while (l > 0 && tn)
3359 +       {
3360 +               x = (chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS + (l-1) * YAFFS_TNODES_INTERNAL_BITS)) & 
3361 +                              YAFFS_TNODES_INTERNAL_MASK;
3362 +                              
3363 +               //T((TSTR(" [%d:%d]"),l,i));
3364 +               
3365 +           if(!tn->internal[x])
3366 +           {
3367 +               //T((TSTR(" added")));
3368 +               
3369 +               tn->internal[x] = yaffs_GetTnode(dev);
3370 +           }
3371 +           
3372 +           tn =        tn->internal[x];
3373 +               l--;
3374 +       
3375 +       }
3376 +       
3377 +       //TSTR(TENDSTR)));
3378 +       
3379 +       return tn;              
3380 +}
3381 +
3382 +
3383 +static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk, yaffs_ExtendedTags *tags, int objectId, int chunkInInode)
3384 +{
3385 +       int j;
3386 +       
3387 +                                       
3388 +       for(j = 0; theChunk && j < dev->chunkGroupSize; j++)
3389 +       {
3390 +               if(yaffs_CheckChunkBit(dev,theChunk / dev->nChunksPerBlock,theChunk % dev->nChunksPerBlock))
3391 +               {
3392 +                       yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL,tags);
3393 +                       if(yaffs_TagsMatch(tags,objectId,chunkInInode))
3394 +                       {
3395 +                               // found it;
3396 +                               return theChunk;
3397 +                                       
3398 +                       }
3399 +               }
3400 +               theChunk++;
3401 +       }
3402 +       return -1;
3403 +}
3404 +
3405 +// DeleteWorker scans backwards through the tnode tree and deletes all the
3406 +// chunks and tnodes in the file
3407 +// Returns 1 if the tree was deleted. Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
3408 +
3409 +static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit)
3410 +{
3411 +       int i;
3412 +       int chunkInInode;
3413 +       int theChunk;
3414 +       yaffs_ExtendedTags tags;
3415 +       int foundChunk;
3416 +       yaffs_Device *dev = in->myDev;
3417 +
3418 +       int allDone = 1;
3419 +       
3420 +       
3421 +       if(tn)
3422 +       {
3423 +               if(level > 0)
3424 +               {
3425 +               
3426 +                       for(i = YAFFS_NTNODES_INTERNAL -1; allDone && i >= 0; i--)
3427 +                       {
3428 +                           if(tn->internal[i])
3429 +                       {
3430 +                                       if(limit && (*limit) < 0)
3431 +                                       {
3432 +                                               allDone = 0;
3433 +                                       }
3434 +                                       else
3435 +                                       {
3436 +                                               allDone = yaffs_DeleteWorker(in,tn->internal[i],level - 1,
3437 +                                                                               (chunkOffset << YAFFS_TNODES_INTERNAL_BITS ) + i ,limit);
3438 +                                       }
3439 +                                       if(allDone)
3440 +                                       {
3441 +                                               yaffs_FreeTnode(dev,tn->internal[i]);
3442 +                                       tn->internal[i] = NULL;
3443 +                                       }
3444 +                           }
3445 +                   
3446 +                       }
3447 +                       return (allDone) ? 1 : 0;
3448 +               }
3449 +               else if(level == 0)
3450 +               {
3451 +                       int hitLimit = 0;
3452 +                       
3453 +                       for(i = YAFFS_NTNODES_LEVEL0 -1; i >= 0 && !hitLimit; i--)
3454 +                       {
3455 +                           if(tn->level0[i])
3456 +                       {
3457 +                                       
3458 +                                       chunkInInode = (chunkOffset << YAFFS_TNODES_LEVEL0_BITS ) + i;
3459 +                                       
3460 +                                       theChunk =  tn->level0[i] << dev->chunkGroupBits;
3461 +                                       
3462 +                                       foundChunk = yaffs_FindChunkInGroup(dev,theChunk,&tags,in->objectId,chunkInInode);
3463 +                                       
3464 +                                       if(foundChunk > 0)
3465 +                                       {
3466 +                                               yaffs_DeleteChunk(dev,foundChunk,1,__LINE__);
3467 +                                               in->nDataChunks--;
3468 +                                               if(limit)
3469 +                                               { 
3470 +                                                       *limit = *limit-1;
3471 +                                                       if(*limit <= 0) 
3472 +                                                       { 
3473 +                                                               hitLimit = 1;
3474 +                                                       }
3475 +                                               }
3476 +                                       
3477 +                                       }
3478 +                                       
3479 +                               tn->level0[i] = 0;
3480 +                           }
3481 +                   
3482 +                       }
3483 +                       return (i < 0) ? 1 : 0;
3484 +
3485 +                       
3486 +               }
3487 +               
3488 +       }
3489 +       
3490 +       return 1;
3491 +       
3492 +}
3493 +
3494 +
3495 +static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
3496 +{
3497 +
3498 +       yaffs_BlockInfo *theBlock;                                      
3499 +       
3500 +       T(YAFFS_TRACE_DELETION,(TSTR("soft delete chunk %d" TENDSTR),chunk));
3501 +                                               
3502 +       theBlock =      yaffs_GetBlockInfo(dev,  chunk/dev->nChunksPerBlock);
3503 +       if(theBlock)
3504 +       {
3505 +               theBlock->softDeletions++;
3506 +               dev->nFreeChunks++;
3507 +       }
3508 +}
3509 +
3510 +// SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
3511 +// All soft deleting does is increment the block's softdelete count and pulls the chunk out
3512 +// of the tnode.
3513 +// THus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
3514 +//
3515 +static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset)
3516 +{
3517 +       int i;
3518 +       int theChunk;
3519 +       int allDone = 1;
3520 +       yaffs_Device *dev = in->myDev;
3521 +       
3522 +       
3523 +       if(tn)
3524 +       {
3525 +               if(level > 0)
3526 +               {
3527 +               
3528 +                       for(i = YAFFS_NTNODES_INTERNAL -1; allDone && i >= 0; i--)
3529 +                       {
3530 +                           if(tn->internal[i])
3531 +                       {
3532 +                                               allDone = yaffs_SoftDeleteWorker(in,tn->internal[i],level - 1,
3533 +                                                                               (chunkOffset << YAFFS_TNODES_INTERNAL_BITS ) + i);
3534 +                                       if(allDone)
3535 +                                       {
3536 +                                               yaffs_FreeTnode(dev,tn->internal[i]);
3537 +                                       tn->internal[i] = NULL;
3538 +                                       }
3539 +                                       else
3540 +                                       {
3541 +                                               //Hoosterman... how could this happen.
3542 +                                       }                           
3543 +                               }                   
3544 +                       }
3545 +                       return (allDone) ? 1 : 0;
3546 +               }
3547 +               else if(level == 0)
3548 +               {
3549 +                       
3550 +                       for(i = YAFFS_NTNODES_LEVEL0 -1; i >=0; i--)
3551 +                       {
3552 +                           if(tn->level0[i])
3553 +                       {
3554 +                                       // Note this does not find the real chunk, only the chunk group.
3555 +                                       // We make an assumption that a chunk group is niot larger than a block.
3556 +                                       theChunk =  (tn->level0[i] << dev->chunkGroupBits);
3557 +                                       
3558 +                                       yaffs_SoftDeleteChunk(dev,theChunk);
3559 +                               tn->level0[i] = 0;
3560 +                           }
3561 +                   
3562 +                       }
3563 +                       return 1;
3564 +                       
3565 +               }
3566 +               
3567 +       }
3568 +       
3569 +       return 1;
3570 +               
3571 +}
3572 +
3573 +
3574 +
3575 +static void yaffs_SoftDeleteFile(yaffs_Object *obj)
3576 +{
3577 +       if(obj->deleted &&
3578 +          obj->variantType == YAFFS_OBJECT_TYPE_FILE &&
3579 +          !obj->softDeleted)
3580 +       {
3581 +               if(obj->nDataChunks <= 0)
3582 +               {
3583 +                               // Empty file with no duplicate object headers, just delete it immediately
3584 +                               yaffs_FreeTnode(obj->myDev,obj->variant.fileVariant.top);
3585 +                               obj->variant.fileVariant.top = NULL;
3586 +                               T(YAFFS_TRACE_TRACING,(TSTR("yaffs: Deleting empty file %d" TENDSTR),obj->objectId));
3587 +                               yaffs_DoGenericObjectDeletion(obj);     
3588 +               }
3589 +               else
3590 +               {
3591 +                       yaffs_SoftDeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0);
3592 +                       obj->softDeleted = 1;
3593 +               }
3594 +       }
3595 +}
3596 +
3597 +
3598 +
3599 +
3600 +
3601 +// Pruning removes any part of the file structure tree that is beyond the
3602 +// bounds of the file (ie that does not point to chunks).
3603 +//
3604 +// A file should only get pruned when its size is reduced.
3605 +//
3606 +// Before pruning, the chunks must be pulled from the tree and the
3607 +// level 0 tnode entries must be zeroed out.
3608 +// Could also use this for file deletion, but that's probably better handled
3609 +// by a special case.
3610 +
3611 +// yaffs_PruneWorker should only be called by yaffs_PruneFileStructure()
3612 +
3613 +static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn, __u32 level, int del0)
3614 +{
3615 +       int i;
3616 +       int hasData;
3617 +       
3618 +       if(tn)
3619 +       {
3620 +               hasData = 0;
3621 +               
3622 +               for(i = 0; i < YAFFS_NTNODES_INTERNAL; i++)
3623 +               {
3624 +                   if(tn->internal[i] && level > 0)
3625 +                   {
3626 +                       tn->internal[i] = yaffs_PruneWorker(dev,tn->internal[i],level - 1, ( i == 0) ? del0 : 1);
3627 +                   }
3628 +                   
3629 +                   if(tn->internal[i])
3630 +                   {
3631 +                       hasData++;
3632 +                       }
3633 +               }
3634 +               
3635 +               if(hasData == 0 && del0)
3636 +               {
3637 +                       // Free and return NULL
3638 +                       
3639 +                       yaffs_FreeTnode(dev,tn);
3640 +                       tn = NULL;
3641 +               }
3642 +               
3643 +       }
3644 +
3645 +       return tn;
3646 +       
3647 +}
3648 +
3649 +static int yaffs_PruneFileStructure(yaffs_Device *dev, yaffs_FileStructure *fStruct)
3650 +{
3651 +       int i;
3652 +       int hasData;
3653 +       int done = 0;
3654 +       yaffs_Tnode *tn;
3655 +       
3656 +       if(fStruct->topLevel > 0)
3657 +       {
3658 +               fStruct->top = yaffs_PruneWorker(dev,fStruct->top, fStruct->topLevel,0);
3659 +               
3660 +               // Now we have a tree with all the non-zero branches NULL but the height
3661 +               // is the same as it was.
3662 +               // Let's see if we can trim internal tnodes to shorten the tree.
3663 +               // We can do this if only the 0th element in the tnode is in use 
3664 +               // (ie all the non-zero are NULL)
3665 +               
3666 +               while(fStruct->topLevel && !done)
3667 +               {
3668 +                       tn = fStruct->top;
3669 +                       
3670 +                       hasData = 0;
3671 +                       for(i = 1; i <YAFFS_NTNODES_INTERNAL; i++)
3672 +                       {
3673 +                               if(tn->internal[i])
3674 +                       {
3675 +                               hasData++;
3676 +                               }
3677 +                       }
3678 +                       
3679 +                       if(!hasData)
3680 +                       {
3681 +                               fStruct->top = tn->internal[0];
3682 +                               fStruct->topLevel--;
3683 +                               yaffs_FreeTnode(dev,tn);
3684 +                       }
3685 +                       else
3686 +                       {
3687 +                               done = 1;
3688 +                       }
3689 +               }
3690 +       }
3691 +       
3692 +       return YAFFS_OK;
3693 +}
3694 +
3695 +
3696 +
3697 +
3698 +
3699 +/////////////////////// End of File Structure functions. /////////////////
3700 +
3701 +// yaffs_CreateFreeObjects creates a bunch more objects and
3702 +// adds them to the object free list.
3703 +static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
3704 +{
3705 +    int i;
3706 +    yaffs_Object *newObjects;
3707 +    yaffs_ObjectList *list;
3708 +    
3709 +    if(nObjects < 1) return YAFFS_OK;
3710 +   
3711 +       // make these things
3712 +       
3713 +    newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
3714 +   
3715 +    if (!newObjects)
3716 +    {
3717 +               T(YAFFS_TRACE_ALLOCATE,(TSTR("yaffs: Could not allocate more objects" TENDSTR)));
3718 +               return YAFFS_FAIL;
3719 +    }
3720 +    
3721 +    // Hook them into the free list
3722 +    for(i = 0; i < nObjects - 1; i++)
3723 +    {
3724 +       newObjects[i].siblings.next = (struct list_head *)(&newObjects[i+1]);
3725 +    }
3726 +       
3727 +       newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
3728 +       dev->freeObjects = newObjects;
3729 +       dev->nFreeObjects+= nObjects;
3730 +       dev->nObjectsCreated+= nObjects;
3731 +       
3732 +       // Now add this bunch of Objects to a list for freeing up.
3733 +       
3734 +       list = YMALLOC(sizeof(yaffs_ObjectList));
3735 +       if(!list)
3736 +       {
3737 +               T(YAFFS_TRACE_ALLOCATE,(TSTR("Could not add objects to management list" TENDSTR)));
3738 +       }
3739 +       else
3740 +       {
3741 +               list->objects = newObjects;
3742 +               list->next = dev->allocatedObjectList;
3743 +               dev->allocatedObjectList = list;
3744 +       }
3745 +       
3746 +       
3747 +       
3748 +       return YAFFS_OK;
3749 +}
3750 +
3751 +
3752 +// AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out
3753 +static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
3754 +{
3755 +       yaffs_Object *tn = NULL;
3756 +       
3757 +       // If there are none left make more
3758 +       if(!dev->freeObjects)
3759 +       {
3760 +               yaffs_CreateFreeObjects(dev,YAFFS_ALLOCATION_NOBJECTS);
3761 +       }
3762 +       
3763 +       if(dev->freeObjects)
3764 +       {
3765 +               tn = dev->freeObjects;
3766 +               dev->freeObjects = (yaffs_Object *)(dev->freeObjects->siblings.next);
3767 +               dev->nFreeObjects--;
3768 +               
3769 +               // Now sweeten it up...
3770 +       
3771 +               memset(tn,0,sizeof(yaffs_Object));
3772 +               tn->myDev = dev;
3773 +               tn->chunkId = -1;
3774 +               tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
3775 +               INIT_LIST_HEAD(&(tn->hardLinks));
3776 +               INIT_LIST_HEAD(&(tn->hashLink));
3777 +               INIT_LIST_HEAD(&tn->siblings);
3778 +               
3779 +               // Add it to the lost and found directory.
3780 +               // NB Can't put root or lostNFound in lostNFound so
3781 +               // check if lostNFound exists first
3782 +               if(dev->lostNFoundDir)
3783 +               {
3784 +                       yaffs_AddObjectToDirectory(dev->lostNFoundDir,tn);      
3785 +               }
3786 +       }
3787 +       
3788 +
3789 +       return tn;
3790 +}
3791 +
3792 +static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev,int number,__u32 mode)
3793 +{
3794 +
3795 +       yaffs_Object *obj = yaffs_CreateNewObject(dev,number,YAFFS_OBJECT_TYPE_DIRECTORY);              
3796 +       if(obj)
3797 +       {
3798 +               obj->fake = 1;                  // it is fake so it has no NAND presence...
3799 +               obj->renameAllowed= 0;  // ... and we're not allowed to rename it...
3800 +               obj->unlinkAllowed= 0;  // ... or unlink it
3801 +               obj->deleted = 0;
3802 +               obj->unlinked = 0;
3803 +               obj->yst_mode = mode;
3804 +               obj->myDev = dev;
3805 +               obj->chunkId = 0; // Not a valid chunk.
3806 +       }
3807 +       
3808 +       return obj;
3809 +       
3810 +}
3811 +
3812 +
3813 +static void yaffs_UnhashObject(yaffs_Object *tn)
3814 +{
3815 +       int bucket;
3816 +       yaffs_Device *dev = tn->myDev;
3817 +       
3818 +       
3819 +       // If it is still linked into the bucket list, free from the list
3820 +       if(!list_empty(&tn->hashLink))
3821 +       {
3822 +               list_del_init(&tn->hashLink);
3823 +               bucket =  yaffs_HashFunction(tn->objectId);
3824 +               dev->objectBucket[bucket].count--;
3825 +       }
3826 +       
3827 +}
3828 +
3829 +
3830 +// FreeObject frees up a Object and puts it back on the free list
3831 +static void yaffs_FreeObject(yaffs_Object *tn)
3832 +{
3833 +
3834 +       yaffs_Device *dev = tn->myDev;
3835 +       
3836 +#ifdef  __KERNEL__
3837 +       if(tn->myInode)
3838 +       {
3839 +               // We're still hooked up to a cached inode.
3840 +               // Don't delete now, but mark for later deletion
3841 +               tn->deferedFree = 1;
3842 +               return;
3843 +       }
3844 +#endif
3845 +       
3846 +       yaffs_UnhashObject(tn);
3847 +       
3848 +       // Link into the free list.
3849 +       tn->siblings.next = (struct list_head *)(dev->freeObjects);
3850 +       dev->freeObjects = tn;
3851 +       dev->nFreeObjects++;
3852 +}
3853 +
3854 +
3855 +
3856 +#ifdef __KERNEL__
3857 +
3858 +void yaffs_HandleDeferedFree(yaffs_Object *obj)
3859 +{
3860 +       if(obj->deferedFree)
3861 +       {
3862 +          yaffs_FreeObject(obj);
3863 +       }
3864 +}
3865 +
3866 +#endif
3867 +
3868 +
3869 +
3870 +static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
3871 +{
3872 +       // Free the list of allocated Objects
3873 +       
3874 +       yaffs_ObjectList *tmp;
3875 +       
3876 +       while( dev->allocatedObjectList)
3877 +       {
3878 +               tmp =  dev->allocatedObjectList->next;
3879 +               YFREE(dev->allocatedObjectList->objects);
3880 +               YFREE(dev->allocatedObjectList);
3881 +               
3882 +               dev->allocatedObjectList =  tmp;
3883 +       }
3884 +       
3885 +       dev->freeObjects = NULL;
3886 +       dev->nFreeObjects = 0;
3887 +}
3888 +
3889 +static void yaffs_InitialiseObjects(yaffs_Device *dev)
3890 +{
3891 +       int i;
3892 +       
3893 +       dev->allocatedObjectList = NULL;
3894 +       dev->freeObjects = NULL;
3895 +       dev->nFreeObjects = 0;
3896 +       
3897 +       for(i = 0; i < YAFFS_NOBJECT_BUCKETS; i++)
3898 +       {
3899 +               INIT_LIST_HEAD(&dev->objectBucket[i].list);
3900 +               dev->objectBucket[i].count = 0; 
3901 +       }
3902 +
3903 +}
3904 +
3905 +
3906 +
3907 +
3908 +
3909 +
3910 +static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
3911 +{
3912 +       static int x = 0;
3913 +       int i;
3914 +       int l = 999;
3915 +       int lowest = 999999;
3916 +
3917 +               
3918 +       // First let's see if we can find one that's empty.
3919 +       
3920 +       for(i = 0; i < 10 && lowest > 0; i++)
3921 +        {
3922 +               x++;
3923 +               x %=  YAFFS_NOBJECT_BUCKETS;
3924 +               if(dev->objectBucket[x].count < lowest)
3925 +               {
3926 +                       lowest = dev->objectBucket[x].count;
3927 +                       l = x;
3928 +               }
3929 +               
3930 +       }
3931 +       
3932 +       // If we didn't find an empty list, then try
3933 +       // looking a bit further for a short one
3934 +       
3935 +       for(i = 0; i < 10 && lowest > 3; i++)
3936 +        {
3937 +               x++;
3938 +               x %=  YAFFS_NOBJECT_BUCKETS;
3939 +               if(dev->objectBucket[x].count < lowest)
3940 +               {
3941 +                       lowest = dev->objectBucket[x].count;
3942 +                       l = x;
3943 +               }
3944 +               
3945 +       }
3946 +       
3947 +       return l;
3948 +}
3949 +
3950 +static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
3951 +{
3952 +       int bucket = yaffs_FindNiceObjectBucket(dev);
3953 +       
3954 +       // Now find an object value that has not already been taken
3955 +       // by scanning the list.
3956 +       
3957 +       int found = 0;
3958 +       struct list_head *i;
3959 +       
3960 +       __u32 n = (__u32)bucket;
3961 +
3962 +       //yaffs_CheckObjectHashSanity();        
3963 +       
3964 +       while(!found)
3965 +       {
3966 +               found = 1;
3967 +               n +=  YAFFS_NOBJECT_BUCKETS;
3968 +               if(1 ||dev->objectBucket[bucket].count > 0)
3969 +               {
3970 +                       list_for_each(i,&dev->objectBucket[bucket].list)
3971 +                       {
3972 +                               // If there is already one in the list
3973 +                               if(i && list_entry(i, yaffs_Object,hashLink)->objectId == n)
3974 +                               {
3975 +                                       found = 0;
3976 +                               }
3977 +                       }
3978 +               }
3979 +       }
3980 +       
3981 +       //T(("bucket %d count %d inode %d\n",bucket,yaffs_objectBucket[bucket].count,n);
3982 +       
3983 +       return n;       
3984 +}
3985 +
3986 +static void yaffs_HashObject(yaffs_Object *in)
3987 +{
3988 +       int bucket = yaffs_HashFunction(in->objectId);
3989 +       yaffs_Device *dev = in->myDev;
3990 +       
3991 +       if(!list_empty(&in->hashLink))
3992 +       {
3993 +               //YINFO("!!!");
3994 +       }
3995 +
3996 +       
3997 +       list_add(&in->hashLink,&dev->objectBucket[bucket].list);
3998 +       dev->objectBucket[bucket].count++;
3999 +
4000 +}
4001 +
4002 +yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev,__u32 number)
4003 +{
4004 +       int bucket = yaffs_HashFunction(number);
4005 +       struct list_head *i;
4006 +       yaffs_Object *in;
4007 +       
4008 +       list_for_each(i,&dev->objectBucket[bucket].list)
4009 +       {
4010 +               // Look if it is in the list
4011 +               if(i)
4012 +               {
4013 +                       in = list_entry(i, yaffs_Object,hashLink);
4014 +                       if(in->objectId == number)
4015 +                       {
4016 +#ifdef __KERNEL__
4017 +                               // Don't tell the VFS about this one if it is defered free
4018 +                               if(in->deferedFree)
4019 +                                 return NULL;
4020 +#endif
4021 +                                 
4022 +                               return in;
4023 +                       }
4024 +               }
4025 +       }
4026 +       
4027 +       return NULL;
4028 +}
4029 +
4030 +
4031 +
4032 +yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type)
4033 +{
4034 +               
4035 +       yaffs_Object *theObject;
4036 +
4037 +       if(number < 0)
4038 +       {
4039 +               number = yaffs_CreateNewObjectNumber(dev);
4040 +       }
4041 +       
4042 +       theObject = yaffs_AllocateEmptyObject(dev);
4043 +       
4044 +       if(theObject)
4045 +       {
4046 +               theObject->fake = 0;
4047 +               theObject->renameAllowed = 1;
4048 +               theObject->unlinkAllowed = 1;
4049 +               theObject->objectId = number;
4050 +               yaffs_HashObject(theObject);
4051 +               theObject->variantType = type;
4052 +#ifdef CONFIG_YAFFS_WINCE
4053 +               yfsd_WinFileTimeNow(theObject->win_atime);
4054 +               theObject->win_ctime[0] = theObject->win_mtime[0] = theObject->win_atime[0];
4055 +               theObject->win_ctime[1] = theObject->win_mtime[1] = theObject->win_atime[1];
4056 +
4057 +#else
4058 +
4059 +               theObject->yst_atime = theObject->yst_mtime = theObject->yst_ctime = Y_CURRENT_TIME;            
4060 +#endif
4061 +               switch(type)
4062 +               {
4063 +                       case YAFFS_OBJECT_TYPE_FILE: 
4064 +                               theObject->variant.fileVariant.fileSize = 0;
4065 +                               theObject->variant.fileVariant.scannedFileSize = 0;
4066 +                               theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; // max __u32
4067 +                               theObject->variant.fileVariant.topLevel = 0;
4068 +                               theObject->variant.fileVariant.top  = yaffs_GetTnode(dev);
4069 +                               break;
4070 +                       case YAFFS_OBJECT_TYPE_DIRECTORY:
4071 +                               INIT_LIST_HEAD(&theObject->variant.directoryVariant.children);
4072 +                               break;
4073 +                       case YAFFS_OBJECT_TYPE_SYMLINK:
4074 +                               // No action required
4075 +                               break;
4076 +                       case YAFFS_OBJECT_TYPE_HARDLINK:
4077 +                               // No action required
4078 +                               break;
4079 +                       case YAFFS_OBJECT_TYPE_SPECIAL:
4080 +                               // No action required
4081 +                               break;
4082 +                       case YAFFS_OBJECT_TYPE_UNKNOWN:
4083 +                               // todo this should not happen
4084 +                               break;
4085 +               }
4086 +       }
4087 +       
4088 +       return theObject;
4089 +}
4090 +
4091 +static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaffs_ObjectType type)
4092 +{
4093 +       yaffs_Object *theObject = NULL;
4094 +       
4095 +       if(number > 0)
4096 +       {
4097 +               theObject = yaffs_FindObjectByNumber(dev,number);
4098 +       }
4099 +       
4100 +       if(!theObject)
4101 +       {
4102 +               theObject = yaffs_CreateNewObject(dev,number,type);
4103 +       }
4104 +       
4105 +       return theObject;
4106 +
4107 +}
4108 +
4109 +static YCHAR *yaffs_CloneString(const YCHAR *str)
4110 +{
4111 +       YCHAR *newStr = NULL;
4112 +       
4113 +       if(str && *str)
4114 +       {
4115 +               newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
4116 +               yaffs_strcpy(newStr,str);
4117 +       }
4118 +
4119 +       return newStr;
4120 +       
4121 +}
4122 +
4123 +//
4124 +// Mknod (create) a new object.
4125 +// equivalentObject only has meaning for a hard link;
4126 +// aliasString only has meaning for a sumlink.
4127 +// rdev only has meaning for devices (a subset of special objects)
4128 +static yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
4129 +                                                                yaffs_Object *parent,
4130 +                                                                const YCHAR *name, 
4131 +                                                                __u32 mode,
4132 +                                                                __u32 uid,
4133 +                                                                __u32 gid,
4134 +                                                                yaffs_Object *equivalentObject,
4135 +                                                                const YCHAR *aliasString,
4136 +                                                                __u32 rdev)
4137 +{
4138 +       yaffs_Object *in;
4139 +
4140 +       yaffs_Device *dev = parent->myDev;
4141 +       
4142 +       // Check if the entry exists. If it does then fail the call since we don't want a dup.
4143 +       if(yaffs_FindObjectByName(parent,name))
4144 +       {
4145 +               return NULL;
4146 +       }
4147 +       
4148 +       in = yaffs_CreateNewObject(dev,-1,type);
4149 +       
4150 +       if(in)
4151 +       {
4152 +               in->chunkId = -1;
4153 +               in->valid = 1;
4154 +               in->variantType = type;
4155 +
4156 +               in->yst_mode  = mode;
4157 +               
4158 +#ifdef CONFIG_YAFFS_WINCE
4159 +               yfsd_WinFileTimeNow(in->win_atime);
4160 +               in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
4161 +               in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
4162 +               
4163 +#else
4164 +               in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
4165 +
4166 +               in->yst_rdev  = rdev;
4167 +               in->yst_uid   = uid;
4168 +               in->yst_gid   = gid;
4169 +#endif         
4170 +               in->nDataChunks = 0;
4171 +
4172 +               yaffs_SetObjectName(in,name);
4173 +               in->dirty = 1;
4174 +               
4175 +               yaffs_AddObjectToDirectory(parent,in);
4176 +               
4177 +               in->myDev = parent->myDev;
4178 +               
4179 +                               
4180 +               switch(type)
4181 +               {
4182 +                       case YAFFS_OBJECT_TYPE_SYMLINK:
4183 +                               in->variant.symLinkVariant.alias = yaffs_CloneString(aliasString);
4184 +                               break;
4185 +                       case YAFFS_OBJECT_TYPE_HARDLINK:
4186 +                               in->variant.hardLinkVariant.equivalentObject = equivalentObject;
4187 +                               in->variant.hardLinkVariant.equivalentObjectId = equivalentObject->objectId;
4188 +                               list_add(&in->hardLinks,&equivalentObject->hardLinks);
4189 +                               break;
4190 +                       case YAFFS_OBJECT_TYPE_FILE: // do nothing
4191 +                       case YAFFS_OBJECT_TYPE_DIRECTORY: // do nothing
4192 +                       case YAFFS_OBJECT_TYPE_SPECIAL: // do nothing
4193 +                       case YAFFS_OBJECT_TYPE_UNKNOWN:
4194 +                               break;
4195 +               }
4196 +
4197 +               if(/*yaffs_GetNumberOfFreeChunks(dev) <= 0 || */
4198 +                  yaffs_UpdateObjectHeader(in,name,0,0,0) < 0)
4199 +               {
4200 +                       // Could not create the object header, fail the creation
4201 +                       yaffs_DestroyObject(in);
4202 +                       in = NULL;
4203 +               }
4204 +
4205 +       }
4206 +       
4207 +       return in;
4208 +}
4209 +
4210 +yaffs_Object *yaffs_MknodFile(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid)
4211 +{
4212 +       return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE,parent,name,mode,uid,gid,NULL,NULL,0);
4213 +}
4214 +
4215 +yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid)
4216 +{
4217 +       return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY,parent,name,mode,uid,gid,NULL,NULL,0);
4218 +}
4219 +
4220 +yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
4221 +{
4222 +       return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL,parent,name,mode,uid,gid,NULL,NULL,rdev);
4223 +}
4224 +
4225 +yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid,const YCHAR *alias)
4226 +{
4227 +       return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK,parent,name,mode,uid,gid,NULL,alias,0);
4228 +}
4229 +
4230 +// NB yaffs_Link returns the object id of the equivalent object.
4231 +yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name, yaffs_Object *equivalentObject)
4232 +{
4233 +       // Get the real object in case we were fed a hard link as an equivalent object
4234 +       equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
4235 +       
4236 +       if(yaffs_MknodObject(YAFFS_OBJECT_TYPE_HARDLINK,parent,name,0,0,0,equivalentObject,NULL,0))
4237 +       {
4238 +               return equivalentObject;
4239 +       }
4240 +       else
4241 +       {
4242 +               return NULL;
4243 +       }
4244 +       
4245 +}
4246 +
4247 +
4248 +static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const YCHAR *newName,int force,int shadows)
4249 +{
4250 +       int unlinkOp;
4251 +       int deleteOp;
4252 +       
4253 +       yaffs_Object * existingTarget;
4254 +
4255 +       if(newDir == NULL)
4256 +       {
4257 +               newDir = obj->parent; // use the old directory
4258 +       }
4259 +       
4260 +       if(newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
4261 +       {
4262 +               T(YAFFS_TRACE_ALWAYS,(TSTR("tragendy: yaffs_ChangeObjectName: newDir is not a directory"TENDSTR)));
4263 +               YBUG();
4264 +       }
4265 +
4266 +       // TODO: Do we need this different handling for YAFFS2 and YAFFS1??
4267 +       if(obj->myDev->isYaffs2)
4268 +       {
4269 +               unlinkOp = (newDir == obj->myDev->unlinkedDir);
4270 +       }
4271 +       else
4272 +       {
4273 +               unlinkOp = (newDir == obj->myDev->unlinkedDir && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
4274 +       }
4275 +
4276 +       deleteOp = (newDir == obj->myDev->deletedDir);
4277 +       
4278 +       existingTarget = yaffs_FindObjectByName(newDir,newName);
4279 +       
4280 +       // If the object is a file going into the unlinked directory, then it is OK to just stuff it in since
4281 +       // duplicate names are allowed.
4282 +       // Otherwise only proceed if the new name does not exist and if we're putting it into a directory.
4283 +       if( (unlinkOp|| 
4284 +                deleteOp ||
4285 +                force || 
4286 +                (shadows > 0) ||
4287 +                !existingTarget)  &&
4288 +            newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
4289 +       {
4290 +               yaffs_SetObjectName(obj,newName);
4291 +               obj->dirty = 1;
4292 +               
4293 +               yaffs_AddObjectToDirectory(newDir,obj);
4294 +               
4295 +               if(unlinkOp) obj->unlinked = 1;
4296 +               
4297 +               // If it is a deletion then we mark it as a shrink for gc purposes.
4298 +               if(yaffs_UpdateObjectHeader(obj,newName,0,deleteOp,shadows) >= 0)
4299 +               {
4300 +                       return YAFFS_OK;
4301 +               }
4302 +       }
4303 +       
4304 +       return YAFFS_FAIL;
4305 +}
4306 +
4307 +
4308 +
4309 +int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, yaffs_Object *newDir, const YCHAR *newName)
4310 +{
4311 +       yaffs_Object *obj;
4312 +       yaffs_Object *existingTarget;
4313 +       int force = 0;
4314 +       
4315 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
4316 +       // Special case for case insemsitive systems (eg. WinCE).
4317 +       // While look-up is case insensitive, the name isn't.
4318 +       // THerefore we might want to change x.txt to X.txt
4319 +       if(oldDir == newDir && yaffs_strcmp(oldName,newName) == 0)
4320 +       {
4321 +               force = 1;
4322 +       }       
4323 +#endif
4324 +       
4325 +       obj = yaffs_FindObjectByName(oldDir,oldName);
4326 +       
4327 +       if(obj && obj->renameAllowed)
4328 +       {
4329 +       
4330 +               // Now do the handling for an existing target, if there is one
4331 +       
4332 +               existingTarget = yaffs_FindObjectByName(newDir,newName);
4333 +               if(existingTarget &&
4334 +                  existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
4335 +                  !list_empty(&existingTarget->variant.directoryVariant.children))
4336 +                {
4337 +                       // There is a target that is a non-empty directory, so we have to fail
4338 +                       return YAFFS_FAIL; // EEXIST or ENOTEMPTY
4339 +                }
4340 +                else if(existingTarget)
4341 +                {
4342 +                       // Nuke the target first, using shadowing
4343 +                        yaffs_ChangeObjectName(obj,newDir,newName,force,existingTarget->objectId);
4344 +                        yaffs_Unlink(newDir,newName);
4345 +                }
4346 +               
4347 +               
4348 +               return yaffs_ChangeObjectName(obj,newDir,newName,force,0);
4349 +       }
4350 +       return YAFFS_FAIL;
4351 +}
4352 +
4353 +
4354 +#if 0
4355 +
4356 +static int yaffs_CheckObjectHashSanity(yaffs_Device *dev)
4357 +{
4358 +       // Scan the buckets and check that the lists 
4359 +       // have as many members as the count says there are
4360 +       int bucket;
4361 +       int countEm;
4362 +       struct list_head *j;
4363 +       int ok = YAFFS_OK;
4364 +       
4365 +       for(bucket = 0; bucket < YAFFS_NOBJECT_BUCKETS; bucket++)
4366 +       {
4367 +               countEm = 0;
4368 +               
4369 +               list_for_each(j,&dev->objectBucket[bucket].list)
4370 +               {
4371 +                       countEm++;
4372 +               }
4373 +               
4374 +               if(countEm != dev->objectBucket[bucket].count)
4375 +               {
4376 +                       T(YAFFS_TRACE_ERROR,(TSTR("Inode hash inconsistency" TENDSTR)));
4377 +                       ok = YAFFS_FAIL;
4378 +               }
4379 +       }
4380 +
4381 +       return ok;
4382 +}
4383 +
4384 +
4385 +void yaffs_ObjectTest(yaffs_Device *dev)
4386 +{
4387 +       yaffs_Object *in[1000];
4388 +       int inNo[1000];
4389 +       yaffs_Object *inold[1000];
4390 +       int i;
4391 +       int j;
4392 +       
4393 +       memset(in,0,1000*sizeof(yaffs_Object *));
4394 +       memset(inold,0,1000*sizeof(yaffs_Object *));
4395 +       
4396 +       yaffs_CheckObjectHashSanity(dev);
4397 +       
4398 +       for(j = 0; j < 10; j++)
4399 +       {
4400 +               //T(("%d\n",j));
4401 +               
4402 +               for(i = 0; i < 1000; i++)
4403 +               {
4404 +                       in[i] = yaffs_CreateNewObject(dev,-1,YAFFS_OBJECT_TYPE_FILE);
4405 +                       if(!in[i])
4406 +                       {
4407 +                               YINFO("No more inodes");
4408 +                       }
4409 +                       else
4410 +                       {
4411 +                               inNo[i] = in[i]->objectId;
4412 +                       }
4413 +               }
4414 +               
4415 +               for(i = 0; i < 1000; i++)
4416 +               {
4417 +                       if(yaffs_FindObjectByNumber(dev,inNo[i]) != in[i])
4418 +                       {
4419 +                               //T(("Differnce in look up test\n"));
4420 +                       }
4421 +                       else
4422 +                       {
4423 +                               // T(("Look up ok\n"));
4424 +                       }
4425 +               }
4426 +               
4427 +               yaffs_CheckObjectHashSanity(dev);
4428 +       
4429 +               for(i = 0; i < 1000; i+=3)
4430 +               {
4431 +                       yaffs_FreeObject(in[i]);        
4432 +                       in[i] = NULL;
4433 +               }
4434 +               
4435 +       
4436 +               yaffs_CheckObjectHashSanity(dev);
4437 +       }
4438 +               
4439 +}
4440 +
4441 +#endif
4442 +
4443 +/////////////////////////// Block Management and Page Allocation ///////////////////
4444 +
4445 +
4446 +static int yaffs_InitialiseBlocks(yaffs_Device *dev,int nBlocks)
4447 +{
4448 +       dev->allocationBlock = -1; // force it to get a new one
4449 +       //Todo we're assuming the malloc will pass.
4450 +       dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
4451 +       // Set up dynamic blockinfo stuff.
4452 +       dev->chunkBitmapStride = (dev->nChunksPerBlock+7)/8;
4453 +       dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
4454 +       if(dev->blockInfo && dev->chunkBits)
4455 +       {
4456 +               memset(dev->blockInfo,0,nBlocks * sizeof(yaffs_BlockInfo));
4457 +               memset(dev->chunkBits,0,dev->chunkBitmapStride * nBlocks);
4458 +               return YAFFS_OK;
4459 +       }
4460 +       
4461 +       return YAFFS_FAIL;
4462 +       
4463 +}
4464 +
4465 +static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
4466 +{
4467 +       YFREE(dev->blockInfo);
4468 +       dev->blockInfo = NULL;
4469 +       YFREE(dev->chunkBits);
4470 +       dev->chunkBits = NULL;
4471 +}
4472 +
4473 +
4474 +static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev, yaffs_BlockInfo *bi)
4475 +{
4476 +       int i;
4477 +       __u32 seq;
4478 +       yaffs_BlockInfo *b;
4479 +       
4480 +       if(!dev->isYaffs2) return 1; // disqualification only applies to yaffs2.
4481 +       
4482 +       if(!bi->hasShrinkHeader) return 1; // can gc
4483 +
4484 +
4485 +       // Find the oldest dirty sequence number if we don't know it and save it
4486 +       // so we don't have to keep recomputing it.
4487 +       if(!dev->oldestDirtySequence)
4488 +       {
4489 +               seq = dev->sequenceNumber;
4490 +
4491 +               for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++)
4492 +               {
4493 +                       b = yaffs_GetBlockInfo(dev,i);
4494 +                       if(b->blockState == YAFFS_BLOCK_STATE_FULL &&
4495 +                       (b->pagesInUse - b->softDeletions )< dev->nChunksPerBlock &&
4496 +                       b->sequenceNumber < seq)
4497 +                       {
4498 +                               seq = b->sequenceNumber;
4499 +                       }
4500 +               }
4501 +               dev->oldestDirtySequence = seq;
4502 +       }
4503 +
4504 +
4505 +       // Can't do gc of this block if there are any blocks older than this one that have
4506 +       // discarded pages.
4507 +       return (bi->sequenceNumber <= dev->oldestDirtySequence);
4508 +       
4509 +       
4510 +       return 1;
4511 +
4512 +}
4513 +
4514 +// FindDiretiestBlock is used to select the dirtiest block (or close enough)
4515 +// for garbage collection.
4516 +//
4517 +
4518 +
4519 +
4520 +static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,int aggressive)
4521 +{
4522 +
4523 +       int b = dev->currentDirtyChecker;
4524 +       
4525 +       int i;
4526 +       int iterations;
4527 +       int dirtiest = -1;
4528 +       int pagesInUse; 
4529 +       yaffs_BlockInfo *bi;
4530 +       static int  nonAggressiveSkip = 0;
4531 +
4532 +       // If we're doing aggressive GC then we are happy to take a less-dirty block, and
4533 +       // search harder.
4534 +       // else (we're doing a leasurely gc), then we only bother to do this if the
4535 +       // block has only a few pages in use.
4536 +       
4537 +
4538 +       nonAggressiveSkip--;
4539 +
4540 +       if(!aggressive &&(nonAggressiveSkip > 0))
4541 +       {
4542 +               return -1;
4543 +       }
4544 +
4545 +       pagesInUse = (aggressive)? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
4546 +
4547 +       if(aggressive)
4548 +       {
4549 +               iterations = dev->internalEndBlock - dev->internalStartBlock + 1;
4550 +       }
4551 +       else
4552 +       {
4553 +               iterations = dev->internalEndBlock - dev->internalStartBlock + 1;
4554 +               iterations = iterations / 16; 
4555 +               if(iterations > 200)
4556 +               {
4557 +                       iterations = 200;
4558 +               }
4559 +       }
4560 +       
4561 +       for(i = 0; i <= iterations && pagesInUse > 0 ; i++)
4562 +       {
4563 +               b++;
4564 +               if ( b < dev->internalStartBlock || b > dev->internalEndBlock)
4565 +               {
4566 +                       b =  dev->internalStartBlock;
4567 +               }
4568 +
4569 +               if(b < dev->internalStartBlock || b > dev->internalEndBlock)
4570 +               {
4571 +                       T(YAFFS_TRACE_ERROR,(TSTR("**>> Block %d is not valid" TENDSTR),b));
4572 +                       YBUG();
4573 +               }
4574 +               
4575 +               bi = yaffs_GetBlockInfo(dev,b);
4576 +               
4577 +               if(bi->blockState == YAFFS_BLOCK_STATE_FULL &&
4578 +                  (bi->pagesInUse - bi->softDeletions )< pagesInUse &&
4579 +                  yaffs_BlockNotDisqualifiedFromGC(dev,bi))
4580 +               {
4581 +                       dirtiest = b;
4582 +                       pagesInUse = (bi->pagesInUse - bi->softDeletions);
4583 +               }
4584 +       }
4585 +       
4586 +       dev->currentDirtyChecker = b;
4587 +       
4588 +       if(dirtiest > 0)
4589 +       {
4590 +               T(YAFFS_TRACE_GC,(TSTR("GC Selected block %d with %d free" TENDSTR),dirtiest,dev->nChunksPerBlock - pagesInUse));
4591 +       }
4592 +       
4593 +       dev->oldestDirtySequence = 0; // clear this
4594 +       
4595 +       if(dirtiest > 0)
4596 +       {
4597 +               nonAggressiveSkip = 4;
4598 +       }
4599 +
4600 +       return dirtiest;
4601 +}
4602 +
4603 +
4604 +static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo)
4605 +{
4606 +       yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,blockNo);
4607 +       
4608 +       int erasedOk = 0;
4609 +       
4610 +       // If the block is still healthy erase it and mark as clean.
4611 +       // If the block has had a data failure, then retire it.
4612 +       bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
4613 +
4614 +       if(!bi->needsRetiring)
4615 +       {
4616 +               erasedOk = yaffs_EraseBlockInNAND(dev,blockNo);
4617 +               if(!erasedOk)
4618 +               {
4619 +                       dev->nErasureFailures++;
4620 +                       T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Erasure failed %d" TENDSTR),blockNo));
4621 +               }
4622 +       }
4623 +
4624 +       if(erasedOk && (yaffs_traceMask & YAFFS_TRACE_ERASE))
4625 +       {
4626 +                       int i;
4627 +                       for(i = 0; i < dev->nChunksPerBlock; i++)
4628 +                       {
4629 +                                       if(!yaffs_CheckChunkErased(dev,blockNo * dev->nChunksPerBlock + i))
4630 +                                       {
4631 +                                               T(YAFFS_TRACE_ERROR,(TSTR(">>Block %d erasure supposedly OK, but chunk %d not erased" TENDSTR),blockNo,i));
4632 +                                       }
4633 +                       }
4634 +       }
4635 +       
4636 +       if( erasedOk )
4637 +       {
4638 +               // Clean it up...
4639 +               bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
4640 +               dev->nErasedBlocks++;
4641 +               bi->pagesInUse = 0;
4642 +               bi->softDeletions = 0;
4643 +               bi->hasShrinkHeader=0;
4644 +               yaffs_ClearChunkBits(dev,blockNo);
4645 +       
4646 +               T(YAFFS_TRACE_ERASE,(TSTR("Erased block %d" TENDSTR),blockNo));
4647 +       }
4648 +       else
4649 +       {
4650 +               dev->nFreeChunks -= dev->nChunksPerBlock; // We lost a block of free space
4651 +               
4652 +               yaffs_RetireBlock(dev,blockNo);
4653 +               T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Block %d retired" TENDSTR),blockNo));
4654 +       }
4655 +}
4656 +
4657 +#if 0
4658 +static void yaffs_DumpBlockStats(yaffs_Device *dev)
4659 +{
4660 +       int i,j;
4661 +       yaffs_BlockInfo *bi;
4662 +       
4663 +       for(i= dev->internalStartBlock; i <=dev->internalEndBlock; i++)
4664 +       {
4665 +               bi = yaffs_GetBlockInfo(dev,i);
4666 +               T(YAFFS_TRACE_ALLOCATE,(TSTR("%3d state %d shrink %d inuse %d/%d seq %d pages"),i,
4667 +               bi->blockState,bi->hasShrinkHeader,bi->pagesInUse,bi->softDeletions,bi->sequenceNumber));       
4668 +               
4669 +               for(j = 0; j < dev->nChunksPerBlock; j++)
4670 +               {
4671 +                       if(yaffs_CheckChunkBit(dev,i,j))
4672 +                       {
4673 +                               T(YAFFS_TRACE_ALLOCATE,(TSTR(" %d"),j));
4674 +
4675 +                       }
4676 +               }
4677 +               T(YAFFS_TRACE_ALLOCATE,(TSTR(" " TENDSTR)));
4678 +
4679 +       }
4680 +}
4681 +#endif
4682 +
4683 +
4684 +static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
4685 +{
4686 +       int i;
4687 +       
4688 +       yaffs_BlockInfo *bi;
4689 +       
4690 +#if 0
4691 +       static int j = 0;
4692 +       j++;
4693 +       if(j < 0 || j > 100)
4694 +       {
4695 +               j = 0;
4696 +               yaffs_DumpBlockStats(dev);
4697 +       }
4698 +       
4699 +#endif
4700 +       
4701 +       if(dev->nErasedBlocks < 1)
4702 +       {
4703 +               // Hoosterman we've got a problem.
4704 +               // Can't get space to gc
4705 +               T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no more eraased blocks" TENDSTR)));
4706 +
4707 +               return -1;
4708 +       }
4709 +       
4710 +       // Find an empty block.
4711 +       
4712 +       for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++)
4713 +       {
4714 +               dev->allocationBlockFinder++;
4715 +               if(dev->allocationBlockFinder < dev->internalStartBlock || dev->allocationBlockFinder> dev->internalEndBlock) 
4716 +               {
4717 +                       dev->allocationBlockFinder = dev->internalStartBlock;
4718 +               }
4719 +               
4720 +               bi = yaffs_GetBlockInfo(dev,dev->allocationBlockFinder);
4721 +
4722 +               if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
4723 +               {
4724 +                       bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
4725 +                       dev->sequenceNumber++;
4726 +                       bi->sequenceNumber = dev->sequenceNumber;
4727 +                       dev->nErasedBlocks--;           
4728 +                       T(YAFFS_TRACE_ALLOCATE,(TSTR("Allocated block %d, seq  %d, %d left" TENDSTR),dev->allocationBlockFinder,dev->sequenceNumber, dev->nErasedBlocks));      
4729 +                       return dev->allocationBlockFinder;
4730 +               }
4731 +       }
4732 +       
4733 +       
4734 +       T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs tragedy: no more eraased blocks, but there should have been %d" TENDSTR),dev->nErasedBlocks));
4735 +       
4736 +       
4737 +       
4738 +
4739 +       
4740 +       return -1;      
4741 +}
4742 +
4743 +
4744 +// To determine if we have enough space we just look at the 
4745 +// number of erased blocks.
4746 +
4747 +static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev)
4748 +{
4749 +       int reservedChunks = (dev->nReservedBlocks * dev->nChunksPerBlock);
4750 +       return (dev->nFreeChunks > reservedChunks);
4751 +}
4752 +
4753 +
4754 +static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
4755 +{
4756 +       int retVal;
4757 +       yaffs_BlockInfo *bi;
4758 +       
4759 +       if(dev->allocationBlock < 0)
4760 +       {
4761 +               // Get next block to allocate off
4762 +               dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
4763 +               dev->allocationPage = 0;
4764 +       }
4765 +       
4766 +       if(!useReserve &&  !yaffs_CheckSpaceForAllocation(dev))
4767 +       {
4768 +               // Not enough space to allocate unless we're allowed to use the reserve.
4769 +               return -1;
4770 +       }
4771 +
4772 +       if(dev->nErasedBlocks < dev->nReservedBlocks && dev->allocationPage == 0)
4773 +       {
4774 +               T(YAFFS_TRACE_ALLOCATE,(TSTR("Allocating reserve" TENDSTR)));   
4775 +       }
4776 +
4777 +       
4778 +       // Next page please....
4779 +       if(dev->allocationBlock >= 0)
4780 +       {
4781 +               bi = yaffs_GetBlockInfo(dev,dev->allocationBlock);
4782 +               
4783 +               retVal = (dev->allocationBlock * dev->nChunksPerBlock) + 
4784 +                                 dev->allocationPage;
4785 +               bi->pagesInUse++;
4786 +               yaffs_SetChunkBit(dev,dev->allocationBlock,dev->allocationPage);
4787 +
4788 +               dev->allocationPage++;
4789 +               
4790 +               dev->nFreeChunks--;
4791 +               
4792 +               // If the block is full set the state to full
4793 +               if(dev->allocationPage >= dev->nChunksPerBlock)
4794 +               {
4795 +                       bi->blockState = YAFFS_BLOCK_STATE_FULL;
4796 +                       dev->allocationBlock = -1;
4797 +               }
4798 +
4799 +
4800 +               return retVal;
4801 +               
4802 +       }
4803 +       T(YAFFS_TRACE_ERROR,(TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
4804 +
4805 +       return -1;      
4806 +}
4807 +
4808 +
4809 +
4810 +
4811 +static int yaffs_GetErasedChunks(yaffs_Device *dev)
4812 +{
4813 +               int n;
4814 +
4815 +               n = dev->nErasedBlocks * dev->nChunksPerBlock;
4816 +
4817 +               if(dev->allocationBlock> 0)
4818 +               {
4819 +                       n += (dev->nChunksPerBlock - dev->allocationPage);
4820 +               }
4821 +
4822 +               return n;
4823 +
4824 +}
4825 +
4826 +static int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
4827 +{
4828 +       int oldChunk;
4829 +       int newChunk;
4830 +       int chunkInBlock;
4831 +       int markNAND;
4832 +       int retVal = YAFFS_OK;
4833 +       int cleanups = 0;
4834 +       int i;
4835 +
4836 +       int chunksBefore = yaffs_GetErasedChunks(dev);
4837 +       int chunksAfter;
4838 +
4839 +       yaffs_ExtendedTags  tags;
4840 +       
4841 +       yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,block);
4842 +       
4843 +       yaffs_Object *object;
4844 +       
4845 +       bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
4846 +
4847 +       T(YAFFS_TRACE_TRACING,(TSTR("Collecting block %d, in use %d, shrink %d, " TENDSTR),block,bi->pagesInUse,bi->hasShrinkHeader));
4848 +       //T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits));        
4849 +       
4850 +       //yaffs_VerifyFreeChunks(dev);
4851 +
4852 +       bi->hasShrinkHeader = 0; // clear the flag so that the block can erase
4853 +       
4854 +       dev->nFreeChunks -= bi->softDeletions;  // Take off the number of soft deleted entries because
4855 +                                               // they're going to get really deleted during GC.
4856 +
4857 +       dev->isDoingGC = 1;
4858 +
4859 +       if(!yaffs_StillSomeChunkBits(dev,block))
4860 +       {
4861 +               T(YAFFS_TRACE_TRACING,(TSTR("Collecting block %d that has no chunks in use" TENDSTR),block));
4862 +               yaffs_BlockBecameDirty(dev,block);
4863 +       }
4864 +       else
4865 +       {
4866 +
4867 +       __u8  *buffer = yaffs_GetTempBuffer(dev,__LINE__);
4868 +
4869 +       for(chunkInBlock = 0,oldChunk = block * dev->nChunksPerBlock; 
4870 +           chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev,block);
4871 +           chunkInBlock++, oldChunk++ )
4872 +       {
4873 +               if(yaffs_CheckChunkBit(dev,block,chunkInBlock))
4874 +               {
4875 +                       
4876 +                       // This page is in use and might need to be copied off
4877 +                       
4878 +                       markNAND = 1;
4879 +                       
4880 +                       //T(("copying page %x from %d to %d\n",mask,oldChunk,newChunk));
4881 +                       
4882 +                       yaffs_InitialiseTags(&tags);
4883 +                       
4884 +                       yaffs_ReadChunkWithTagsFromNAND(dev,oldChunk,buffer, &tags);
4885 +
4886 +                       object = yaffs_FindObjectByNumber(dev,tags.objectId);
4887 +                       
4888 +                       T(YAFFS_TRACE_GC_DETAIL,(TSTR("Collecting page %d, %d %d %d " TENDSTR),chunkInBlock,tags.objectId,tags.chunkId,tags.byteCount));
4889 +                       
4890 +                       if(!object)
4891 +                       {
4892 +                               T(YAFFS_TRACE_ERROR,(TSTR("page %d in gc has no object " TENDSTR),oldChunk));
4893 +                       }
4894 +                       
4895 +                       if(object && object->deleted && tags.chunkId != 0)
4896 +                       {
4897 +                               // Data chunk in a deleted file, throw it away
4898 +                               // It's a soft deleted data chunk,
4899 +                               // No need to copy this, just forget about it and fix up the
4900 +                               // object.
4901 +                               
4902 +                               //yaffs_PutChunkIntoFile(object, tags.chunkId, 0,0); 
4903 +                               object->nDataChunks--;
4904 +                               
4905 +                               if(object->nDataChunks <= 0)
4906 +                               {
4907 +                                       // remeber to clean up the object
4908 +                                       dev->gcCleanupList[cleanups] = tags.objectId;
4909 +                                       cleanups++;
4910 +                               }
4911 +                               markNAND = 0;
4912 +                       }
4913 +                       else if( 0 /* Todo object && object->deleted && object->nDataChunks == 0 */)
4914 +                       {
4915 +                               // Deleted object header with no data chunks.
4916 +                               // Can be discarded and the file deleted.
4917 +                               object->chunkId = 0;
4918 +                               yaffs_FreeTnode(object->myDev,object->variant.fileVariant.top);
4919 +                               object->variant.fileVariant.top = NULL;
4920 +                               yaffs_DoGenericObjectDeletion(object);
4921 +                               
4922 +                       }
4923 +                       else if(object)
4924 +                       {
4925 +                               // It's either a data chunk in a live file or
4926 +                               // an ObjectHeader, so we're interested in it.
4927 +                               // NB Need to keep the ObjectHeaders of deleted files
4928 +                               // until the whole file has been deleted off
4929 +                               tags.serialNumber++;
4930 +
4931 +                               dev->nGCCopies++;
4932 +                               
4933 +                               if(tags.chunkId == 0)
4934 +                               {
4935 +                                       // It is an object Id,
4936 +                                       // We need to nuke the shrinkheader flags first
4937 +                                       // We no longer want the shrinkHeader flag since its work is done
4938 +                                       // and if it is left in place it will mess up scanning.
4939 +                                       
4940 +                                       yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
4941 +                                       oh->isShrink = 0;
4942 +                                       tags.extraIsShrinkHeader = 0;
4943 +                               }
4944 +
4945 +                               newChunk = yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags,1);
4946 +                       
4947 +                               if(newChunk < 0)
4948 +                               {
4949 +                                       retVal =  YAFFS_FAIL;
4950 +                               }
4951 +                               else
4952 +                               {
4953 +                       
4954 +                                       // Ok, now fix up the Tnodes etc.
4955 +                       
4956 +                                       if(tags.chunkId == 0)
4957 +                                       {
4958 +                                               // It's a header
4959 +                                               object->chunkId = newChunk;
4960 +                                               object->serial = tags.serialNumber;
4961 +                                       }
4962 +                                       else
4963 +                                       {
4964 +                                               // It's a data chunk
4965 +                                               yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk,0);
4966 +                                       }
4967 +                               }
4968 +                       }
4969 +                       
4970 +                       yaffs_DeleteChunk(dev,oldChunk,markNAND,__LINE__);                      
4971 +                       
4972 +               }
4973 +       }
4974 +
4975 +       yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
4976 +
4977 +       //yaffs_VerifyFreeChunks(dev);
4978 +
4979 +       // Do any required cleanups
4980 +       for(i = 0; i < cleanups; i++)
4981 +       {                                               
4982 +               // Time to delete the file too
4983 +               object =  yaffs_FindObjectByNumber(dev,dev->gcCleanupList[i]);
4984 +               if(object)
4985 +               {
4986 +                       yaffs_FreeTnode(dev,object->variant.fileVariant.top);
4987 +                       object->variant.fileVariant.top = NULL;
4988 +                       T(YAFFS_TRACE_GC,(TSTR("yaffs: About to finally delete object %d" TENDSTR),object->objectId));
4989 +                       yaffs_DoGenericObjectDeletion(object);
4990 +               }
4991 +
4992 +       }
4993 +
4994 +       }
4995 +
4996 +       if(chunksBefore >= (chunksAfter = yaffs_GetErasedChunks(dev)))
4997 +       {
4998 +                       T(YAFFS_TRACE_GC,(TSTR("gc did not increase free chunks before %d after %d" TENDSTR),chunksBefore,chunksAfter));
4999 +       }
5000 +       
5001 +       
5002 +       dev->isDoingGC = 0;
5003 +       
5004 +       //yaffs_VerifyFreeChunks(dev);
5005 +                       
5006 +       return YAFFS_OK;
5007 +}
5008 +
5009 +#if 0
5010 +static yaffs_Object *yaffs_FindDeletedUnlinkedFile(yaffs_Device *dev)
5011 +{
5012 +       // find a file to delete
5013 +       struct list_head *i;    
5014 +       yaffs_Object *l;
5015 +
5016 +
5017 +       //Scan the unlinked files looking for one to delete
5018 +       list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children)
5019 +       {
5020 +               if(i)
5021 +               {
5022 +                       l = list_entry(i, yaffs_Object,siblings);
5023 +                       if(l->deleted)
5024 +                       {
5025 +                               return l;                       
5026 +                       }
5027 +               }
5028 +       }       
5029 +       return NULL;
5030 +}
5031 +
5032 +
5033 +static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev)
5034 +{
5035 +       // This does background deletion on unlinked files.. only deleted ones.
5036 +       // If we don't have a file we're working on then find one
5037 +       if(!dev->unlinkedDeletion && dev->nDeletedFiles > 0)
5038 +       {
5039 +               dev->unlinkedDeletion = yaffs_FindDeletedUnlinkedFile(dev);
5040 +       }
5041 +       
5042 +       // OK, we're working on a file...
5043 +       if(dev->unlinkedDeletion)
5044 +       {
5045 +               yaffs_Object *obj = dev->unlinkedDeletion;
5046 +               int delresult;
5047 +               int limit; // Number of chunks to delete in a file.
5048 +                                  // NB this can be exceeded, but not by much.
5049 +                                  
5050 +               limit = -1;
5051 +
5052 +               delresult = yaffs_DeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0,&limit);
5053 +               
5054 +               if(obj->nDataChunks == 0)
5055 +               {
5056 +                       // Done all the deleting of data chunks.
5057 +                       // Now dump the header and clean up
5058 +                       yaffs_FreeTnode(dev,obj->variant.fileVariant.top);
5059 +                       obj->variant.fileVariant.top = NULL;
5060 +                       yaffs_DoGenericObjectDeletion(obj);
5061 +                       dev->nDeletedFiles--;
5062 +                       dev->nUnlinkedFiles--;
5063 +                       dev->nBackgroundDeletions++;
5064 +                       dev->unlinkedDeletion = NULL;   
5065 +               }
5066 +       }
5067 +}
5068 +
5069 +#endif
5070 +
5071 +
5072 +
5073 +// New garbage collector
5074 +// If we're very low on erased blocks then we do aggressive garbage collection
5075 +// otherwise we do "leasurely" garbage collection.
5076 +// Aggressive gc looks further (whole array) and will accept dirtier blocks.
5077 +// Passive gc only inspects smaller areas and will only accept cleaner blocks.
5078 +//
5079 +// The idea is to help clear out space in a more spread-out manner.
5080 +// Dunno if it really does anything useful.
5081 +//
5082 +static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
5083 +{
5084 +       int block;
5085 +       int aggressive; 
5086 +       int gcOk = YAFFS_OK;
5087 +       int maxTries = 0;
5088 +       
5089 +       //yaffs_VerifyFreeChunks(dev);
5090 +       
5091 +       if(dev->isDoingGC)
5092 +       {
5093 +               // Bail out so we don't get recursive gc
5094 +               return YAFFS_OK;
5095 +       }
5096 +
5097 +       // This loop should pass the first time.
5098 +       // We'll only see looping here if the erase of the collected block fails.
5099 +       
5100 +       do{
5101 +               maxTries++;
5102 +               if(dev->nErasedBlocks < dev->nReservedBlocks)
5103 +               {
5104 +                       // We need a block soon...
5105 +                       aggressive = 1;
5106 +               }
5107 +               else 
5108 +               {
5109 +                       // We're in no hurry
5110 +                       aggressive = 0;
5111 +               }
5112 +       
5113 +               block = yaffs_FindBlockForGarbageCollection(dev,aggressive);
5114 +       
5115 +               if(block > 0)
5116 +               {
5117 +                       dev->garbageCollections++;
5118 +                       if(!aggressive)
5119 +                       {
5120 +                               dev->passiveGarbageCollections++;
5121 +                       }
5122 +
5123 +                       T(YAFFS_TRACE_GC,(TSTR("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),dev->nErasedBlocks,aggressive));
5124 +
5125 +                       gcOk =  yaffs_GarbageCollectBlock(dev,block);
5126 +               }
5127 +
5128 +               if(dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) 
5129 +               {
5130 +                       T(YAFFS_TRACE_GC,(TSTR("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" TENDSTR),dev->nErasedBlocks,maxTries,block));
5131 +               }
5132 +       } while((dev->nErasedBlocks < dev->nReservedBlocks) && (block > 0) && (maxTries < 2));
5133 +
5134 +       return aggressive ? gcOk: YAFFS_OK;
5135 +}
5136 +
5137 +
5138 +//////////////////////////// TAGS ///////////////////////////////////////
5139 +
5140 +
5141 +
5142 +#if 0
5143 +
5144 +void yaffs_CalcTagsECC(yaffs_Tags *tags)
5145 +{
5146 +       // Calculate an ecc
5147 +       
5148 +       unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
5149 +       unsigned  i,j;
5150 +       unsigned  ecc = 0;
5151 +       unsigned bit = 0;
5152 +
5153 +       tags->ecc = 0;
5154 +       
5155 +       for(i = 0; i < 8; i++)
5156 +       {
5157 +               for(j = 1; j &0xff; j<<=1)
5158 +               {
5159 +                       bit++;
5160 +                       if(b[i] & j)
5161 +                       {
5162 +                               ecc ^= bit;
5163 +                       }
5164 +               }
5165 +       }
5166 +       
5167 +       tags->ecc = ecc;
5168 +       
5169 +       
5170 +}
5171 +
5172 +int  yaffs_CheckECCOnTags(yaffs_Tags *tags)
5173 +{
5174 +       unsigned ecc = tags->ecc;
5175 +       
5176 +       yaffs_CalcTagsECC(tags);
5177 +       
5178 +       ecc ^= tags->ecc;
5179 +       
5180 +       if(ecc && ecc <= 64)
5181 +       {
5182 +               // TODO: Handle the failure better. Retire?
5183 +               unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
5184 +
5185 +               ecc--;
5186 +                               
5187 +               b[ecc / 8] ^= (1 << (ecc & 7));
5188 +               
5189 +               // Now recvalc the ecc
5190 +               yaffs_CalcTagsECC(tags);
5191 +               
5192 +               return 1; // recovered error
5193 +       }
5194 +       else if(ecc)
5195 +       {
5196 +               // Wierd ecc failure value
5197 +               // TODO Need to do somethiong here
5198 +               return -1; //unrecovered error
5199 +       }
5200 +       
5201 +       return 0;
5202 +}
5203 +
5204 +static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr)
5205 +{
5206 +       yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
5207 +       
5208 +       yaffs_CalcTagsECC(tagsPtr);
5209 +       
5210 +       sparePtr->tagByte0 = tu->asBytes[0];
5211 +       sparePtr->tagByte1 = tu->asBytes[1];
5212 +       sparePtr->tagByte2 = tu->asBytes[2];
5213 +       sparePtr->tagByte3 = tu->asBytes[3];
5214 +       sparePtr->tagByte4 = tu->asBytes[4];
5215 +       sparePtr->tagByte5 = tu->asBytes[5];
5216 +       sparePtr->tagByte6 = tu->asBytes[6];
5217 +       sparePtr->tagByte7 = tu->asBytes[7];
5218 +}
5219 +
5220 +static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr)
5221 +{
5222 +       yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
5223 +       int result;
5224 +
5225 +       tu->asBytes[0]= sparePtr->tagByte0;
5226 +       tu->asBytes[1]= sparePtr->tagByte1;
5227 +       tu->asBytes[2]= sparePtr->tagByte2;
5228 +       tu->asBytes[3]= sparePtr->tagByte3;
5229 +       tu->asBytes[4]= sparePtr->tagByte4;
5230 +       tu->asBytes[5]= sparePtr->tagByte5;
5231 +       tu->asBytes[6]= sparePtr->tagByte6;
5232 +       tu->asBytes[7]= sparePtr->tagByte7;
5233 +       
5234 +       result =  yaffs_CheckECCOnTags(tagsPtr);
5235 +       if(result> 0)
5236 +       {
5237 +               dev->tagsEccFixed++;
5238 +       }
5239 +       else if(result <0)
5240 +       {
5241 +               dev->tagsEccUnfixed++;
5242 +       }
5243 +}
5244 +
5245 +static void yaffs_SpareInitialise(yaffs_Spare *spare)
5246 +{
5247 +       memset(spare,0xFF,sizeof(yaffs_Spare));
5248 +}
5249 +
5250 +#endif
5251 +
5252 +#if 0
5253 +static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_ExtendedTags *tags, int useReserve)
5254 +{
5255 +       // NB There must be tags, data is optional
5256 +       // If there is data, then an ECC is calculated on it.
5257 +       
5258 +       yaffs_Spare spare;
5259 +       
5260 +       if(!tags)
5261 +       {
5262 +               return YAFFS_FAIL;
5263 +       }
5264 +       
5265 +       //yaffs_SpareInitialise(&spare);
5266 +       
5267 +       //if(!dev->useNANDECC && buffer)
5268 +       //{
5269 +       //      yaffs_CalcECC(buffer,&spare);
5270 +       //}
5271 +       
5272 +       //yaffs_LoadTagsIntoSpare(&spare,tags);
5273 +       
5274 +       return yaffs_WriteNewChunkToNAND(dev,buffer,&spare,useReserve);
5275 +       
5276 +}
5277 +#endif
5278 +
5279 +static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, int chunkInObject)
5280 +{
5281 +       return  (  tags->chunkId == chunkInObject &&
5282 +                          tags->objectId == objectId &&
5283 +                          !tags->chunkDeleted) ? 1 : 0;
5284 +       
5285 +}
5286 +
5287 +/////////////////////////////////////////////////////////////////////////////////////////////////////////
5288 +
5289 +
5290 +static int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
5291 +{
5292 +       //Get the Tnode, then get the level 0 offset chunk offset
5293 +    yaffs_Tnode *tn;     
5294 +    int theChunk = -1;
5295 +    yaffs_ExtendedTags localTags;
5296 +    int retVal = -1;
5297 +    
5298 +    yaffs_Device *dev = in->myDev;
5299 +    
5300 +    
5301 +    if(!tags)
5302 +    {
5303 +       // Passed a NULL, so use our own tags space
5304 +       tags = &localTags;
5305 +    }
5306 +    
5307 +    tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
5308 +    
5309 +    if(tn)
5310 +    {
5311 +               theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
5312 +               
5313 +               retVal = yaffs_FindChunkInGroup(dev,theChunk,tags,in->objectId,chunkInInode);
5314 +    }
5315 +    return retVal;
5316 +}
5317 +
5318 +static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
5319 +{
5320 +       //Get the Tnode, then get the level 0 offset chunk offset
5321 +    yaffs_Tnode *tn;     
5322 +    int theChunk = -1;
5323 +    yaffs_ExtendedTags localTags;
5324 +
5325 +    yaffs_Device *dev = in->myDev;
5326 +    int retVal = -1;
5327 +    
5328 +    if(!tags)
5329 +    {
5330 +       // Passed a NULL, so use our own tags space
5331 +       tags = &localTags;
5332 +    }
5333 +    
5334 +    tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
5335 +    
5336 +    if(tn)
5337 +    {
5338 +    
5339 +               theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
5340 +               
5341 +               retVal = yaffs_FindChunkInGroup(dev,theChunk,tags,in->objectId,chunkInInode);
5342 +    
5343 +               // Delete the entry in the filestructure (if found)
5344 +               if(retVal != -1)
5345 +               {
5346 +                       tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = 0;
5347 +               }
5348 +    }
5349 +    else
5350 +    {
5351 +       //T(("No level 0 found for %d\n", chunkInInode));
5352 +    }
5353 +    
5354 +    if(retVal == -1)
5355 +    {
5356 +       //T(("Could not find %d to delete\n",chunkInInode));
5357 +    }
5358 +    return retVal;
5359 +}
5360 +
5361 +
5362 +#ifdef YAFFS_PARANOID
5363 +
5364 +static int yaffs_CheckFileSanity(yaffs_Object *in)
5365 +{
5366 +       int chunk;
5367 +       int nChunks;
5368 +       int fSize;
5369 +       int failed = 0;
5370 +       int objId;
5371 +       yaffs_Tnode *tn;
5372 +    yaffs_Tags localTags;
5373 +    yaffs_Tags *tags = &localTags;
5374 +    int theChunk;
5375 +    int chunkDeleted;
5376 +    
5377 +       
5378 +       if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
5379 +       {
5380 +               //T(("Object not a file\n"));
5381 +               return YAFFS_FAIL;
5382 +       }
5383 +       
5384 +       objId = in->objectId;
5385 +       fSize  = in->variant.fileVariant.fileSize;
5386 +       nChunks = (fSize + in->myDev->nBytesPerChunk -1)/in->myDev->nBytesPerChunk;
5387 +       
5388 +       for(chunk = 1; chunk <= nChunks; chunk++)
5389 +       {
5390 +               tn = yaffs_FindLevel0Tnode(in->myDev,&in->variant.fileVariant, chunk);
5391 +    
5392 +               if(tn)
5393 +               {
5394 +    
5395 +                       theChunk = tn->level0[chunk & YAFFS_TNODES_LEVEL0_MASK] << in->myDev->chunkGroupBits;
5396 +                       
5397 +               if(yaffs_CheckChunkBits(dev,theChunk/dev->nChunksPerBlock,theChunk%dev->nChunksPerBlock))
5398 +                       {
5399 +
5400 +
5401 +                               yaffs_ReadChunkTagsFromNAND(in->myDev,theChunk,tags,&chunkDeleted);
5402 +                               if(yaffs_TagsMatch(tags,in->objectId,chunk,chunkDeleted))
5403 +                               {
5404 +                                       // found it;
5405 +                               
5406 +                               }
5407 +                       }
5408 +                       else
5409 +                       {
5410 +                               //T(("File problem file [%d,%d] NAND %d  tags[%d,%d]\n",
5411 +                               //              objId,chunk,theChunk,tags->chunkId,tags->objectId);
5412 +                                               
5413 +                               failed = 1;
5414 +                                                       
5415 +                       }
5416 +    
5417 +               }
5418 +               else
5419 +               {
5420 +                       //T(("No level 0 found for %d\n", chunk));
5421 +               }
5422 +       }
5423 +       
5424 +       return failed ? YAFFS_FAIL : YAFFS_OK;
5425 +}
5426 +
5427 +#endif
5428 +
5429 +static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan)
5430 +{
5431 +       // NB inScan is zero unless scanning. For forward scanning, inScan is > 0; for backward scanning inScan is < 0
5432 +       yaffs_Tnode *tn;
5433 +       yaffs_Device *dev = in->myDev;
5434 +       int existingChunk;
5435 +       yaffs_ExtendedTags existingTags;
5436 +       yaffs_ExtendedTags newTags;
5437 +       unsigned existingSerial, newSerial;
5438 +       
5439 +       if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
5440 +       {
5441 +               // Just ignore an attempt at putting a chunk into a non-file during scanning
5442 +               // If it is not during Scanning then something went wrong!
5443 +               if(!inScan)
5444 +               {
5445 +                       T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy:attempt to put data chunk into a non-file" TENDSTR)));
5446 +                       YBUG();
5447 +               }
5448 +               
5449 +               yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__);
5450 +               return YAFFS_OK;
5451 +       }
5452 +               
5453 +       tn = yaffs_AddOrFindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
5454 +       if(!tn)
5455 +       {
5456 +               return YAFFS_FAIL;
5457 +       }
5458 +
5459 +       existingChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK];            
5460 +       
5461 +       if(inScan != 0)
5462 +       {
5463 +               // If we're scanning then we need to test for duplicates
5464 +               // NB This does not need to be efficient since it should only ever 
5465 +               // happen when the power fails during a write, then only one
5466 +               // chunk should ever be affected.
5467 +               //
5468 +               // Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
5469 +               // Update: For backward scanning we don't need to re-read tags so this is quite cheap.
5470 +               
5471 +       
5472 +               
5473 +               if(existingChunk != 0)
5474 +               {
5475 +                       // NB Right now existing chunk will not be real chunkId if the device >= 32MB
5476 +                       //    thus we have to do a FindChunkInFile to get the real chunk id.
5477 +                       //
5478 +                       // We have a duplicate now we need to decide which one to use:
5479 +                       //
5480 +                       // Backwards scanning YAFFS2: The old one is what we use, dump the new one.
5481 +                       // Forward scanning YAFFS2: The new one is what we use, dump the old one.
5482 +                       // YAFFS1: Get both sets of tags and compare serial numbers.
5483 +                       //
5484 +                       //
5485 +                       
5486 +                       if(inScan > 0)
5487 +                       {
5488 +                               // Only do this for forward scanning
5489 +                               yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND, NULL,&newTags);
5490 +                       
5491 +                       
5492 +                               // Do a proper find
5493 +                               existingChunk = yaffs_FindChunkInFile(in,chunkInInode, &existingTags);
5494 +                       }
5495 +
5496 +                       if(existingChunk <=0)
5497 +                       {
5498 +                               //Hoosterman - how did this happen?
5499 +                               
5500 +                               T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: existing chunk < 0 in scan" TENDSTR)));
5501 +
5502 +                       }
5503 +
5504 +                       
5505 +                       // NB The deleted flags should be false, otherwise the chunks will 
5506 +                       // not be loaded during a scan
5507 +                       
5508 +                       newSerial = newTags.serialNumber;
5509 +                       existingSerial = existingTags.serialNumber;
5510 +                       
5511 +                       if( (inScan > 0) &&
5512 +                           ( in->myDev->isYaffs2  ||
5513 +                             existingChunk <= 0 ||
5514 +                            ((existingSerial+1) & 3) == newSerial))
5515 +                       {
5516 +                               // Forward scanning.                            
5517 +                               // Use new
5518 +                               // Delete the old one and drop through to update the tnode
5519 +                               yaffs_DeleteChunk(dev,existingChunk,1,__LINE__);
5520 +                       }
5521 +                       else
5522 +                       {
5523 +                               // Backward scanning or we want to use the existing one
5524 +                               // Use existing.
5525 +                               // Delete the new one and return early so that the tnode isn't changed
5526 +                               yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__);
5527 +                               return YAFFS_OK;
5528 +                       }
5529 +               }
5530 +
5531 +       }
5532 +               
5533 +       if(existingChunk == 0)
5534 +       {
5535 +               in->nDataChunks++;
5536 +       }
5537 +       
5538 +       tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = (chunkInNAND >> dev->chunkGroupBits);
5539 +       
5540 +       return YAFFS_OK;
5541 +}
5542 +
5543 +
5544 +
5545 +static int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffer)
5546 +{
5547 +    int chunkInNAND = yaffs_FindChunkInFile(in,chunkInInode,NULL);
5548 +    
5549 +    if(chunkInNAND >= 0)
5550 +    {
5551 +               return yaffs_ReadChunkWithTagsFromNAND(in->myDev,chunkInNAND,buffer,NULL);
5552 +       }
5553 +       else
5554 +       {
5555 +               T(YAFFS_TRACE_NANDACCESS,(TSTR("Chunk %d not found zero instead" TENDSTR),chunkInNAND));
5556 +
5557 +               memset(buffer,0,in->myDev->nBytesPerChunk); // get sane data if you read a hole
5558 +               return 0;
5559 +       }
5560 +
5561 +}
5562 +
5563 +
5564 +void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND,int lyn)
5565 +{
5566 +       int block;
5567 +       int page;
5568 +       yaffs_ExtendedTags tags;
5569 +       yaffs_BlockInfo *bi;
5570 +       
5571 +       if(chunkId <= 0) return;        
5572 +       
5573 +       dev->nDeletions++;
5574 +       block = chunkId / dev->nChunksPerBlock;
5575 +       page = chunkId % dev->nChunksPerBlock;
5576 +       
5577 +       bi = yaffs_GetBlockInfo(dev,block);
5578 +       
5579 +       T(YAFFS_TRACE_DELETION,(TSTR("line %d delete of chunk %d" TENDSTR),lyn,chunkId));
5580 +       
5581 +       if(markNAND && 
5582 +         bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
5583 +         !dev->isYaffs2)
5584 +       {
5585 +//             yaffs_SpareInitialise(&spare);
5586 +
5587 +#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
5588 +
5589 +                //read data before write, to ensure correct ecc 
5590 +                //if we're using MTD verification under Linux
5591 +//                yaffs_ReadChunkFromNAND(dev,chunkId,NULL,&spare,0);
5592 +#endif
5593 +
5594 +               yaffs_InitialiseTags(&tags);
5595 +
5596 +               tags.chunkDeleted = 1;
5597 +
5598 +       
5599 +               yaffs_WriteChunkWithTagsToNAND(dev,chunkId,NULL,&tags);
5600 +               yaffs_HandleUpdateChunk(dev,chunkId,&tags);
5601 +       }
5602 +       else
5603 +       {
5604 +                       dev->nUnmarkedDeletions++;
5605 +       }       
5606 +       
5607 +       
5608 +       // Pull out of the management area.
5609 +       // If the whole block became dirty, this will kick off an erasure.
5610 +       if(     bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
5611 +           bi->blockState == YAFFS_BLOCK_STATE_FULL ||     
5612 +           bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
5613 +           bi->blockState == YAFFS_BLOCK_STATE_COLLECTING)
5614 +       {
5615 +               dev->nFreeChunks++;
5616 +
5617 +               yaffs_ClearChunkBit(dev,block,page);
5618 +               
5619 +               bi->pagesInUse--;
5620 +               
5621 +               if(bi->pagesInUse == 0 &&
5622 +                  !bi->hasShrinkHeader &&
5623 +              bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
5624 +              bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING)
5625 +           {
5626 +               yaffs_BlockBecameDirty(dev,block);
5627 +           }
5628 +
5629 +       }
5630 +       else
5631 +       {
5632 +               // T(("Bad news deleting chunk %d\n",chunkId));
5633 +       }
5634 +       
5635 +}
5636 +
5637 +
5638 +
5639 +
5640 +static int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *buffer,int nBytes,int useReserve)
5641 +{
5642 +       // Find old chunk Need to do this to get serial number
5643 +       // Write new one and patch into tree.
5644 +       // Invalidate old tags.
5645 +
5646 +    int prevChunkId;
5647 +    yaffs_ExtendedTags prevTags;
5648 +    
5649 +    int newChunkId;
5650 +    yaffs_ExtendedTags newTags;
5651 +
5652 +    yaffs_Device *dev = in->myDev;    
5653 +
5654 +       yaffs_CheckGarbageCollection(dev);
5655 +
5656 +       // Get the previous chunk at this location in the file if it exists
5657 +    prevChunkId  = yaffs_FindChunkInFile(in,chunkInInode,&prevTags);
5658 +    
5659 +    // Set up new tags
5660 +    yaffs_InitialiseTags(&newTags);
5661 +    
5662 +       newTags.chunkId = chunkInInode;
5663 +       newTags.objectId = in->objectId;
5664 +       newTags.serialNumber = (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
5665 +       newTags.byteCount = nBytes;
5666 +               
5667 +//     yaffs_CalcTagsECC(&newTags);
5668 +
5669 +       newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags,useReserve);
5670 +       
5671 +       if(newChunkId >= 0)
5672 +       {
5673 +               yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId,0);
5674 +               
5675 +               
5676 +               if(prevChunkId >= 0)
5677 +               {
5678 +                       yaffs_DeleteChunk(dev,prevChunkId,1,__LINE__);
5679 +       
5680 +               }
5681 +               
5682 +               yaffs_CheckFileSanity(in);
5683 +       }
5684 +       return newChunkId;
5685 +
5686 +
5687 +
5688 +
5689 +
5690 +}
5691 +
5692 +
5693 +// UpdateObjectHeader updates the header on NAND for an object.
5694 +// If name is not NULL, then that new name is used.
5695 +//
5696 +int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink,int shadows)
5697 +{
5698 +
5699 +       yaffs_BlockInfo *bi;
5700 +       
5701 +       yaffs_Device *dev = in->myDev;
5702 +       
5703 +    int prevChunkId;
5704 +    int retVal = 0;
5705 +    
5706 +    int newChunkId;
5707 +    yaffs_ExtendedTags newTags;
5708 +    
5709 +    __u8 *buffer = NULL;
5710 +    YCHAR oldName[YAFFS_MAX_NAME_LENGTH+1];
5711 +    
5712 +   // __u8 bufferOld[YAFFS_BYTES_PER_CHUNK];
5713 +    
5714 +    yaffs_ObjectHeader *oh = NULL;
5715 +    // yaffs_ObjectHeader *ohOld = (yaffs_ObjectHeader *)bufferOld;
5716 +
5717 +    
5718 +    if(!in->fake || force)
5719 +    {
5720 +  
5721 +               yaffs_CheckGarbageCollection(dev);              
5722 +    
5723 +           buffer = yaffs_GetTempBuffer(in->myDev,__LINE__);
5724 +           oh  = (yaffs_ObjectHeader *)buffer;
5725 +    
5726 +               prevChunkId = in->chunkId;
5727 +    
5728 +               if(prevChunkId >= 0)
5729 +               {
5730 +                       yaffs_ReadChunkWithTagsFromNAND(dev,prevChunkId,buffer,NULL);
5731 +                       memcpy(oldName,oh->name,sizeof(oh->name));      
5732 +               }
5733 +
5734 +               memset(buffer,0xFF,dev->nBytesPerChunk);
5735 +
5736 +               // Header data
5737 +               oh->type = in->variantType;
5738 +               
5739 +               oh->yst_mode = in->yst_mode;
5740 +               
5741 +               // shadowing
5742 +               oh->shadowsObject = shadows;
5743 +
5744 +#ifdef CONFIG_YAFFS_WINCE
5745 +               oh->win_atime[0] = in->win_atime[0];
5746 +               oh->win_ctime[0] = in->win_ctime[0];
5747 +               oh->win_mtime[0] = in->win_mtime[0];
5748 +               oh->win_atime[1] = in->win_atime[1];
5749 +               oh->win_ctime[1] = in->win_ctime[1];
5750 +               oh->win_mtime[1] = in->win_mtime[1];
5751 +#else
5752 +               oh->yst_uid = in->yst_uid;
5753 +               oh->yst_gid = in->yst_gid;
5754 +               oh->yst_atime = in->yst_atime;
5755 +               oh->yst_mtime = in->yst_mtime;
5756 +               oh->yst_ctime = in->yst_ctime;
5757 +               oh->yst_rdev = in->yst_rdev;
5758 +#endif 
5759 +               if(in->parent)
5760 +               {
5761 +                       oh->parentObjectId = in->parent->objectId;
5762 +               }
5763 +               else
5764 +               {
5765 +                       oh->parentObjectId = 0;
5766 +               }
5767 +               
5768 +               //oh->sum = in->sum;
5769 +               if(name && *name)
5770 +               {
5771 +                       memset(oh->name,0,sizeof(oh->name));
5772 +                       yaffs_strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH);
5773 +               }
5774 +               else if(prevChunkId)
5775 +               {       
5776 +                       memcpy(oh->name, oldName,sizeof(oh->name));
5777 +               }
5778 +               else
5779 +               {
5780 +                       memset(oh->name,0,sizeof(oh->name));    
5781 +               }
5782 +               
5783 +               oh->isShrink = isShrink;
5784 +       
5785 +               switch(in->variantType)
5786 +               {
5787 +                       case YAFFS_OBJECT_TYPE_UNKNOWN:         
5788 +                               // Should not happen
5789 +                               break;
5790 +                       case YAFFS_OBJECT_TYPE_FILE:
5791 +                               oh->fileSize = (oh->parentObjectId == YAFFS_OBJECTID_DELETED ||
5792 +                                               oh->parentObjectId == YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.fileVariant.fileSize;
5793 +                               break;
5794 +                       case YAFFS_OBJECT_TYPE_HARDLINK:
5795 +                               oh->equivalentObjectId = in->variant.hardLinkVariant.equivalentObjectId;
5796 +                               break;
5797 +                       case YAFFS_OBJECT_TYPE_SPECIAL: 
5798 +                               // Do nothing
5799 +                               break;
5800 +                       case YAFFS_OBJECT_TYPE_DIRECTORY:       
5801 +                               // Do nothing
5802 +                               break;
5803 +                       case YAFFS_OBJECT_TYPE_SYMLINK:
5804 +                               yaffs_strncpy(oh->alias,in->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
5805 +                               oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
5806 +                               break;
5807 +               }
5808 +
5809 +               // Tags
5810 +               yaffs_InitialiseTags(&newTags);
5811 +               in->serial++;
5812 +               newTags.chunkId = 0;
5813 +               newTags.objectId = in->objectId;
5814 +               newTags.serialNumber = in->serial;
5815 +               
5816 +               // Add extra info for file header
5817 +               
5818 +               newTags.extraHeaderInfoAvailable = 1;
5819 +               newTags.extraParentObjectId = oh->parentObjectId;
5820 +               newTags.extraFileLength = oh->fileSize;
5821 +               newTags.extraIsShrinkHeader = oh->isShrink;
5822 +               newTags.extraEquivalentObjectId = oh->equivalentObjectId;
5823 +               newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
5824 +               newTags.extraObjectType  = in->variantType;
5825 +               
5826 +               // Create new chunk in NAND
5827 +               newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags, (prevChunkId >= 0) ? 1 : 0 );
5828 +    
5829 +               if(newChunkId >= 0)
5830 +               {
5831 +               
5832 +                       in->chunkId = newChunkId;       
5833 +               
5834 +                       if(prevChunkId >= 0)
5835 +                       {
5836 +                               yaffs_DeleteChunk(dev,prevChunkId,1,__LINE__);
5837 +                       }
5838 +               
5839 +                       in->dirty = 0;
5840 +                       
5841 +                       // If this was a shrink, then mark the block that the chunk lives on
5842 +                       if(isShrink)
5843 +                       {
5844 +                               bi = yaffs_GetBlockInfo(in->myDev,newChunkId / in->myDev->nChunksPerBlock);
5845 +                               bi->hasShrinkHeader = 1;
5846 +                       }
5847 +                       
5848 +               }
5849 +               
5850 +               retVal =  newChunkId;
5851 +
5852 +    }
5853 +    
5854 +       if(buffer) 
5855 +               yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
5856 +       
5857 +    return retVal;
5858 +}
5859 +
5860 +
5861 +/////////////////////// Short Operations Cache ////////////////////////////////
5862 +//     In many siturations where there is no high level buffering (eg WinCE) a lot of
5863 +//     reads might be short sequential reads, and a lot of writes may be short 
5864 +//  sequential writes. eg. scanning/writing a jpeg file.
5865 +//     In these cases, a short read/write cache can provide a huge perfomance benefit 
5866 +//  with dumb-as-a-rock code.
5867 +//  There are a limited number (~10) of cache chunks per device so that we don't
5868 +//  need a very intelligent search.
5869 +
5870 +
5871 +
5872 +
5873 +
5874 +static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
5875 +{
5876 +       yaffs_Device *dev = obj->myDev;
5877 +       int lowest = -99; // Stop compiler whining.
5878 +       int i;
5879 +       yaffs_ChunkCache *cache;
5880 +       int chunkWritten = 0;
5881 +       //int nBytes;
5882 +       int nCaches = obj->myDev->nShortOpCaches;
5883 +       
5884 +       if  (nCaches > 0)
5885 +       {
5886 +               do{
5887 +                       cache = NULL;
5888 +               
5889 +                       // Find the dirty cache for this object with the lowest chunk id.
5890 +                       for(i = 0; i < nCaches; i++)
5891 +                       {
5892 +                               if(dev->srCache[i].object == obj &&
5893 +                                  dev->srCache[i].dirty)
5894 +                               {
5895 +                                       if(!cache ||  dev->srCache[i].chunkId < lowest)
5896 +                                       {
5897 +                                               cache = &dev->srCache[i];
5898 +                                               lowest = cache->chunkId;
5899 +                                       }
5900 +                               }
5901 +                       }
5902 +               
5903 +                       if(cache && !cache->locked)
5904 +                       {
5905 +                               //Write it out and free it up
5906 +
5907 +#if 0
5908 +                               nBytes = cache->object->variant.fileVariant.fileSize - ((cache->chunkId -1) * YAFFS_BYTES_PER_CHUNK);
5909 +                       
5910 +                               if(nBytes > YAFFS_BYTES_PER_CHUNK)
5911 +                               {
5912 +                                       nBytes= YAFFS_BYTES_PER_CHUNK;
5913 +                               }
5914 +#endif                 
5915 +                               chunkWritten = yaffs_WriteChunkDataToObject(cache->object,
5916 +                                                                                                                       cache->chunkId,
5917 +                                                                                                                       cache->data,
5918 +                                                                                                                       cache->nBytes,1);
5919 +
5920 +                               cache->dirty = 0;
5921 +                               cache->object = NULL;
5922 +                       }
5923 +               
5924 +               } while(cache && chunkWritten > 0);
5925 +       
5926 +               if(cache)
5927 +               {
5928 +                       //Hoosterman, disk full while writing cache out.
5929 +                       T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
5930 +
5931 +               }
5932 +       }       
5933 +               
5934 +}
5935 +
5936 +
5937 +// Grab us a chunk for use.
5938 +// First look for an empty one. 
5939 +// Then look for the least recently used non-dirty one.
5940 +// Then look for the least recently used dirty one...., flush and look again.
5941 +static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
5942 +{
5943 +       int i;
5944 +       int usage;
5945 +       int theOne;
5946 +       
5947 +       if(dev->nShortOpCaches > 0)
5948 +       {
5949 +               for(i = 0; i < dev->nShortOpCaches; i++)
5950 +               {
5951 +                       if(!dev->srCache[i].object)
5952 +                       {
5953 +                               //T(("Grabbing empty %d\n",i));
5954 +                               
5955 +                               //printf("Grabbing empty %d\n",i);
5956 +                       
5957 +                               return &dev->srCache[i];
5958 +                       }
5959 +               }
5960 +               
5961 +               return NULL;
5962 +       
5963 +               theOne = -1; 
5964 +               usage = 0; // just to stop the compiler grizzling
5965 +       
5966 +               for(i = 0; i < dev->nShortOpCaches; i++)
5967 +               {
5968 +                       if(!dev->srCache[i].dirty &&
5969 +                       ((dev->srCache[i].lastUse < usage  && theOne >= 0)|| 
5970 +                               theOne < 0))
5971 +                       {
5972 +                               usage = dev->srCache[i].lastUse;
5973 +                               theOne = i;
5974 +                       }
5975 +               }
5976 +       
5977 +               //T(("Grabbing non-empty %d\n",theOne));
5978 +               
5979 +               //if(theOne >= 0) printf("Grabbed non-empty cache %d\n",theOne);
5980 +               
5981 +               return  theOne >= 0 ?  &dev->srCache[theOne] : NULL;
5982 +       }
5983 +       else
5984 +       {
5985 +               return NULL;
5986 +       }
5987 +       
5988 +}
5989 +
5990 +
5991 +static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
5992 +{
5993 +       yaffs_ChunkCache *cache;
5994 +       yaffs_Object *theObj;
5995 +       int usage;
5996 +       int i;
5997 +       int pushout;
5998 +       
5999 +       if(dev->nShortOpCaches > 0)
6000 +       {
6001 +               // Try find a non-dirty one...
6002 +       
6003 +               cache = yaffs_GrabChunkCacheWorker(dev);
6004 +       
6005 +               if(!cache)
6006 +               {
6007 +                       // They were all dirty, find the last recently used object and flush
6008 +                       // its cache, then  find again.
6009 +                       // NB what's here is not very accurate, we actually flush the object
6010 +                       // the last recently used page.
6011 +                       
6012 +                       // With locking we can't assume we can use entry zero
6013 +                       
6014 +               
6015 +                       theObj = NULL;
6016 +                       usage = -1;
6017 +                       cache = NULL;
6018 +                       pushout = -1;
6019 +       
6020 +                       for(i = 0; i < dev->nShortOpCaches; i++)
6021 +                       {
6022 +                               if( dev->srCache[i].object && 
6023 +                                       !dev->srCache[i].locked &&
6024 +                                       (dev->srCache[i].lastUse < usage || !cache))
6025 +                               {
6026 +                                       usage  = dev->srCache[i].lastUse;
6027 +                                       theObj = dev->srCache[i].object;
6028 +                                       cache = &dev->srCache[i];
6029 +                                       pushout = i;
6030 +                               }
6031 +                       }
6032 +               
6033 +                       if(!cache || cache->dirty)
6034 +                       {
6035 +                       
6036 +                               //printf("Dirty ");
6037 +                               yaffs_FlushFilesChunkCache(theObj);
6038 +               
6039 +                               // Try again
6040 +                               cache = yaffs_GrabChunkCacheWorker(dev);
6041 +                       }
6042 +                       else
6043 +                       {
6044 +                               //printf(" pushout %d\n",pushout);
6045 +                       }
6046 +                       
6047 +               }
6048 +               return cache;
6049 +       }
6050 +       else
6051 +               return NULL;
6052 +
6053 +}
6054 +
6055 +
6056 +// Find a cached chunk
6057 +static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj, int chunkId)
6058 +{
6059 +       yaffs_Device *dev = obj->myDev;
6060 +       int i;
6061 +       if(dev->nShortOpCaches > 0)
6062 +       {
6063 +               for(i = 0; i < dev->nShortOpCaches; i++)
6064 +               {
6065 +                       if(dev->srCache[i].object == obj && 
6066 +                       dev->srCache[i].chunkId == chunkId)
6067 +                       {
6068 +                               dev->cacheHits++;
6069 +                       
6070 +                               return &dev->srCache[i];
6071 +                       }
6072 +               }
6073 +       }
6074 +       return NULL;
6075 +}
6076 +
6077 +// Mark the chunk for the least recently used algorithym
6078 +static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache, int isAWrite)
6079 +{
6080 +
6081 +       if(dev->nShortOpCaches > 0)
6082 +       {
6083 +               if( dev->srLastUse < 0 || 
6084 +                       dev->srLastUse > 100000000)
6085 +               {
6086 +                       // Reset the cache usages
6087 +                       int i;
6088 +                       for(i = 1; i < dev->nShortOpCaches; i++)
6089 +                       {
6090 +                               dev->srCache[i].lastUse = 0;
6091 +                       }
6092 +                       dev->srLastUse = 0;
6093 +               }
6094 +
6095 +               dev->srLastUse++;
6096 +       
6097 +               cache->lastUse = dev->srLastUse;
6098 +
6099 +               if(isAWrite)
6100 +               {
6101 +                       cache->dirty = 1;
6102 +               }
6103 +       }
6104 +}
6105 +
6106 +// Invalidate a single cache page.
6107 +// Do this when a whole page gets written,
6108 +// ie the short cache for this page is no longer valid.
6109 +static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)
6110 +{
6111 +       if(object->myDev->nShortOpCaches > 0)
6112 +       {
6113 +               yaffs_ChunkCache *cache = yaffs_FindChunkCache(object,chunkId);
6114 +
6115 +               if(cache)
6116 +               {
6117 +                       cache->object = NULL;
6118 +               }
6119 +       }
6120 +}
6121 +
6122 +
6123 +// Invalidate all the cache pages associated with this object
6124 +// Do this whenever ther file is deleted or resized.
6125 +static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
6126 +{
6127 +       int i;
6128 +       yaffs_Device *dev = in->myDev;
6129 +       
6130 +       if(dev->nShortOpCaches > 0)
6131 +       { 
6132 +               // Now invalidate it.
6133 +               for(i = 0; i < dev->nShortOpCaches; i++)
6134 +               {
6135 +                       if(dev->srCache[i].object == in)
6136 +                       {
6137 +                               dev->srCache[i].object = NULL;
6138 +                       }
6139 +               }
6140 +       }
6141 +}
6142 +
6143 +
6144 +
6145 +
6146 +
6147 +///////////////////////// File read/write ///////////////////////////////
6148 +// Read and write have very similar structures.
6149 +// In general the read/write has three parts to it
6150 +// * An incomplete chunk to start with (if the read/write is not chunk-aligned)
6151 +// * Some complete chunks
6152 +// * An incomplete chunk to end off with
6153 +//
6154 +// Curve-balls: the first chunk might also be the last chunk.
6155 +
6156 +int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nBytes)
6157 +{
6158 +       
6159 +       
6160 +       int chunk;
6161 +       int start;
6162 +       int nToCopy;
6163 +       int n = nBytes;
6164 +       int nDone = 0;
6165 +       yaffs_ChunkCache *cache;
6166 +       
6167 +       yaffs_Device *dev;
6168 +       
6169 +       dev = in->myDev;
6170 +       
6171 +       while(n > 0)
6172 +       {
6173 +               chunk = offset / dev->nBytesPerChunk + 1; // The first chunk is 1
6174 +               start = offset % dev->nBytesPerChunk;
6175 +
6176 +               // OK now check for the curveball where the start and end are in
6177 +               // the same chunk.      
6178 +               if(     (start + n) < dev->nBytesPerChunk)
6179 +               {
6180 +                       nToCopy = n;
6181 +               }
6182 +               else
6183 +               {
6184 +                       nToCopy = dev->nBytesPerChunk - start;
6185 +               }
6186 +       
6187 +               cache = yaffs_FindChunkCache(in,chunk);
6188 +               
6189 +               // If the chunk is already in the cache or it is less than a whole chunk
6190 +               // then use the cache (if there is caching)
6191 +               // else bypass the cache.
6192 +               if( cache || nToCopy != dev->nBytesPerChunk)
6193 +               {
6194 +                       if(dev->nShortOpCaches > 0)
6195 +                       {
6196 +                               
6197 +                               // If we can't find the data in the cache, then load it up.
6198 +                               
6199 +                               if(!cache)
6200 +                               {
6201 +                                       cache = yaffs_GrabChunkCache(in->myDev);
6202 +                                       cache->object = in;
6203 +                                       cache->chunkId = chunk;
6204 +                                       cache->dirty = 0;
6205 +                                       cache->locked = 0;
6206 +                                       yaffs_ReadChunkDataFromObject(in,chunk,cache->data);
6207 +                                       cache->nBytes = 0;      
6208 +                               }
6209 +                       
6210 +                               yaffs_UseChunkCache(dev,cache,0);
6211 +
6212 +                               cache->locked = 1;
6213 +
6214 +#ifdef CONFIG_YAFFS_WINCE
6215 +                               yfsd_UnlockYAFFS(TRUE);
6216 +#endif
6217 +                               memcpy(buffer,&cache->data[start],nToCopy);
6218 +
6219 +#ifdef CONFIG_YAFFS_WINCE
6220 +                               yfsd_LockYAFFS(TRUE);
6221 +#endif
6222 +                               cache->locked = 0;
6223 +                       }
6224 +                       else
6225 +                       {
6226 +                               // Read into the local buffer then copy...
6227 +                               
6228 +                               __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
6229 +                               yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);            
6230 +#ifdef CONFIG_YAFFS_WINCE
6231 +                               yfsd_UnlockYAFFS(TRUE);
6232 +#endif
6233 +                               memcpy(buffer,&localBuffer[start],nToCopy);
6234 +
6235 +#ifdef CONFIG_YAFFS_WINCE
6236 +                               yfsd_LockYAFFS(TRUE);
6237 +#endif
6238 +                               yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
6239 +                       }
6240 +
6241 +               }
6242 +               else
6243 +               {
6244 +#ifdef CONFIG_YAFFS_WINCE
6245 +                       __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
6246 +                       
6247 +                       // Under WinCE can't do direct transfer. Need to use a local buffer.
6248 +                       // This is because we otherwise screw up WinCE's memory mapper
6249 +                       yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
6250 +
6251 +#ifdef CONFIG_YAFFS_WINCE
6252 +                               yfsd_UnlockYAFFS(TRUE);
6253 +#endif
6254 +                       memcpy(buffer,localBuffer,dev->nBytesPerChunk);
6255 +
6256 +#ifdef CONFIG_YAFFS_WINCE
6257 +                               yfsd_LockYAFFS(TRUE);
6258 +                               yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
6259 +#endif
6260 +
6261 +#else
6262 +                       // A full chunk. Read directly into the supplied buffer.
6263 +                       yaffs_ReadChunkDataFromObject(in,chunk,buffer);
6264 +#endif
6265 +               }
6266 +               
6267 +               n -= nToCopy;
6268 +               offset += nToCopy;
6269 +               buffer += nToCopy;
6270 +               nDone += nToCopy;
6271 +               
6272 +       }
6273 +       
6274 +       return nDone;
6275 +}
6276 +
6277 +
6278 +
6279 +int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, int nBytes, int writeThrough)
6280 +{      
6281 +       
6282 +       int chunk;
6283 +       int start;
6284 +       int nToCopy;
6285 +       int n = nBytes;
6286 +       int nDone = 0;
6287 +       int nToWriteBack;
6288 +       int startOfWrite = offset;
6289 +       int chunkWritten = 0;
6290 +       int nBytesRead;
6291 +       
6292 +       yaffs_Device *dev;
6293 +       
6294 +       dev = in->myDev;
6295 +       
6296 +       
6297 +       while(n > 0 && chunkWritten >= 0)
6298 +       {
6299 +               chunk = offset / dev->nBytesPerChunk + 1;
6300 +               start = offset % dev->nBytesPerChunk;
6301 +               
6302 +
6303 +               // OK now check for the curveball where the start and end are in
6304 +               // the same chunk.
6305 +               
6306 +               if((start + n) < dev->nBytesPerChunk)
6307 +               {
6308 +                       nToCopy = n;
6309 +                       
6310 +                       // Now folks, to calculate how many bytes to write back....
6311 +                       // If we're overwriting and not writing to then end of file then
6312 +                       // we need to write back as much as was there before.
6313 +                       
6314 +                       nBytesRead = in->variant.fileVariant.fileSize - ((chunk -1) * dev->nBytesPerChunk);
6315 +                       
6316 +                       if(nBytesRead > dev->nBytesPerChunk)
6317 +                       {
6318 +                               nBytesRead = dev->nBytesPerChunk;
6319 +                       }
6320 +                       
6321 +                       nToWriteBack = (nBytesRead > (start + n)) ? nBytesRead : (start +n);
6322 +                       
6323 +               }
6324 +               else
6325 +               {
6326 +                       nToCopy = dev->nBytesPerChunk - start;
6327 +                       nToWriteBack = dev->nBytesPerChunk;
6328 +               }
6329 +       
6330 +               if(nToCopy != dev->nBytesPerChunk)
6331 +               {
6332 +                       // An incomplete start or end chunk (or maybe both start and end chunk)
6333 +                       if(dev->nShortOpCaches > 0)
6334 +                          {
6335 +                               yaffs_ChunkCache *cache;
6336 +                               // If we can't find the data in the cache, then load it up.
6337 +                               cache = yaffs_FindChunkCache(in,chunk);
6338 +                               if(!cache && yaffs_CheckSpaceForAllocation(in->myDev))
6339 +                               {
6340 +                                       cache = yaffs_GrabChunkCache(in->myDev);
6341 +                                       cache->object = in;
6342 +                                       cache->chunkId = chunk;
6343 +                                       cache->dirty = 0;
6344 +                                       cache->locked = 0;
6345 +                                       yaffs_ReadChunkDataFromObject(in,chunk,cache->data);            
6346 +                               }
6347 +                       
6348 +                               if(cache)
6349 +                               {       
6350 +                                       yaffs_UseChunkCache(dev,cache,1);
6351 +                                       cache->locked = 1;
6352 +#ifdef CONFIG_YAFFS_WINCE
6353 +                               yfsd_UnlockYAFFS(TRUE);
6354 +#endif
6355 +       
6356 +                                       memcpy(&cache->data[start],buffer,nToCopy);
6357 +
6358 +#ifdef CONFIG_YAFFS_WINCE
6359 +                               yfsd_LockYAFFS(TRUE);
6360 +#endif
6361 +                                       cache->locked = 0;
6362 +                                       cache->nBytes = nToWriteBack;
6363 +                                       
6364 +                                       if(writeThrough)
6365 +                                       {
6366 +                                               chunkWritten = yaffs_WriteChunkDataToObject(cache->object,
6367 +                                                                                           cache->chunkId,
6368 +                                                                                           cache->data,
6369 +                                                                                           cache->nBytes,1);
6370 +                                               cache->dirty = 0;
6371 +                                       }
6372 +
6373 +                               }
6374 +                               else
6375 +                               {
6376 +                                       chunkWritten = -1; // fail the write
6377 +                               }
6378 +                       }
6379 +                       else
6380 +                       {
6381 +                               // An incomplete start or end chunk (or maybe both start and end chunk)
6382 +                               // Read into the local buffer then copy, then copy over and write back.
6383 +                               
6384 +                               __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
6385 +               
6386 +                               yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
6387 +                               
6388 +#ifdef CONFIG_YAFFS_WINCE
6389 +                               yfsd_UnlockYAFFS(TRUE);
6390 +#endif
6391 +                                       
6392 +                               memcpy(&localBuffer[start],buffer,nToCopy);
6393 +                       
6394 +#ifdef CONFIG_YAFFS_WINCE
6395 +                               yfsd_LockYAFFS(TRUE);
6396 +#endif
6397 +                               chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,localBuffer,nToWriteBack,0);
6398 +                               
6399 +                               yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
6400 +                       
6401 +                               //T(("Write with readback to chunk %d %d  start %d  copied %d wrote back %d\n",chunk,chunkWritten,start, nToCopy, nToWriteBack));
6402 +                       }
6403 +                       
6404 +               }
6405 +               else
6406 +               {
6407 +                       
6408 +#ifdef CONFIG_YAFFS_WINCE
6409 +                       // Under WinCE can't do direct transfer. Need to use a local buffer.
6410 +                       // This is because we otherwise screw up WinCE's memory mapper
6411 +                               __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
6412 +#ifdef CONFIG_YAFFS_WINCE
6413 +                               yfsd_UnlockYAFFS(TRUE);
6414 +#endif
6415 +                       memcpy(localBuffer,buffer,dev->nBytesPerChunk);
6416 +#ifdef CONFIG_YAFFS_WINCE
6417 +                               yfsd_LockYAFFS(TRUE);
6418 +#endif
6419 +                       chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,localBuffer,dev->nBytesPerChunk,0);
6420 +                       yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
6421 +#else
6422 +                       // A full chunk. Write directly from the supplied buffer.
6423 +                       chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,buffer,dev->nBytesPerChunk,0);
6424 +#endif
6425 +                       // Since we've overwritten the cached data, we better invalidate it.
6426 +                       yaffs_InvalidateChunkCache(in,chunk);
6427 +                       //T(("Write to chunk %d %d\n",chunk,chunkWritten));
6428 +               }
6429 +               
6430 +               if(chunkWritten >= 0)
6431 +               {
6432 +                       n -= nToCopy;
6433 +                       offset += nToCopy;
6434 +                       buffer += nToCopy;
6435 +                       nDone += nToCopy;
6436 +               }
6437 +               
6438 +       }
6439 +       
6440 +       // Update file object
6441 +       
6442 +       if((startOfWrite + nDone) > in->variant.fileVariant.fileSize)
6443 +       {
6444 +               in->variant.fileVariant.fileSize = (startOfWrite + nDone);
6445 +       }
6446 +       
6447 +       in->dirty = 1;
6448 +       
6449 +       return nDone;
6450 +}
6451 +
6452 +static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
6453 +{
6454 +
6455 +       yaffs_Device *dev = in->myDev;
6456 +       int oldFileSize = in->variant.fileVariant.fileSize;
6457 +
6458 +       
6459 +       int lastDel = 1 + (oldFileSize-1)/dev->nBytesPerChunk;
6460 +               
6461 +       int startDel = 1 + (newSize + dev->nBytesPerChunk - 1)/
6462 +                                               dev->nBytesPerChunk;
6463 +       int i;
6464 +       int chunkId;
6465 +
6466 +       // Delete backwards so that we don't end up with holes if
6467 +       // power is lost part-way through the operation.
6468 +       for(i = lastDel; i >= startDel; i--)
6469 +       {
6470 +               // NB this could be optimised somewhat,
6471 +               // eg. could retrieve the tags and write them without
6472 +               // using yaffs_DeleteChunk
6473 +
6474 +               chunkId = yaffs_FindAndDeleteChunkInFile(in,i,NULL);
6475 +               if(chunkId > 0)
6476 +               {
6477 +                       if(chunkId < (dev->internalStartBlock * dev->nChunksPerBlock) || 
6478 +                      chunkId >= ((dev->internalEndBlock+1) * dev->nChunksPerBlock))
6479 +                       {
6480 +                               T(YAFFS_TRACE_ALWAYS,(TSTR("Found daft chunkId %d for %d"TENDSTR),chunkId,i));
6481 +                       }
6482 +                       else
6483 +                       {
6484 +                               in->nDataChunks--;
6485 +                               yaffs_DeleteChunk(dev,chunkId,1,__LINE__);
6486 +                       }
6487 +               }
6488 +       }
6489 +               
6490 +}
6491 +
6492 +int yaffs_ResizeFile(yaffs_Object *in, int newSize)
6493 +{
6494 +
6495 +       int oldFileSize = in->variant.fileVariant.fileSize;
6496 +       int sizeOfPartialChunk;
6497 +       yaffs_Device *dev = in->myDev;
6498 +       
6499 +        sizeOfPartialChunk  = newSize % dev->nBytesPerChunk;
6500 +               
6501 +
6502 +       yaffs_FlushFilesChunkCache(in); 
6503 +       yaffs_InvalidateWholeChunkCache(in);
6504 +
6505 +       yaffs_CheckGarbageCollection(dev);
6506 +       
6507 +       if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
6508 +       {
6509 +               return yaffs_GetFileSize(in);
6510 +       }
6511 +       
6512 +       if(newSize < oldFileSize)
6513 +       {
6514 +
6515 +               yaffs_PruneResizedChunks(in,newSize);
6516 +               
6517 +               if(sizeOfPartialChunk != 0)
6518 +               {
6519 +                       int lastChunk = 1+ newSize/dev->nBytesPerChunk;
6520 +                       __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
6521 +                       
6522 +                       // Got to read and rewrite the last chunk with its new size and zero pad
6523 +                       yaffs_ReadChunkDataFromObject(in,lastChunk,localBuffer);
6524 +                       
6525 +                       memset(localBuffer + sizeOfPartialChunk,0, dev->nBytesPerChunk - sizeOfPartialChunk);
6526 +                       
6527 +                       yaffs_WriteChunkDataToObject(in,lastChunk,localBuffer,sizeOfPartialChunk,1);
6528 +                               
6529 +                       yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
6530 +               }
6531 +               
6532 +               in->variant.fileVariant.fileSize = newSize;
6533 +               
6534 +               yaffs_PruneFileStructure(dev,&in->variant.fileVariant);
6535 +               
6536 +               // Write a new object header to show we've shrunk the file
6537 +               // Do this only if the file is not in the deleted directories.
6538 +               if(in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
6539 +                  in->parent->objectId != YAFFS_OBJECTID_DELETED
6540 +                 )
6541 +               {
6542 +                       yaffs_UpdateObjectHeader(in,NULL, 0, 1,0);
6543 +               }
6544 +
6545 +               
6546 +               return newSize;
6547 +               
6548 +       }
6549 +       else
6550 +       {
6551 +               return oldFileSize;
6552 +       }
6553 +}
6554 +
6555 +
6556 +loff_t yaffs_GetFileSize(yaffs_Object *obj)
6557 +{
6558 +       obj = yaffs_GetEquivalentObject(obj);
6559 +       
6560 +       switch(obj->variantType)
6561 +       {
6562 +               case YAFFS_OBJECT_TYPE_FILE: 
6563 +                       return obj->variant.fileVariant.fileSize;
6564 +               case YAFFS_OBJECT_TYPE_SYMLINK:
6565 +                       return yaffs_strlen(obj->variant.symLinkVariant.alias);
6566 +               default:
6567 +                       return 0;
6568 +       }
6569 +}
6570 +
6571 +
6572 +
6573 +// yaffs_FlushFile() updates the file's
6574 +// objectId in NAND
6575 +
6576 +int yaffs_FlushFile(yaffs_Object *in, int updateTime)
6577 +{
6578 +       int retVal;
6579 +       if(in->dirty)
6580 +       {
6581 +               //T(("flushing object header\n"));
6582 +               
6583 +               yaffs_FlushFilesChunkCache(in);
6584 +               if(updateTime)
6585 +               {
6586 +#ifdef CONFIG_YAFFS_WINCE
6587 +                       yfsd_WinFileTimeNow(in->win_mtime);
6588 +#else
6589 +
6590 +                       in->yst_mtime = Y_CURRENT_TIME;
6591 +
6592 +#endif
6593 +               }
6594 +
6595 +               retVal = (yaffs_UpdateObjectHeader(in,NULL,0,0,0) >= 0)? YAFFS_OK : YAFFS_FAIL;
6596 +       }
6597 +       else
6598 +       {
6599 +               retVal = YAFFS_OK;
6600 +       }
6601 +       
6602 +       return retVal;
6603 +       
6604 +}
6605 +
6606 +
6607 +static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
6608 +{
6609 +
6610 +       // First off, invalidate the file's data in the cache, without flushing.
6611 +       yaffs_InvalidateWholeChunkCache(in);
6612 +
6613 +       if(in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir))
6614 +       {
6615 +               // Move to the unlinked directory so we have a record that it was deleted.
6616 +               yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0,0);
6617 +
6618 +       }
6619 +
6620 +       
6621 +       yaffs_RemoveObjectFromDirectory(in);
6622 +       yaffs_DeleteChunk(in->myDev,in->chunkId,1,__LINE__);
6623 +       in->chunkId = -1;
6624 +#if 0
6625 +#ifdef __KERNEL__
6626 +       if(in->myInode)
6627 +       {
6628 +               in->myInode->u.generic_ip = NULL;
6629 +               in->myInode = 0;
6630 +       }
6631 +#endif
6632 +#endif
6633 +
6634 +       yaffs_FreeObject(in);
6635 +       return YAFFS_OK;
6636 +
6637 +}
6638 +
6639 +// yaffs_DeleteFile deletes the whole file data
6640 +// and the inode associated with the file.
6641 +// It does not delete the links associated with the file.
6642 +static int yaffs_UnlinkFile(yaffs_Object *in)
6643 +{
6644 +
6645 +#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND_DELETION
6646 +
6647 +       // Delete the file data & tnodes
6648 +
6649 +        yaffs_DeleteWorker(in, in->variant.fileVariant.top, in->variant.fileVariant.topLevel, 0,NULL);
6650 +        
6651 +
6652 +       yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top);
6653 +       
6654 +       return  yaffs_DoGenericObjectDeletion(in);
6655 +#else
6656 +       int retVal;
6657 +       int immediateDeletion=0;
6658 +
6659 +       if(1)
6660 +       {
6661 +               //in->unlinked = 1;
6662 +               //in->myDev->nUnlinkedFiles++;
6663 +               //in->renameAllowed = 0;
6664 +#ifdef __KERNEL__
6665 +               if(!in->myInode)
6666 +               {
6667 +                       immediateDeletion = 1;
6668 +
6669 +               }
6670 +#else
6671 +               if(in->inUse <= 0)
6672 +               {
6673 +                       immediateDeletion = 1;
6674 +
6675 +               }
6676 +#endif
6677 +               if(immediateDeletion)
6678 +               {
6679 +                       retVal = yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0,0);
6680 +                       T(YAFFS_TRACE_TRACING,(TSTR("yaffs: immediate deletion of file %d" TENDSTR),in->objectId));
6681 +                       in->deleted=1;
6682 +                       in->myDev->nDeletedFiles++;
6683 +                       if( 0 && in->myDev->isYaffs2)
6684 +                       {
6685 +                               yaffs_ResizeFile(in,0);
6686 +                       }
6687 +                       yaffs_SoftDeleteFile(in);
6688 +               }
6689 +               else
6690 +               {
6691 +                       retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL,0,0);
6692 +               }
6693 +       
6694 +       }
6695 +       return retVal;
6696 +
6697 +       
6698 +#endif
6699 +}
6700 +
6701 +int yaffs_DeleteFile(yaffs_Object *in)
6702 +{
6703 +       int retVal = YAFFS_OK;
6704 +       
6705 +       if(in->nDataChunks > 0)
6706 +       {
6707 +               // Use soft deletion
6708 +               if(!in->unlinked)
6709 +               {
6710 +                       retVal = yaffs_UnlinkFile(in);
6711 +               }
6712 +               if(retVal == YAFFS_OK && 
6713 +               in->unlinked &&
6714 +               !in->deleted)
6715 +               {
6716 +                       in->deleted = 1;
6717 +                       in->myDev->nDeletedFiles++;
6718 +                       yaffs_SoftDeleteFile(in);
6719 +               }
6720 +               return in->deleted ? YAFFS_OK : YAFFS_FAIL;     
6721 +       }
6722 +       else
6723 +       {
6724 +               // The file has no data chunks so we toss it immediately
6725 +               yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top);
6726 +               in->variant.fileVariant.top = NULL;
6727 +               yaffs_DoGenericObjectDeletion(in);      
6728 +               
6729 +               return YAFFS_OK;        
6730 +       }
6731 +}
6732 +
6733 +static int yaffs_DeleteDirectory(yaffs_Object *in)
6734 +{
6735 +       //First check that the directory is empty.
6736 +       if(list_empty(&in->variant.directoryVariant.children))
6737 +       {
6738 +               return  yaffs_DoGenericObjectDeletion(in);
6739 +       }
6740 +       
6741 +       return YAFFS_FAIL;
6742 +       
6743 +}
6744 +
6745 +static int yaffs_DeleteSymLink(yaffs_Object *in)
6746 +{
6747 +       YFREE(in->variant.symLinkVariant.alias);
6748 +
6749 +       return  yaffs_DoGenericObjectDeletion(in);
6750 +}
6751 +
6752 +static int yaffs_DeleteHardLink(yaffs_Object *in)
6753 +{
6754 +       // remove this hardlink from the list assocaited with the equivalent
6755 +       // object
6756 +       list_del(&in->hardLinks);
6757 +       return  yaffs_DoGenericObjectDeletion(in);      
6758 +}
6759 +
6760 +
6761 +static void yaffs_DestroyObject(yaffs_Object *obj)
6762 +{
6763 +       switch(obj->variantType)
6764 +       {
6765 +               case YAFFS_OBJECT_TYPE_FILE: yaffs_DeleteFile(obj); break;
6766 +               case YAFFS_OBJECT_TYPE_DIRECTORY: yaffs_DeleteDirectory(obj); break;
6767 +               case YAFFS_OBJECT_TYPE_SYMLINK: yaffs_DeleteSymLink(obj); break;
6768 +               case YAFFS_OBJECT_TYPE_HARDLINK: yaffs_DeleteHardLink(obj); break;
6769 +               case YAFFS_OBJECT_TYPE_SPECIAL: yaffs_DoGenericObjectDeletion(obj); break;
6770 +               case YAFFS_OBJECT_TYPE_UNKNOWN: break; // should not happen.
6771 +       }
6772 +}
6773 +
6774 +
6775 +static int yaffs_UnlinkWorker(yaffs_Object *obj)
6776 +{
6777 +
6778 +       
6779 +       if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
6780 +       {
6781 +               return  yaffs_DeleteHardLink(obj);
6782 +       }
6783 +       else if(!list_empty(&obj->hardLinks))
6784 +       {       
6785 +               // Curve ball: We're unlinking an object that has a hardlink.
6786 +               //
6787 +               //      This problem arises because we are not strictly following
6788 +               //  The Linux link/inode model.
6789 +               //
6790 +               // We can't really delete the object.
6791 +               // Instead, we do the following:
6792 +               // - Select a hardlink.
6793 +               // - Unhook it from the hard links
6794 +               // - Unhook it from its parent directory (so that the rename can work)
6795 +               // - Rename the object to the hardlink's name.
6796 +               // - Delete the hardlink
6797 +               
6798 +               
6799 +               yaffs_Object *hl;
6800 +               int retVal;
6801 +               YCHAR name[YAFFS_MAX_NAME_LENGTH+1];
6802 +               
6803 +               hl = list_entry(obj->hardLinks.next,yaffs_Object,hardLinks);
6804 +               
6805 +               list_del_init(&hl->hardLinks);
6806 +               list_del_init(&hl->siblings);
6807 +               
6808 +               yaffs_GetObjectName(hl,name,YAFFS_MAX_NAME_LENGTH+1);
6809 +               
6810 +               retVal = yaffs_ChangeObjectName(obj, hl->parent, name,0,0);
6811 +               
6812 +               if(retVal == YAFFS_OK)
6813 +               {
6814 +                       retVal = yaffs_DoGenericObjectDeletion(hl);
6815 +               }
6816 +               return retVal;
6817 +                               
6818 +       }
6819 +       else
6820 +       {
6821 +               switch(obj->variantType)
6822 +               {
6823 +                       case YAFFS_OBJECT_TYPE_FILE:
6824 +                               return yaffs_UnlinkFile(obj);
6825 +                               break;
6826 +                       case YAFFS_OBJECT_TYPE_DIRECTORY:
6827 +                               return yaffs_DeleteDirectory(obj);
6828 +                               break;
6829 +                       case YAFFS_OBJECT_TYPE_SYMLINK:
6830 +                               return yaffs_DeleteSymLink(obj);
6831 +                               break;
6832 +                       case YAFFS_OBJECT_TYPE_SPECIAL:
6833 +                               return yaffs_DoGenericObjectDeletion(obj);
6834 +                               break;
6835 +                       case YAFFS_OBJECT_TYPE_HARDLINK:
6836 +                       case YAFFS_OBJECT_TYPE_UNKNOWN:
6837 +                       default:
6838 +                               return YAFFS_FAIL;
6839 +               }
6840 +       }
6841 +}
6842 +
6843 +int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)
6844 +{
6845 +       yaffs_Object *obj;
6846 +       
6847 +        obj = yaffs_FindObjectByName(dir,name);
6848 +        
6849 +        if(obj && obj->unlinkAllowed)
6850 +        {
6851 +               return yaffs_UnlinkWorker(obj);
6852 +        }
6853 +        
6854 +        return YAFFS_FAIL;
6855 +       
6856 +}
6857 +
6858 +//////////////// Initialisation Scanning /////////////////
6859 +
6860 +
6861 +void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, int backwardScanning)
6862 +{
6863 +       //Todo
6864 +}
6865 +
6866 +#if 0
6867 +// For now we use the SmartMedia check.
6868 +// We look at the blockStatus byte in the first two chunks
6869 +// These must be 0xFF to pass as OK.
6870 +// todo: this function needs to be modifyable foir different NAND types
6871 +// and different chunk sizes.  Suggest make this into a per-device configurable
6872 +// function.
6873 +static int yaffs_IsBlockBad(yaffs_Device *dev, int blk)
6874 +{
6875 +       yaffsExtendedTags *tags;
6876 +       
6877 +       yaffs_ReadChunkFromNAND(dev,blk * dev->nChunksPerBlock,NULL,&tags,1);
6878 +#if 1
6879 +       if(yaffs_CountBits(spare.blockStatus) < 7)
6880 +       {
6881 +               return 1;
6882 +       }
6883 +#else
6884 +       if(spare.blockStatus != 0xFF)
6885 +       {
6886 +               return 1;
6887 +       }
6888 +#endif
6889 +       yaffs_ReadChunkFromNAND(dev,blk * dev->nChunksPerBlock + 1,NULL,&spare,1);
6890 +
6891 +#if 1
6892 +       if(yaffs_CountBits(spare.blockStatus) < 7)
6893 +       {
6894 +               return 1;
6895 +       }
6896 +#else
6897 +       if(spare.blockStatus != 0xFF)
6898 +       {
6899 +               return 1;
6900 +       }
6901 +#endif
6902 +       
6903 +       return 0;
6904 +       
6905 +}
6906 +
6907 +#endif
6908 +
6909 +
6910 +typedef struct 
6911 +{
6912 +       int seq;
6913 +       int block;
6914 +} yaffs_BlockIndex;
6915 +
6916 +
6917 +
6918 +static int yaffs_Scan(yaffs_Device *dev)
6919 +{
6920 +       yaffs_ExtendedTags tags;
6921 +       int blk;
6922 +       int blockIterator;
6923 +       int startIterator;
6924 +       int endIterator;
6925 +       int nBlocksToScan = 0;
6926 +       
6927 +       int chunk;
6928 +       int c;
6929 +       int deleted;
6930 +       yaffs_BlockState state;
6931 +       yaffs_Object *hardList = NULL;
6932 +       yaffs_Object *hl;
6933 +       yaffs_BlockInfo *bi;
6934 +       int sequenceNumber;     
6935 +       yaffs_ObjectHeader *oh;
6936 +       yaffs_Object *in;
6937 +       yaffs_Object *parent;
6938 +       int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
6939 +       
6940 +       __u8 *chunkData;
6941 +
6942 +       yaffs_BlockIndex *blockIndex = NULL;
6943 +
6944 +       T(YAFFS_TRACE_SCAN,(TSTR("yaffs_Scan starts  intstartblk %d intendblk %d..." TENDSTR),dev->internalStartBlock,dev->internalEndBlock));
6945 +       
6946 +       chunkData = yaffs_GetTempBuffer(dev,__LINE__);
6947 +       
6948 +       
6949 +       dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
6950 +       
6951 +       if(dev->isYaffs2)
6952 +       {
6953 +               blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));               
6954 +       }
6955 +       
6956 +       
6957 +       // Scan all the blocks to determine their state
6958 +       for(blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++)
6959 +       {
6960 +               bi = yaffs_GetBlockInfo(dev,blk);
6961 +               yaffs_ClearChunkBits(dev,blk);
6962 +               bi->pagesInUse = 0;
6963 +               bi->softDeletions = 0;
6964 +                               
6965 +               yaffs_QueryInitialBlockState(dev,blk,&state,&sequenceNumber);
6966 +               
6967 +               bi->blockState = state;
6968 +               bi->sequenceNumber = sequenceNumber;
6969 +
6970 +               T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block scanning block %d state %d seq %d" TENDSTR),blk,state,sequenceNumber));
6971 +               
6972 +               if(state == YAFFS_BLOCK_STATE_DEAD)
6973 +               {
6974 +                       T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("block %d is bad" TENDSTR),blk));
6975 +               }
6976 +               else if(state == YAFFS_BLOCK_STATE_EMPTY)
6977 +               {
6978 +                       T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block empty " TENDSTR)));
6979 +                       dev->nErasedBlocks++;
6980 +                       dev->nFreeChunks += dev->nChunksPerBlock;
6981 +               }
6982 +               else if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
6983 +               {
6984 +                                       
6985 +                       // Determine the highest sequence number
6986 +                       if( dev->isYaffs2 &&
6987 +                           sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
6988 +                           sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER)
6989 +                        {
6990 +                               
6991 +                               blockIndex[nBlocksToScan].seq = sequenceNumber;
6992 +                               blockIndex[nBlocksToScan].block = blk;
6993 +                               
6994 +                               nBlocksToScan++;
6995 +
6996 +                               if(sequenceNumber >= dev->sequenceNumber)
6997 +                               {
6998 +                                       dev->sequenceNumber = sequenceNumber;
6999 +                               }
7000 +                       }
7001 +                       else if(dev->isYaffs2)
7002 +                       {
7003 +                               // TODO: Nasty sequence number!
7004 +                               T(YAFFS_TRACE_SCAN,(TSTR("Block scanning block %d has bad sequence number %d" TENDSTR),blk,sequenceNumber));
7005 +
7006 +                       }
7007 +               }
7008 +       }
7009 +       
7010 +       // Sort the blocks
7011 +       // Dungy old bubble sort for now...
7012 +       if(dev->isYaffs2)
7013 +       {
7014 +               yaffs_BlockIndex temp;
7015 +               int i;
7016 +               int j;
7017 +               
7018 +               for(i = 0; i < nBlocksToScan; i++)
7019 +                       for(j = i+1; j < nBlocksToScan; j++)
7020 +                        if(blockIndex[i].seq > blockIndex[j].seq)
7021 +                        {
7022 +                               temp = blockIndex[j];
7023 +                               blockIndex[j] = blockIndex[i];
7024 +                               blockIndex[i] = temp;
7025 +                        }
7026 +       }
7027 +       
7028 +       
7029 +       // Now scan the blocks looking at the data.
7030 +       if(dev->isYaffs2)
7031 +       {
7032 +               startIterator = 0;
7033 +               endIterator = nBlocksToScan-1;
7034 +               T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("%d blocks to be scanned" TENDSTR),nBlocksToScan));
7035 +       }
7036 +       else
7037 +       {
7038 +               startIterator = dev->internalStartBlock;
7039 +               endIterator = dev->internalEndBlock;
7040 +       }
7041 +       
7042 +       // For each block....
7043 +       for(blockIterator = startIterator; blockIterator <= endIterator; blockIterator++)
7044 +       {
7045 +       
7046 +               if(dev->isYaffs2)
7047 +               {
7048 +                       // get the block to scan in the correct order
7049 +                       blk = blockIndex[blockIterator].block;
7050 +               }
7051 +               else
7052 +               {
7053 +                       blk = blockIterator;
7054 +               }
7055 +
7056 +
7057 +               bi = yaffs_GetBlockInfo(dev,blk);
7058 +               state = bi->blockState;
7059 +               
7060 +               deleted = 0;
7061 +               
7062 +               // For each chunk in each block that needs scanning....
7063 +               for(c = 0; c < dev->nChunksPerBlock && 
7064 +                                  state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++)
7065 +               {
7066 +                       // Read the tags and decide what to do
7067 +                       chunk = blk * dev->nChunksPerBlock + c;
7068 +                       
7069 +                       yaffs_ReadChunkWithTagsFromNAND(dev,chunk,NULL,&tags);
7070 +
7071 +                       // Let's have a good look at this chunk...
7072 +       
7073 +                       
7074 +                       if(!dev->isYaffs2 && tags.chunkDeleted)
7075 +                       {
7076 +                               // YAFFS1 only...
7077 +                               // A deleted chunk
7078 +                               deleted++;
7079 +                               dev->nFreeChunks ++;
7080 +                               //T((" %d %d deleted\n",blk,c));
7081 +                       }
7082 +                       else if(!tags.chunkUsed)
7083 +                       {
7084 +                               // An unassigned chunk in the block
7085 +                               // This means that either the block is empty or 
7086 +                               // this is the one being allocated from
7087 +                               
7088 +                               if(c == 0)
7089 +                               {
7090 +                                       // We're looking at the first chunk in the block so the block is unused
7091 +                                       state = YAFFS_BLOCK_STATE_EMPTY;
7092 +                                       dev->nErasedBlocks++;
7093 +                               }
7094 +                               else
7095 +                               {
7096 +                                       // this is the block being allocated from
7097 +                                       T(YAFFS_TRACE_SCAN,(TSTR(" Allocating from %d %d" TENDSTR),blk,c));
7098 +                                       state = YAFFS_BLOCK_STATE_ALLOCATING;
7099 +                                       dev->allocationBlock = blk;
7100 +                                       dev->allocationPage = c;
7101 +                                       dev->allocationBlockFinder = blk; // Set it to here to encourage the allocator to
7102 +                                                                                                         // go forth from here.
7103 +                                       //Yaffs2 sanity check:
7104 +                                       // This should be the one with the highest sequence number
7105 +                                       if(dev->isYaffs2 && (dev->sequenceNumber != bi->sequenceNumber))
7106 +                                       {
7107 +                                               T(YAFFS_TRACE_ALWAYS,
7108 +                                                               (TSTR("yaffs: Allocation block %d was not highest sequence id: block seq = %d, dev seq = %d" TENDSTR),
7109 +                                                               blk,bi->sequenceNumber,dev->sequenceNumber));
7110 +                                       }
7111 +                               }
7112 +
7113 +                               dev->nFreeChunks += (dev->nChunksPerBlock - c);
7114 +                       }
7115 +                       else if(tags.chunkId > 0)
7116 +                       {
7117 +                               // chunkId > 0 so it is a data chunk...
7118 +                               unsigned int endpos;
7119 +
7120 +                               yaffs_SetChunkBit(dev,blk,c);
7121 +                               bi->pagesInUse++;
7122 +                                                               
7123 +                               in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
7124 +                               // PutChunkIntoFile checks for a clash (two data chunks with
7125 +                               // the same chunkId).
7126 +                               yaffs_PutChunkIntoFile(in,tags.chunkId,chunk,1);
7127 +                               endpos = (tags.chunkId - 1)* dev->nBytesPerChunk + tags.byteCount;
7128 +                               if(in->variantType == YAFFS_OBJECT_TYPE_FILE && in->variant.fileVariant.scannedFileSize <endpos)
7129 +                               {
7130 +                                       in->variant.fileVariant.scannedFileSize = endpos;
7131 +                                       if(!dev->useHeaderFileSize)
7132 +                                       {       
7133 +                                                       in->variant.fileVariant.fileSize = in->variant.fileVariant.scannedFileSize;
7134 +                                       }
7135 +
7136 +                               }
7137 +                               //T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));  
7138 +                       }
7139 +                       else
7140 +                       {
7141 +                               // chunkId == 0, so it is an ObjectHeader.
7142 +                               // Thus, we read in the object header and make the object
7143 +                               yaffs_SetChunkBit(dev,blk,c);
7144 +                               bi->pagesInUse++;
7145 +                                                       
7146 +                               yaffs_ReadChunkWithTagsFromNAND(dev,chunk,chunkData,NULL);
7147 +                               
7148 +                               oh = (yaffs_ObjectHeader *)chunkData;
7149 +                               
7150 +                               in = yaffs_FindObjectByNumber(dev,tags.objectId);
7151 +                               if(in && in->variantType != oh->type)
7152 +                               {
7153 +                                       // This should not happen, but somehow
7154 +                                       // Wev'e ended up with an objectId that has been reused but not yet 
7155 +                                       // deleted, and worse still it has changed type. Delete the old object.
7156 +                                       
7157 +                                       yaffs_DestroyObject(in);
7158 +                                       
7159 +                                       in = 0;
7160 +                               }
7161 +                               
7162 +                               in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type);
7163 +                               
7164 +                               if(oh->shadowsObject > 0)
7165 +                               {
7166 +                                       yaffs_HandleShadowedObject(dev,oh->shadowsObject,0);
7167 +                               }
7168 +                               
7169 +                               if(in->valid)
7170 +                               {
7171 +                                       // We have already filled this one. We have a duplicate and need to resolve it.
7172 +                                       
7173 +                                       unsigned existingSerial = in->serial;
7174 +                                       unsigned newSerial = tags.serialNumber;
7175 +                                       
7176 +                                       if( dev->isYaffs2 ||
7177 +                                           ((existingSerial+1) & 3) == newSerial)
7178 +                                       {
7179 +                                               // Use new one - destroy the exisiting one
7180 +                                               yaffs_DeleteChunk(dev,in->chunkId,1,__LINE__);
7181 +                                               in->valid = 0;
7182 +                                       }
7183 +                                       else
7184 +                                       {
7185 +                                               // Use existing - destroy this one.
7186 +                                               yaffs_DeleteChunk(dev,chunk,1,__LINE__);
7187 +                                       }
7188 +                               }
7189 +                               
7190 +                               if(!in->valid &&
7191 +                                  (tags.objectId == YAFFS_OBJECTID_ROOT ||
7192 +                                   tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))
7193 +                               {
7194 +                                       // We only load some info, don't fiddle with directory structure
7195 +                                       in->valid = 1;
7196 +                                       in->variantType = oh->type;
7197 +       
7198 +                                       in->yst_mode  = oh->yst_mode;
7199 +#ifdef CONFIG_YAFFS_WINCE
7200 +                                       in->win_atime[0] = oh->win_atime[0];
7201 +                                       in->win_ctime[0] = oh->win_ctime[0];
7202 +                                       in->win_mtime[0] = oh->win_mtime[0];
7203 +                                       in->win_atime[1] = oh->win_atime[1];
7204 +                                       in->win_ctime[1] = oh->win_ctime[1];
7205 +                                       in->win_mtime[1] = oh->win_mtime[1];
7206 +#else
7207 +                                       in->yst_uid   = oh->yst_uid;
7208 +                                       in->yst_gid   = oh->yst_gid;
7209 +                                       in->yst_atime = oh->yst_atime;
7210 +                                       in->yst_mtime = oh->yst_mtime;
7211 +                                       in->yst_ctime = oh->yst_ctime;
7212 +                                       in->yst_rdev = oh->yst_rdev;
7213 +#endif
7214 +                                       in->chunkId  = chunk;
7215 +
7216 +                               }
7217 +                               else if(!in->valid)
7218 +                               {
7219 +                                       // we need to load this info
7220 +                               
7221 +                                       in->valid = 1;
7222 +                                       in->variantType = oh->type;
7223 +       
7224 +                                       in->yst_mode  = oh->yst_mode;
7225 +#ifdef CONFIG_YAFFS_WINCE
7226 +                                       in->win_atime[0] = oh->win_atime[0];
7227 +                                       in->win_ctime[0] = oh->win_ctime[0];
7228 +                                       in->win_mtime[0] = oh->win_mtime[0];
7229 +                                       in->win_atime[1] = oh->win_atime[1];
7230 +                                       in->win_ctime[1] = oh->win_ctime[1];
7231 +                                       in->win_mtime[1] = oh->win_mtime[1];
7232 +#else
7233 +                                       in->yst_uid   = oh->yst_uid;
7234 +                                       in->yst_gid   = oh->yst_gid;
7235 +                                       in->yst_atime = oh->yst_atime;
7236 +                                       in->yst_mtime = oh->yst_mtime;
7237 +                                       in->yst_ctime = oh->yst_ctime;
7238 +                                       in->yst_rdev = oh->yst_rdev;
7239 +#endif
7240 +                                       in->chunkId  = chunk;
7241 +
7242 +                                       yaffs_SetObjectName(in,oh->name);
7243 +                                       in->dirty = 0;
7244 +                                                       
7245 +                                       // directory stuff...
7246 +                                       // hook up to parent
7247 +       
7248 +                                       parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY);
7249 +                                       if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN)
7250 +                                       {
7251 +                                               // Set up as a directory
7252 +                                               parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY;
7253 +                                               INIT_LIST_HEAD(&parent->variant.directoryVariant.children);
7254 +                                       }
7255 +                                       else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
7256 +                                       {
7257 +                                               // Hoosterman, another problem....
7258 +                                               // We're trying to use a non-directory as a directory
7259 +
7260 +                                               T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." TENDSTR)));
7261 +                                               parent = dev->lostNFoundDir;
7262 +                                       }
7263 +                               
7264 +                                       yaffs_AddObjectToDirectory(parent,in);
7265 +
7266 +                                       if(0 && (parent == dev->deletedDir ||
7267 +                                          parent == dev->unlinkedDir))
7268 +                                       {
7269 +                                               in->deleted = 1; // If it is unlinked at start up then it wants deleting
7270 +                                               dev->nDeletedFiles++;
7271 +                                       }
7272 +                               
7273 +                                       // Note re hardlinks.
7274 +                                       // Since we might scan a hardlink before its equivalent object is scanned
7275 +                                       // we put them all in a list.
7276 +                                       // After scanning is complete, we should have all the objects, so we run through this
7277 +                                       // list and fix up all the chains.              
7278 +       
7279 +                                       switch(in->variantType)
7280 +                                       {
7281 +                                               case YAFFS_OBJECT_TYPE_UNKNOWN:         // Todo got a problem
7282 +                                                       break;
7283 +                                               case YAFFS_OBJECT_TYPE_FILE:
7284 +                                                       if(dev->isYaffs2 && oh->isShrink)
7285 +                                                       {
7286 +                                                               // Prune back the shrunken chunks
7287 +                                                               yaffs_PruneResizedChunks(in,oh->fileSize);
7288 +                                                               // Mark the block as having a shrinkHeader
7289 +                                                               bi->hasShrinkHeader = 1;
7290 +                                                       }
7291 +                                                       
7292 +                                                       if(dev->useHeaderFileSize)
7293 +                                               
7294 +                                                               in->variant.fileVariant.fileSize = oh->fileSize;
7295 +                                                               
7296 +                                                       break;
7297 +                                               case YAFFS_OBJECT_TYPE_HARDLINK:
7298 +                                                       in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId;
7299 +                                                       in->hardLinks.next = (struct list_head *)hardList;
7300 +                                                       hardList = in;
7301 +                                                       break;
7302 +                                               case YAFFS_OBJECT_TYPE_DIRECTORY:       // Do nothing
7303 +                                                       break;
7304 +                                               case YAFFS_OBJECT_TYPE_SPECIAL: // Do nothing
7305 +                                                       break;
7306 +                                               case YAFFS_OBJECT_TYPE_SYMLINK:         // Do nothing
7307 +                                                       in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias);
7308 +                                                       break;
7309 +                                       }
7310 +
7311 +                                       if(parent == dev->deletedDir)
7312 +                                       {
7313 +                                               yaffs_DestroyObject(in);
7314 +                                               bi->hasShrinkHeader = 1;
7315 +                                       }
7316 +                                       //T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));        
7317 +                               }
7318 +                       }
7319 +               }
7320 +               
7321 +               if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
7322 +               {
7323 +                       // If we got this far while scanning, then the block is fully allocated.
7324 +                       state = YAFFS_BLOCK_STATE_FULL; 
7325 +               }
7326 +               
7327 +               bi->blockState = state;
7328 +               
7329 +               // Now let's see if it was dirty
7330 +               if(     bi->pagesInUse == 0 &&
7331 +                       !bi->hasShrinkHeader &&
7332 +               bi->blockState == YAFFS_BLOCK_STATE_FULL)
7333 +           {
7334 +               yaffs_BlockBecameDirty(dev,blk);
7335 +           }
7336 +
7337 +       }
7338 +       
7339 +       if(blockIndex)
7340 +       {
7341 +               YFREE(blockIndex);
7342 +       }
7343 +       
7344 +       // Ok, we've done all the scanning.
7345 +       
7346 +       // Fix up the hard link chains.
7347 +       // We should now have scanned all the objects, now it's time to add these 
7348 +       // hardlinks.
7349 +       while(hardList)
7350 +       {
7351 +               hl = hardList;
7352 +               hardList = (yaffs_Object *)(hardList->hardLinks.next);
7353 +               
7354 +               in = yaffs_FindObjectByNumber(dev,hl->variant.hardLinkVariant.equivalentObjectId);
7355 +               
7356 +               if(in)
7357 +               {
7358 +                       // Add the hardlink pointers
7359 +                       hl->variant.hardLinkVariant.equivalentObject=in;
7360 +                       list_add(&hl->hardLinks,&in->hardLinks);
7361 +               }
7362 +               else
7363 +               {
7364 +                       //Todo Need to report/handle this better.
7365 +                       // Got a problem... hardlink to a non-existant object
7366 +                       hl->variant.hardLinkVariant.equivalentObject=NULL;
7367 +                       INIT_LIST_HEAD(&hl->hardLinks);
7368 +                       
7369 +               }
7370 +               
7371 +       }
7372 +       
7373 +       // Handle the unlinked files. Since they were left in an unlinked state we should
7374 +       // just delete them.
7375 +       {
7376 +               struct list_head *i;    
7377 +               struct list_head *n;
7378 +                       
7379 +               yaffs_Object *l;
7380 +               // Soft delete all the unlinked files
7381 +               list_for_each_safe(i,n,&dev->unlinkedDir->variant.directoryVariant.children)
7382 +               {
7383 +                       if(i)
7384 +                       {
7385 +                               l = list_entry(i, yaffs_Object,siblings);
7386 +                               yaffs_DestroyObject(l);         
7387 +                       }
7388 +               }       
7389 +       }
7390 +       
7391 +       yaffs_ReleaseTempBuffer(dev,chunkData,__LINE__);
7392 +
7393 +       T(YAFFS_TRACE_SCAN,(TSTR("yaffs_Scan ends" TENDSTR)));
7394 +
7395 +       return YAFFS_OK;
7396 +}
7397 +
7398 +
7399 +static int yaffs_ScanBackwards(yaffs_Device *dev)
7400 +{
7401 +       yaffs_ExtendedTags tags;
7402 +       int blk;
7403 +       int blockIterator;
7404 +       int startIterator;
7405 +       int endIterator;
7406 +       int nBlocksToScan = 0;
7407 +       
7408 +       int chunk;
7409 +       int c;
7410 +       int deleted;
7411 +       yaffs_BlockState state;
7412 +       yaffs_Object *hardList = NULL;
7413 +       yaffs_Object *hl;
7414 +       yaffs_BlockInfo *bi;
7415 +       int sequenceNumber;     
7416 +       yaffs_ObjectHeader *oh;
7417 +       yaffs_Object *in;
7418 +       yaffs_Object *parent;
7419 +       int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
7420 +       
7421 +       __u8 *chunkData;
7422 +
7423 +       yaffs_BlockIndex *blockIndex = NULL;
7424 +
7425 +
7426 +       if(!dev->isYaffs2)
7427 +       {
7428 +               T(YAFFS_TRACE_SCAN,(TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR)));
7429 +               return YAFFS_FAIL;
7430 +       }
7431 +       
7432 +       T(YAFFS_TRACE_SCAN,(TSTR("yaffs_ScanBackwards starts  intstartblk %d intendblk %d..." TENDSTR),dev->internalStartBlock,dev->internalEndBlock));
7433 +               
7434 +       chunkData = yaffs_GetTempBuffer(dev,__LINE__);
7435 +       
7436 +       
7437 +       dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
7438 +       
7439 +       blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));               
7440 +       
7441 +       
7442 +       // Scan all the blocks to determine their state
7443 +       for(blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++)
7444 +       {
7445 +               bi = yaffs_GetBlockInfo(dev,blk);
7446 +               yaffs_ClearChunkBits(dev,blk);
7447 +               bi->pagesInUse = 0;
7448 +               bi->softDeletions = 0;
7449 +                               
7450 +               yaffs_QueryInitialBlockState(dev,blk,&state,&sequenceNumber);
7451 +               
7452 +               bi->blockState = state;
7453 +               bi->sequenceNumber = sequenceNumber;
7454 +
7455 +               T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block scanning block %d state %d seq %d" TENDSTR),blk,state,sequenceNumber));
7456 +               
7457 +               if(state == YAFFS_BLOCK_STATE_DEAD)
7458 +               {
7459 +                       T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("block %d is bad" TENDSTR),blk));
7460 +               }
7461 +               else if(state == YAFFS_BLOCK_STATE_EMPTY)
7462 +               {
7463 +                       T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block empty " TENDSTR)));
7464 +                       dev->nErasedBlocks++;
7465 +                       dev->nFreeChunks += dev->nChunksPerBlock;
7466 +               }
7467 +               else if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
7468 +               {
7469 +                                       
7470 +                       // Determine the highest sequence number
7471 +                       if( dev->isYaffs2 &&
7472 +                           sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
7473 +                           sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER)
7474 +                        {
7475 +                               
7476 +                               blockIndex[nBlocksToScan].seq = sequenceNumber;
7477 +                               blockIndex[nBlocksToScan].block = blk;
7478 +                               
7479 +                               nBlocksToScan++;
7480 +
7481 +                               if(sequenceNumber >= dev->sequenceNumber)
7482 +                               {
7483 +                                       dev->sequenceNumber = sequenceNumber;
7484 +                               }
7485 +                       }
7486 +                       else if(dev->isYaffs2)
7487 +                       {
7488 +                               // TODO: Nasty sequence number!
7489 +                               T(YAFFS_TRACE_SCAN,(TSTR("Block scanning block %d has bad sequence number %d" TENDSTR),blk,sequenceNumber));
7490 +
7491 +                       }
7492 +               }
7493 +       }
7494 +       
7495 +       // Sort the blocks
7496 +       // Dungy old bubble sort for now...
7497 +       {
7498 +               yaffs_BlockIndex temp;
7499 +               int i;
7500 +               int j;
7501 +               
7502 +               for(i = 0; i < nBlocksToScan; i++)
7503 +                       for(j = i+1; j < nBlocksToScan; j++)
7504 +                        if(blockIndex[i].seq > blockIndex[j].seq)
7505 +                        {
7506 +                               temp = blockIndex[j];
7507 +                               blockIndex[j] = blockIndex[i];
7508 +                               blockIndex[i] = temp;
7509 +                        }
7510 +       }
7511 +       
7512 +       
7513 +       // Now scan the blocks looking at the data.
7514 +       startIterator = 0;
7515 +       endIterator = nBlocksToScan-1;
7516 +       T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("%d blocks to be scanned" TENDSTR),nBlocksToScan));
7517 +
7518 +       
7519 +       // For each block.... backwards
7520 +       for(blockIterator = endIterator; blockIterator >= startIterator; blockIterator--)
7521 +       {
7522 +       
7523 +               // get the block to scan in the correct order
7524 +               blk = blockIndex[blockIterator].block;
7525 +
7526 +
7527 +               bi = yaffs_GetBlockInfo(dev,blk);
7528 +               state = bi->blockState;
7529 +               
7530 +               deleted = 0;
7531 +               
7532 +               if( 0 && // Disable since this is redundant.
7533 +                   state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
7534 +               {
7535 +                       // Let's look at the first chunk in the block
7536 +                       chunk = blk * dev->nChunksPerBlock;
7537 +                       
7538 +                       yaffs_ReadChunkWithTagsFromNAND(dev,chunk,NULL,&tags);
7539 +
7540 +                       // Let's have a good look at this chunk...
7541 +       
7542 +                       if(!tags.chunkUsed)
7543 +                       {
7544 +                               // An unassigned chunk in the block
7545 +                               // This means that either the block is empty or 
7546 +                               // this is the one being allocated from
7547 +                               
7548 +                               // We're looking at the first chunk in the block so the block is unused
7549 +                               state = YAFFS_BLOCK_STATE_EMPTY;
7550 +                               dev->nErasedBlocks++;
7551 +                               dev->nFreeChunks += dev->nChunksPerBlock;
7552 +                       }
7553 +               
7554 +               }
7555 +               
7556 +               // For each chunk in each block that needs scanning....
7557 +               for(c = dev->nChunksPerBlock-1; c >= 0 && 
7558 +                                 (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
7559 +                                  state == YAFFS_BLOCK_STATE_ALLOCATING); c--)
7560 +               {
7561 +                       // Scan backwards... 
7562 +                       // Read the tags and decide what to do
7563 +                       chunk = blk * dev->nChunksPerBlock + c;
7564 +                       
7565 +                       yaffs_ReadChunkWithTagsFromNAND(dev,chunk,NULL,&tags);
7566 +
7567 +                       // Let's have a good look at this chunk...
7568 +       
7569 +                       if(!tags.chunkUsed)
7570 +                       {
7571 +                               // An unassigned chunk in the block
7572 +                               // This means that either the block is empty or 
7573 +                               // this is the one being allocated from
7574 +                               
7575 +                               if(c == 0)
7576 +                               {
7577 +                                       // We're looking at the first chunk in the block so the block is unused
7578 +                                       state = YAFFS_BLOCK_STATE_EMPTY;
7579 +                                       dev->nErasedBlocks++;
7580 +                               }
7581 +                               else
7582 +                               {
7583 +                                       // this is the block being allocated from
7584 +                                       if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
7585 +                                       {
7586 +                                         T(YAFFS_TRACE_SCAN,(TSTR(" Allocating from %d %d" TENDSTR),blk,c));
7587 +                                       }
7588 +                                       state = YAFFS_BLOCK_STATE_ALLOCATING;
7589 +                                       dev->allocationBlock = blk;
7590 +                                       dev->allocationPage = c;
7591 +                                       dev->allocationBlockFinder = blk; // Set it to here to encourage the allocator to
7592 +                                                                                                         // go forth from here.
7593 +                                       //Yaffs2 sanity check:
7594 +                                       // This should be the one with the highest sequence number
7595 +                                       if(dev->isYaffs2 && (dev->sequenceNumber != bi->sequenceNumber))
7596 +                                       {
7597 +                                               T(YAFFS_TRACE_ALWAYS,
7598 +                                                               (TSTR("yaffs: Allocation block %d was not highest sequence id: block seq = %d, dev seq = %d" TENDSTR),
7599 +                                                               blk,bi->sequenceNumber,dev->sequenceNumber));
7600 +                                       }
7601 +                               }
7602 +
7603 +                               dev->nFreeChunks ++;
7604 +                       }
7605 +                       else if(tags.chunkId > 0)
7606 +                       {
7607 +                               // chunkId > 0 so it is a data chunk...
7608 +                               unsigned int endpos;
7609 +                               
7610 +                               __u32 chunkBase = (tags.chunkId - 1)* dev->nBytesPerChunk;
7611 +
7612 +                               yaffs_SetChunkBit(dev,blk,c);
7613 +                               bi->pagesInUse++;
7614 +                                                               
7615 +                               in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
7616 +                               if(in->variantType == YAFFS_OBJECT_TYPE_FILE &&
7617 +                                  chunkBase < in->variant.fileVariant.shrinkSize)
7618 +                               {
7619 +                                       // This has not been invalidated by a resize
7620 +                                       yaffs_PutChunkIntoFile(in,tags.chunkId,chunk,-1);
7621 +                               
7622 +                               
7623 +                                       // File size is calculated by looking at the data chunks if we have not 
7624 +                                       // seen an object header yet. Stop this practice once we find an object header.
7625 +                                       endpos = (tags.chunkId - 1)* dev->nBytesPerChunk + tags.byteCount;
7626 +                                       if(!in->valid && // have not got an object header yet
7627 +                                          in->variant.fileVariant.scannedFileSize <endpos)
7628 +                                       {
7629 +                                               in->variant.fileVariant.scannedFileSize = endpos;
7630 +                                               in->variant.fileVariant.fileSize = in->variant.fileVariant.scannedFileSize;
7631 +                                       }
7632 +
7633 +                               }
7634 +                               else
7635 +                               {
7636 +                                       // This chunk has been invalidated by a resize, so delete
7637 +                                       yaffs_DeleteChunk(dev,chunk,1,__LINE__);
7638 +                                       
7639 +                                       
7640 +                               }
7641 +                               //T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));  
7642 +                       }
7643 +                       else
7644 +                       {
7645 +                               // chunkId == 0, so it is an ObjectHeader.
7646 +                               // Thus, we read in the object header and make the object
7647 +                               yaffs_SetChunkBit(dev,blk,c);
7648 +                               bi->pagesInUse++;
7649 +                               
7650 +                               oh = NULL;
7651 +                               in = NULL;
7652 +                               
7653 +                               if(tags.extraHeaderInfoAvailable)
7654 +                               {
7655 +                                       in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,tags.extraObjectType);
7656 +                               }
7657 +
7658 +                               
7659 +                               if(!in || !in->valid)
7660 +                               {
7661 +                               
7662 +                                       // If we don't have  valid info then we need to read the chunk
7663 +                                       // TODO In future we can probably defer reading the chunk and 
7664 +                                       // living with invalid data until needed.
7665 +                                                               
7666 +                                       yaffs_ReadChunkWithTagsFromNAND(dev,chunk,chunkData,NULL);
7667 +                               
7668 +                                       oh = (yaffs_ObjectHeader *)chunkData;
7669 +                               
7670 +                                       if(!in)
7671 +                                          in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type);
7672 +                                       
7673 +                               }
7674 +                               
7675 +                               if(!in)
7676 +                               {
7677 +                                       // TODO Hoosterman we have a problem!
7678 +                                       T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: Could not make object for object  %d  at chunk %d during scan" TENDSTR),tags.objectId,chunk));
7679 +
7680 +                               }
7681 +                               
7682 +                               if(in->valid)
7683 +                               {
7684 +                                       // We have already filled this one. We have a duplicate that will be discarded, but 
7685 +                                       // we first have to suck out resize info if it is a file.
7686 +                                       
7687 +                                       if( (in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
7688 +                                           ((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) ||
7689 +                                           (tags.extraHeaderInfoAvailable && tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))
7690 +                                          )
7691 +                                       {
7692 +                                               __u32 thisSize = (oh) ? oh->fileSize : tags.extraFileLength;
7693 +                                               __u32 parentObjectId = (oh) ? oh->parentObjectId : tags.extraParentObjectId;
7694 +                                               unsigned isShrink = (oh)  ? oh->isShrink : tags.extraIsShrinkHeader;
7695 +                                               
7696 +                                               // If it is deleted (unlinked at start also means deleted)
7697 +                                               // we treat the file size as being zeroed at this point.
7698 +                                               if(parentObjectId == YAFFS_OBJECTID_DELETED ||
7699 +                                                  parentObjectId == YAFFS_OBJECTID_UNLINKED)
7700 +                                               {
7701 +                                                       thisSize = 0;
7702 +                                                       isShrink = 1;
7703 +                                               }
7704 +                                                                                               
7705 +                                               if(isShrink &&
7706 +                                                  in->variant.fileVariant.shrinkSize > thisSize)
7707 +                                               {
7708 +                                                       in->variant.fileVariant.shrinkSize = thisSize;
7709 +                                               }
7710 +                                               
7711 +                                               if(isShrink)
7712 +                                               {
7713 +                                                       bi->hasShrinkHeader = 1;
7714 +                                               }
7715 +                                               
7716 +                                       }
7717 +                                       // Use existing - destroy this one.
7718 +                                       yaffs_DeleteChunk(dev,chunk,1,__LINE__);
7719 +               
7720 +                               }
7721 +                               
7722 +                               if(!in->valid &&
7723 +                                  (tags.objectId == YAFFS_OBJECTID_ROOT ||
7724 +                                   tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))
7725 +                               {
7726 +                                       // We only load some info, don't fiddle with directory structure
7727 +                                       in->valid = 1;
7728 +                                       in->variantType = oh->type;
7729 +       
7730 +                                       in->yst_mode  = oh->yst_mode;
7731 +#ifdef CONFIG_YAFFS_WINCE
7732 +                                       in->win_atime[0] = oh->win_atime[0];
7733 +                                       in->win_ctime[0] = oh->win_ctime[0];
7734 +                                       in->win_mtime[0] = oh->win_mtime[0];
7735 +                                       in->win_atime[1] = oh->win_atime[1];
7736 +                                       in->win_ctime[1] = oh->win_ctime[1];
7737 +                                       in->win_mtime[1] = oh->win_mtime[1];
7738 +#else
7739 +                                       in->yst_uid   = oh->yst_uid;
7740 +                                       in->yst_gid   = oh->yst_gid;
7741 +                                       in->yst_atime = oh->yst_atime;
7742 +                                       in->yst_mtime = oh->yst_mtime;
7743 +                                       in->yst_ctime = oh->yst_ctime;
7744 +                                       in->yst_rdev = oh->yst_rdev;
7745 +#endif
7746 +                                       in->chunkId  = chunk;
7747 +
7748 +                               }
7749 +                               else if(!in->valid)
7750 +                               {
7751 +                                       // we need to load this info
7752 +                               
7753 +                                       in->valid = 1;
7754 +                                       in->variantType = oh->type;
7755 +       
7756 +                                       in->yst_mode  = oh->yst_mode;
7757 +#ifdef CONFIG_YAFFS_WINCE
7758 +                                       in->win_atime[0] = oh->win_atime[0];
7759 +                                       in->win_ctime[0] = oh->win_ctime[0];
7760 +                                       in->win_mtime[0] = oh->win_mtime[0];
7761 +                                       in->win_atime[1] = oh->win_atime[1];
7762 +                                       in->win_ctime[1] = oh->win_ctime[1];
7763 +                                       in->win_mtime[1] = oh->win_mtime[1];
7764 +#else
7765 +                                       in->yst_uid   = oh->yst_uid;
7766 +                                       in->yst_gid   = oh->yst_gid;
7767 +                                       in->yst_atime = oh->yst_atime;
7768 +                                       in->yst_mtime = oh->yst_mtime;
7769 +                                       in->yst_ctime = oh->yst_ctime;
7770 +                                       in->yst_rdev = oh->yst_rdev;
7771 +#endif
7772 +                                       in->chunkId  = chunk;
7773 +                                       
7774 +                                       if(oh->shadowsObject > 0)
7775 +                                       {
7776 +                                               yaffs_HandleShadowedObject(dev,oh->shadowsObject,0);
7777 +                                       }
7778 +
7779 +
7780 +                                       yaffs_SetObjectName(in,oh->name);
7781 +                                       in->dirty = 0;
7782 +                                                       
7783 +                                       // directory stuff...
7784 +                                       // hook up to parent
7785 +       
7786 +                                       parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY);
7787 +                                       if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN)
7788 +                                       {
7789 +                                               // Set up as a directory
7790 +                                               parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY;
7791 +                                               INIT_LIST_HEAD(&parent->variant.directoryVariant.children);
7792 +                                       }
7793 +                                       else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
7794 +                                       {
7795 +                                               // Hoosterman, another problem....
7796 +                                               // We're trying to use a non-directory as a directory
7797 +
7798 +                                               T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." TENDSTR)));
7799 +                                               parent = dev->lostNFoundDir;
7800 +                                       }
7801 +                               
7802 +                                       yaffs_AddObjectToDirectory(parent,in);
7803 +
7804 +                                       if((parent == dev->deletedDir ||
7805 +                                          parent == dev->unlinkedDir))
7806 +                                       {
7807 +                                               in->deleted = 1; // If it is unlinked at start up then it wants deleting
7808 +                                       }
7809 +                                       
7810 +                                       if( oh->isShrink)
7811 +                                       {
7812 +                                               // Mark the block as having a shrinkHeader
7813 +                                               bi->hasShrinkHeader = 1;
7814 +                                       }
7815 +                                       
7816 +                               
7817 +                                       // Note re hardlinks.
7818 +                                       // Since we might scan a hardlink before its equivalent object is scanned
7819 +                                       // we put them all in a list.
7820 +                                       // After scanning is complete, we should have all the objects, so we run through this
7821 +                                       // list and fix up all the chains.              
7822 +       
7823 +                                       switch(in->variantType)
7824 +                                       {
7825 +                                               case YAFFS_OBJECT_TYPE_UNKNOWN:         // Todo got a problem
7826 +                                                       break;
7827 +                                               case YAFFS_OBJECT_TYPE_FILE:
7828 +
7829 +                                                       
7830 +                                                       if(in->variant.fileVariant.scannedFileSize < oh->fileSize)
7831 +                                                       {
7832 +                                                               in->variant.fileVariant.fileSize = oh->fileSize;
7833 +                                                               in->variant.fileVariant.scannedFileSize = in->variant.fileVariant.fileSize;
7834 +                                                       }                                                                       
7835 +                                                       
7836 +                                                       if(oh->isShrink &&
7837 +                                                          in->variant.fileVariant.shrinkSize > oh->fileSize)
7838 +                                                       {
7839 +                                                               in->variant.fileVariant.shrinkSize = oh->fileSize;
7840 +                                                       }                                               
7841 +                                                               
7842 +                                                       break;
7843 +                                               case YAFFS_OBJECT_TYPE_HARDLINK:
7844 +                                                       in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId;
7845 +                                                       in->hardLinks.next = (struct list_head *)hardList;
7846 +                                                       hardList = in;
7847 +                                                       break;
7848 +                                               case YAFFS_OBJECT_TYPE_DIRECTORY:       // Do nothing
7849 +                                                       break;
7850 +                                               case YAFFS_OBJECT_TYPE_SPECIAL: // Do nothing
7851 +                                                       break;
7852 +                                               case YAFFS_OBJECT_TYPE_SYMLINK:         // Do nothing
7853 +                                                       in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias);
7854 +                                                       break;
7855 +                                       }
7856 +
7857 +#if 0
7858 +                                       if(parent == dev->deletedDir)
7859 +                                       {
7860 +                                               yaffs_DestroyObject(in);
7861 +                                               bi->hasShrinkHeader = 1;
7862 +                                       }
7863 +#endif
7864 +                                       //T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));        
7865 +                               }
7866 +                       }
7867 +               }
7868 +               
7869 +               if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
7870 +               {
7871 +                       // If we got this far while scanning, then the block is fully allocated.
7872 +                       state = YAFFS_BLOCK_STATE_FULL; 
7873 +               }
7874 +               
7875 +               bi->blockState = state;
7876 +               
7877 +               // Now let's see if it was dirty
7878 +               if(     bi->pagesInUse == 0 &&
7879 +                       !bi->hasShrinkHeader &&
7880 +               bi->blockState == YAFFS_BLOCK_STATE_FULL)
7881 +           {
7882 +               yaffs_BlockBecameDirty(dev,blk);
7883 +           }
7884 +
7885 +       }
7886 +       
7887 +       if(blockIndex)
7888 +       {
7889 +               YFREE(blockIndex);
7890 +       }
7891 +       
7892 +       // Ok, we've done all the scanning.
7893 +       
7894 +       // Fix up the hard link chains.
7895 +       // We should now have scanned all the objects, now it's time to add these 
7896 +       // hardlinks.
7897 +       while(hardList)
7898 +       {
7899 +               hl = hardList;
7900 +               hardList = (yaffs_Object *)(hardList->hardLinks.next);
7901 +               
7902 +               in = yaffs_FindObjectByNumber(dev,hl->variant.hardLinkVariant.equivalentObjectId);
7903 +               
7904 +               if(in)
7905 +               {
7906 +                       // Add the hardlink pointers
7907 +                       hl->variant.hardLinkVariant.equivalentObject=in;
7908 +                       list_add(&hl->hardLinks,&in->hardLinks);
7909 +               }
7910 +               else
7911 +               {
7912 +                       //Todo Need to report/handle this better.
7913 +                       // Got a problem... hardlink to a non-existant object
7914 +                       hl->variant.hardLinkVariant.equivalentObject=NULL;
7915 +                       INIT_LIST_HEAD(&hl->hardLinks);
7916 +                       
7917 +               }
7918 +               
7919 +       }
7920 +       
7921 +       {
7922 +               struct list_head *i;    
7923 +               struct list_head *n;
7924 +                       
7925 +               yaffs_Object *l;
7926 +               
7927 +               // Soft delete all the unlinked files
7928 +               list_for_each_safe(i,n,&dev->unlinkedDir->variant.directoryVariant.children)
7929 +               {
7930 +                       if(i)
7931 +                       {
7932 +                               l = list_entry(i, yaffs_Object,siblings);
7933 +                               yaffs_DestroyObject(l);         
7934 +                       }
7935 +               }       
7936 +               
7937 +               // Soft delete all the deletedDir files
7938 +               list_for_each_safe(i,n,&dev->deletedDir->variant.directoryVariant.children)
7939 +               {
7940 +                       if(i)
7941 +                       {
7942 +                               l = list_entry(i, yaffs_Object,siblings);
7943 +                               yaffs_DestroyObject(l);         
7944 +                               
7945 +                       }
7946 +               }       
7947 +       }
7948 +       
7949 +       yaffs_ReleaseTempBuffer(dev,chunkData,__LINE__);
7950 +
7951 +       T(YAFFS_TRACE_SCAN,(TSTR("yaffs_ScanBackwards ends" TENDSTR)));
7952 +
7953 +       return YAFFS_OK;
7954 +}
7955 +
7956 +
7957 +
7958 +////////////////////////// Directory Functions /////////////////////////
7959 +
7960 +
7961 +static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj)
7962 +{
7963 +
7964 +       if(!directory)
7965 +       {
7966 +               T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: Trying to add an object to a null pointer directory" TENDSTR)));
7967 +               YBUG();
7968 +       }
7969 +       if(directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
7970 +       {
7971 +               T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: Trying to add an object to a non-directory" TENDSTR)));
7972 +               YBUG();
7973 +       }
7974 +
7975 +               if(obj->siblings.prev == NULL)
7976 +       {
7977 +               // Not initialised
7978 +               INIT_LIST_HEAD(&obj->siblings);
7979 +               
7980 +       }
7981 +       else if(!list_empty(&obj->siblings))
7982 +       {
7983 +               // If it is holed up somewhere else, un hook it
7984 +               list_del_init(&obj->siblings);
7985 +       }
7986 +       // Now add it
7987 +       list_add(&obj->siblings,&directory->variant.directoryVariant.children);
7988 +       obj->parent = directory;
7989 +       
7990 +       if(directory == obj->myDev->unlinkedDir || directory == obj->myDev->deletedDir)
7991 +       {
7992 +               obj->unlinked = 1;
7993 +               obj->myDev->nUnlinkedFiles++;
7994 +               obj->renameAllowed = 0;
7995 +       }
7996 +}
7997 +
7998 +static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
7999 +{
8000 +       list_del_init(&obj->siblings);
8001 +       obj->parent = NULL;
8002 +}
8003 +
8004 +yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,const YCHAR *name)
8005 +{
8006 +       int sum;
8007 +       
8008 +       struct list_head *i;
8009 +       YCHAR buffer[YAFFS_MAX_NAME_LENGTH+1];
8010 +       
8011 +       yaffs_Object *l;
8012 +       
8013 +       if(!name)
8014 +       {
8015 +               return NULL;
8016 +       }
8017 +
8018 +       if(!directory)
8019 +       {
8020 +               T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: yaffs_FindObjectByName: null pointer directory"TENDSTR)));
8021 +               YBUG();
8022 +       }
8023 +       if(directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
8024 +       {
8025 +               T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: yaffs_FindObjectByName: non-directory"TENDSTR)));
8026 +               YBUG();
8027 +       }
8028 +
8029 +       sum = yaffs_CalcNameSum(name);
8030 +       
8031 +       list_for_each(i,&directory->variant.directoryVariant.children)
8032 +       {
8033 +               if(i)
8034 +               {
8035 +                       l = list_entry(i, yaffs_Object,siblings);
8036 +               
8037 +                       // Special case for lost-n-found
8038 +                       if(l->objectId == YAFFS_OBJECTID_LOSTNFOUND)
8039 +                       {
8040 +                               if(yaffs_strcmp(name,YAFFS_LOSTNFOUND_NAME) == 0)
8041 +                               {
8042 +                                       return l;
8043 +                               }
8044 +                       }
8045 +                       else if(yaffs_SumCompare(l->sum, sum)||
8046 +                                   l->chunkId <= 0) //LostnFound cunk called Objxxx
8047 +                       {
8048 +                               // Do a real check
8049 +                               yaffs_GetObjectName(l,buffer,YAFFS_MAX_NAME_LENGTH);
8050 +                               if(yaffs_strcmp(name,buffer) == 0)
8051 +                               {
8052 +                                       return l;
8053 +                               }
8054 +                       
8055 +                       }                       
8056 +               }
8057 +       }
8058 +       
8059 +       return NULL;
8060 +}
8061 +
8062 +
8063 +int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,int (*fn)(yaffs_Object *))
8064 +{
8065 +       struct list_head *i;    
8066 +       yaffs_Object *l;
8067 +       
8068 +
8069 +       if(!theDir)
8070 +       {
8071 +               T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: yaffs_FindObjectByName: null pointer directory"TENDSTR)));
8072 +               YBUG();
8073 +       }
8074 +       if(theDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
8075 +       {
8076 +               T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: yaffs_FindObjectByName: non-directory"TENDSTR)));
8077 +               YBUG();
8078 +       }
8079 +       
8080 +       list_for_each(i,&theDir->variant.directoryVariant.children)
8081 +       {
8082 +               if(i)
8083 +               {
8084 +                       l = list_entry(i, yaffs_Object,siblings);
8085 +                       if(l && !fn(l))
8086 +                       {
8087 +                               return YAFFS_FAIL;
8088 +                       }
8089 +               }
8090 +       }
8091 +       
8092 +       return YAFFS_OK;
8093 +
8094 +}
8095 +
8096 +
8097 +// GetEquivalentObject dereferences any hard links to get to the
8098 +// actual object.
8099 +
8100 +yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj)
8101 +{
8102 +       if(obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
8103 +       {
8104 +               // We want the object id of the equivalent object, not this one
8105 +               obj = obj->variant.hardLinkVariant.equivalentObject;
8106 +       }
8107 +       return obj;
8108 +
8109 +}
8110 +
8111 +int yaffs_GetObjectName(yaffs_Object *obj,YCHAR *name,int buffSize)
8112 +{
8113 +       memset(name,0,buffSize * sizeof(YCHAR));
8114 +       
8115 +       if(obj->objectId == YAFFS_OBJECTID_LOSTNFOUND)
8116 +       {
8117 +               yaffs_strncpy(name,YAFFS_LOSTNFOUND_NAME,buffSize - 1);
8118 +       }
8119 +       else if(obj->chunkId <= 0)
8120 +       {
8121 +               YCHAR locName[20];
8122 +               // make up a name
8123 +               yaffs_sprintf(locName,_Y("%s%d"),YAFFS_LOSTNFOUND_PREFIX,obj->objectId);
8124 +               yaffs_strncpy(name,locName,buffSize - 1);
8125 +
8126 +       }
8127 +#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
8128 +       else if(obj->shortName[0])
8129 +       {
8130 +               yaffs_strcpy(name,obj->shortName);
8131 +       }
8132 +#endif
8133 +       else
8134 +       {
8135 +               __u8 *buffer = yaffs_GetTempBuffer(obj->myDev,__LINE__);
8136 +               
8137 +               yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
8138 +
8139 +               memset(buffer,0,obj->myDev->nBytesPerChunk);
8140 +       
8141 +               if(obj->chunkId >= 0)
8142 +               {
8143 +                       yaffs_ReadChunkWithTagsFromNAND(obj->myDev,obj->chunkId,buffer,NULL);
8144 +               }
8145 +               yaffs_strncpy(name,oh->name,buffSize - 1);
8146 +
8147 +               yaffs_ReleaseTempBuffer(obj->myDev,buffer,__LINE__);
8148 +       }
8149 +       
8150 +       return yaffs_strlen(name);
8151 +}
8152 +
8153 +int yaffs_GetObjectFileLength(yaffs_Object *obj)
8154 +{
8155 +       
8156 +       // Dereference any hard linking
8157 +       obj = yaffs_GetEquivalentObject(obj);
8158 +       
8159 +       if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
8160 +       {
8161 +               return obj->variant.fileVariant.fileSize;
8162 +       }
8163 +       if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
8164 +       {
8165 +               return yaffs_strlen(obj->variant.symLinkVariant.alias);
8166 +       }
8167 +       else
8168 +       {
8169 +               // Only a directory should drop through to here
8170 +               return obj->myDev->nBytesPerChunk;
8171 +       }       
8172 +}
8173 +
8174 +int yaffs_GetObjectLinkCount(yaffs_Object *obj)
8175 +{
8176 +       int count = 0; 
8177 +       struct list_head *i;
8178 +       
8179 +       if(!obj->unlinked)
8180 +       {
8181 +               count++;        // the object itself
8182 +       }
8183 +       list_for_each(i,&obj->hardLinks)
8184 +       {
8185 +               count++;        // add the hard links;
8186 +       }
8187 +       return count;
8188 +       
8189 +}
8190 +
8191 +
8192 +int yaffs_GetObjectInode(yaffs_Object *obj)
8193 +{
8194 +       obj = yaffs_GetEquivalentObject(obj);
8195 +       
8196 +       return obj->objectId;
8197 +}
8198 +
8199 +unsigned yaffs_GetObjectType(yaffs_Object *obj)
8200 +{
8201 +       obj = yaffs_GetEquivalentObject(obj);
8202 +       
8203 +       switch(obj->variantType)
8204 +       {
8205 +               case YAFFS_OBJECT_TYPE_FILE:            return DT_REG; break;
8206 +               case YAFFS_OBJECT_TYPE_DIRECTORY:       return DT_DIR; break;
8207 +               case YAFFS_OBJECT_TYPE_SYMLINK:         return DT_LNK; break;
8208 +               case YAFFS_OBJECT_TYPE_HARDLINK:        return DT_REG; break;
8209 +               case YAFFS_OBJECT_TYPE_SPECIAL:         
8210 +                       if(S_ISFIFO(obj->yst_mode)) return DT_FIFO;
8211 +                       if(S_ISCHR(obj->yst_mode)) return DT_CHR;
8212 +                       if(S_ISBLK(obj->yst_mode)) return DT_BLK;
8213 +                       if(S_ISSOCK(obj->yst_mode)) return DT_SOCK;
8214 +               default: return DT_REG; break;
8215 +       }
8216 +}
8217 +
8218 +YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj)
8219 +{
8220 +       obj = yaffs_GetEquivalentObject(obj);
8221 +       if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
8222 +       {
8223 +               return yaffs_CloneString(obj->variant.symLinkVariant.alias);
8224 +       }
8225 +       else
8226 +       {
8227 +               return yaffs_CloneString(_Y(""));
8228 +       }
8229 +}
8230 +
8231 +#ifndef CONFIG_YAFFS_WINCE
8232 +
8233 +int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
8234 +{
8235 +       unsigned int valid = attr->ia_valid;
8236 +       
8237 +       if(valid & ATTR_MODE) obj->yst_mode = attr->ia_mode;
8238 +       if(valid & ATTR_UID) obj->yst_uid = attr->ia_uid;
8239 +       if(valid & ATTR_GID) obj->yst_gid = attr->ia_gid;
8240 +       
8241 +       if(valid & ATTR_ATIME) obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
8242 +       if(valid & ATTR_CTIME) obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
8243 +       if(valid & ATTR_MTIME) obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
8244 +       
8245 +       if(valid & ATTR_SIZE) yaffs_ResizeFile(obj,attr->ia_size);
8246 +       
8247 +       yaffs_UpdateObjectHeader(obj,NULL,1,0,0);
8248 +       
8249 +       return YAFFS_OK;
8250 +       
8251 +}
8252 +int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)
8253 +{
8254 +       unsigned int valid = 0;
8255 +       
8256 +       attr->ia_mode = obj->yst_mode;  valid |= ATTR_MODE;
8257 +       attr->ia_uid = obj->yst_uid;            valid |= ATTR_UID;
8258 +       attr->ia_gid = obj->yst_gid;            valid |= ATTR_GID;
8259 +       
8260 +       Y_TIME_CONVERT(attr->ia_atime)= obj->yst_atime; valid |= ATTR_ATIME;
8261 +       Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;        valid |= ATTR_CTIME;
8262 +       Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;        valid |= ATTR_MTIME;
8263 +
8264 +       attr->ia_size = yaffs_GetFileSize(obj); valid |= ATTR_SIZE;
8265 +       
8266 +       attr->ia_valid = valid;
8267 +       
8268 +       return YAFFS_OK;
8269 +       
8270 +}
8271 +
8272 +#endif
8273 +
8274 +int yaffs_DumpObject(yaffs_Object *obj)
8275 +{
8276 +//     __u8 buffer[YAFFS_BYTES_PER_CHUNK];
8277 +       YCHAR name[257];
8278 +//     yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
8279 +
8280 +//     memset(buffer,0,YAFFS_BYTES_PER_CHUNK);
8281 +       
8282 +//     if(obj->chunkId >= 0)
8283 +//     {
8284 +//             yaffs_ReadChunkFromNAND(obj->myDev,obj->chunkId,buffer,NULL);
8285 +//     }
8286 +       
8287 +       yaffs_GetObjectName(obj,name,256);
8288 +       
8289 +       T(YAFFS_TRACE_ALWAYS,(TSTR("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d type %d size %d\n" TENDSTR),
8290 +                       obj->objectId,yaffs_GetObjectInode(obj), name, obj->dirty, obj->valid, obj->serial, 
8291 +                       obj->sum, obj->chunkId, yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
8292 +
8293 +#if 0
8294 +       YPRINTF(("Object %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d\n",
8295 +                       obj->objectId, oh->name, obj->dirty, obj->valid, obj->serial, 
8296 +                       obj->sum, obj->chunkId));
8297 +               switch(obj->variantType)
8298 +       {
8299 +               case YAFFS_OBJECT_TYPE_FILE: 
8300 +                       YPRINTF((" FILE length %d\n",obj->variant.fileVariant.fileSize));
8301 +                       break;
8302 +               case YAFFS_OBJECT_TYPE_DIRECTORY:
8303 +                       YPRINTF((" DIRECTORY\n"));
8304 +                       break;
8305 +               case YAFFS_OBJECT_TYPE_HARDLINK: //todo
8306 +               case YAFFS_OBJECT_TYPE_SYMLINK:
8307 +               case YAFFS_OBJECT_TYPE_UNKNOWN:
8308 +               default:
8309 +       }
8310 +#endif
8311 +       
8312 +       return YAFFS_OK;
8313 +}
8314 +
8315 +
8316 +///////////////////////// Initialisation code ///////////////////////////
8317 +
8318 +
8319 +static int yaffs_CheckDevFunctions(const yaffs_Device *dev)
8320 +{
8321 +
8322 +       // Common functions, gotta have
8323 +       if(!dev->eraseBlockInNAND ||
8324 +          !dev->initialiseNAND) return 0;
8325 +
8326 +#ifdef CONFIG_YAFFS_YAFFS2
8327 +
8328 +       // Can use the "with tags" style interface for yaffs1 or yaffs2
8329 +       if(dev->writeChunkWithTagsToNAND &&
8330 +          dev->readChunkWithTagsFromNAND &&
8331 +          !dev->writeChunkToNAND &&
8332 +          !dev->readChunkFromNAND &&
8333 +          dev->markNANDBlockBad &&
8334 +          dev->queryNANDBlock) return 1;
8335 +#endif
8336 +
8337 +       // Can use the "spare" style interface for yaffs1
8338 +       if(!dev->isYaffs2 &&
8339 +          !dev->writeChunkWithTagsToNAND &&
8340 +          !dev->readChunkWithTagsFromNAND &&
8341 +          dev->writeChunkToNAND &&
8342 +          dev->readChunkFromNAND &&
8343 +          !dev->markNANDBlockBad &&
8344 +          !dev->queryNANDBlock) return 1;
8345 +
8346 +       return 0; // bad
8347 +}
8348 +
8349 +
8350 +int yaffs_GutsInitialise(yaffs_Device *dev)
8351 +{
8352 +       unsigned x;
8353 +       int bits;
8354 +       int extraBits;
8355 +       int nBlocks;
8356 +
8357 +       T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR)));
8358 +       // Check stuff that must be set
8359 +
8360 +       if(!dev)
8361 +       {
8362 +               T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Need a device" TENDSTR)));
8363 +               return YAFFS_FAIL;
8364 +       }
8365 +       
8366 +       dev->internalStartBlock = dev->startBlock;
8367 +       dev->internalEndBlock =  dev->endBlock;
8368 +       dev->blockOffset = 0;
8369 +       dev->chunkOffset = 0;
8370 +       dev->nFreeChunks = 0;
8371 +       
8372 +       if(dev->startBlock == 0)
8373 +       {
8374 +               dev->internalStartBlock = dev->startBlock + 1;
8375 +               dev->internalEndBlock =  dev->endBlock + 1;
8376 +               dev->blockOffset = 1;
8377 +               dev->chunkOffset = dev->nChunksPerBlock;
8378 +       }
8379 +
8380 +       // Check geometry parameters.
8381 +
8382 +       if(     (dev->isYaffs2 && dev->nBytesPerChunk <1024)  ||
8383 +               (!dev->isYaffs2 && dev->nBytesPerChunk !=512)  ||
8384 +               dev->nChunksPerBlock < 2 ||
8385 +               dev->nReservedBlocks < 2 ||
8386 +               dev->internalStartBlock <= 0 ||
8387 +               dev->internalEndBlock <= 0 ||
8388 +               dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2) // otherwise it is too small
8389 +         )
8390 +       {
8391 +               T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s " TENDSTR),
8392 +                  dev->nBytesPerChunk, dev->isYaffs2 ? "2" : ""));
8393 +               return YAFFS_FAIL;
8394 +       }
8395 +
8396 +       if(yaffs_InitialiseNAND(dev) != YAFFS_OK)
8397 +       {
8398 +               T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: InitialiseNAND failed" TENDSTR)));
8399 +               return YAFFS_FAIL;
8400 +       }
8401 +
8402 +       // Got the right mix of functions?
8403 +       //
8404 +       if(!yaffs_CheckDevFunctions(dev))
8405 +       {
8406 +               //Function missing
8407 +               T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: device function(s) missing or wrong\n" TENDSTR)));
8408 +
8409 +               return YAFFS_FAIL;
8410 +       }
8411 +
8412 +       // This is really a compilation check.
8413 +       if(!yaffs_CheckStructures())
8414 +       {
8415 +               T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs_CheckStructures failed\n" TENDSTR)));
8416 +               return YAFFS_FAIL;
8417 +       }
8418 +
8419 +       if(dev->isMounted)
8420 +       {
8421 +               T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: device already mounted\n" TENDSTR)));
8422 +               return YAFFS_FAIL;
8423 +       }
8424 +
8425 +       //
8426 +       //
8427 +       // Finished with most checks. One or two more checks happen later on too.
8428 +       //
8429 +
8430 +       dev->isMounted = 1;
8431 +
8432 +
8433 +       nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
8434 +
8435 +
8436 +
8437 +       // OK now calculate a few things for the device
8438 +       // Calculate chunkGroupBits.
8439 +       // We need to find the next power of 2 > than internalEndBlock
8440 +       
8441 +       x = dev->nChunksPerBlock * (dev->internalEndBlock+1);
8442 +       
8443 +       for(bits = extraBits = 0; x > 1; bits++)
8444 +       {
8445 +               if(x & 1) extraBits++;
8446 +               x >>= 1;
8447 +       }
8448 +
8449 +       if(extraBits > 0) bits++;
8450 +       
8451 +       
8452 +       // Level0 Tnodes are 16 bits, so if the bitwidth of the
8453 +       // chunk range we're using is greater than 16 we need
8454 +       // to figure out chunk shift and chunkGroupSize
8455 +       if(bits <= 16) 
8456 +       {
8457 +               dev->chunkGroupBits = 0;
8458 +       }
8459 +       else
8460 +       {
8461 +               dev->chunkGroupBits = bits - 16;
8462 +       }
8463 +       
8464 +       dev->chunkGroupSize = 1 << dev->chunkGroupBits;
8465 +
8466 +       if(dev->nChunksPerBlock < dev->chunkGroupSize)
8467 +       {
8468 +               // We have a problem because the soft delete won't work if
8469 +               // the chunk group size > chunks per block.
8470 +               // This can be remedied by using larger "virtual blocks".
8471 +               T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: chunk group too large\n" TENDSTR)));
8472 +               
8473 +               return YAFFS_FAIL;
8474 +       }
8475 +
8476 +       
8477 +       // OK, we've finished verifying the device, lets continue with initialisation
8478 +       
8479 +       // More device initialisation
8480 +       dev->garbageCollections = 0;
8481 +       dev->passiveGarbageCollections = 0;
8482 +       dev->currentDirtyChecker = 0;
8483 +       dev->bufferedBlock = -1;
8484 +       dev->doingBufferedBlockRewrite = 0;
8485 +       dev->nDeletedFiles = 0;
8486 +       dev->nBackgroundDeletions=0;
8487 +       dev->nUnlinkedFiles = 0;
8488 +       dev->eccFixed=0;
8489 +       dev->eccUnfixed=0;
8490 +       dev->tagsEccFixed=0;
8491 +       dev->tagsEccUnfixed=0;
8492 +       dev->nErasureFailures = 0;
8493 +       dev->nErasedBlocks = 0;
8494 +       dev->isDoingGC = 0;
8495 +       
8496 +       //dev->localBuffer = YMALLOC(dev->nBytesPerChunk);
8497 +       // Initialise temporary buffers
8498 +       {
8499 +               int i;
8500 +               for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
8501 +               {
8502 +                       dev->tempBuffer[i].line = 0; // not in use
8503 +                       dev->tempBuffer[i].buffer = YMALLOC(dev->nBytesPerChunk);
8504 +               }
8505 +       }
8506 +       
8507 +
8508 +       
8509 +       yaffs_InitialiseBlocks(dev,nBlocks);
8510 +       
8511 +       yaffs_InitialiseTnodes(dev);
8512 +
8513 +       yaffs_InitialiseObjects(dev);
8514 +       
8515 +       dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32));
8516 +       
8517 +       if(dev->nShortOpCaches > 0)
8518 +       { 
8519 +               int i;
8520 +               
8521 +               if(dev->nShortOpCaches >  YAFFS_MAX_SHORT_OP_CACHES)
8522 +               {
8523 +                       dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
8524 +               }
8525 +               
8526 +               dev->srCache = YMALLOC( dev->nShortOpCaches * sizeof(yaffs_ChunkCache));
8527 +               
8528 +               for(i=0; i < dev->nShortOpCaches; i++)
8529 +               {
8530 +                       dev->srCache[i].object = NULL;
8531 +                       dev->srCache[i].lastUse = 0;
8532 +                       dev->srCache[i].dirty = 0;
8533 +                       dev->srCache[i].data = YMALLOC(dev->nBytesPerChunk);
8534 +               }
8535 +               dev->srLastUse = 0;
8536 +       }
8537 +
8538 +       dev->cacheHits = 0;
8539 +       
8540 +       
8541 +       // Initialise the unlinked, root and lost and found directories
8542 +       dev->lostNFoundDir = dev->rootDir = dev->unlinkedDir = dev->deletedDir = NULL;
8543 +       
8544 +       dev->unlinkedDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_UNLINKED, S_IFDIR);
8545 +       dev->deletedDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_DELETED, S_IFDIR);
8546 +
8547 +       dev->rootDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_ROOT,YAFFS_ROOT_MODE | S_IFDIR);
8548 +       dev->lostNFoundDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_LOSTNFOUND,YAFFS_LOSTNFOUND_MODE | S_IFDIR);
8549 +       yaffs_AddObjectToDirectory(dev->rootDir,dev->lostNFoundDir);
8550 +       
8551 +       if(dev->isYaffs2) 
8552 +       {
8553 +               dev->useHeaderFileSize = 1;
8554 +       }
8555 +               
8556 +       // Now scan the flash.  
8557 +       
8558 +       if(dev->isYaffs2)
8559 +               yaffs_ScanBackwards(dev);
8560 +       else
8561 +               yaffs_Scan(dev);
8562 +       
8563 +       // Zero out stats
8564 +       dev->nPageReads = 0;
8565 +       dev->nPageWrites =  0;
8566 +       dev->nBlockErasures = 0;
8567 +       dev->nGCCopies = 0;
8568 +       dev->nRetriedWrites = 0;
8569 +
8570 +       dev->nRetiredBlocks = 0;
8571 +       
8572 +       yaffs_VerifyFreeChunks(dev);
8573 +
8574 +       T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
8575 +       return YAFFS_OK;
8576 +               
8577 +}
8578 +
8579 +void yaffs_Deinitialise(yaffs_Device *dev)
8580 +{
8581 +       if(dev->isMounted)
8582 +       {
8583 +               int i;
8584 +       
8585 +               yaffs_DeinitialiseBlocks(dev);
8586 +               yaffs_DeinitialiseTnodes(dev);
8587 +               yaffs_DeinitialiseObjects(dev);
8588 +               if(dev->nShortOpCaches > 0)
8589 +               {
8590 +                               
8591 +                       for(i=0; i < dev->nShortOpCaches; i++)
8592 +                       {
8593 +                               YFREE(dev->srCache[i].data);
8594 +                       }
8595 +
8596 +                       YFREE(dev->srCache);
8597 +               }
8598 +
8599 +               YFREE(dev->gcCleanupList);
8600 +
8601 +               for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
8602 +               {
8603 +                       YFREE(dev->tempBuffer[i].buffer);
8604 +               }
8605 +               
8606 +               dev->isMounted = 0;
8607 +       }
8608 +       
8609 +}
8610 +
8611 +#if 0
8612 +
8613 +int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
8614 +{
8615 +       int nFree = dev->nFreeChunks - (dev->nChunksPerBlock * YAFFS_RESERVED_BLOCKS);
8616 +       
8617 +       struct list_head *i;    
8618 +       yaffs_Object *l;
8619 +       
8620 +       
8621 +       // To the free chunks add the chunks that are in the deleted unlinked files.
8622 +       list_for_each(i,&dev->deletedDir->variant.directoryVariant.children)
8623 +       {
8624 +               l = list_entry(i, yaffs_Object,siblings);
8625 +               if(l->deleted)
8626 +               {
8627 +                       nFree++;
8628 +                       nFree += l->nDataChunks;
8629 +               }
8630 +       }
8631 +       
8632 +       
8633 +       // printf("___________ nFreeChunks is %d nFree is %d\n",dev->nFreeChunks,nFree);        
8634 +
8635 +       if(nFree < 0) nFree = 0;
8636 +
8637 +       return nFree;   
8638 +       
8639 +}
8640 +
8641 +#endif
8642 +
8643 +static int  yaffs_CountFreeChunks(yaffs_Device *dev)
8644 +{
8645 +       int nFree;
8646 +       int b;
8647 +
8648 +       yaffs_BlockInfo *blk;   
8649 +
8650 +       
8651 +       for(nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock; b++)
8652 +       {
8653 +               blk = yaffs_GetBlockInfo(dev,b);
8654 +               
8655 +               switch(blk->blockState)
8656 +               {
8657 +                       case YAFFS_BLOCK_STATE_EMPTY:
8658 +                       case YAFFS_BLOCK_STATE_ALLOCATING: 
8659 +                       case YAFFS_BLOCK_STATE_COLLECTING:
8660 +                       case YAFFS_BLOCK_STATE_FULL: nFree += (dev->nChunksPerBlock - blk->pagesInUse + blk->softDeletions); break;
8661 +                       default: break;
8662 +               }
8663 +
8664 +       }
8665 +       
8666 +       return nFree;
8667 +}      
8668 +       
8669 +
8670 +
8671 +int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
8672 +{
8673 +       // This is what we report to the outside world
8674 +
8675 +       int nFree;
8676 +       int nDirtyCacheChunks;
8677 +               
8678 +#if 1  
8679 +       nFree = dev->nFreeChunks;
8680 +#else
8681 +       nFree = yaffs_CountFreeChunks(dev);
8682 +#endif
8683 +       
8684 +       // Now count the number of dirty chunks in the cache and subtract those
8685 +       
8686 +       {
8687 +               int i;
8688 +               for( nDirtyCacheChunks = 0,i = 0; i < dev->nShortOpCaches; i++)
8689 +               {
8690 +                       if(dev->srCache[i].dirty) nDirtyCacheChunks++;
8691 +               }
8692 +       }
8693 +       
8694 +       nFree -= nDirtyCacheChunks;
8695 +       
8696 +       nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock);
8697 +       
8698 +       if(nFree < 0) nFree = 0;
8699 +
8700 +       return nFree;   
8701 +       
8702 +}
8703 +
8704 +static int  yaffs_freeVerificationFailures;
8705 +
8706 +static void yaffs_VerifyFreeChunks(yaffs_Device *dev)
8707 +{
8708 +       int counted = yaffs_CountFreeChunks(dev);
8709 +       
8710 +       int difference = dev->nFreeChunks - counted;
8711 +       
8712 +       if(difference)
8713 +       {
8714 +               T(YAFFS_TRACE_ALWAYS,(TSTR("Freechunks verification failure %d %d %d" TENDSTR),dev->nFreeChunks,counted,difference)); 
8715 +               yaffs_freeVerificationFailures++;       
8716 +       }
8717 +}
8718 +
8719 +/////////////////// YAFFS test code //////////////////////////////////
8720 +
8721 +#define yaffs_CheckStruct(structure,syze, name) \
8722 +           if(sizeof(structure) != syze) \
8723 +              { \
8724 +                T(YAFFS_TRACE_ALWAYS,(TSTR("%s should be %d but is %d\n" TENDSTR),name,syze,sizeof(structure))); \
8725 +                return YAFFS_FAIL; \
8726 +                  }
8727 +                
8728 +                
8729 +static int yaffs_CheckStructures(void)
8730 +{
8731 +//     yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags")
8732 +//     yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion")
8733 +//     yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare")
8734 +#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
8735 +       yaffs_CheckStruct(yaffs_Tnode,2* YAFFS_NTNODES_LEVEL0,"yaffs_Tnode")
8736 +#endif
8737 +       yaffs_CheckStruct(yaffs_ObjectHeader,512,"yaffs_ObjectHeader")
8738 +       
8739 +       
8740 +       return YAFFS_OK;
8741 +}
8742 +
8743 +#if 0
8744 +void yaffs_GutsTest(yaffs_Device *dev)
8745 +{
8746 +       
8747 +       if(yaffs_CheckStructures() != YAFFS_OK)
8748 +       {
8749 +               T(YAFFS_TRACE_ALWAYS,(TSTR("One or more structures malformed-- aborting\n" TENDSTR)));
8750 +               return;
8751 +       }
8752 +       
8753 +       yaffs_TnodeTest(dev);
8754 +       yaffs_ObjectTest(dev);  
8755 +}
8756 +#endif
8757 +
8758 +
8759 diff --git a/fs/yaffs/yaffs_guts.h b/fs/yaffs/yaffs_guts.h
8760 new file mode 100644
8761 index 0000000..58c52e0
8762 --- /dev/null
8763 +++ b/fs/yaffs/yaffs_guts.h
8764 @@ -0,0 +1,759 @@
8765 +/*
8766 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
8767 + * yaffs_guts.h: Configuration etc for yaffs_guts
8768 + *
8769 + * Copyright (C) 2002 Aleph One Ltd.
8770 + *   for Toby Churchill Ltd and Brightstar Engineering
8771 + *
8772 + * Created by Charles Manning <charles@aleph1.co.uk>
8773 + *
8774 + * This program is free software; you can redistribute it and/or modify
8775 + * it under the terms of the GNU Lesser General Public License version 2.1 as
8776 + * published by the Free Software Foundation.
8777 + *
8778 + *
8779 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
8780 + *
8781 + * $Id: yaffs_guts.h,v 1.11 2005/07/31 06:52:40 charles Exp $
8782 + */
8783 +
8784 +#ifndef __YAFFS_GUTS_H__
8785 +#define __YAFFS_GUTS_H__
8786 +
8787 +#include "devextras.h"
8788 +#include "yportenv.h"
8789 +
8790 +#define YAFFS_OK       1
8791 +#define YAFFS_FAIL  0
8792 +
8793 +// Give us a Y=0x59, 
8794 +// Give us an A=0x41, 
8795 +// Give us an FF=0xFF 
8796 +// Give us an S=0x53
8797 +// And what have we got... 
8798 +#define YAFFS_MAGIC                                    0x5941FF53
8799 +
8800 +#define YAFFS_NTNODES_LEVEL0           16
8801 +#define YAFFS_TNODES_LEVEL0_BITS       4
8802 +#define YAFFS_TNODES_LEVEL0_MASK       0xf
8803 +
8804 +#define YAFFS_NTNODES_INTERNAL                 (YAFFS_NTNODES_LEVEL0 / 2)
8805 +#define YAFFS_TNODES_INTERNAL_BITS     (YAFFS_TNODES_LEVEL0_BITS - 1)
8806 +#define YAFFS_TNODES_INTERNAL_MASK     0x7
8807 +#define YAFFS_TNODES_MAX_LEVEL         6
8808 +
8809 +#ifndef CONFIG_YAFFS_NO_YAFFS1
8810 +#define YAFFS_BYTES_PER_SPARE          16
8811 +#define YAFFS_BYTES_PER_CHUNK          512
8812 +#define YAFFS_CHUNK_SIZE_SHIFT         9
8813 +#define YAFFS_CHUNKS_PER_BLOCK         32
8814 +#define YAFFS_BYTES_PER_BLOCK          (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
8815 +#endif
8816 +
8817 +#define YAFFS_MIN_YAFFS2_CHUNK_SIZE    1024
8818 +#define YAFFS_MIN_YAFFS2_SPARE_SIZE    32
8819 +
8820 +#define YAFFS_MAX_CHUNK_ID                     0x000FFFFF
8821 +
8822 +#define YAFFS_UNUSED_OBJECT_ID         0x0003FFFF
8823 +
8824 +#define YAFFS_ALLOCATION_NOBJECTS      100
8825 +#define YAFFS_ALLOCATION_NTNODES       100
8826 +#define YAFFS_ALLOCATION_NLINKS                100
8827 +
8828 +#define YAFFS_NOBJECT_BUCKETS          256
8829 +
8830 +
8831 +#define YAFFS_OBJECT_SPACE                     0x40000
8832 +
8833 +#ifdef CONFIG_YAFFS_UNICODE
8834 +#define YAFFS_MAX_NAME_LENGTH          127
8835 +#define YAFFS_MAX_ALIAS_LENGTH         79
8836 +#else
8837 +#define YAFFS_MAX_NAME_LENGTH          255
8838 +#define YAFFS_MAX_ALIAS_LENGTH         159
8839 +#endif
8840 +
8841 +#define YAFFS_SHORT_NAME_LENGTH                15
8842 +
8843 +
8844 +#define YAFFS_OBJECTID_ROOT                    1
8845 +#define YAFFS_OBJECTID_LOSTNFOUND      2
8846 +#define YAFFS_OBJECTID_UNLINKED                3
8847 +#define YAFFS_OBJECTID_DELETED         4
8848 +
8849 +#define YAFFS_MAX_SHORT_OP_CACHES      20
8850 +
8851 +#define YAFFS_N_TEMP_BUFFERS           4
8852 +
8853 +// Sequence numbers are used in YAFFS2 to determine block allocation order.
8854 +// The range is limited slightly to help distinguish bad numbers from good.
8855 +// This also allows us to perhaps in the future use special numbers for
8856 +// special purposes.
8857 +// EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years, 
8858 +// and is a larger number than the lifetime of a 2GB device.
8859 +
8860 +#define YAFFS_LOWEST_SEQUENCE_NUMBER   0x00001000
8861 +#define YAFFS_HIGHEST_SEQUENCE_NUMBER  0xEFFFFF00
8862 +
8863 +
8864 +// ChunkCache is used for short read/write operations.
8865 +typedef struct
8866 +{
8867 +       struct yaffs_ObjectStruct *object;
8868 +       int chunkId;
8869 +       int lastUse;
8870 +       int dirty;      
8871 +       int nBytes;     // Only valid if the cache is dirty
8872 +       int locked; // Can't push out or flush while locked..
8873 +#ifdef CONFIG_YAFFS_YAFFS2
8874 +       __u8 *data;
8875 +#else
8876 +       __u8 data[YAFFS_BYTES_PER_CHUNK];
8877 +#endif
8878 +} yaffs_ChunkCache;
8879 +
8880 +
8881 +#ifndef CONFIG_YAFFS_NO_YAFFS1
8882 +// Tags structures in RAM
8883 +// NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise
8884 +// the structure size will get blown out.
8885 +
8886 +typedef struct
8887 +{   
8888 +       unsigned chunkId:20;
8889 +    unsigned serialNumber:2;
8890 +    unsigned byteCount:10;
8891 +    unsigned objectId:18;
8892 +    unsigned ecc:12;
8893 +    unsigned unusedStuff:2;
8894 +
8895 +} yaffs_Tags;
8896 +
8897 +typedef union
8898 +{
8899 +    yaffs_Tags asTags;
8900 +    __u8       asBytes[8];
8901 +} yaffs_TagsUnion;
8902 +
8903 +#endif
8904 +
8905 +typedef enum
8906 +{
8907 +       YAFFS_ECC_RESULT_UNKNOWN,
8908 +       YAFFS_ECC_RESULT_NO_ERROR,
8909 +       YAFFS_ECC_RESULT_FIXED,
8910 +       YAFFS_ECC_RESULT_UNFIXED
8911 +} yaffs_ECCResult;
8912 +
8913 +typedef enum
8914 +{
8915 +       YAFFS_OBJECT_TYPE_UNKNOWN,
8916 +       YAFFS_OBJECT_TYPE_FILE,
8917 +       YAFFS_OBJECT_TYPE_SYMLINK,
8918 +       YAFFS_OBJECT_TYPE_DIRECTORY,
8919 +       YAFFS_OBJECT_TYPE_HARDLINK,
8920 +       YAFFS_OBJECT_TYPE_SPECIAL
8921 +} yaffs_ObjectType;
8922 +
8923 +
8924 +typedef struct
8925 +{
8926 +
8927 +       unsigned validMarker0;
8928 +       unsigned chunkUsed;                 //  Status of the chunk: used or unused
8929 +       unsigned objectId;                      // If 0 then this is not part of an object (unused)
8930 +       unsigned chunkId;                       // If 0 then this is a header, else a data chunk
8931 +       unsigned byteCount;                 // Only valid for data chunks
8932 +       
8933 +       
8934 +       // The following stuff only has meaning when we read
8935 +       yaffs_ECCResult eccResult;  // Only valid when we read.
8936 +       unsigned blockBad;                      // Only valid on reading
8937 +
8938 +       // YAFFS 1 stuff        
8939 +       unsigned chunkDeleted;          // The chunk is marked deleted
8940 +       unsigned serialNumber;          // Yaffs1 2-bit serial number
8941 +       
8942 +       // YAFFS2 stuff
8943 +       unsigned sequenceNumber;        // The sequence number of this block
8944 +
8945 +       // Extra info if this is an object header (YAFFS2 only)
8946 +       
8947 +       unsigned extraHeaderInfoAvailable; // There is extra info available if this is not zero
8948 +       unsigned extraParentObjectId;      // The parent object
8949 +       unsigned extraIsShrinkHeader;      // Is it a shrink header?
8950 +       unsigned extraShadows;             // Does this shadow another object?
8951 +       
8952 +       yaffs_ObjectType extraObjectType;  // What object type?
8953 +
8954 +       unsigned extraFileLength;          // Length if it is a file
8955 +       unsigned extraEquivalentObjectId;  // Equivalent object Id if it is a hard link
8956 +
8957 +       unsigned validMarker1;  
8958 +       
8959 +} yaffs_ExtendedTags;
8960 +
8961 +#ifndef CONFIG_YAFFS_NO_YAFFS1
8962 +// Spare structure
8963 +typedef struct
8964 +{
8965 +    __u8  tagByte0;
8966 +    __u8  tagByte1;
8967 +    __u8  tagByte2;
8968 +    __u8  tagByte3;
8969 +    __u8  pageStatus;  // set to 0 to delete the chunk
8970 +    __u8  blockStatus;
8971 +    __u8  tagByte4;
8972 +    __u8  tagByte5;
8973 +    __u8  ecc1[3];
8974 +    __u8  tagByte6;
8975 +    __u8  tagByte7;
8976 +    __u8  ecc2[3];
8977 +} yaffs_Spare;
8978 +
8979 +//Special structure for passing through to mtd
8980 +struct yaffs_NANDSpare {
8981 +       yaffs_Spare     spare;
8982 +       int             eccres1;
8983 +       int             eccres2;
8984 +};
8985 +#endif
8986 +
8987 +
8988 +// Block data in RAM
8989 +
8990 +typedef enum {
8991 +       YAFFS_BLOCK_STATE_UNKNOWN       = 0,
8992 +
8993 +       YAFFS_BLOCK_STATE_SCANNING,
8994 +       YAFFS_BLOCK_STATE_NEEDS_SCANNING,// The block might have something on it (ie it is allocating or full, perhaps empty)
8995 +                                                                       // but it needs to be scanned to determine its true state.
8996 +                                                                       // This state is only valid during yaffs_Scan.
8997 +                                                                       // NB We tolerate empty because the pre-scanner might be incapable of deciding
8998 +                                                                       // However, if this state is returned on a YAFFS2 device, then we expect a sequence number
8999 +                                                                       
9000 +       YAFFS_BLOCK_STATE_EMPTY,                // This block is empty
9001 +       
9002 +       YAFFS_BLOCK_STATE_ALLOCATING,   // This block is partially allocated. 
9003 +                                                                       // This is the one currently being used for page
9004 +                                                                       // allocation. Should never be more than one of these
9005 +                                                       
9006 +
9007 +       YAFFS_BLOCK_STATE_FULL,                 // All the pages in this block have been allocated.
9008 +                                                                       // At least one page holds valid data.
9009 +                                                        
9010 +       YAFFS_BLOCK_STATE_DIRTY,                // All pages have been allocated and deleted. 
9011 +                                                                       // Erase me, reuse me.
9012 +                                                                       
9013 +       YAFFS_BLOCK_STATE_COLLECTING,   // This block is being garbage collected
9014 +                                                       
9015 +       YAFFS_BLOCK_STATE_DEAD                  // This block has failed and is not in use
9016 +
9017 +} yaffs_BlockState;
9018 +
9019 +
9020 +
9021 +
9022 +typedef struct
9023 +{
9024 +
9025 +    int   softDeletions:12;  // number of soft deleted pages
9026 +    int   pagesInUse:12;       // number of pages in use
9027 +    yaffs_BlockState blockState:4;     // One of the above block states
9028 +    __u32 needsRetiring:1;     // Data has failed on this block, need to get valid data off
9029 +                                               // and retire the block.
9030 +#ifdef CONFIG_YAFFS_YAFFS2
9031 +       __u32 hasShrinkHeader:1;// This block has at least one object header that does a shrink
9032 +       __u32 sequenceNumber;   // block sequence number for yaffs2
9033 +#endif
9034 +
9035 +} yaffs_BlockInfo;
9036 +
9037 +
9038 +//////////////////// Object structure ///////////////////////////
9039 +// This is the object structure as stored on NAND
9040 +
9041 +typedef struct
9042 +{
9043 +       yaffs_ObjectType type;
9044 +
9045 +       // Apply to everything  
9046 +       int   parentObjectId;
9047 +       __u16 sum__NoLongerUsed;        // checksum of name. Calc this off the name to prevent inconsistencies
9048 +       YCHAR  name[YAFFS_MAX_NAME_LENGTH + 1];
9049 +
9050 +       // Thes following apply to directories, files, symlinks - not hard links
9051 +       __u32 yst_mode;  // protection
9052 +
9053 +#ifdef CONFIG_YAFFS_WINCE
9054 +       __u32 notForWinCE[5];
9055 +#else
9056 +       __u32 yst_uid;   // user ID of owner
9057 +       __u32 yst_gid;    // group ID of owner 
9058 +       __u32 yst_atime; // time of last access
9059 +       __u32 yst_mtime; // time of last modification
9060 +       __u32 yst_ctime; // time of last change
9061 +#endif
9062 +
9063 +       // File size  applies to files only
9064 +       int fileSize; 
9065 +               
9066 +       // Equivalent object id applies to hard links only.
9067 +       int  equivalentObjectId;
9068 +       
9069 +       // Alias is for symlinks only.
9070 +       YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
9071 +       
9072 +       __u32 yst_rdev;  // device stuff for block and char devices (maj/min)
9073 +       
9074 +#ifdef CONFIG_YAFFS_WINCE
9075 +       __u32 win_ctime[2];
9076 +       __u32 win_atime[2];
9077 +       __u32 win_mtime[2];
9078 +       __u32 roomToGrow[4];
9079 +#else
9080 +       __u32 roomToGrow[10];
9081 +#endif
9082 +
9083 +       int shadowsObject; // This object header shadows the specified object if not > 0
9084 +
9085 +       // isShrink applies to object headers written when we shrink the file (ie resize)
9086 +       __u32 isShrink;
9087 +       
9088 +} yaffs_ObjectHeader;
9089 +
9090 +
9091 +
9092 +////////////////////  Tnode ///////////////////////////
9093 +
9094 +union yaffs_Tnode_union
9095 +{
9096 +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
9097 +       union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL+1];
9098 +#else
9099 +       union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL];
9100 +#endif
9101 +       __u16 level0[YAFFS_NTNODES_LEVEL0];
9102 +       
9103 +};
9104 +
9105 +typedef union yaffs_Tnode_union yaffs_Tnode;
9106 +
9107 +struct yaffs_TnodeList_struct
9108 +{
9109 +       struct yaffs_TnodeList_struct *next;
9110 +       yaffs_Tnode *tnodes;
9111 +};
9112 +
9113 +typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
9114 +
9115 +
9116 +
9117 +///////////////////  Object ////////////////////////////////
9118 +// An object can be one of:
9119 +// - a directory (no data, has children links
9120 +// - a regular file (data.... not prunes :->).
9121 +// - a symlink [symbolic link] (the alias).
9122 +// - a hard link
9123 +
9124 +
9125 +typedef struct 
9126 +{
9127 +       __u32 fileSize;
9128 +       __u32 scannedFileSize;
9129 +       __u32 shrinkSize;
9130 +       int   topLevel;
9131 +       yaffs_Tnode *top;
9132 +} yaffs_FileStructure;
9133 +
9134 +typedef struct
9135 +{
9136 +       struct list_head children; // list of child links
9137 +} yaffs_DirectoryStructure;
9138 +
9139 +typedef struct
9140 +{
9141 +       YCHAR *alias;
9142 +} yaffs_SymLinkStructure;
9143 +
9144 +typedef struct
9145 +{
9146 +       struct yaffs_ObjectStruct *equivalentObject;
9147 +       __u32   equivalentObjectId;
9148 +} yaffs_HardLinkStructure;
9149 +
9150 +typedef union
9151 +{
9152 +       yaffs_FileStructure fileVariant;
9153 +       yaffs_DirectoryStructure directoryVariant;
9154 +       yaffs_SymLinkStructure symLinkVariant;
9155 +       yaffs_HardLinkStructure hardLinkVariant;
9156 +} yaffs_ObjectVariant;
9157 +
9158 +
9159 +struct  yaffs_ObjectStruct
9160 +{
9161 +       __u8 deleted: 1;                // This should only apply to unlinked files.
9162 +       __u8 softDeleted: 1;    // it has also been soft deleted
9163 +       __u8 unlinked: 1;               // An unlinked file. The file should be in the unlinked pseudo directory.
9164 +       __u8 fake:1;                    // A fake object has no presence on NAND.
9165 +       __u8 renameAllowed:1;           // Some objects are not allowed to be renamed.
9166 +       __u8 unlinkAllowed:1;
9167 +       __u8 dirty:1;                   // the object needs to be written to flash
9168 +       __u8 valid:1;                   // When the file system is being loaded up, this 
9169 +                                                       // object might be created before the data
9170 +                                                       // is available (ie. file data records appear before the header).
9171 +       __u8 serial;                    // serial number of chunk in NAND. Store here so we don't have to
9172 +
9173 +       __u8  deferedFree: 1;           // For Linux kernel. Object is removed from NAND, but still in the inode cache.
9174 +                                       // Free of object is defered.
9175 +                                       
9176 +       __u8 lazyLoaded;                // Vital info has been loaded from tags. Not all info available.
9177 +                                       // 
9178 +
9179 +                                       // read back the old one to update.
9180 +       __u16 sum;                      // sum of the name to speed searching
9181 +       
9182 +       struct yaffs_DeviceStruct *myDev; // The device I'm on
9183 +       
9184 +                                                               
9185 +       struct list_head hashLink;      // list of objects in this hash bucket
9186 +                                                       
9187 +
9188 +       struct list_head hardLinks; // all the equivalent hard linked objects
9189 +                                                               // live on this list
9190 +       // directory structure stuff
9191 +       struct yaffs_ObjectStruct  *parent;     //my parent directory
9192 +       struct list_head siblings;      // siblings in a directory
9193 +                                                               // also used for linking up the free list
9194 +               
9195 +       // Where's my object header in NAND?
9196 +       int chunkId;            // where it lives
9197 +
9198 +       int nDataChunks;        // Number of data chunks attached to the file.  
9199 +       
9200 +       __u32 objectId;         // the object id value
9201 +       
9202 +       
9203 +       __u32 yst_mode;         // protection
9204 +
9205 +#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
9206 +       YCHAR shortName[YAFFS_SHORT_NAME_LENGTH+1];
9207 +#endif
9208 +
9209 +#ifndef __KERNEL__
9210 +       __u32 inUse;
9211 +#endif
9212 +
9213 +#ifdef CONFIG_YAFFS_WINCE
9214 +       __u32 win_ctime[2];
9215 +       __u32 win_mtime[2];
9216 +       __u32 win_atime[2];
9217 +#else
9218 +       __u32 yst_uid;          // user ID of owner
9219 +       __u32 yst_gid;          // group ID of owner 
9220 +       __u32 yst_atime;        // time of last access
9221 +       __u32 yst_mtime;        // time of last modification
9222 +       __u32 yst_ctime;        // time of last change
9223 +#endif
9224 +
9225 +       __u32 yst_rdev;             // device stuff for block and char devices
9226 +
9227 +
9228 +
9229 +#ifdef __KERNEL__
9230 +       struct inode *myInode;
9231 +
9232 +#endif
9233 +
9234 +
9235 +       
9236 +       yaffs_ObjectType variantType;
9237 +       
9238 +       yaffs_ObjectVariant variant;
9239 +       
9240 +};
9241 +
9242 +
9243 +
9244 +typedef struct yaffs_ObjectStruct yaffs_Object;
9245 +
9246 +
9247 +struct yaffs_ObjectList_struct
9248 +{
9249 +       yaffs_Object *objects;
9250 +       struct yaffs_ObjectList_struct *next;
9251 +};
9252 +
9253 +typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
9254 +
9255 +typedef struct
9256 +{
9257 +       struct list_head list;
9258 +       int count;
9259 +} yaffs_ObjectBucket;
9260 +
9261 +///////////////////// Temporary buffers ////////////////////
9262 +//
9263 +// These are chunk-sized working buffers. Each device has a few
9264 +
9265 +typedef struct {
9266 +       __u8 *buffer;
9267 +       int line; // track from whence this buffer was allocated
9268 +       int maxLine;
9269 +} yaffs_TempBuffer;
9270 +
9271 +//////////////////// Device ////////////////////////////////
9272 +
9273 +struct yaffs_DeviceStruct
9274 +{
9275 +       struct list_head devList;
9276 +       const char *name;
9277 +
9278 +       // Entry parameters set up way early. Yaffs sets up the rest.
9279 +       int   nBytesPerChunk;    // Should be a power of 2 >= 512
9280 +       int       nChunksPerBlock;       // does not need to be a power of 2
9281 +       int   nBytesPerSpare;    // spare area size
9282 +       int   startBlock;                // Start block we're allowed to use
9283 +       int   endBlock;                  // End block we're allowed to use
9284 +       int   nReservedBlocks;   // We want this tuneable so that we can reduce
9285 +                                                        // reserved blocks on NOR and RAM.
9286 +       
9287 +       int   nShortOpCaches;   // If <= 0, then short op caching is disabled, else
9288 +                                                       // the number of short op caches (don't use too many).
9289 +                                                       
9290 +       int useHeaderFileSize; // Flag to determine if we should use file sizes from the header 
9291 +
9292 +       int   useNANDECC;               // Flag to decide whether or not to use NANDECC
9293 +       
9294 +       
9295 +       void *genericDevice; // Pointer to device context
9296 +                                                // On an mtd this holds the mtd pointer.
9297 +
9298 +       // NAND access functions (Must be set before calling YAFFS)
9299 +       
9300 +
9301 +       int (*writeChunkToNAND)(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, const yaffs_Spare *spare);
9302 +       int (*readChunkFromNAND)(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);
9303 +       int (*eraseBlockInNAND)(struct yaffs_DeviceStruct *dev,int blockInNAND);        
9304 +       int (*initialiseNAND)(struct yaffs_DeviceStruct *dev);
9305 +
9306 +#ifdef CONFIG_YAFFS_YAFFS2
9307 +       int (*writeChunkWithTagsToNAND)(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *tags);
9308 +       int (*readChunkWithTagsFromNAND)(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags);
9309 +       int (*markNANDBlockBad)(struct yaffs_DeviceStruct *dev, int blockNo);
9310 +       int (*queryNANDBlock)(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber);
9311 +#endif
9312 +
9313 +       int isYaffs2;
9314 +
9315 +       // End of stuff that must be set before initialisation.
9316 +       
9317 +       // Runtime parameters. Set up by YAFFS.
9318 +       
9319 +       __u16 chunkGroupBits; // 0 for devices <= 32MB. else log2(nchunks) - 16
9320 +       __u16 chunkGroupSize; // == 2^^chunkGroupBits
9321 +       
9322 +#ifdef __KERNEL__
9323 +
9324 +       struct semaphore sem;// Semaphore for waiting on erasure.
9325 +       struct semaphore grossLock; // Gross locking semaphore
9326 +       __u8 * spareBuffer; // For mtdif2 use. Don't know the size of the buffer at compile time so we have to allocate it.
9327 +       void (*putSuperFunc)(struct super_block *sb);
9328 +#endif
9329 +
9330 +       int isMounted;
9331 +       
9332 +       // Stuff to support block offsetting to support start block zero
9333 +       int internalStartBlock;
9334 +       int internalEndBlock;
9335 +       int blockOffset;
9336 +       int chunkOffset;
9337 +       
9338 +       // Block Info
9339 +       yaffs_BlockInfo *blockInfo;
9340 +       __u8 *chunkBits;   // bitmap of chunks in use
9341 +       int   chunkBitmapStride; // Number of bytes of chunkBits per block. 
9342 +                                                        //     Must be consistent with nChunksPerBlock.
9343 +
9344 +
9345 +       int   nErasedBlocks;
9346 +       int   allocationBlock;                  // Current block being allocated off
9347 +       __u32 allocationPage;
9348 +       int   allocationBlockFinder;    // Used to search for next allocation block
9349 +       
9350 +       // Runtime state
9351 +       int   nTnodesCreated;   
9352 +       yaffs_Tnode *freeTnodes;
9353 +       int  nFreeTnodes;
9354 +       yaffs_TnodeList *allocatedTnodeList;
9355 +
9356 +       int   isDoingGC;
9357 +
9358 +       int   nObjectsCreated;
9359 +       yaffs_Object *freeObjects;
9360 +       int   nFreeObjects;
9361 +
9362 +       yaffs_ObjectList *allocatedObjectList;
9363 +
9364 +       yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS];
9365 +
9366 +       int       nFreeChunks;
9367 +               
9368 +       int   currentDirtyChecker;      // Used to find current dirtiest block
9369 +       
9370 +       __u32  *gcCleanupList; // objects to delete at the end of a GC. 
9371 +       
9372 +       // Operations since mount
9373 +       int nPageWrites;
9374 +       int nPageReads;
9375 +       int nBlockErasures;
9376 +       int nErasureFailures;
9377 +       int nGCCopies;
9378 +       int garbageCollections;
9379 +       int passiveGarbageCollections;
9380 +       int nRetriedWrites;
9381 +       int nRetiredBlocks;
9382 +       int eccFixed;
9383 +       int eccUnfixed;
9384 +       int tagsEccFixed;
9385 +       int tagsEccUnfixed;
9386 +       int nDeletions;
9387 +       int nUnmarkedDeletions;
9388 +       
9389 +       yaffs_Object *rootDir;
9390 +       yaffs_Object *lostNFoundDir;
9391 +       
9392 +       // Buffer areas for storing data to recover from write failures
9393 +//     __u8            bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];
9394 +//     yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK];
9395 +       int bufferedBlock;      // Which block is buffered here?
9396 +       int doingBufferedBlockRewrite;
9397 +
9398 +       yaffs_ChunkCache *srCache;
9399 +       int srLastUse;
9400 +
9401 +       int cacheHits;
9402 +
9403 +       // Stuff for background deletion and unlinked files.
9404 +       yaffs_Object *unlinkedDir;              // Directory where unlinked and deleted files live.
9405 +       yaffs_Object *deletedDir;               // Directory where deleted objects are sent to disappear.
9406 +       yaffs_Object *unlinkedDeletion; // Current file being background deleted.
9407 +       int nDeletedFiles;                              // Count of files awaiting deletion;
9408 +       int nUnlinkedFiles;                             // Count of unlinked files. 
9409 +       int nBackgroundDeletions;                       // Count of background deletions.       
9410 +       
9411 +       //__u8 *localBuffer;
9412 +       
9413 +       yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
9414 +       int maxTemp;
9415 +       int unmanagedTempAllocations;
9416 +       int unmanagedTempDeallocations;
9417 +       
9418 +       // yaffs2 runtime stuff
9419 +       unsigned sequenceNumber;                //Sequence number of currently allocating block
9420 +       unsigned oldestDirtySequence;
9421 +       
9422 +};
9423 +
9424 +typedef struct yaffs_DeviceStruct yaffs_Device;
9425 +
9426 +
9427 +// Function to manipulate block info
9428 +static  Y_INLINE yaffs_BlockInfo* yaffs_GetBlockInfo(yaffs_Device *dev, int blk)
9429 +{
9430 +       if(blk < dev->internalStartBlock || blk > dev->internalEndBlock)
9431 +       {
9432 +               T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),blk));
9433 +               YBUG();
9434 +       }
9435 +       return &dev->blockInfo[blk - dev->internalStartBlock];
9436 +}
9437 +
9438 +
9439 +//////////// YAFFS Functions //////////////////
9440 +
9441 +int yaffs_GutsInitialise(yaffs_Device *dev);
9442 +void yaffs_Deinitialise(yaffs_Device *dev);
9443 +
9444 +int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev);
9445 +
9446 +
9447 +// Rename
9448 +int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, yaffs_Object *newDir, const YCHAR *newName);
9449 +
9450 +// generic Object functions
9451 +int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name);
9452 +int yaffs_DeleteFile(yaffs_Object *obj);
9453 +
9454 +// Object access functions.
9455 +int yaffs_GetObjectName(yaffs_Object *obj,YCHAR *name,int buffSize);
9456 +int yaffs_GetObjectFileLength(yaffs_Object *obj);
9457 +int yaffs_GetObjectInode(yaffs_Object *obj);
9458 +unsigned yaffs_GetObjectType(yaffs_Object *obj);
9459 +int yaffs_GetObjectLinkCount(yaffs_Object *obj);
9460 +
9461 +// Change inode attributes
9462 +int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr);
9463 +int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr);
9464 +
9465 +// File operations
9466 +int yaffs_ReadDataFromFile(yaffs_Object *obj, __u8 *buffer, __u32 offset, int nBytes);
9467 +int yaffs_WriteDataToFile(yaffs_Object *obj, const __u8 *buffer, __u32 offset, int nBytes, int writeThrough);
9468 +int yaffs_ResizeFile(yaffs_Object *obj, int newSize);
9469 +
9470 +yaffs_Object *yaffs_MknodFile(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid);
9471 +int yaffs_FlushFile(yaffs_Object *obj,int updateTime);
9472 +
9473 +
9474 +// Directory operations
9475 +yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid);
9476 +yaffs_Object *yaffs_FindObjectByName(yaffs_Object *theDir,const YCHAR *name);
9477 +int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,int (*fn)(yaffs_Object *));
9478 +
9479 +yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev,__u32 number);
9480 +
9481 +// Link operations
9482 +yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name, yaffs_Object *equivalentObject);
9483 +
9484 +yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj);
9485 +
9486 +// Symlink operations
9487 +yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name, __u32 mode,  __u32 uid, __u32 gid, const YCHAR *alias);
9488 +YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj);
9489 +
9490 +// Special inodes (fifos, sockets and devices)
9491 +yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid,__u32 rdev);
9492 +
9493 +
9494 +// Special directories
9495 +yaffs_Object *yaffs_Root(yaffs_Device *dev);
9496 +yaffs_Object *yaffs_LostNFound(yaffs_Device *dev);
9497 +
9498 +#ifdef CONFIG_YAFFS_WINCE
9499 +// CONFIG_YAFFS_WINCE special stuff
9500 +void  yfsd_WinFileTimeNow(__u32 target[2]);
9501 +#endif
9502 +
9503 +#ifdef __KERNEL__
9504 +
9505 +void yaffs_HandleDeferedFree(yaffs_Object *obj);
9506 +#endif
9507 +
9508 +
9509 +
9510 +
9511 +// Debug dump 
9512 +int yaffs_DumpObject(yaffs_Object *obj);
9513 +
9514 +
9515 +void yaffs_GutsTest(yaffs_Device *dev);
9516 +
9517 +
9518 +void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
9519 +void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND,int lyn);
9520 +int yaffs_CheckFF(__u8 *buffer,int nBytes);
9521 +
9522 +#endif
9523 +
9524 diff --git a/fs/yaffs/yaffs_mtdif.c b/fs/yaffs/yaffs_mtdif.c
9525 new file mode 100644
9526 index 0000000..90146fb
9527 --- /dev/null
9528 +++ b/fs/yaffs/yaffs_mtdif.c
9529 @@ -0,0 +1,153 @@
9530 +/*
9531 + * YAFFS: Yet another FFS. A NAND-flash specific file system. 
9532 + * yaffs_mtdif.c  NAND mtd wrapper functions.
9533 + *
9534 + * Copyright (C) 2002 Aleph One Ltd.
9535 + *   for Toby Churchill Ltd and Brightstar Engineering
9536 + *
9537 + * Created by Charles Manning <charles@aleph1.co.uk>
9538 + *
9539 + * This program is free software; you can redistribute it and/or modify
9540 + * it under the terms of the GNU General Public License version 2 as
9541 + * published by the Free Software Foundation.
9542 + *
9543 + */
9544 +
9545 +const char *yaffs_mtdif_c_version = "$Id: yaffs_mtdif.c,v 1.7 2005/08/01 20:52:35 luc Exp $";
9546
9547 +#include "yportenv.h"
9548 +
9549 +#ifdef CONFIG_YAFFS_YAFFS1
9550 +
9551 +#include "yaffs_mtdif.h"
9552 +
9553 +#include "linux/mtd/mtd.h"
9554 +#include "linux/types.h"
9555 +#include "linux/time.h"
9556 +#include "linux/mtd/nand.h"
9557 +
9558 +static struct nand_oobinfo yaffs_oobinfo = {
9559 +       .useecc = 1,
9560 +       .eccbytes = 6,
9561 +       .eccpos = {8, 9, 10, 13, 14, 15}
9562 +};
9563 +
9564 +static struct nand_oobinfo yaffs_noeccinfo = {
9565 +       .useecc = 0,
9566 +};
9567 +
9568 +
9569 +int nandmtd_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare)
9570 +{
9571 +       struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
9572 +       size_t dummy;
9573 +    int retval = 0;
9574 +       
9575 +       loff_t addr = ((loff_t)chunkInNAND) * dev->nBytesPerChunk;
9576 +       
9577 +       __u8 *spareAsBytes = (__u8 *)spare;
9578 +
9579 +       if(data && spare)
9580 +       {
9581 +               if(dev->useNANDECC)
9582 +                       retval = mtd->write_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,spareAsBytes,&yaffs_oobinfo);
9583 +               else
9584 +                       retval = mtd->write_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,spareAsBytes,&yaffs_noeccinfo);
9585 +       }
9586 +       else
9587 +       {
9588 +       if(data)
9589 +               retval = mtd->write(mtd,addr,dev->nBytesPerChunk,&dummy,data);
9590 +       if(spare)
9591 +               retval = mtd->write_oob(mtd,addr,YAFFS_BYTES_PER_SPARE,&dummy,spareAsBytes);
9592 +       }
9593 +
9594 +    if (retval == 0)
9595 +       return YAFFS_OK;
9596 +    else
9597 +        return YAFFS_FAIL;
9598 +}
9599 +
9600 +int nandmtd_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare)
9601 +{
9602 +       struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
9603 +       size_t dummy;
9604 +    int retval = 0;
9605 +       
9606 +       loff_t addr = ((loff_t)chunkInNAND) * dev->nBytesPerChunk;
9607 +       
9608 +       __u8 *spareAsBytes = (__u8 *)spare;
9609 +       
9610 +       if(data && spare)
9611 +       {
9612 +               if(dev->useNANDECC)
9613 +               {   // Careful, this call adds 2 ints to the end of the spare data.  Calling function should
9614 +            // allocate enough memory for spare, i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)].
9615 +               retval = mtd->read_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,spareAsBytes,&yaffs_oobinfo);            
9616 +               }
9617 +               else
9618 +               {
9619 +                       retval = mtd->read_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,spareAsBytes,&yaffs_noeccinfo);
9620 +               }
9621 +       }
9622 +       else
9623 +       {
9624 +       if(data)
9625 +               retval = mtd->read(mtd,addr,dev->nBytesPerChunk,&dummy,data);
9626 +       if(spare)
9627 +               retval = mtd->read_oob(mtd,addr,YAFFS_BYTES_PER_SPARE,&dummy,spareAsBytes);
9628 +       }
9629 +
9630 +    if (retval == 0)
9631 +       return YAFFS_OK;
9632 +    else
9633 +        return YAFFS_FAIL;
9634 +}
9635 +
9636 +// Callback not needed for NAND
9637 +#if 0
9638 +static void nandmtd_EraseCallback(struct erase_info *ei)
9639 +{
9640 +       yaffs_Device *dev = (yaffs_Device *)ei->priv;   
9641 +       up(&dev->sem);
9642 +}
9643 +#endif
9644 +
9645 +
9646 +int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
9647 +{
9648 +       struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
9649 +       __u32 addr = ((loff_t) blockNumber) * dev->nBytesPerChunk * dev->nChunksPerBlock;
9650 +       struct erase_info ei;
9651 +    int retval = 0;
9652 +       
9653 +       ei.mtd = mtd;
9654 +       ei.addr = addr;
9655 +       ei.len = dev->nBytesPerChunk * dev->nChunksPerBlock;
9656 +       ei.time = 1000;
9657 +       ei.retries = 2;
9658 +       ei.callback = NULL;
9659 +       ei.priv = (u_long)dev;
9660 +       
9661 +       // Todo finish off the ei if required
9662 +       
9663 +       sema_init(&dev->sem,0);
9664 +
9665 +       retval = mtd->erase(mtd,&ei);   
9666 +       
9667 +       //No need for callback 
9668 +       // down(&dev->sem); // Wait for the erasure to complete
9669 +
9670 +    if (retval == 0)   
9671 +       return YAFFS_OK;
9672 +    else
9673 +        return YAFFS_FAIL;
9674 +}
9675 +
9676 +int nandmtd_InitialiseNAND(yaffs_Device *dev)
9677 +{
9678 +       return YAFFS_OK;
9679 +}
9680 +
9681 +#endif // CONFIG_YAFFS_YAFFS1
9682 +
9683 diff --git a/fs/yaffs/yaffs_mtdif.h b/fs/yaffs/yaffs_mtdif.h
9684 new file mode 100644
9685 index 0000000..8846828
9686 --- /dev/null
9687 +++ b/fs/yaffs/yaffs_mtdif.h
9688 @@ -0,0 +1,33 @@
9689 +/*
9690 + * YAFFS: Yet another FFS. A NAND-flash specific file system. 
9691 + * yaffs_mtdif.h  NAND mtd interface wrappers
9692 + *
9693 + * Copyright (C) 2002 Aleph One Ltd.
9694 + *   for Toby Churchill Ltd and Brightstar Engineering
9695 + *
9696 + * Created by Charles Manning <charles@aleph1.co.uk>
9697 + *
9698 + * This program is free software; you can redistribute it and/or modify
9699 + * it under the terms of the GNU Lesser General Public License version 2.1 as
9700 + * published by the Free Software Foundation.
9701 + *
9702 + *
9703 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
9704 + *
9705 + * $Id: yaffs_mtdif.h,v 1.2 2005/07/19 20:41:59 charles Exp $
9706 + */
9707 +
9708 +#ifndef __YAFFS_MTDIF_H__
9709 +#define __YAFFS_MTDIF_H__
9710 +
9711 +#include "yaffs_guts.h"
9712 +
9713 +int nandmtd_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare);
9714 +int nandmtd_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);
9715 +int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
9716 +int nandmtd_InitialiseNAND(yaffs_Device *dev);
9717 +#endif
9718 +
9719 +
9720 +
9721 +
9722 diff --git a/fs/yaffs/yaffs_mtdif2.c b/fs/yaffs/yaffs_mtdif2.c
9723 new file mode 100644
9724 index 0000000..0c4cc39
9725 --- /dev/null
9726 +++ b/fs/yaffs/yaffs_mtdif2.c
9727 @@ -0,0 +1,177 @@
9728 +/*
9729 + * YAFFS: Yet another FFS. A NAND-flash specific file system. 
9730 + * yaffs_mtdif.c  NAND mtd wrapper functions.
9731 + *
9732 + * Copyright (C) 2002 Aleph One Ltd.
9733 + *   for Toby Churchill Ltd and Brightstar Engineering
9734 + *
9735 + * Created by Charles Manning <charles@aleph1.co.uk>
9736 + *
9737 + * This program is free software; you can redistribute it and/or modify
9738 + * it under the terms of the GNU General Public License version 2 as
9739 + * published by the Free Software Foundation.
9740 + *
9741 + */
9742 +
9743 +// mtd interface for YAFFS2
9744 +
9745 +const char *yaffs_mtdif2_c_version = "$Id: yaffs_mtdif2.c,v 1.6 2005/08/01 20:52:35 luc Exp $";
9746
9747 +#include "yportenv.h"
9748 +
9749 +#ifdef CONFIG_YAFFS_YAFFS2
9750 +
9751 +#include "yaffs_mtdif2.h"
9752 +
9753 +#include "linux/mtd/mtd.h"
9754 +#include "linux/types.h"
9755 +#include "linux/time.h"
9756 +
9757 +#include "yaffs_packedtags2.h"
9758 +
9759 +
9760 +
9761 +
9762 +int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags)
9763 +{
9764 +       struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
9765 +       size_t dummy;
9766 +       int retval = 0;
9767 +
9768 +
9769 +       loff_t addr = ((loff_t)chunkInNAND) * dev->nBytesPerChunk;
9770 +
9771 +       yaffs_PackedTags2 pt;
9772 +       
9773 +       T(YAFFS_TRACE_MTD,(TSTR("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p" TENDSTR),chunkInNAND,data,tags));  
9774 +
9775 +       if(tags)
9776 +       {
9777 +               yaffs_PackTags2(&pt,tags);
9778 +       }
9779 +
9780 +       if(data && tags)
9781 +       {
9782 +               if(dev->useNANDECC)
9783 +                 retval = mtd->write_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,(__u8 *)&pt,NULL);
9784 +               else
9785 +                 retval = mtd->write_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,(__u8 *)&pt,NULL);
9786 +       }
9787 +       else
9788 +       {
9789 +       if(data)
9790 +               retval = mtd->write(mtd,addr,dev->nBytesPerChunk,&dummy,data);
9791 +       if(tags)
9792 +               retval = mtd->write_oob(mtd,addr,mtd->oobsize,&dummy,(__u8 *)&pt);
9793 +               
9794 +       }
9795 +
9796 +    if (retval == 0)
9797 +       return YAFFS_OK;
9798 +    else
9799 +        return YAFFS_FAIL;
9800 +}
9801 +
9802 +int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags)
9803 +{
9804 +       struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
9805 +       size_t dummy;
9806 +        int retval = 0;
9807 +       
9808 +
9809 +       loff_t addr = ((loff_t)chunkInNAND) * dev->nBytesPerChunk;
9810 +       
9811 +       yaffs_PackedTags2 pt;
9812 +
9813 +       T(YAFFS_TRACE_MTD,(TSTR("nandmtd2_ReadChunkWithTagsToNAND chunk %d data %p tags %p" TENDSTR),chunkInNAND,data,tags));   
9814 +
9815 +       if(data && tags)
9816 +       {
9817 +               if(dev->useNANDECC)
9818 +               {
9819 +                       retval = mtd->read_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,dev->spareBuffer,NULL);            
9820 +               }
9821 +               else
9822 +               {
9823 +                       retval = mtd->read_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,dev->spareBuffer,NULL);
9824 +               }
9825 +               memcpy(&pt,dev->spareBuffer,sizeof(pt));
9826 +       }
9827 +       else
9828 +       {
9829 +       if(data)
9830 +               retval = mtd->read(mtd,addr,dev->nBytesPerChunk,&dummy,data);
9831 +       if(tags) {
9832 +               retval = mtd->read_oob(mtd,addr,mtd->oobsize,&dummy,dev->spareBuffer);
9833 +               memcpy(&pt, mtd->oobinfo.oobfree[0][0] + (char *)dev->spareBuffer, sizeof(pt));
9834 +       }
9835 +       }
9836 +
9837 +    if(tags)
9838 +       yaffs_UnpackTags2(tags,&pt);
9839 +    
9840 +    if (retval == 0)
9841 +       return YAFFS_OK;
9842 +    else
9843 +        return YAFFS_FAIL;
9844 +}
9845 +
9846 +int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
9847 +{
9848 +       struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
9849 +       int retval;
9850 +       T(YAFFS_TRACE_MTD,(TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR),blockNo));      
9851 +       
9852 +       
9853 +       retval = mtd->block_markbad(mtd,blockNo * dev->nChunksPerBlock * dev->nBytesPerChunk);
9854 +
9855 +    if (retval == 0)
9856 +       return YAFFS_OK;
9857 +    else
9858 +        return YAFFS_FAIL;
9859 +
9860 +}
9861 +
9862 +int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber)
9863 +{
9864 +       struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
9865 +       int retval;
9866 +       
9867 +       T(YAFFS_TRACE_MTD,(TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR),blockNo));        
9868 +       retval = mtd->block_isbad(mtd,blockNo* dev->nChunksPerBlock * dev->nBytesPerChunk);
9869 +       
9870 +       if(retval)
9871 +       {
9872 +               T(YAFFS_TRACE_MTD,(TSTR("block is bad" TENDSTR)));
9873 +       
9874 +               *state = YAFFS_BLOCK_STATE_DEAD;
9875 +               *sequenceNumber = 0;
9876 +       }
9877 +       else
9878 +       {
9879 +               yaffs_ExtendedTags t;
9880 +               nandmtd2_ReadChunkWithTagsFromNAND(dev,blockNo * dev->nChunksPerBlock,NULL, &t);
9881 +               
9882 +               if(t.chunkUsed)
9883 +               {
9884 +                 *sequenceNumber = t.sequenceNumber;
9885 +                 *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
9886 +               }
9887 +               else
9888 +               {
9889 +                 *sequenceNumber = 0;
9890 +                 *state = YAFFS_BLOCK_STATE_EMPTY;
9891 +               }
9892 +       }
9893 +               T(YAFFS_TRACE_MTD,(TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,*state));
9894 +
9895 +    if (retval == 0)
9896 +       return YAFFS_OK;
9897 +    else
9898 +        return YAFFS_FAIL;
9899 +}
9900 +
9901 +#endif
9902 +
9903 +
9904 +
9905 diff --git a/fs/yaffs/yaffs_mtdif2.h b/fs/yaffs/yaffs_mtdif2.h
9906 new file mode 100644
9907 index 0000000..5b308ee
9908 --- /dev/null
9909 +++ b/fs/yaffs/yaffs_mtdif2.h
9910 @@ -0,0 +1,27 @@
9911 +/*
9912 + * YAFFS: Yet another FFS. A NAND-flash specific file system. 
9913 + * yaffs_mtdif.c  NAND mtd wrapper functions.
9914 + *
9915 + * Copyright (C) 2002 Aleph One Ltd.
9916 + *   for Toby Churchill Ltd and Brightstar Engineering
9917 + *
9918 + * Created by Charles Manning <charles@aleph1.co.uk>
9919 + *
9920 + * This program is free software; you can redistribute it and/or modify
9921 + * it under the terms of the GNU General Public License version 2 as
9922 + * published by the Free Software Foundation.
9923 + *
9924 + */
9925 +
9926 +
9927 +#ifndef __YAFFS_MTDIF2_H__
9928 +#define __YAFFS_MTDIF2_H__
9929 +
9930 +
9931 +#include "yaffs_guts.h"
9932 +int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags);
9933 +int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags);
9934 +int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
9935 +int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber);
9936 +
9937 +#endif 
9938 diff --git a/fs/yaffs/yaffs_nandemul2k.h b/fs/yaffs/yaffs_nandemul2k.h
9939 new file mode 100644
9940 index 0000000..b35d474
9941 --- /dev/null
9942 +++ b/fs/yaffs/yaffs_nandemul2k.h
9943 @@ -0,0 +1,38 @@
9944 +/*
9945 + * YAFFS: Yet another FFS. A NAND-flash specific file system. 
9946 + *
9947 + * Copyright (C) 2002 Aleph One Ltd.
9948 + *   for Toby Churchill Ltd and Brightstar Engineering
9949 + *
9950 + * Created by Charles Manning <charles@aleph1.co.uk>
9951 + *
9952 + * This program is free software; you can redistribute it and/or modify
9953 + * it under the terms of the GNU Lesser General Public License version 2.1 as
9954 + * published by the Free Software Foundation.
9955 + *
9956 + *
9957 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
9958 + *
9959 + * yaffs_nandemul2k.h: Interface to emulated NAND functions (2k page size)
9960 + *
9961 + * $Id: yaffs_nandemul2k.h,v 1.1 2004/12/17 04:39:04 charles Exp $
9962 + */
9963
9964 +#ifndef __YAFFS_NANDEMUL2K_H__
9965 +#define __YAFFS_NANDEMUL2K_H__
9966 +
9967 +#include "yaffs_guts.h" 
9968
9969
9970 +int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_ExtendedTags *tags);
9971 +int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags);
9972 +int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
9973 +int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber);
9974 +int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND);
9975 +int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);
9976 +int nandemul2k_GetBytesPerChunk(void);
9977 +int nandemul2k_GetChunksPerBlock(void);
9978 +int nandemul2k_GetNumberOfBlocks(void);
9979 +
9980 +#endif
9981 +
9982 diff --git a/fs/yaffs/yaffs_packedtags1.c b/fs/yaffs/yaffs_packedtags1.c
9983 new file mode 100644
9984 index 0000000..bab338f
9985 --- /dev/null
9986 +++ b/fs/yaffs/yaffs_packedtags1.c
9987 @@ -0,0 +1,42 @@
9988 +#include "yaffs_packedtags1.h"
9989 +#include "yportenv.h"
9990 +
9991 +void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t)
9992 +{
9993 +       pt->chunkId = t->chunkId;
9994 +       pt->serialNumber = t->serialNumber;
9995 +       pt->byteCount = t->byteCount;
9996 +       pt->objectId = t->objectId;
9997 +       pt->ecc = 0;
9998 +       pt->deleted = (t->chunkDeleted) ? 0 : 1;
9999 +       pt->unusedStuff = 0;
10000 +       pt->shouldBeFF = 0xFFFFFFFF;
10001 +       
10002 +}
10003 +
10004 +void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt)
10005 +{
10006 +       static const __u8 allFF[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,0xff, 0xff, 0xff, 0xff};
10007 +       
10008 +       if(memcmp(allFF,pt,sizeof(yaffs_PackedTags1)))
10009 +       {
10010 +               t->blockBad = 0;
10011 +               if(pt->shouldBeFF != 0xFFFFFFFF)
10012 +               {
10013 +                       t->blockBad = 1;
10014 +               }
10015 +               t->chunkUsed = 1;
10016 +               t->objectId = pt->objectId;
10017 +               t->chunkId = pt->chunkId;
10018 +               t->byteCount = pt->byteCount;
10019 +               t->eccResult =  YAFFS_ECC_RESULT_NO_ERROR;
10020 +               t->chunkDeleted = (pt->deleted) ? 0 : 1;
10021 +               t->serialNumber = pt->serialNumber;
10022 +       }
10023 +       else
10024 +       {
10025 +               memset(t,0,sizeof(yaffs_ExtendedTags));
10026 +               
10027 +       }
10028 +}
10029 +
10030 diff --git a/fs/yaffs/yaffs_packedtags1.h b/fs/yaffs/yaffs_packedtags1.h
10031 new file mode 100644
10032 index 0000000..0f76615
10033 --- /dev/null
10034 +++ b/fs/yaffs/yaffs_packedtags1.h
10035 @@ -0,0 +1,28 @@
10036 +// This is used to pack YAFFS1 tags, not YAFFS2 tags.
10037 +
10038 +#ifndef __YAFFS_PACKEDTAGS1_H__
10039 +#define __YAFFS_PACKEDTAGS1_H__
10040 +
10041 +
10042 +#include "yaffs_guts.h"
10043 +
10044 +typedef struct
10045 +{   
10046 +    unsigned chunkId:20;
10047 +    unsigned serialNumber:2;
10048 +    unsigned byteCount:10;
10049 +    unsigned objectId:18;
10050 +    unsigned ecc:12;
10051 +    unsigned deleted:1;
10052 +    unsigned unusedStuff:1;
10053 +    unsigned shouldBeFF;
10054 +
10055 +} yaffs_PackedTags1;
10056 +
10057 +
10058 +
10059 +void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t);
10060 +void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt);
10061 +#endif
10062 +
10063 +
10064 diff --git a/fs/yaffs/yaffs_packedtags2.c b/fs/yaffs/yaffs_packedtags2.c
10065 new file mode 100644
10066 index 0000000..f4de18d
10067 --- /dev/null
10068 +++ b/fs/yaffs/yaffs_packedtags2.c
10069 @@ -0,0 +1,164 @@
10070 +/*
10071 + * YAFFS: Yet another FFS. A NAND-flash specific file system. 
10072 + *
10073 + * yaffs_packedtags2.c: Tags packing for YAFFS2
10074 + *
10075 + * Copyright (C) 2002 Aleph One Ltd.
10076 + *
10077 + * Created by Charles Manning <charles@aleph1.co.uk>
10078 + *
10079 + *
10080 + * This program is free software; you can redistribute it and/or
10081 + * modify it under the terms of the GNU Lesser General Public License
10082 + * version 2.1 as published by the Free Software Foundation.
10083 + */
10084
10085 +#include "yaffs_packedtags2.h"
10086 +#include "yportenv.h"
10087 +#include "yaffs_tagsvalidity.h"
10088 +
10089 +
10090 +
10091 +// This code packs a set of extended tags into a binary structure for NAND storage
10092 +
10093 +// Some of the information is "extra" struff which can be packed in to speed scanning
10094 +// This is defined by having the EXTRA_HEADER_INFO_FLAG set.
10095 +
10096 +
10097 +// Extra flags applied to chunkId
10098 +
10099 +#define EXTRA_HEADER_INFO_FLAG 0x80000000
10100 +#define EXTRA_SHRINK_FLAG      0x40000000
10101 +#define EXTRA_SHADOWS_FLAG     0x20000000
10102 +#define EXTRA_SPARE_FLAGS      0x10000000
10103 +
10104 +#define ALL_EXTRA_FLAGS                0xF0000000
10105 +
10106 +
10107 +
10108 +// Also, the top 4 bits of the object Id are set to the object type.
10109 +#define EXTRA_OBJECT_TYPE_SHIFT (28)
10110 +#define EXTRA_OBJECT_TYPE_MASK  ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)
10111 +
10112 +
10113 +
10114 +static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 *pt)
10115 +{
10116 +       T(YAFFS_TRACE_MTD,(TSTR("packed tags obj %d chunk %d byte %d seq %d"TENDSTR),pt->t.objectId,pt->t.chunkId,pt->t.byteCount,pt->t.sequenceNumber));
10117 +}
10118 +
10119 +static void yaffs_DumpTags2(const yaffs_ExtendedTags *t)
10120 +{
10121 +       T(YAFFS_TRACE_MTD,(TSTR("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d"TENDSTR),
10122 +            t->eccResult, t->blockBad, t->chunkUsed, t->objectId, t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber, t->sequenceNumber));
10123 +         
10124 +}
10125 +
10126 +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t)
10127 +{
10128 +       pt->t.chunkId = t->chunkId;
10129 +       pt->t.sequenceNumber = t->sequenceNumber;
10130 +       pt->t.byteCount = t->byteCount;
10131 +       pt->t.objectId = t->objectId;
10132 +       
10133 +       if(t->chunkId == 0 && t->extraHeaderInfoAvailable)
10134 +       {
10135 +               // Store the extra header info instead
10136 +               pt->t.chunkId = EXTRA_HEADER_INFO_FLAG | t->extraParentObjectId; // We save the parent object in the chunkId
10137 +               if(t->extraIsShrinkHeader) 
10138 +               {
10139 +                   pt->t.chunkId |= EXTRA_SHRINK_FLAG;
10140 +               }
10141 +               if(t->extraShadows) 
10142 +               {
10143 +                   pt->t.chunkId |= EXTRA_SHADOWS_FLAG;
10144 +               }
10145 +               
10146 +               pt->t.objectId &= ~EXTRA_OBJECT_TYPE_MASK;
10147 +               pt->t.objectId |= (t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
10148 +                
10149 +               if(t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)
10150 +               {
10151 +                  pt->t.byteCount = t->extraEquivalentObjectId;
10152 +               }
10153 +               else if(t->extraObjectType == YAFFS_OBJECT_TYPE_FILE)
10154 +               {
10155 +                  pt->t.byteCount = t->extraFileLength;
10156 +               }
10157 +               else
10158 +               {
10159 +                  pt->t.byteCount = 0;
10160 +               }
10161 +       }
10162 +       
10163 +       yaffs_DumpPackedTags2(pt);
10164 +       yaffs_DumpTags2(t);
10165 +       
10166 +#ifndef YAFFS_IGNORE_TAGS_ECC
10167 +       { 
10168 +         yaffs_ECCCalculateOther((unsigned char *)&pt->t,sizeof(yaffs_PackedTags2TagsPart),&pt->ecc);
10169 +       }
10170 +#endif
10171 +}
10172 +
10173 +void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt)
10174 +{
10175 +
10176 +       
10177 +       memset(t,0,sizeof(yaffs_ExtendedTags));
10178 +       
10179 +       yaffs_InitialiseTags(t);
10180 +       
10181 +       if(pt->t.sequenceNumber != 0xFFFFFFFF)
10182 +       {
10183 +               // Page is in use
10184 +#ifdef YAFFS_IGNORE_TAGS_ECC
10185 +               {
10186 +                       t->eccResult = 0;
10187 +               }
10188 +#else
10189 +               {
10190 +                       yaffs_ECCOther ecc;
10191 +                       yaffs_ECCCalculateOther((unsigned char *)&pt->t,sizeof(yaffs_PackedTags2TagsPart),&ecc);
10192 +                       t->eccResult = yaffs_ECCCorrectOther((unsigned char *)&pt->t,sizeof(yaffs_PackedTags2TagsPart),&pt->ecc,&ecc);
10193 +               }
10194 +#endif
10195 +               t->blockBad = 0;
10196 +               t->chunkUsed = 1;
10197 +               t->objectId = pt->t.objectId;
10198 +               t->chunkId =  pt->t.chunkId;
10199 +               t->byteCount = pt->t.byteCount;
10200 +               t->chunkDeleted = 0;
10201 +               t->serialNumber = 0;
10202 +               t->sequenceNumber = pt->t.sequenceNumber;
10203 +               
10204 +               // Do extra header info stuff
10205 +               
10206 +               if(pt->t.chunkId & EXTRA_HEADER_INFO_FLAG)
10207 +               {
10208 +                       t->chunkId = 0;
10209 +                       t->byteCount = 0;
10210 +                       
10211 +                       t->extraHeaderInfoAvailable = 1;
10212 +                       t->extraParentObjectId = pt->t.chunkId & (~(ALL_EXTRA_FLAGS));
10213 +                       t->extraIsShrinkHeader =  (pt->t.chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
10214 +                       t->extraShadows =  (pt->t.chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
10215 +                       t->extraObjectType = pt->t.objectId >> EXTRA_OBJECT_TYPE_SHIFT;
10216 +                       t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
10217 +                       
10218 +                       if(t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)
10219 +                       {
10220 +                           t->extraEquivalentObjectId = pt->t.byteCount;
10221 +                       }
10222 +                       else 
10223 +                       {
10224 +                           t->extraFileLength = pt->t.byteCount;
10225 +                       }
10226 +               }
10227 +       }
10228 +
10229 +       yaffs_DumpPackedTags2(pt);
10230 +       yaffs_DumpTags2(t);
10231 +
10232 +}
10233 +
10234 diff --git a/fs/yaffs/yaffs_packedtags2.h b/fs/yaffs/yaffs_packedtags2.h
10235 new file mode 100644
10236 index 0000000..564dd58
10237 --- /dev/null
10238 +++ b/fs/yaffs/yaffs_packedtags2.h
10239 @@ -0,0 +1,30 @@
10240 +// This is used to pack YAFFS2 tags, not YAFFS1tags.
10241 +
10242 +#ifndef __YAFFS_PACKEDTAGS2_H__
10243 +#define __YAFFS_PACKEDTAGS2_H__
10244 +
10245 +
10246 +#include "yaffs_guts.h"
10247 +#include "yaffs_ecc.h"
10248 +
10249 +
10250 +typedef struct
10251 +{   
10252 +    unsigned sequenceNumber;
10253 +    unsigned objectId;    
10254 +    unsigned chunkId;
10255 +    unsigned byteCount;    
10256 +} yaffs_PackedTags2TagsPart;
10257 +
10258 +typedef struct
10259 +{
10260 +    yaffs_PackedTags2TagsPart t;
10261 +    yaffs_ECCOther ecc;
10262 +} yaffs_PackedTags2;
10263 +
10264 +
10265 +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const  yaffs_ExtendedTags *t);
10266 +void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt);
10267 +#endif
10268 +
10269 +
10270 diff --git a/fs/yaffs/yaffs_tagscompat.c b/fs/yaffs/yaffs_tagscompat.c
10271 new file mode 100644
10272 index 0000000..fdf1cbc
10273 --- /dev/null
10274 +++ b/fs/yaffs/yaffs_tagscompat.c
10275 @@ -0,0 +1,698 @@
10276 +/*
10277 + * YAFFS: Yet another FFS. A NAND-flash specific file system. 
10278 + * yaffs_tagscompat.h: Tags compatability layer to use YAFFS1 formatted NAND.
10279 + *
10280 + * Copyright (C) 2002 Aleph One Ltd.
10281 + *
10282 + * Created by Charles Manning <charles@aleph1.co.uk>
10283 + *
10284 + * This program is free software; you can redistribute it and/or modify
10285 + * it under the terms of the GNU General Public License version 2 as
10286 + * published by the Free Software Foundation.
10287 + *
10288 + * $Id: yaffs_tagscompat.c,v 1.3 2005/07/31 06:47:12 marty Exp $
10289 + */
10290 +
10291 +#include "yaffs_guts.h"
10292 +#include "yaffs_tagscompat.h"
10293 +#include "yaffs_ecc.h"
10294 +
10295 +static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND);
10296 +#ifdef NOTYET
10297 +static void yaffs_CheckWrittenBlock(yaffs_Device *dev,int chunkInNAND);
10298 +static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare);
10299 +static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_Spare *spare);
10300 +static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND);
10301 +#endif
10302 +
10303 +
10304 +static const char yaffs_countBitsTable[256] =
10305 +{
10306 +0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
10307 +1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
10308 +1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
10309 +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
10310 +1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
10311 +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
10312 +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
10313 +3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
10314 +1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
10315 +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
10316 +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
10317 +3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
10318 +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
10319 +3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
10320 +3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
10321 +4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
10322 +};
10323 +
10324 +static int yaffs_CountBits(__u8 x)
10325 +{
10326 +       int retVal;
10327 +       retVal = yaffs_countBitsTable[x];
10328 +       return retVal;
10329 +}
10330 +
10331 +
10332 +/////////////// Tags ECC calculations ///////////////////
10333 +
10334 +void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
10335 +{
10336 +       yaffs_ECCCalculate(data , spare->ecc1);
10337 +       yaffs_ECCCalculate(&data[256] , spare->ecc2);
10338 +}
10339 +
10340 +void yaffs_CalcTagsECC(yaffs_Tags *tags)
10341 +{
10342 +       // Calculate an ecc
10343 +
10344 +       unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
10345 +       unsigned  i,j;
10346 +       unsigned  ecc = 0;
10347 +       unsigned bit = 0;
10348 +
10349 +       tags->ecc = 0;
10350 +
10351 +       for(i = 0; i < 8; i++)
10352 +       {
10353 +               for(j = 1; j &0xff; j<<=1)
10354 +               {
10355 +                       bit++;
10356 +                       if(b[i] & j)
10357 +                       {
10358 +                               ecc ^= bit;
10359 +                       }
10360 +               }
10361 +       }
10362 +
10363 +       tags->ecc = ecc;
10364 +
10365 +
10366 +}
10367 +
10368 +int  yaffs_CheckECCOnTags(yaffs_Tags *tags)
10369 +{
10370 +       unsigned ecc = tags->ecc;
10371 +
10372 +       yaffs_CalcTagsECC(tags);
10373 +
10374 +       ecc ^= tags->ecc;
10375 +       
10376 +       if(ecc && ecc <= 64)
10377 +       {
10378 +               // TODO: Handle the failure better. Retire?
10379 +               unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
10380 +
10381 +               ecc--;
10382 +
10383 +               b[ecc / 8] ^= (1 << (ecc & 7));
10384 +
10385 +               // Now recvalc the ecc
10386 +               yaffs_CalcTagsECC(tags);
10387 +
10388 +               return 1; // recovered error
10389 +       }
10390 +       else if(ecc)
10391 +       {
10392 +               // Wierd ecc failure value
10393 +               // TODO Need to do somethiong here
10394 +               return -1; //unrecovered error
10395 +       }
10396 +
10397 +       return 0;
10398 +}
10399 +
10400 +//////////////////////////// Tags ///////////////////////////////////////
10401 +
10402 +static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr)
10403 +{
10404 +       yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
10405 +
10406 +       yaffs_CalcTagsECC(tagsPtr);
10407 +       
10408 +       sparePtr->tagByte0 = tu->asBytes[0];
10409 +       sparePtr->tagByte1 = tu->asBytes[1];
10410 +       sparePtr->tagByte2 = tu->asBytes[2];
10411 +       sparePtr->tagByte3 = tu->asBytes[3];
10412 +       sparePtr->tagByte4 = tu->asBytes[4];
10413 +       sparePtr->tagByte5 = tu->asBytes[5];
10414 +       sparePtr->tagByte6 = tu->asBytes[6];
10415 +       sparePtr->tagByte7 = tu->asBytes[7];
10416 +}
10417 +
10418 +static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr)
10419 +{
10420 +       yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
10421 +       int result;
10422 +
10423 +       tu->asBytes[0]= sparePtr->tagByte0;
10424 +       tu->asBytes[1]= sparePtr->tagByte1;
10425 +       tu->asBytes[2]= sparePtr->tagByte2;
10426 +       tu->asBytes[3]= sparePtr->tagByte3;
10427 +       tu->asBytes[4]= sparePtr->tagByte4;
10428 +       tu->asBytes[5]= sparePtr->tagByte5;
10429 +       tu->asBytes[6]= sparePtr->tagByte6;
10430 +       tu->asBytes[7]= sparePtr->tagByte7;
10431 +       
10432 +       result =  yaffs_CheckECCOnTags(tagsPtr);
10433 +       if(result> 0)
10434 +       {
10435 +               dev->tagsEccFixed++;
10436 +       }
10437 +       else if(result <0)
10438 +       {
10439 +               dev->tagsEccUnfixed++;
10440 +       }
10441 +}
10442 +
10443 +static void yaffs_SpareInitialise(yaffs_Spare *spare)
10444 +{
10445 +       memset(spare,0xFF,sizeof(yaffs_Spare));
10446 +}
10447 +
10448 +
10449 +
10450 +
10451 +static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)
10452 +{
10453 +       if(chunkInNAND < dev->startBlock * dev->nChunksPerBlock)
10454 +       {
10455 +               T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),chunkInNAND));
10456 +               return YAFFS_FAIL;
10457 +       }
10458 +
10459 +       dev->nPageWrites++;
10460 +       return dev->writeChunkToNAND(dev,chunkInNAND,data,spare);
10461 +}
10462 +
10463 +
10464 +
10465 +static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
10466 +                                                       int chunkInNAND, 
10467 +                                                       __u8 *data, 
10468 +                                                       yaffs_Spare *spare,
10469 +                                                       yaffs_ECCResult *eccResult,
10470 +                                                       int doErrorCorrection)
10471 +{
10472 +       int retVal;
10473 +       yaffs_Spare localSpare;
10474 +
10475 +       dev->nPageReads++;
10476 +       
10477 +       
10478 +
10479 +       
10480 +       if(!spare && data)
10481 +       {
10482 +               // If we don't have a real spare, then we use a local one.
10483 +               // Need this for the calculation of the ecc
10484 +               spare = &localSpare;
10485 +       }
10486 +       
10487 +
10488 +       if(!dev->useNANDECC)
10489 +       {
10490 +               retVal  = dev->readChunkFromNAND(dev,chunkInNAND,data,spare);
10491 +               if(data && doErrorCorrection)
10492 +               {
10493 +                       // Do ECC correction
10494 +                       //Todo handle any errors
10495 +               int eccResult1,eccResult2;
10496 +               __u8 calcEcc[3];
10497 +                
10498 +                       yaffs_ECCCalculate(data,calcEcc);
10499 +                       eccResult1 = yaffs_ECCCorrect (data,spare->ecc1, calcEcc);
10500 +                       yaffs_ECCCalculate(&data[256],calcEcc);
10501 +                       eccResult2 = yaffs_ECCCorrect(&data[256],spare->ecc2, calcEcc);
10502 +
10503 +                       if(eccResult1>0)
10504 +                       {
10505 +                               T(YAFFS_TRACE_ERROR, (TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND));
10506 +                               dev->eccFixed++;
10507 +                       }
10508 +                       else if(eccResult1<0)
10509 +                       {
10510 +                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND));
10511 +                               dev->eccUnfixed++;
10512 +                       }
10513 +
10514 +                       if(eccResult2>0)
10515 +                       {
10516 +                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND));
10517 +                               dev->eccFixed++;
10518 +                       }
10519 +                       else if(eccResult2<0)
10520 +                       {
10521 +                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND));
10522 +                               dev->eccUnfixed++;
10523 +                       }
10524 +
10525 +                       if(eccResult1 || eccResult2)
10526 +                       {
10527 +                               // Hoosterman, we had a data problem on this page
10528 +                               yaffs_HandleReadDataError(dev,chunkInNAND);
10529 +                       }
10530 +                       
10531 +                       if(eccResult1 < 0 || eccResult2 < 0) 
10532 +                               *eccResult = YAFFS_ECC_RESULT_UNFIXED;
10533 +                       else if(eccResult1 > 0 || eccResult2 > 0)
10534 +                               *eccResult = YAFFS_ECC_RESULT_FIXED;
10535 +                       else
10536 +                               *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
10537 +               }
10538 +       }
10539 +       else
10540 +       {
10541 +        // Must allocate enough memory for spare+2*sizeof(int) for ecc results from device.
10542 +       struct yaffs_NANDSpare nspare;
10543 +               retVal  = dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare*)&nspare);
10544 +               memcpy (spare, &nspare, sizeof(yaffs_Spare));
10545 +               if(data && doErrorCorrection)
10546 +               {
10547 +                       if(nspare.eccres1>0)
10548 +                       {
10549 +                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND));
10550 +                       }
10551 +                       else if(nspare.eccres1<0)
10552 +                       {
10553 +                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND));
10554 +                       }
10555 +
10556 +                       if(nspare.eccres2>0)
10557 +                       {
10558 +                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND));
10559 +                       }
10560 +                       else if(nspare.eccres2<0)
10561 +                       {
10562 +                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND));
10563 +                       }
10564 +
10565 +                       if(nspare.eccres1 || nspare.eccres2)
10566 +                       {
10567 +                               // Hoosterman, we had a data problem on this page
10568 +                               yaffs_HandleReadDataError(dev,chunkInNAND);
10569 +                       }
10570 +                       
10571 +                       if(nspare.eccres1 < 0 || nspare.eccres2 < 0) 
10572 +                               *eccResult = YAFFS_ECC_RESULT_UNFIXED;
10573 +                       else if(nspare.eccres1 > 0 || nspare.eccres2 > 0)
10574 +                               *eccResult = YAFFS_ECC_RESULT_FIXED;
10575 +                       else
10576 +                               *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
10577 +
10578 +
10579 +               }
10580 +       }
10581 +       return retVal;
10582 +}
10583 +
10584 +#ifdef NOTYET
10585 +static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND)
10586 +{
10587 +
10588 +       static int init = 0;
10589 +       static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
10590 +       static __u8 data[YAFFS_BYTES_PER_CHUNK];
10591 +    // Might as well always allocate the larger size for dev->useNANDECC == true;
10592 +       static __u8 spare[sizeof(struct yaffs_NANDSpare)];
10593 +
10594 +       dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare *)spare);
10595 +
10596 +       if(!init)
10597 +       {
10598 +               memset(cmpbuf,0xff,YAFFS_BYTES_PER_CHUNK);
10599 +               init = 1;
10600 +       }
10601 +
10602 +       if(memcmp(cmpbuf,data,YAFFS_BYTES_PER_CHUNK)) return  YAFFS_FAIL;
10603 +       if(memcmp(cmpbuf,spare,16)) return YAFFS_FAIL;
10604 +
10605 +
10606 +       return YAFFS_OK;
10607 +
10608 +}
10609 +#endif
10610 +
10611 +#if 0
10612 +int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
10613 +{
10614 +       dev->nBlockErasures++;
10615 +       return dev->eraseBlockInNAND(dev,blockInNAND);
10616 +}
10617 +
10618 +int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
10619 +{
10620 +       return dev->initialiseNAND(dev);
10621 +}
10622 +
10623 +#endif
10624 +
10625 +#if 0
10626 +static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8 *data, yaffs_Spare *spare,int useReserve)
10627 +{
10628 +       int chunk;
10629 +
10630 +       int writeOk = 1;
10631 +       int attempts = 0;
10632 +
10633 +       unsigned char rbData[YAFFS_BYTES_PER_CHUNK];
10634 +       yaffs_Spare rbSpare;
10635 +
10636 +       do{
10637 +               chunk = yaffs_AllocateChunk(dev,useReserve);
10638 +
10639 +               if(chunk >= 0)
10640 +               {
10641 +
10642 +                       // First check this chunk is erased...
10643 +#ifndef CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
10644 +                       writeOk = yaffs_CheckChunkErased(dev,chunk);
10645 +#endif
10646 +                       if(!writeOk)
10647 +                       {
10648 +                               T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d was not erased" TENDSTR),chunk));
10649 +                       }
10650 +                       else
10651 +                       {
10652 +                               writeOk =  yaffs_WriteChunkToNAND(dev,chunk,data,spare);
10653 +                       }
10654 +                       attempts++;
10655 +                       if(writeOk)
10656 +                       {
10657 +                               // Readback & verify
10658 +                               // If verify fails, then delete this chunk and try again
10659 +                               // To verify we compare everything except the block and
10660 +                               // page status bytes.
10661 +                               // NB We check a raw read without ECC correction applied
10662 +                               yaffs_ReadChunkFromNAND(dev,chunk,rbData,&rbSpare,0);
10663 +
10664 +#ifndef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
10665 +                               if(!yaffs_VerifyCompare(data,rbData,spare,&rbSpare))
10666 +                               {
10667 +                                       // Didn't verify
10668 +                                       T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs write verify failed on chunk %d" TENDSTR), chunk));
10669 +
10670 +                                       writeOk = 0;
10671 +                               }
10672 +#endif
10673 +
10674 +                       }
10675 +                       if(writeOk)
10676 +                       {
10677 +                               // Copy the data into the write buffer.
10678 +                               // NB We do this at the end to prevent duplicates in the case of a write error.
10679 +                               //Todo
10680 +                               yaffs_HandleWriteChunkOk(dev,chunk,data,spare);
10681 +                       }
10682 +                       else
10683 +                       {
10684 +                               yaffs_HandleWriteChunkError(dev,chunk);
10685 +                       }
10686 +               }
10687 +
10688 +       } while(chunk >= 0 && ! writeOk);
10689 +
10690 +       if(attempts > 1)
10691 +       {
10692 +               T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs write required %d attempts" TENDSTR),attempts));
10693 +               dev->nRetriedWrites+= (attempts - 1);
10694 +       }
10695 +
10696 +       return chunk;
10697 +}
10698 +
10699 +#endif
10700 +
10701 +///
10702 +// Functions for robustisizing
10703 +//
10704 +//
10705 +#if 0
10706 +
10707 +static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND)
10708 +{
10709 +       // Ding the blockStatus in the first two pages of the block.
10710 +
10711 +       yaffs_Spare spare;
10712 +
10713 +       memset(&spare, 0xff,sizeof(yaffs_Spare));
10714 +
10715 +       spare.blockStatus = 0;
10716 +
10717 +       // TODO change this retirement marking for other NAND types
10718 +       yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL , &spare);
10719 +       yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1, NULL , &spare);
10720 +
10721 +       yaffs_GetBlockInfo(dev,blockInNAND)->blockState = YAFFS_BLOCK_STATE_DEAD;
10722 +       dev->nRetiredBlocks++;
10723 +}
10724 +
10725 +#endif
10726 +
10727 +#if 0
10728 +static int yaffs_RewriteBufferedBlock(yaffs_Device *dev)
10729 +{
10730 +       dev->doingBufferedBlockRewrite = 1;
10731 +       //
10732 +       //      Remove erased chunks
10733 +       //  Rewrite existing chunks to a new block
10734 +       //      Set current write block to the new block
10735 +
10736 +       dev->doingBufferedBlockRewrite = 0;
10737 +
10738 +       return 1;
10739 +}
10740 +
10741 +#endif
10742 +
10743 +static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND)
10744 +{
10745 +       int blockInNAND = chunkInNAND/dev->nChunksPerBlock;
10746 +
10747 +       // Mark the block for retirement
10748 +       yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
10749 +       T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>>Block %d marked for retirement" TENDSTR),blockInNAND));
10750 +
10751 +
10752 +       //TODO
10753 +       // Just do a garbage collection on the affected block then retire the block
10754 +       // NB recursion
10755 +}
10756 +
10757 +
10758 +#ifdef NOTYET
10759 +static void yaffs_CheckWrittenBlock(yaffs_Device *dev,int chunkInNAND)
10760 +{
10761 +}
10762 +
10763 +static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare)
10764 +{
10765 +}
10766 +
10767 +static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_Spare *spare)
10768 +{
10769 +}
10770 +
10771 +static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND)
10772 +{
10773 +       int blockInNAND = chunkInNAND/dev->nChunksPerBlock;
10774 +
10775 +       // Mark the block for retirement
10776 +       yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
10777 +       // Delete the chunk
10778 +       yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__);
10779 +}
10780 +
10781 +
10782 +
10783 +
10784 +static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1)
10785 +{
10786 +
10787 +
10788 +       if( memcmp(d0,d1,YAFFS_BYTES_PER_CHUNK) != 0 ||
10789 +               s0->tagByte0 != s1->tagByte0 ||
10790 +               s0->tagByte1 != s1->tagByte1 ||
10791 +               s0->tagByte2 != s1->tagByte2 ||
10792 +               s0->tagByte3 != s1->tagByte3 ||
10793 +               s0->tagByte4 != s1->tagByte4 ||
10794 +               s0->tagByte5 != s1->tagByte5 ||
10795 +               s0->tagByte6 != s1->tagByte6 ||
10796 +               s0->tagByte7 != s1->tagByte7 ||
10797 +               s0->ecc1[0]  != s1->ecc1[0]  ||
10798 +               s0->ecc1[1]  != s1->ecc1[1]  ||
10799 +               s0->ecc1[2]  != s1->ecc1[2]  ||
10800 +               s0->ecc2[0]  != s1->ecc2[0]  ||
10801 +               s0->ecc2[1]  != s1->ecc2[1]  ||
10802 +               s0->ecc2[2]  != s1->ecc2[2] )
10803 +               {
10804 +                       return 0;
10805 +               }
10806 +
10807 +       return 1;
10808 +}
10809 +#endif /* NOTYET */
10810 +
10811 +#if 0
10812 +typedef struct
10813 +{
10814 +
10815 +       unsigned validMarker0;
10816 +       unsigned chunkUsed;                 //  Status of the chunk: used or unused
10817 +       unsigned objectId;                      // If 0 then this is not part of an object (unused)
10818 +       unsigned chunkId;                       // If 0 then this is a header
10819 +       unsigned byteCount;                 // Only valid for data chunks
10820 +       // The following stuff only has meaning when we read
10821 +       yaffs_ECCResult eccResult;  // Only valid when we read.
10822 +       unsigned blockBad;                      // Only valid on reading
10823 +
10824 +       // YAFFS 1 stuff        
10825 +       unsigned chunkDeleted;          // The chunk is marked deleted
10826 +       unsigned serialNumber;          // Yaffs1 2-bit serial number
10827 +       
10828 +       // YAFFS2 stuff
10829 +       unsigned sequenceNumber;        // The sequence number of this block
10830 +
10831 +       unsigned validMarker1;
10832 +
10833 +} yaffs_ExtendedTags;
10834 +
10835 +
10836 +typedef struct
10837 +{   
10838 +    unsigned chunkId:20;
10839 +    unsigned serialNumber:2;
10840 +    unsigned byteCount:10;
10841 +    unsigned objectId:18;
10842 +    unsigned ecc:12;
10843 +    unsigned unusedStuff:2;
10844 +} yaffs_Tags;
10845 +
10846 +
10847 +#endif
10848 +
10849 +int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *eTags)
10850 +{
10851 +       yaffs_Spare spare;
10852 +       yaffs_Tags tags;        
10853 +       
10854 +       yaffs_SpareInitialise(&spare);
10855 +       
10856 +       if(eTags->chunkDeleted)
10857 +       {
10858 +               spare.pageStatus = 0;
10859 +       }
10860 +       else
10861 +       {
10862 +               tags.objectId = eTags->objectId;
10863 +               tags.chunkId = eTags->chunkId;
10864 +               tags.byteCount = eTags->byteCount;
10865 +               tags.serialNumber = eTags->serialNumber;
10866 +               
10867 +// NCB
10868 +               if (!dev->useNANDECC && data)
10869 +               {
10870 +                   yaffs_CalcECC(data,&spare);
10871 +               }
10872 +
10873 +// /NCB
10874 +                yaffs_LoadTagsIntoSpare(&spare,&tags);
10875 +               
10876 +       }
10877 +       
10878 +       return yaffs_WriteChunkToNAND(dev,chunkInNAND,data,&spare);
10879 +}
10880 +
10881 +
10882 +int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *eTags)
10883 +{
10884 +
10885 +       yaffs_Spare spare;
10886 +       yaffs_Tags tags;
10887 +       yaffs_ECCResult eccResult;
10888 +       
10889 +// NCB
10890 +     static yaffs_Spare spareFF;
10891 +     static int init;
10892 +     
10893 +     if(!init)
10894 +     {
10895 +            memset(&spareFF,0xFF,sizeof(spareFF));
10896 +            init = 1;
10897 +     }
10898 +// /NCB
10899 +       if(yaffs_ReadChunkFromNAND(dev,chunkInNAND,data,&spare,&eccResult,1))
10900 +       {
10901 +// added NCB - eTags may be NULL
10902 +               if (eTags) {
10903 +
10904 +                int deleted = (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
10905 +                       
10906 +                yaffs_GetTagsFromSpare(dev,&spare,&tags);
10907 +                
10908 +                eTags->chunkDeleted = deleted;
10909 +                eTags->objectId = tags.objectId;
10910 +                eTags->chunkId = tags.chunkId;
10911 +                eTags->byteCount = tags.byteCount;
10912 +                eTags->serialNumber = tags.serialNumber;
10913 +                eTags->eccResult = eccResult;
10914 +                eTags->blockBad = 0; // We're reading it therefore it is not a bad block
10915 +                
10916 +// NCB added 18/2/2005
10917 +                eTags->chunkUsed = (memcmp(&spareFF,&spare,sizeof(spareFF)) != 0) ? 1:0;
10918 +               }
10919 +                
10920 +                return YAFFS_OK;
10921 +       }
10922 +       else
10923 +       { 
10924 +               return YAFFS_FAIL;
10925 +       }
10926 +}
10927 +
10928 +int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockInNAND)
10929 +{
10930 +
10931 +       yaffs_Spare spare;
10932 +
10933 +       memset(&spare, 0xff,sizeof(yaffs_Spare));
10934 +
10935 +       spare.blockStatus = 0;
10936 +
10937 +       yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL , &spare);
10938 +       yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1, NULL , &spare);
10939 +       
10940 +       return YAFFS_OK;
10941 +       
10942 +}
10943 +
10944 +
10945 +int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber)
10946 +{
10947 +     
10948 +     yaffs_Spare spare0,spare1;
10949 +     static yaffs_Spare spareFF;
10950 +     static int init;
10951 +     yaffs_ECCResult dummy;
10952 +     
10953 +     if(!init)
10954 +     {
10955 +            memset(&spareFF,0xFF,sizeof(spareFF));
10956 +            init = 1;
10957 +     }
10958 +     
10959 +     *sequenceNumber = 0;
10960 +     
10961 +     yaffs_ReadChunkFromNAND(dev,blockNo * dev->nChunksPerBlock,NULL,&spare0,&dummy,1);
10962 +     yaffs_ReadChunkFromNAND(dev,blockNo * dev->nChunksPerBlock + 1,NULL,&spare1,&dummy,1);
10963 +     
10964 +     if(yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
10965 +       *state = YAFFS_BLOCK_STATE_DEAD;
10966 +     else if(memcmp(&spareFF,&spare0,sizeof(spareFF)) == 0)
10967 +         *state = YAFFS_BLOCK_STATE_EMPTY;
10968 +     else
10969 +        *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;  
10970 +
10971 +     return YAFFS_OK;
10972 +}
10973 +
10974 diff --git a/fs/yaffs/yaffs_tagscompat.h b/fs/yaffs/yaffs_tagscompat.h
10975 new file mode 100644
10976 index 0000000..20b627f
10977 --- /dev/null
10978 +++ b/fs/yaffs/yaffs_tagscompat.h
10979 @@ -0,0 +1,30 @@
10980 +/*
10981 + * YAFFS: Yet another FFS. A NAND-flash specific file system. 
10982 + * yaffs_ramdisk.h: yaffs ram disk component
10983 + *
10984 + * Copyright (C) 2002 Aleph One Ltd.
10985 + *
10986 + * Created by Charles Manning <charles@aleph1.co.uk>
10987 + *
10988 + * This program is free software; you can redistribute it and/or modify
10989 + * it under the terms of the GNU General Public License version 2 as
10990 + * published by the Free Software Foundation.
10991 + *
10992 + * $Id: yaffs_tagscompat.h,v 1.1 2004/11/03 08:14:07 charles Exp $
10993 + */
10994 +
10995 +// This provides a rma disk under yaffs.
10996 +// NB this is not intended for NAND emulation.
10997 +// Use this with dev->useNANDECC enabled, then ECC overheads are not required.
10998 +
10999 +#ifndef __YAFFS_TAGSCOMPAT_H__
11000 +#define __YAFFS_TAGSCOMPAT_H__
11001 +
11002 +
11003 +#include "yaffs_guts.h"
11004 +int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags);
11005 +int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags);
11006 +int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
11007 +int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber);
11008 +
11009 +#endif
11010 diff --git a/fs/yaffs/yaffs_tagsvalidity.c b/fs/yaffs/yaffs_tagsvalidity.c
11011 new file mode 100644
11012 index 0000000..2cbbeaa
11013 --- /dev/null
11014 +++ b/fs/yaffs/yaffs_tagsvalidity.c
11015 @@ -0,0 +1,35 @@
11016 +
11017 +/*
11018 + * YAFFS: Yet another FFS. A NAND-flash specific file system. 
11019 + *
11020 + * Copyright (C) 2002 Aleph One Ltd.
11021 + *   for Toby Churchill Ltd and Brightstar Engineering
11022 + *
11023 + * Created by Charles Manning <charles@aleph1.co.uk>
11024 + *
11025 + * This program is free software; you can redistribute it and/or modify
11026 + * it under the terms of the GNU General Public License version 2 as
11027 + * published by the Free Software Foundation.
11028 + *
11029 + * $Id: yaffs_tagsvalidity.c,v 1.1 2005/04/29 18:09:16 charles Exp $
11030 + */
11031 +//yaffs_tagsvalidity.c
11032 +
11033 +#include "yaffs_tagsvalidity.h"
11034 +
11035 +
11036 +
11037 +void yaffs_InitialiseTags(yaffs_ExtendedTags *tags)
11038 +{
11039 +       memset(tags,0,sizeof(yaffs_ExtendedTags));
11040 +       tags->validMarker0 = 0xAAAAAAAA;
11041 +       tags->validMarker1 = 0x55555555;
11042 +}
11043 +
11044 +int yaffs_ValidateTags(yaffs_ExtendedTags *tags)
11045 +{
11046 +       return (tags->validMarker0 == 0xAAAAAAAA &&
11047 +               tags->validMarker1 == 0x55555555);
11048 +
11049 +}
11050 +
11051 diff --git a/fs/yaffs/yaffs_tagsvalidity.h b/fs/yaffs/yaffs_tagsvalidity.h
11052 new file mode 100644
11053 index 0000000..26673d1
11054 --- /dev/null
11055 +++ b/fs/yaffs/yaffs_tagsvalidity.h
11056 @@ -0,0 +1,27 @@
11057 +
11058 +/*
11059 + * YAFFS: Yet another FFS. A NAND-flash specific file system. 
11060 + *
11061 + * Copyright (C) 2002 Aleph One Ltd.
11062 + *   for Toby Churchill Ltd and Brightstar Engineering
11063 + *
11064 + * Created by Charles Manning <charles@aleph1.co.uk>
11065 + *
11066 + * This program is free software; you can redistribute it and/or modify
11067 + * it under the terms of the GNU General Public License version 2 as
11068 + * published by the Free Software Foundation.
11069 + *
11070 + * $Id: yaffs_tagsvalidity.h,v 1.1 2005/04/29 18:09:16 charles Exp $
11071 + */
11072 +//yaffs_tagsvalidity.h
11073 +
11074 +
11075 +#ifndef __YAFFS_TAGS_VALIDITY_H__
11076 +#define __YAFFS_TAGS_VALIDITY_H__
11077 +
11078 +#include "yaffs_guts.h"
11079 +
11080 +void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
11081 +int yaffs_ValidateTags(yaffs_ExtendedTags *tags);
11082 +#endif
11083 +
11084 diff --git a/fs/yaffs/yaffsinterface.h b/fs/yaffs/yaffsinterface.h
11085 new file mode 100644
11086 index 0000000..e4b0ff1
11087 --- /dev/null
11088 +++ b/fs/yaffs/yaffsinterface.h
11089 @@ -0,0 +1,25 @@
11090 +/*
11091 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
11092 + * yaffsinterface.h: Interface to the guts of yaffs.
11093 + *
11094 + * Copyright (C) 2002 Aleph One Ltd.
11095 + *   for Toby Churchill Ltd and Brightstar Engineering
11096 + *
11097 + * Created by Charles Manning <charles@aleph1.co.uk>
11098 + *
11099 + * This program is free software; you can redistribute it and/or modify
11100 + * it under the terms of the GNU Lesser General Public License version 2.1 as
11101 + * published by the Free Software Foundation.
11102 + *
11103 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
11104 + *
11105 + */
11106
11107 +#ifndef __YAFFSINTERFACE_H__
11108 +#define __YAFFSINTERFACE_H__
11109 +
11110 +
11111 +int yaffs_Initialise(unsigned nBlocks);
11112 +
11113 +#endif
11114 +
11115 diff --git a/fs/yaffs/yportenv.h b/fs/yaffs/yportenv.h
11116 new file mode 100644
11117 index 0000000..13c63bb
11118 --- /dev/null
11119 +++ b/fs/yaffs/yportenv.h
11120 @@ -0,0 +1,165 @@
11121 +/*
11122 + * YAFFS: Yet another FFS. A NAND-flash specific file system. 
11123 + * yportenv.h: Portable services used by yaffs. This is done to allow
11124 + * simple migration from kernel space into app space for testing.
11125 + *
11126 + * Copyright (C) 2002 Aleph One Ltd.
11127 + *   for Toby Churchill Ltd and Brightstar Engineering
11128 + *
11129 + * Created by Charles Manning <charles@aleph1.co.uk>
11130 + *
11131 + * This program is free software; you can redistribute it and/or modify
11132 + * it under the terms of the GNU Lesser General Public License version 2.1 as
11133 + * published by the Free Software Foundation.
11134 + *
11135 + *
11136 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
11137 + *
11138 + * $Id: yportenv.h,v 1.6 2005/07/31 00:26:57 charles Exp $
11139 + *
11140 + */
11141
11142 +#ifndef __YPORTENV_H__
11143 +#define __YPORTENV_H__
11144 +
11145 +
11146 +#if defined CONFIG_YAFFS_WINCE
11147 +
11148 +#include "ywinceenv.h"
11149 +
11150 +#elif  defined __KERNEL__
11151 +
11152 +
11153 +
11154 +// Linux kernel
11155 +#include <linux/config.h>
11156 +#include <linux/kernel.h>
11157 +#include <linux/version.h>
11158 +#include <linux/mm.h>
11159 +#include <linux/string.h>
11160 +#include <linux/slab.h>
11161 +
11162 +#define YCHAR char
11163 +#define YUCHAR unsigned char
11164 +#define _Y(x)     x
11165 +#define yaffs_strcpy(a,b)    strcpy(a,b)
11166 +#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
11167 +#define yaffs_strlen(s)             strlen(s)
11168 +#define yaffs_sprintf       sprintf
11169 +#define yaffs_toupper(a)     toupper(a)
11170 +
11171 +#define Y_INLINE inline
11172 +
11173 +#define YAFFS_LOSTNFOUND_NAME          "lost+found"
11174 +#define YAFFS_LOSTNFOUND_PREFIX                "obj"
11175 +
11176 +//#define YPRINTF(x) printk x
11177 +#define YMALLOC(x) kmalloc(x,GFP_KERNEL)
11178 +#define YFREE(x)   kfree(x)
11179 +
11180 +#define YAFFS_ROOT_MODE                                0666
11181 +#define YAFFS_LOSTNFOUND_MODE          0666
11182 +
11183 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
11184 +#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
11185 +#define Y_TIME_CONVERT(x) (x).tv_sec
11186 +#else
11187 +#define Y_CURRENT_TIME CURRENT_TIME
11188 +#define Y_TIME_CONVERT(x) (x)
11189 +#endif
11190 +
11191 +#define yaffs_SumCompare(x,y) ((x) == (y))
11192 +#define yaffs_strcmp(a,b) strcmp(a,b)
11193 +
11194 +#define TENDSTR "\n"
11195 +#define TSTR(x) KERN_WARNING x
11196 +#define TOUT(p) printk p
11197 +
11198 +
11199 +#elif defined CONFIG_YAFFS_DIRECT
11200 +
11201 +// Direct interface
11202 +#include "ydirectenv.h"
11203 +
11204 +#elif defined CONFIG_YAFFS_UTIL
11205 +
11206 +// Stuff for YAFFS utilities
11207 +
11208 +#include "stdlib.h"
11209 +#include "stdio.h"
11210 +#include "string.h"
11211 +
11212 +#include "devextras.h"
11213 +
11214 +#define YMALLOC(x) malloc(x)
11215 +#define YFREE(x)   free(x)
11216 +
11217 +
11218 +#define YCHAR char
11219 +#define YUCHAR unsigned char
11220 +#define _Y(x)     x
11221 +#define yaffs_strcpy(a,b)    strcpy(a,b)
11222 +#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
11223 +#define yaffs_strlen(s)             strlen(s)
11224 +#define yaffs_sprintf       sprintf
11225 +#define yaffs_toupper(a)     toupper(a)
11226 +
11227 +#define Y_INLINE inline
11228 +
11229 +//#define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s))
11230 +//#define YALERT(s) YINFO(s)
11231 +
11232 +
11233 +#define TENDSTR "\n"
11234 +#define TSTR(x) x
11235 +#define TOUT(p) printf p
11236 +
11237 +
11238 +#define YAFFS_LOSTNFOUND_NAME          "lost+found"
11239 +#define YAFFS_LOSTNFOUND_PREFIX                "obj"
11240 +//#define YPRINTF(x) printf x
11241 +
11242 +
11243 +#define YAFFS_ROOT_MODE                                0666
11244 +#define YAFFS_LOSTNFOUND_MODE          0666
11245 +
11246 +#define yaffs_SumCompare(x,y) ((x) == (y))
11247 +#define yaffs_strcmp(a,b) strcmp(a,b)
11248 +
11249 +#else
11250 +// Should have specified a configuration type
11251 +#error Unknown configuration
11252 +
11253 +#endif 
11254 +
11255 +
11256 +extern unsigned yaffs_traceMask;
11257 +
11258 +#define YAFFS_TRACE_ERROR              0x00000001
11259 +#define YAFFS_TRACE_OS                 0x00000002
11260 +#define YAFFS_TRACE_ALLOCATE           0x00000004
11261 +#define YAFFS_TRACE_SCAN               0x00000008
11262 +#define YAFFS_TRACE_BAD_BLOCKS         0x00000010
11263 +#define YAFFS_TRACE_ERASE              0x00000020
11264 +#define YAFFS_TRACE_GC                 0x00000040
11265 +#define YAFFS_TRACE_WRITE              0x00000080
11266 +#define YAFFS_TRACE_TRACING            0x00000100
11267 +#define YAFFS_TRACE_DELETION           0x00000200
11268 +#define YAFFS_TRACE_BUFFERS            0x00000400
11269 +#define YAFFS_TRACE_NANDACCESS         0x00000800
11270 +#define YAFFS_TRACE_GC_DETAIL          0x00001000
11271 +#define YAFFS_TRACE_SCAN_DEBUG         0x00002000
11272 +#define YAFFS_TRACE_MTD                        0x00004000
11273 +#define YAFFS_TRACE_ALWAYS             0x40000000
11274 +#define YAFFS_TRACE_BUG                        0x80000000
11275 +
11276 +#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ERROR)) TOUT(p);} while(0) 
11277 +
11278 +
11279 +#ifndef CONFIG_YAFFS_WINCE
11280 +#define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__))
11281 +#endif
11282 +
11283 +#endif
11284 +
11285 +
11286