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)