Add NAND flash/YAFFS2 patches for RB532 by David Goodenough
[openwrt/svn-archive/archive.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