1 diff --git a/fs/Kconfig b/fs/Kconfig
2 index f9b5842..556f12a 100644
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.
10 + tristate "Yet Another Flash File System (YAFFS) support"
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/>).
19 tristate "Journalling Flash File System (JFFS) support"
21 diff --git a/fs/Makefile b/fs/Makefile
22 index 078d3d1..2062d2f 100644
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
35 index 0000000..615c2b2
37 +++ b/fs/yaffs/Makefile
40 +# Makefile for the Linux msdos filesystem routines.
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).
46 +# Note 2! The CFLAGS definitions are now in the main makefile.
49 +EXTRA_CFLAGS += -DCONFIG_YAFFS_YAFFS1 -DCONFIG_YAFFS_YAFFS2
52 +obj-$(CONFIG_YAFFS_FS) += yaffs.o
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 \
57 diff --git a/fs/yaffs/devextras.h b/fs/yaffs/devextras.h
59 index 0000000..752c2cc
61 +++ b/fs/yaffs/devextras.h
64 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
67 + * Copyright (C) 2002 Aleph One Ltd.
68 + * for Toby Churchill Ltd and Brightstar Engineering
70 + * Created by Charles Manning <charles@aleph1.co.uk>
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.
76 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
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
82 + * $Id: devextras.h,v 1.1 2004/11/03 08:14:07 charles Exp $
90 +#define __inline__ __inline
94 +#if !(defined __KERNEL__) || (defined WIN32)
96 +// User space defines
98 +typedef unsigned char __u8;
99 +typedef unsigned short __u16;
100 +typedef unsigned __u32;
104 + * Simple doubly linked list implementation.
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.
113 + #define prefetch(x) 1
117 + struct list_head *next, *prev;
120 +#define LIST_HEAD_INIT(name) { &(name), &(name) }
122 +#define LIST_HEAD(name) \
123 + struct list_head name = LIST_HEAD_INIT(name)
125 +#define INIT_LIST_HEAD(ptr) do { \
126 + (ptr)->next = (ptr); (ptr)->prev = (ptr); \
130 + * Insert a new entry between two known consecutive entries.
132 + * This is only for internal list manipulation where we know
133 + * the prev/next entries already!
135 +static __inline__ void __list_add(struct list_head * new,
136 + struct list_head * prev,
137 + struct list_head * next)
146 + * list_add - add a new entry
147 + * @new: new entry to be added
148 + * @head: list head to add it after
150 + * Insert a new entry after the specified head.
151 + * This is good for implementing stacks.
153 +static __inline__ void list_add(struct list_head *new, struct list_head *head)
155 + __list_add(new, head, head->next);
159 + * list_add_tail - add a new entry
160 + * @new: new entry to be added
161 + * @head: list head to add it before
163 + * Insert a new entry before the specified head.
164 + * This is useful for implementing queues.
166 +static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
168 + __list_add(new, head->prev, head);
172 + * Delete a list entry by making the prev/next entries
173 + * point to each other.
175 + * This is only for internal list manipulation where we know
176 + * the prev/next entries already!
178 +static __inline__ void __list_del(struct list_head * prev,
179 + struct list_head * next)
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.
190 +static __inline__ void list_del(struct list_head *entry)
192 + __list_del(entry->prev, entry->next);
196 + * list_del_init - deletes entry from list and reinitialize it.
197 + * @entry: the element to delete from the list.
199 +static __inline__ void list_del_init(struct list_head *entry)
201 + __list_del(entry->prev, entry->next);
202 + INIT_LIST_HEAD(entry);
206 + * list_empty - tests whether a list is empty
207 + * @head: the list to test.
209 +static __inline__ int list_empty(struct list_head *head)
211 + return head->next == head;
215 + * list_splice - join two lists
216 + * @list: the new list to add.
217 + * @head: the place to add it in the first list.
219 +static __inline__ void list_splice(struct list_head *list, struct list_head *head)
221 + struct list_head *first = list->next;
223 + if (first != list) {
224 + struct list_head *last = list->prev;
225 + struct list_head *at = head->next;
227 + first->prev = head;
228 + head->next = first;
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.
241 +#define list_entry(ptr, type, member) \
242 + ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
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.
249 +#define list_for_each(pos, head) \
250 + for (pos = (head)->next, prefetch(pos->next); pos != (head); \
251 + pos = pos->next, prefetch(pos->next))
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.
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)
269 +#define DT_UNKNOWN 0
280 +#include <sys/stat.h>
284 + * Attribute flags. These should be or-ed together to figure out what
285 + * has been changed!
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
301 + unsigned int ia_valid;
309 + unsigned int ia_attr_flags;
318 +#include <linux/types.h>
319 +#include <linux/list.h>
320 +#include <linux/fs.h>
321 +#include <linux/stat.h>
334 diff --git a/fs/yaffs/yaffs_ecc.c b/fs/yaffs/yaffs_ecc.c
336 index 0000000..166bcad
338 +++ b/fs/yaffs/yaffs_ecc.c
341 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
343 + * yaffs_ecc.c: ECC generation/correction algorithms.
345 + * Copyright (C) 2002 Aleph One Ltd.
347 + * Created by Charles Manning <charles@aleph1.co.uk>
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.
356 + * This code implements the ECC algorithm used in SmartMedia.
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.
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.
371 +const char *yaffs_ecc_c_version = "$Id: yaffs_ecc.c,v 1.4 2005/07/31 00:28:04 charles Exp $";
373 +#include "yportenv.h"
375 +#include "yaffs_ecc.h"
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,
397 +static int yaffs_CountBits(unsigned char x)
408 +static int yaffs_CountBits32(unsigned x)
420 +void yaffs_ECCCalculate(const unsigned char *data,unsigned char *ecc)
424 + unsigned char col_parity = 0;
425 + unsigned char line_parity = 0;
426 + unsigned char line_parity_prime = 0;
430 + for(i = 0; i < 256; i++)
432 + b = column_parity_table[*data++];
435 + if(b & 0x01) // odd number of bits in the byte
438 + line_parity_prime ^= ~i;
443 + ecc[2] = (~col_parity) | 0x03;
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;
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;
467 +#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
468 + // Swap the bytes into the wrong order
475 +int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc, const unsigned char *test_ecc)
477 + unsigned char d0, d1, d2; // deltas
479 + d0 = read_ecc[0] ^ test_ecc[0];
480 + d1 = read_ecc[1] ^ test_ecc[1];
481 + d2 = read_ecc[2] ^ test_ecc[2];
485 + if((d0 | d1 | d2) == 0)
491 + if( ((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
492 + ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
493 + ((d2 ^ (d2 >> 1)) & 0x54) == 0x54)
495 + // Single bit (recoverable) error in data
500 +#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
501 + // swap the bytes to correct for the wrong order
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;
521 + if(d2 & 0x80) bit |= 0x04;
522 + if(d2 & 0x20) bit |= 0x02;
523 + if(d2 & 0x08) bit |= 0x01;
525 + data[byte] ^= (1 << bit);
530 + if((yaffs_CountBits(d0)+yaffs_CountBits(d1)+yaffs_CountBits(d2)) == 1)
532 + // Reccoverable error in ecc
534 + read_ecc[0] = test_ecc[0];
535 + read_ecc[1] = test_ecc[1];
536 + read_ecc[2] = test_ecc[2];
541 + // Unrecoverable error
550 +void yaffs_ECCCalculateOther(const unsigned char *data,unsigned nBytes, yaffs_ECCOther *eccOther)
554 + unsigned char col_parity = 0;
555 + unsigned line_parity = 0;
556 + unsigned line_parity_prime = 0;
559 + for(i = 0; i < nBytes; i++)
561 + b = column_parity_table[*data++];
564 + if(b & 0x01) // odd number of bits in the byte
567 + line_parity_prime ^= ~i;
572 + eccOther->colParity = (col_parity >> 2) & 0x3f;
573 + eccOther->lineParity = line_parity;
574 + eccOther->lineParityPrime = line_parity_prime;
577 +int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes, yaffs_ECCOther *read_ecc, const yaffs_ECCOther *test_ecc)
579 + unsigned char cDelta; // column parity delta
580 + unsigned lDelta; // line parity delta
581 + unsigned lDeltaPrime; // line parity delta
584 + cDelta = read_ecc->colParity ^ test_ecc->colParity;
585 + lDelta = read_ecc->lineParity ^ test_ecc->lineParity;
586 + lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime;
588 + if((cDelta | lDelta | lDeltaPrime) == 0)
594 + if( lDelta == ~lDeltaPrime &&
595 + (((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15)) // Not correct
597 + // Single bit (recoverable) error in data
601 + if(cDelta & 0x20) bit |= 0x04;
602 + if(cDelta & 0x08) bit |= 0x02;
603 + if(cDelta & 0x02) bit |= 0x01;
605 + data[lDelta] ^= (1 << bit);
610 + if((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) + yaffs_CountBits(cDelta)) == 1)
612 + // Reccoverable error in ecc
614 + *read_ecc = *test_ecc;
618 + // Unrecoverable error
627 diff --git a/fs/yaffs/yaffs_ecc.h b/fs/yaffs/yaffs_ecc.h
629 index 0000000..f96d707
631 +++ b/fs/yaffs/yaffs_ecc.h
634 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
636 + * yaffs_ecc.c: ECC generation/correction algorithms.
638 + * Copyright (C) 2002 Aleph One Ltd.
640 + * Created by Charles Manning <charles@aleph1.co.uk>
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.
649 + * This code implements the ECC algorithm used in SmartMedia.
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.
658 +#ifndef __YAFFS_ECC_H__
659 +#define __YAFFS_ECC_H__
663 + unsigned char colParity;
664 + unsigned lineParity;
665 + unsigned lineParityPrime;
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);
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);
674 diff --git a/fs/yaffs/yaffs_fs.c b/fs/yaffs/yaffs_fs.c
676 index 0000000..717f41a
678 +++ b/fs/yaffs/yaffs_fs.c
681 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
684 + * Copyright (C) 2002 Aleph One Ltd.
685 + * for Toby Churchill Ltd and Brightstar Engineering
687 + * Created by Charles Manning <charles@aleph1.co.uk>
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.
693 + * This is the file system front-end to YAFFS that hooks it up to
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.
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.
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;
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>
732 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
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 ?
742 +#include <linux/locks.h>
743 +#define BDEVNAME_SIZE 0
744 +#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
748 +#include <asm/uaccess.h>
750 +#include "yportenv.h"
751 +#include "yaffs_guts.h"
756 +unsigned yaffs_traceMask = YAFFS_TRACE_ALWAYS | YAFFS_TRACE_BAD_BLOCKS;
757 +//unsigned yaffs_traceMask = 0xFFFFFFFF;
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
766 +//#define T(x) printk x
770 +#define yaffs_InodeToObject(iptr) ((yaffs_Object *)((iptr)->u.generic_ip))
771 +#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
773 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
774 +#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
776 +#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
780 +static void yaffs_put_super(struct super_block *sb);
782 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, loff_t *pos);
784 +static int yaffs_file_flush(struct file* file);
786 +static int yaffs_sync_object(struct file * file, struct dentry *dentry, int datasync);
788 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
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);
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);
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);
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);
805 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev);
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);
810 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
811 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
813 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
815 +static void yaffs_read_inode (struct inode *inode);
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 *);
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);
825 +static int yaffs_writepage(struct page *page);
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);
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);
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,
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,
850 +static struct inode_operations yaffs_file_inode_operations = {
851 + .setattr = yaffs_setattr,
854 +static struct inode_operations yaffs_symlink_inode_operations = {
855 + .readlink = yaffs_readlink,
856 + .follow_link = yaffs_follow_link,
857 + .setattr = yaffs_setattr,
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,
873 +static struct file_operations yaffs_dir_operations = {
874 + .read = generic_read_dir,
875 + .readdir = yaffs_readdir,
876 + .fsync = yaffs_sync_object,
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,
890 +static void yaffs_GrossLock(yaffs_Device *dev)
892 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs locking\n"));
894 + down(&dev->grossLock);
897 +static void yaffs_GrossUnlock(yaffs_Device *dev)
899 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs unlocking\n"));
900 + up(&dev->grossLock);
904 +static int yaffs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
906 + unsigned char *alias;
909 + yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
912 + yaffs_GrossLock(dev);
914 + alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
916 + yaffs_GrossUnlock(dev);
921 + ret = vfs_readlink(dentry, buffer, buflen, alias);
926 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
928 + unsigned char *alias;
930 + yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
933 + yaffs_GrossLock(dev);
935 + alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
937 + yaffs_GrossUnlock(dev);
942 + ret = vfs_follow_link(nd,alias);
945 + return ERR_PTR (ret);
949 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,yaffs_Object *obj);
952 + * Lookup is used to find objects in the fs
954 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
956 +static struct dentry * yaffs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *n)
958 +static struct dentry * yaffs_lookup(struct inode *dir, struct dentry *dentry)
962 + struct inode *inode = NULL; // NCB 2.5/2.6 needs NULL here
964 + yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
967 + yaffs_GrossLock(dev);
970 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_lookup for %d:%s\n",yaffs_InodeToObject(dir)->objectId,dentry->d_name.name));
972 + obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir),dentry->d_name.name);
974 + obj = yaffs_GetEquivalentObject(obj); // in case it was a hardlink
980 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_lookup found %d\n",obj->objectId));
982 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode,0,obj);
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 */
989 + //dget(dentry); // try to solve directory bug
990 + d_add(dentry,inode);
992 + yaffs_GrossUnlock(dev);
1002 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_lookup not found\n"));
1005 + yaffs_GrossUnlock(dev);
1007 +/* added NCB for 2.5/6 compatability - forces add even if inode is NULL which creates dentry hash*/
1008 + d_add(dentry,inode);
1011 + // return (ERR_PTR(-EIO));
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)
1019 + T(YAFFS_TRACE_OS,("yaffs_put_inode: ino %d, count %d\n",(int)inode->i_ino, atomic_read(&inode->i_count)));
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)
1026 + yaffs_Object *obj;
1027 + yaffs_Device *dev;
1029 + obj = yaffs_InodeToObject(inode);
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"));
1037 + yaffs_GrossLock(dev);
1039 + // Clear the association between the inode ant the yaffs_Object.
1040 + obj->myInode = NULL;
1041 + inode->u.generic_ip = NULL;
1043 + // If the object freeing was deferred, then the real free happens now.
1044 + // This should fix the inode inconsistency problem.
1046 + yaffs_HandleDeferedFree(obj);
1048 + yaffs_GrossUnlock(dev);
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)
1060 + yaffs_Object *obj = yaffs_InodeToObject(inode);
1061 + yaffs_Device *dev;
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"));
1069 + yaffs_GrossLock(dev);
1070 + yaffs_DeleteFile(obj);
1071 + yaffs_GrossUnlock(dev);
1073 + clear_inode(inode);
1077 +static int yaffs_file_flush(struct file* file)
1079 + yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
1081 + yaffs_Device *dev = obj->myDev;
1083 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_file_flush object %d (%s)\n",obj->objectId,
1084 + obj->dirty ? "dirty" : "clean"));
1086 + yaffs_GrossLock(dev);
1088 + yaffs_FlushFile(obj,1);
1090 + yaffs_GrossUnlock(dev);
1097 +static int yaffs_readpage_nolock(struct file *f, struct page * pg)
1099 + // Lifted from jffs2
1101 + yaffs_Object *obj;
1102 + unsigned char *pg_buf;
1105 + yaffs_Device *dev;
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));
1110 + obj = yaffs_DentryToObject(f->f_dentry);
1115 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1116 + BUG_ON(!PageLocked(pg));
1118 + if (!PageLocked(pg))
1122 + pg_buf = kmap(pg);
1123 + /* FIXME: Can kmap fail? */
1125 + yaffs_GrossLock(dev);
1127 + ret = yaffs_ReadDataFromFile(obj, pg_buf, pg->index << PAGE_CACHE_SHIFT, PAGE_CACHE_SIZE);
1129 + yaffs_GrossUnlock(dev);
1131 + if(ret >= 0) ret = 0;
1134 + ClearPageUptodate(pg);
1137 + SetPageUptodate(pg);
1138 + ClearPageError(pg);
1141 + flush_dcache_page(pg);
1145 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_readpage done\n"));
1149 +static int yaffs_readpage_unlock(struct file *f, struct page *pg)
1151 + int ret = yaffs_readpage_nolock(f,pg);
1156 +static int yaffs_readpage(struct file *f, struct page * pg)
1158 + return yaffs_readpage_unlock(f,pg);
1161 +// writepage inspired by/stolen from smbfs
1164 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1165 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
1167 +static int yaffs_writepage(struct page *page)
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;
1175 + yaffs_Object *obj;
1181 + inode = mapping->host;
1185 + if (offset > inode->i_size)
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);
1193 + end_index = inode->i_size >> PAGE_CACHE_SHIFT;
1196 + if (page->index < end_index)
1198 + nBytes = PAGE_CACHE_SIZE;
1202 + nBytes = inode->i_size & (PAGE_CACHE_SIZE-1);
1204 + // What's happening here?
1205 + ///* OK, are we completely out? */
1206 + //if (page->index >= end_index+1 || !offset)
1212 + buffer = kmap(page);
1214 + obj = yaffs_InodeToObject(inode);
1215 + yaffs_GrossLock(obj->myDev);
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));
1220 + nWritten = yaffs_WriteDataToFile(obj,buffer,page->index << PAGE_CACHE_SHIFT,nBytes,0);
1222 + T(YAFFS_TRACE_OS,(KERN_DEBUG"writepag1: obj = %05x, ino = %05x\n", (int) obj->variant.fileVariant.fileSize, (int) inode->i_size));
1224 + yaffs_GrossUnlock(obj->myDev);
1227 + SetPageUptodate(page);
1231 + return (nWritten == nBytes) ? 0 : -ENOSPC;
1236 +static int yaffs_prepare_write(struct file *f, struct page *pg, unsigned offset, unsigned to)
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);
1247 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, unsigned to)
1250 + void *addr = page_address(pg) + offset;
1251 + loff_t pos = (((loff_t)pg->index) << PAGE_CACHE_SHIFT) + offset;
1252 + int nBytes = to - offset;
1255 + unsigned spos = pos;
1256 + unsigned saddr = (unsigned)addr;
1258 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_commit_write addr %x pos %x nBytes %d\n",saddr,spos,nBytes));
1260 + nWritten = yaffs_file_write(f,addr, nBytes, &pos);
1262 + if(nWritten != nBytes)
1264 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_commit_write not same size nWritten %d nBytes %d\n",nWritten,nBytes));
1266 + ClearPageUptodate(pg);
1270 + SetPageUptodate(pg);
1273 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_commit_write returning %d\n",nWritten));
1281 +static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
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))
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;
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;
1305 + inode->i_size = yaffs_GetObjectFileLength(obj);
1306 + inode->i_blocks = (inode->i_size + 511) >> 9;
1308 + inode->i_nlink = yaffs_GetObjectLinkCount(obj);
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)));
1313 + switch (obj->yst_mode & S_IFMT)
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));
1319 + init_special_inode(inode, obj->yst_mode,(dev_t)(obj->yst_rdev));
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;
1327 + case S_IFDIR: // directory
1328 + inode->i_op = &yaffs_dir_inode_operations;
1329 + inode->i_fop = &yaffs_dir_operations;
1331 + case S_IFLNK: // symlink
1332 + inode->i_op = &yaffs_symlink_inode_operations;
1337 + inode->u.generic_ip = obj;
1338 + obj->myInode = inode;
1343 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_FileInode invalid parameters\n"));
1348 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,yaffs_Object *obj)
1350 + struct inode * inode;
1354 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_get_inode for NULL super_block!!\n"));
1361 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_get_inode for NULL object!!\n"));
1366 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_get_inode for object %d\n",obj->objectId));
1368 + inode = iget(sb,obj->objectId);
1370 + // NB Side effect: iget calls back to yaffs_read_inode().
1371 + // iget also increments the inode's i_count
1376 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, loff_t *pos)
1378 + yaffs_Object *obj;
1379 + int nWritten,ipos;
1380 + struct inode *inode;
1381 + yaffs_Device *dev;
1384 + obj = yaffs_DentryToObject(f->f_dentry);
1388 + yaffs_GrossLock(dev);
1390 + inode = f->f_dentry->d_inode;
1392 + if(!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
1394 + ipos = inode->i_size;
1404 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_file_write: hey obj is null!\n"));
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));
1411 + nWritten = yaffs_WriteDataToFile(obj,buf,ipos,n,0);
1413 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_file_write writing %d bytes, %d written at %d\n",n,nWritten,ipos));
1418 + if(ipos > inode->i_size)
1420 + inode->i_size = ipos;
1421 + inode->i_blocks = (ipos + 511)>>9;
1423 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_file_write size updated to %d bytes, %d blocks\n",ipos,(int)(inode->i_blocks)));
1427 + yaffs_GrossUnlock(dev);
1429 + return nWritten != n ? -ENOSPC : nWritten;
1434 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
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;
1443 + char name[YAFFS_MAX_NAME_LENGTH +1];
1445 + obj = yaffs_DentryToObject(f->f_dentry);
1448 + yaffs_GrossLock(dev);
1450 + offset = f->f_pos;
1452 + T(YAFFS_TRACE_OS,("yaffs_readdir: starting at %d\n",(int)offset));
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)
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)
1477 + list_for_each(i,&obj->variant.directoryVariant.children)
1480 + if(curoffs >= offset)
1482 + l = list_entry(i, yaffs_Object,siblings);
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)));
1487 + if(filldir(dirent,
1491 + yaffs_GetObjectInode(l),
1492 + yaffs_GetObjectType(l))
1506 + yaffs_GrossUnlock(dev);
1513 + * File creation. Allocate an inode, and we're done..
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)
1518 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
1521 + struct inode *inode;
1523 + yaffs_Object *obj = NULL;
1524 + yaffs_Device *dev;
1526 + yaffs_Object *parent = yaffs_InodeToObject(dir);
1528 + int error = -ENOSPC;
1529 + uid_t uid = current->fsuid;
1530 + gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
1534 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_mknod: parent object %d type %d\n",
1535 + parent->objectId,parent->variantType));
1539 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_mknod: could not get parent object\n"));
1543 + T(YAFFS_TRACE_OS,("yaffs_mknod: making oject for %s, mode %x dev %x\n",
1544 + dentry->d_name.name, mode,rdev));
1546 + dev = parent->myDev;
1548 + yaffs_GrossLock(dev);
1550 + switch (mode & S_IFMT)
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));
1558 + obj = yaffs_MknodSpecial(parent,dentry->d_name.name,mode,uid, gid,rdev);
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);
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);
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?
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)));
1584 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_mknod failed making object\n"));
1588 + yaffs_GrossUnlock(dev);
1593 +static int yaffs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
1596 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_mkdir\n"));
1597 + retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
1599 + // attempt to fix dir bug - didn't work
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)
1611 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
1614 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_create\n"));
1615 + return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
1619 +static int yaffs_unlink(struct inode * dir, struct dentry *dentry)
1623 + yaffs_Device *dev;
1626 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_unlink %d:%s\n",(int)(dir->i_ino),dentry->d_name.name));
1628 + dev = yaffs_InodeToObject(dir)->myDev;
1630 + yaffs_GrossLock(dev);
1633 + retVal = yaffs_Unlink(yaffs_InodeToObject(dir),dentry->d_name.name);
1636 + yaffs_GrossUnlock(dev);
1638 + if( retVal == YAFFS_OK)
1640 + dentry->d_inode->i_nlink--;
1641 + mark_inode_dirty(dentry->d_inode);
1646 + return -ENOTEMPTY;
1652 + * Create a link...
1654 +static int yaffs_link(struct dentry *old_dentry, struct inode * dir, struct dentry * dentry)
1656 + struct inode *inode = old_dentry->d_inode;
1657 + yaffs_Object *obj = NULL;
1658 + yaffs_Object *link=NULL;
1659 + yaffs_Device *dev;
1661 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_link\n"));
1663 + obj = yaffs_InodeToObject(inode);
1666 + yaffs_GrossLock(dev);
1668 + if (!S_ISDIR(inode->i_mode)) // Don't link directories
1670 + link = yaffs_Link(yaffs_InodeToObject(dir),dentry->d_name.name,obj);
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)));
1684 + yaffs_GrossUnlock(dev);
1698 +static int yaffs_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
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;
1705 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_symlink\n"));
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,
1712 + yaffs_GrossUnlock(dev);
1717 + struct inode* inode;
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"));
1726 + T(YAFFS_TRACE_OS,(KERN_DEBUG"symlink not created\n"));
1733 +static int yaffs_sync_object(struct file * file, struct dentry *dentry, int datasync)
1736 + yaffs_Object *obj;
1737 + yaffs_Device *dev;
1739 + obj = yaffs_DentryToObject(dentry);
1743 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_sync_object\n"));
1744 + yaffs_GrossLock(dev);
1745 + yaffs_FlushFile(obj,1);
1746 + yaffs_GrossUnlock(dev);
1751 + * The VFS layer already does all the dentry stuff for rename.
1753 + * NB: POSIX says you can rename an object over an old object of the same name
1755 +static int yaffs_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir,struct dentry *new_dentry)
1757 + yaffs_Device *dev;
1758 + int retVal = YAFFS_FAIL;
1760 + yaffs_Object *target;
1762 + dev = yaffs_InodeToObject(old_dir)->myDev;
1764 + yaffs_GrossLock(dev);
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);
1770 + target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
1771 + !list_empty(&target->variant.directoryVariant.children))
1773 + retVal = YAFFS_FAIL;
1778 + // Unlink the target if it exists
1779 + removed = yaffs_Unlink(yaffs_InodeToObject(new_dir),new_dentry->d_name.name);
1782 + retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir),old_dentry->d_name.name,
1783 + yaffs_InodeToObject(new_dir),new_dentry->d_name.name);
1786 + yaffs_GrossUnlock(dev);
1788 + if(retVal == YAFFS_OK)
1790 + if(removed == YAFFS_OK)
1792 + new_dentry->d_inode->i_nlink--;
1793 + mark_inode_dirty(new_dentry->d_inode);
1800 + return -ENOTEMPTY;
1806 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
1808 + struct inode *inode = dentry->d_inode;
1810 + yaffs_Device *dev;
1812 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_setattr of object %d\n",yaffs_InodeToObject(inode)->objectId));
1814 + if((error = inode_change_ok(inode,attr)) == 0)
1817 + dev = yaffs_InodeToObject(inode)->myDev;
1818 + yaffs_GrossLock(dev);
1819 + if(yaffs_SetAttributes(yaffs_InodeToObject(inode),attr) == YAFFS_OK)
1827 + yaffs_GrossUnlock(dev);
1829 + error = inode_setattr(inode,attr);
1834 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1835 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
1837 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
1842 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
1843 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_statfs\n"));
1845 + yaffs_GrossLock(dev);
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)
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);
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);
1869 + buf->f_bavail = buf->f_bfree;
1871 + yaffs_GrossUnlock(dev);
1875 +static void yaffs_read_inode (struct inode *inode)
1877 + // NB This is called as a side effect of other functions and
1878 + // thus gross locking should always be in place already.
1880 + yaffs_Object *obj ;
1881 + yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
1883 + T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_read_inode for %d\n",(int)inode->i_ino));
1885 + obj = yaffs_FindObjectByNumber(dev,inode->i_ino);
1887 + yaffs_FillInodeFromObject(inode,obj);
1891 +static LIST_HEAD(yaffs_dev_list);
1893 +static void yaffs_put_super(struct super_block *sb)
1895 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
1897 + yaffs_GrossLock(dev);
1898 + if(dev->putSuperFunc)
1900 + dev->putSuperFunc(sb);
1902 + yaffs_Deinitialise(dev);
1903 + yaffs_GrossUnlock(dev);
1905 + /* we assume this is protected by lock_kernel() in mount/umount */
1906 + list_del(&dev->devList);
1912 +#ifdef CONFIG_YAFFS_YAFFS1
1914 +static void yaffs_MTDPutSuper(struct super_block *sb)
1917 + struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
1924 + put_mtd_device(mtd);
1930 +static struct super_block *yaffs_internal_read_super(int yaffsVersion, struct super_block * sb, void * data, int silent)
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;
1940 + sb->s_magic = YAFFS_MAGIC;
1941 + sb->s_op = &yaffs_super_ops;
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");
1950 + printk(KERN_INFO"yaffs: dev is %d name is \"%s\"\n", sb->s_dev, yaffs_devname(sb, devname_buf));
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)));
1959 +#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
1960 + T(YAFFS_TRACE_OS,("yaffs: Write verification disabled. All guarantees null and void\n"));
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)));
1967 + // Check it's an mtd device.....
1968 + if(MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
1970 + return NULL; // This isn't an mtd device
1974 + mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
1977 + T(YAFFS_TRACE_ALWAYS,("yaffs: MTD device #%u doesn't appear to exist\n", MINOR(sb->s_dev)));
1981 + // Check it's NAND
1982 + if(mtd->type != MTD_NANDFLASH)
1984 + T(YAFFS_TRACE_ALWAYS,("yaffs: MTD device is not NAND it's type %d\n", mtd->type));
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));
2000 + if(yaffsVersion == 2)
2002 + // Check for version 2 style functions
2004 +// !mtd->block_isbad ||
2005 +// !mtd->block_markbad ||
2008 + !mtd->write_ecc ||
2013 + T(YAFFS_TRACE_ALWAYS,("yaffs: MTD device does not support required functions\n"));;
2017 + if(mtd->oobblock < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
2018 + mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE)
2020 + T(YAFFS_TRACE_ALWAYS,("yaffs: MTD device does not support have the right page sizes\n"));
2025 + // Check for V1 style functions
2029 + !mtd->write_ecc ||
2034 + T(YAFFS_TRACE_ALWAYS,("yaffs: MTD device does not support required functions\n"));;
2038 + if(mtd->oobblock != YAFFS_BYTES_PER_CHUNK ||
2039 + mtd->oobsize != YAFFS_BYTES_PER_SPARE)
2041 + T(YAFFS_TRACE_ALWAYS,("yaffs: MTD device does not support have the right page sizes\n"));
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
2051 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
2052 + sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device),GFP_KERNEL);
2054 + sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device),GFP_KERNEL);
2058 + // Deep shit could not allocate device structure
2059 + T(YAFFS_TRACE_ALWAYS,("yaffs_read_super: Failed trying to allocate yaffs_Device. \n"));
2063 + memset(dev,0,sizeof(yaffs_Device));
2064 + dev->genericDevice = mtd;
2065 + dev->name = mtd->name;
2067 + // Set up the memory size parameters....
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
2078 + // ... and the functions.
2079 + if(yaffsVersion == 2)
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;
2095 + dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
2096 + dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
2097 + dev->isYaffs2 = 0;
2099 + // ... and common functions
2100 + dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
2101 + dev->initialiseNAND = nandmtd_InitialiseNAND;
2103 + dev->putSuperFunc = yaffs_MTDPutSuper;
2105 +#ifndef CONFIG_YAFFS_DOES_ECC
2106 + dev->useNANDECC = 1;
2109 + /* we assume this is protected by lock_kernel() in mount/umount */
2110 + list_add_tail(&dev->devList, &yaffs_dev_list);
2112 + init_MUTEX(&dev->grossLock);
2115 + yaffs_GrossLock(dev);
2117 + err = yaffs_GutsInitialise(dev);
2119 + T(YAFFS_TRACE_OS,("yaffs_read_super: guts initialised %s\n", (err == YAFFS_OK) ? "OK" : "FAILED"));
2121 + // Create root inode
2122 + if(err == YAFFS_OK)
2123 + inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,yaffs_Root(dev));
2125 + yaffs_GrossUnlock(dev);
2131 + inode->i_op = & yaffs_dir_inode_operations;
2132 + inode->i_fop = & yaffs_dir_operations;
2134 + T(YAFFS_TRACE_OS,("yaffs_read_super: got root inode\n"));
2137 + root = d_alloc_root(inode);
2139 + T(YAFFS_TRACE_OS,("yaffs_read_super: d_alloc_root done\n"));
2145 + sb->s_root = root;
2147 + T(YAFFS_TRACE_OS,("yaffs_read_super: done\n"));
2153 +#ifdef CONFIG_YAFFS_YAFFS1
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)
2158 + return yaffs_internal_read_super(1,sb,data,silent) ? 0 : -1;
2161 +static struct super_block *yaffs_read_super(struct file_system_type * fs, int flags, const char *dev_name, void *data)
2164 + return get_sb_bdev(fs, flags, dev_name, data, yaffs_internal_read_super_mtd);
2167 +static struct file_system_type yaffs_fs_type = {
2168 + .owner = THIS_MODULE,
2170 + .get_sb = yaffs_read_super,
2171 + .kill_sb = kill_block_super,
2172 + .fs_flags = FS_REQUIRES_DEV,
2175 +static struct super_block *yaffs_read_super(struct super_block * sb, void * data, int silent)
2177 + return yaffs_internal_read_super(1,sb,data,silent);
2180 +static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super, FS_REQUIRES_DEV);
2183 +#endif // CONFIG_YAFFS_YAFFS1
2185 +#ifdef CONFIG_YAFFS_YAFFS2
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)
2190 + return yaffs_internal_read_super(2,sb,data,silent) ? 0 : -1;
2193 +static struct super_block *yaffs2_read_super(struct file_system_type * fs, int flags, const char *dev_name, void *data)
2196 + return get_sb_bdev(fs, flags, dev_name, data, yaffs2_internal_read_super_mtd);
2199 +static struct file_system_type yaffs2_fs_type = {
2200 + .owner = THIS_MODULE,
2202 + .get_sb = yaffs2_read_super,
2203 + .kill_sb = kill_block_super,
2204 + .fs_flags = FS_REQUIRES_DEV,
2207 +static struct super_block *yaffs2_read_super(struct super_block * sb, void * data, int silent)
2209 + return yaffs_internal_read_super(2,sb,data,silent);
2212 +static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super, FS_REQUIRES_DEV);
2215 +#endif // CONFIG_YAFFS_YAFFS2
2220 +static struct proc_dir_entry *my_proc_entry;
2222 +static char * yaffs_dump_dev(char *buf,yaffs_Device *dev)
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);
2256 +static int yaffs_proc_read(
2265 + struct list_head *item;
2267 + int step = offset;
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.
2276 + *(int *)start = 1;
2278 + /* Print header first */
2280 + buf += sprintf(buf, "YAFFS built:" __DATE__ " "__TIME__
2281 + "\n%s\n%s\n", yaffs_fs_c_version, yaffs_guts_c_version);
2284 + /* hold lock_kernel while traversing yaffs_dev_list */
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);
2294 + buf += sprintf(buf,"\nDevice %d \"%s\"\n", n, dev->name);
2295 + buf = yaffs_dump_dev(buf, dev);
2300 + return buf-page < count ? buf-page : count;
2303 +// Stuff to handle installation of file systems
2304 +struct file_system_to_install
2306 + struct file_system_type *fst;
2310 +static struct file_system_to_install fs_to_install[] =
2312 +#ifdef CONFIG_YAFFS_YAFFS1
2313 + { &yaffs_fs_type,0},
2315 +#ifdef CONFIG_YAFFS_YAFFS2
2316 + { &yaffs2_fs_type,0},
2321 +static int __init init_yaffs_fs(void)
2324 + struct file_system_to_install *fsinst;
2326 + T(YAFFS_TRACE_ALWAYS,("yaffs " __DATE__ " " __TIME__ " Installing. \n"));
2330 + /* Install the proc_fs entry */
2331 + my_proc_entry = create_proc_read_entry("yaffs",
2332 + S_IRUGO | S_IFREG,
2336 + if(!my_proc_entry)
2343 + // Now add the file system entries
2345 + fsinst = fs_to_install;
2347 + while(fsinst->fst && !error)
2349 + error = register_filesystem(fsinst->fst);
2352 + fsinst->installed = 1;
2357 + // Any errors? uninstall
2360 + fsinst = fs_to_install;
2362 + while(fsinst->fst)
2364 + if(fsinst->installed)
2366 + unregister_filesystem(fsinst->fst);
2367 + fsinst->installed = 0;
2376 +static void __exit exit_yaffs_fs(void)
2379 + struct file_system_to_install *fsinst;
2381 + T(YAFFS_TRACE_ALWAYS,("yaffs " __DATE__ " " __TIME__ " removing. \n"));
2383 + remove_proc_entry("yaffs",&proc_root);
2385 + fsinst = fs_to_install;
2387 + while(fsinst->fst)
2389 + if(fsinst->installed)
2391 + unregister_filesystem(fsinst->fst);
2392 + fsinst->installed = 0;
2399 +module_init(init_yaffs_fs)
2400 +module_exit(exit_yaffs_fs)
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");
2407 diff --git a/fs/yaffs/yaffs_guts.c b/fs/yaffs/yaffs_guts.c
2408 new file mode 100644
2409 index 0000000..bf13f91
2411 +++ b/fs/yaffs/yaffs_guts.c
2414 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
2416 + * Copyright (C) 2002 Aleph One Ltd.
2417 + * for Toby Churchill Ltd and Brightstar Engineering
2419 + * Created by Charles Manning <charles@aleph1.co.uk>
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.
2428 +const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.15 2005/08/02 04:24:22 charles Exp $";
2430 +#include "yportenv.h"
2432 +#include "yaffsinterface.h"
2433 +#include "yaffs_guts.h"
2434 +#include "yaffs_tagsvalidity.h"
2437 +#include "yaffs_tagscompat.h"
2439 +#ifdef CONFIG_YAFFS_WINCE
2440 +void yfsd_LockYAFFS(BOOL fsLockOnly);
2441 +void yfsd_UnlockYAFFS(BOOL fsLockOnly);
2444 +#define YAFFS_PASSIVE_GC_CHUNKS 2
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)
2454 +#include "yaffs_ecc.h"
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.
2461 +static const char yaffs_countBitsTable[256] =
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
2481 +static int yaffs_CountBits(__u8 x)
2484 + retVal = yaffs_countBitsTable[x];
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);
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);
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);
2511 +static int yaffs_CheckObjectHashSanity(yaffs_Device *dev);
2513 +static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan);
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);
2523 +static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev,int blockNo);
2525 +static __u8 *yaffs_GetTempBuffer(yaffs_Device *dev,int lineNo);
2526 +static void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo);
2529 +// Robustification (if it ever comes about...)
2530 +static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND);
2532 +static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND);
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);
2538 +static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND);
2540 +static int yaffs_UnlinkWorker(yaffs_Object *obj);
2541 +static void yaffs_DestroyObject(yaffs_Object *obj);
2544 +static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1,int dataSize);
2547 +static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, int chunkInObject);
2550 +loff_t yaffs_GetFileSize(yaffs_Object *obj);
2553 +static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve);
2555 +static void yaffs_VerifyFreeChunks(yaffs_Device *dev);
2557 +#ifdef YAFFS_PARANOID
2558 +static int yaffs_CheckFileSanity(yaffs_Object *in);
2560 +#define yaffs_CheckFileSanity(in)
2563 +static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);
2564 +static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
2566 +static int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *buffer, yaffs_ExtendedTags *tags)
2568 + chunkInNAND -= dev->chunkOffset;
2570 + if(dev->readChunkWithTagsFromNAND)
2571 + return dev->readChunkWithTagsFromNAND(dev,chunkInNAND,buffer,tags);
2573 + return yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,chunkInNAND,buffer,tags);
2576 +static Y_INLINE int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, const __u8 *buffer, yaffs_ExtendedTags *tags)
2578 + chunkInNAND -= dev->chunkOffset;
2582 + tags->sequenceNumber = dev->sequenceNumber;
2583 + tags->chunkUsed = 1;
2584 + if(!yaffs_ValidateTags(tags))
2586 + T(YAFFS_TRACE_ERROR,(TSTR("Writing uninitialised tags" TENDSTR)));
2589 + T(YAFFS_TRACE_WRITE,(TSTR("Writing chunk %d tags %d %d"TENDSTR),chunkInNAND,tags->objectId,tags->chunkId));
2593 + T(YAFFS_TRACE_ERROR,(TSTR("Writing with no tags" TENDSTR)));
2597 + if(dev->writeChunkWithTagsToNAND)
2598 + return dev->writeChunkWithTagsToNAND(dev,chunkInNAND,buffer,tags);
2600 + return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,chunkInNAND,buffer,tags);
2603 +static Y_INLINE int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo)
2605 + blockNo -= dev->blockOffset;
2607 + if(dev->markNANDBlockBad)
2608 + return dev->markNANDBlockBad(dev,blockNo);
2610 + return yaffs_TagsCompatabilityMarkNANDBlockBad(dev,blockNo);
2612 +static Y_INLINE int yaffs_QueryInitialBlockState(yaffs_Device *dev,int blockNo, yaffs_BlockState *state, unsigned *sequenceNumber)
2614 + blockNo -= dev->blockOffset;
2616 + if(dev->queryNANDBlock)
2617 + return dev->queryNANDBlock(dev,blockNo,state,sequenceNumber);
2619 + return yaffs_TagsCompatabilityQueryNANDBlock(dev,blockNo,state,sequenceNumber);
2622 +static int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
2626 + blockInNAND -= dev->blockOffset;
2628 + dev->nBlockErasures++;
2629 + result = dev->eraseBlockInNAND(dev,blockInNAND);
2631 + if(!result)result = dev->eraseBlockInNAND(dev,blockInNAND); // If at first we don't succeed, try again *once*.
2635 +static int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
2637 + return dev->initialiseNAND(dev);
2643 +// Temporary buffer manipulations
2645 +static __u8 *yaffs_GetTempBuffer(yaffs_Device *dev,int lineNo)
2648 + for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
2650 + if(dev->tempBuffer[i].line == 0)
2652 + dev->tempBuffer[i].line = lineNo;
2653 + if((i+1) > dev->maxTemp)
2655 + dev->maxTemp = i + 1;
2656 + for(j = 0; j <= i; j++)
2657 + dev->tempBuffer[j].maxLine = dev->tempBuffer[j].line;
2660 + return dev->tempBuffer[i].buffer;
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++)
2667 + T(YAFFS_TRACE_BUFFERS,(TSTR(" %d "),dev->tempBuffer[i].line));
2669 + T(YAFFS_TRACE_BUFFERS,(TSTR(" "TENDSTR)));
2671 + dev->unmanagedTempAllocations++;
2672 + // Get an unmanaged one
2673 + return YMALLOC(dev->nBytesPerChunk);
2678 +static void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo)
2681 + for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
2683 + if(dev->tempBuffer[i].buffer == buffer)
2685 + dev->tempBuffer[i].line = 0;
2692 + // assume it is an unmanaged one.
2693 + T(YAFFS_TRACE_BUFFERS,(TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR),lineNo));
2695 + dev->unmanagedTempDeallocations++;
2701 +// Chunk bitmap manipulations
2703 +static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
2705 + if(blk < dev->internalStartBlock || blk > dev->internalEndBlock)
2707 + T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),blk));
2710 + return dev->chunkBits + (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
2713 +static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev,int blk)
2715 + __u8 *blkBits = yaffs_BlockBits(dev,blk);
2717 + memset(blkBits,0,dev->chunkBitmapStride);
2720 +static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device *dev,int blk,int chunk)
2722 + __u8 *blkBits = yaffs_BlockBits(dev,blk);
2724 + blkBits[chunk/8] &= ~ (1<<(chunk & 7));
2727 +static Y_INLINE void yaffs_SetChunkBit(yaffs_Device *dev,int blk,int chunk)
2729 + __u8 *blkBits = yaffs_BlockBits(dev,blk);
2731 + blkBits[chunk/8] |= (1<<(chunk & 7));
2734 +static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device *dev,int blk,int chunk)
2736 + __u8 *blkBits = yaffs_BlockBits(dev,blk);
2737 + return (blkBits[chunk/8] & (1<<(chunk & 7))) ? 1 :0;
2740 +static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev,int blk)
2742 + __u8 *blkBits = yaffs_BlockBits(dev,blk);
2744 + for(i = 0; i < dev->chunkBitmapStride; i++)
2746 + if(*blkBits) return 1;
2753 +static Y_INLINE int yaffs_HashFunction(int n)
2755 + return (n % YAFFS_NOBJECT_BUCKETS);
2759 +yaffs_Object *yaffs_Root(yaffs_Device *dev)
2761 + return dev->rootDir;
2764 +yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
2766 + return dev->lostNFoundDir;
2772 +int yaffs_CheckFF(__u8 *buffer,int nBytes)
2774 + //Horrible, slow implementation
2777 + if(*buffer != 0xFF) return 0;
2783 +static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND)
2786 + int retval = YAFFS_OK;
2787 + __u8 *data = yaffs_GetTempBuffer(dev,__LINE__);
2788 + yaffs_ExtendedTags tags;
2790 +// NCB dev->readChunkWithTagsFromNAND(dev,chunkInNAND,data,&tags);
2791 + yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND,data,&tags);
2793 + if(!yaffs_CheckFF(data,dev->nBytesPerChunk) || tags.chunkUsed)
2795 + T(YAFFS_TRACE_NANDACCESS,(TSTR("Chunk %d not erased" TENDSTR),chunkInNAND));
2796 + retval = YAFFS_FAIL;
2799 + yaffs_ReleaseTempBuffer(dev,data,__LINE__);
2808 +static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, const __u8 *data, yaffs_ExtendedTags *tags,int useReserve)
2818 + chunk = yaffs_AllocateChunk(dev,useReserve);
2823 + // First check this chunk is erased...
2824 +#ifndef CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
2825 + writeOk = yaffs_CheckChunkErased(dev,chunk);
2829 + T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d was not erased" TENDSTR),chunk));
2833 + writeOk = yaffs_WriteChunkWithTagsToNAND(dev,chunk,data,tags);
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.
2842 + yaffs_HandleWriteChunkOk(dev,chunk,data,tags);
2846 + yaffs_HandleWriteChunkError(dev,chunk);
2850 + } while(chunk >= 0 && ! writeOk);
2854 + T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs write required %d attempts" TENDSTR),attempts));
2855 + dev->nRetriedWrites+= (attempts - 1);
2866 +// Functions for robustisizing
2870 +static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND)
2873 + yaffs_MarkBlockBad(dev,blockInNAND);
2875 + yaffs_GetBlockInfo(dev,blockInNAND)->blockState = YAFFS_BLOCK_STATE_DEAD;
2877 + dev->nRetiredBlocks++;
2882 +static int yaffs_RewriteBufferedBlock(yaffs_Device *dev)
2884 + dev->doingBufferedBlockRewrite = 1;
2886 + // Remove erased chunks
2887 + // Rewrite existing chunks to a new block
2888 + // Set current write block to the new block
2890 + dev->doingBufferedBlockRewrite = 0;
2896 +static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND)
2898 + int blockInNAND = chunkInNAND/dev->nChunksPerBlock;
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));
2906 + // Just do a garbage collection on the affected block then retire the block
2911 +static void yaffs_CheckWrittenBlock(yaffs_Device *dev,int chunkInNAND)
2917 +static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags)
2921 +static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_ExtendedTags *tags)
2925 +static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND)
2927 + int blockInNAND = chunkInNAND/dev->nChunksPerBlock;
2929 + // Mark the block for retirement
2930 + yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
2931 + // Delete the chunk
2932 + yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__);
2938 +static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1,int dataSize)
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] )
2966 +///////////////////////// Object management //////////////////
2967 +// List of spare objects
2968 +// The list is hooked together using the first pointer
2971 +// static yaffs_Object *yaffs_freeObjects = NULL;
2973 +// static int yaffs_nFreeObjects;
2975 +// static yaffs_ObjectList *yaffs_allocatedObjectList = NULL;
2977 +// static yaffs_ObjectBucket yaffs_objectBucket[YAFFS_NOBJECT_BUCKETS];
2980 +static __u16 yaffs_CalcNameSum(const YCHAR *name)
2985 + YUCHAR *bname = (YUCHAR *)name;
2988 + while ((*bname) && (i <=YAFFS_MAX_NAME_LENGTH))
2991 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
2992 + sum += yaffs_toupper(*bname) * i;
2994 + sum += (*bname) * i;
3003 +static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
3005 +#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
3006 + if(name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH)
3008 + yaffs_strcpy(obj->shortName,name);
3012 + obj->shortName[0]=_Y('\0');
3015 + obj->sum = yaffs_CalcNameSum(name);
3019 +void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
3021 + yaffs_ECCCalculate(data , spare->ecc1);
3022 + yaffs_ECCCalculate(&data[256] , spare->ecc2);
3027 +///////////////////////// TNODES ///////////////////////
3029 +// List of spare tnodes
3030 +// The list is hooked together using the first pointer
3033 +//static yaffs_Tnode *yaffs_freeTnodes = NULL;
3035 +// static int yaffs_nFreeTnodes;
3037 +//static yaffs_TnodeList *yaffs_allocatedTnodeList = NULL;
3041 +// yaffs_CreateTnodes creates a bunch more tnodes and
3042 +// adds them to the tnode free list.
3043 +// Don't use this function directly
3045 +static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes)
3048 + yaffs_Tnode *newTnodes;
3049 + yaffs_TnodeList *tnl;
3051 + if(nTnodes < 1) return YAFFS_OK;
3053 + // make these things
3055 + newTnodes = YMALLOC(nTnodes * sizeof(yaffs_Tnode));
3059 + T(YAFFS_TRACE_ERROR,(TSTR("yaffs: Could not allocate Tnodes"TENDSTR)));
3060 + return YAFFS_FAIL;
3063 + // Hook them into the free list
3064 + for(i = 0; i < nTnodes - 1; i++)
3066 + newTnodes[i].internal[0] = &newTnodes[i+1];
3067 +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
3068 + newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
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;
3076 + dev->freeTnodes = newTnodes;
3077 + dev->nFreeTnodes+= nTnodes;
3078 + dev->nTnodesCreated += nTnodes;
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));
3086 + T(YAFFS_TRACE_ERROR,(TSTR("yaffs: Could not add tnodes to management list" TENDSTR)));
3091 + tnl->tnodes = newTnodes;
3092 + tnl->next = dev->allocatedTnodeList;
3093 + dev->allocatedTnodeList = tnl;
3097 + T(YAFFS_TRACE_ALLOCATE,(TSTR("yaffs: Tnodes added" TENDSTR)));
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)
3107 + yaffs_Tnode *tn = NULL;
3109 + // If there are none left make more
3110 + if(!dev->freeTnodes)
3112 + yaffs_CreateTnodes(dev,YAFFS_ALLOCATION_NTNODES);
3115 + if(dev->freeTnodes)
3117 + tn = dev->freeTnodes;
3118 +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
3119 + if(tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1)
3121 + // Hoosterman, this thing looks like it isn't in the list
3122 + T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 1" TENDSTR)));
3125 + dev->freeTnodes = dev->freeTnodes->internal[0];
3126 + dev->nFreeTnodes--;
3128 + memset(tn,0,sizeof(yaffs_Tnode));
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)
3141 +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
3142 + if(tn->internal[YAFFS_NTNODES_INTERNAL] != 0)
3144 + // Hoosterman, this thing looks like it is already in the list
3145 + T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 2" TENDSTR)));
3147 + tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
3149 + tn->internal[0] = dev->freeTnodes;
3150 + dev->freeTnodes = tn;
3151 + dev->nFreeTnodes++;
3156 +static void yaffs_DeinitialiseTnodes(yaffs_Device*dev)
3158 + // Free the list of allocated tnodes
3159 + yaffs_TnodeList *tmp;
3161 + while(dev->allocatedTnodeList)
3163 + tmp = dev->allocatedTnodeList->next;
3165 + YFREE(dev->allocatedTnodeList->tnodes);
3166 + YFREE(dev->allocatedTnodeList);
3167 + dev->allocatedTnodeList = tmp;
3171 + dev->freeTnodes = NULL;
3172 + dev->nFreeTnodes = 0;
3175 +static void yaffs_InitialiseTnodes(yaffs_Device*dev)
3177 + dev->allocatedTnodeList = NULL;
3178 + dev->freeTnodes = NULL;
3179 + dev->nFreeTnodes = 0;
3180 + dev->nTnodesCreated = 0;
3185 +void yaffs_TnodeTest(yaffs_Device *dev)
3190 + yaffs_Tnode *tn[1000];
3192 + YINFO("Testing TNodes");
3194 + for(j = 0; j < 50; j++)
3196 + for(i = 0; i < 1000; i++)
3198 + tn[i] = yaffs_GetTnode(dev);
3201 + YALERT("Getting tnode failed");
3204 + for(i = 0; i < 1000; i+=3)
3206 + yaffs_FreeTnode(dev,tn[i]);
3215 +////////////////// END OF TNODE MANIPULATION ///////////////////////////
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.
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)
3227 + yaffs_Tnode *tn = fStruct->top;
3229 + int requiredTallness;
3230 + int level = fStruct->topLevel;
3232 + // Check sane level and chunk Id
3233 + if(level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
3236 +// sprintf(str,"Bad level %d",level);
3241 + if(chunkId > YAFFS_MAX_CHUNK_ID)
3244 +// sprintf(str,"Bad chunkId %d",chunkId);
3249 + // First check we're tall enough (ie enough topLevel)
3251 + i = chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS);
3252 + requiredTallness = 0;
3255 + i >>= YAFFS_TNODES_INTERNAL_BITS;
3256 + requiredTallness++;
3260 + if(requiredTallness > fStruct->topLevel)
3262 + // Not tall enough, so we can't find it, return NULL.
3267 + // Traverse down to level 0
3268 + while (level > 0 && tn)
3270 + tn = tn->internal[(chunkId >>(/* dev->chunkGroupBits + */ YAFFS_TNODES_LEVEL0_BITS + (level-1) * YAFFS_TNODES_INTERNAL_BITS)) &
3271 + YAFFS_TNODES_INTERNAL_MASK];
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.
3284 +// Used when modifying the tree.
3286 +static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStructure *fStruct, __u32 chunkId)
3291 + int requiredTallness;
3298 + //T((TSTR("AddOrFind topLevel=%d, chunk=%d"),fStruct->topLevel,chunkId));
3300 + // Check sane level and page Id
3301 + if(fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
3304 +// sprintf(str,"Bad level %d",fStruct->topLevel);
3309 + if(chunkId > YAFFS_MAX_CHUNK_ID)
3312 +// sprintf(str,"Bad chunkId %d",chunkId);
3317 + // First check we're tall enough (ie enough topLevel)
3319 + x = chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS);
3320 + requiredTallness = 0;
3323 + x >>= YAFFS_TNODES_INTERNAL_BITS;
3324 + requiredTallness++;
3327 + //T((TSTR(" required=%d"),requiredTallness));
3330 + if(requiredTallness > fStruct->topLevel)
3332 + // Not tall enough,gotta make the tree taller
3333 + for(i = fStruct->topLevel; i < requiredTallness; i++)
3335 + //T((TSTR(" add new top")));
3337 + tn = yaffs_GetTnode(dev);
3341 + tn->internal[0] = fStruct->top;
3342 + fStruct->top = tn;
3346 + T(YAFFS_TRACE_ERROR,(TSTR("yaffs: no more tnodes" TENDSTR)));
3350 + fStruct->topLevel = requiredTallness;
3354 + // Traverse down to level 0, adding anything we need
3356 + l = fStruct->topLevel;
3357 + tn = fStruct->top;
3358 + while (l > 0 && tn)
3360 + x = (chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS + (l-1) * YAFFS_TNODES_INTERNAL_BITS)) &
3361 + YAFFS_TNODES_INTERNAL_MASK;
3363 + //T((TSTR(" [%d:%d]"),l,i));
3365 + if(!tn->internal[x])
3367 + //T((TSTR(" added")));
3369 + tn->internal[x] = yaffs_GetTnode(dev);
3372 + tn = tn->internal[x];
3377 + //TSTR(TENDSTR)));
3383 +static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk, yaffs_ExtendedTags *tags, int objectId, int chunkInInode)
3388 + for(j = 0; theChunk && j < dev->chunkGroupSize; j++)
3390 + if(yaffs_CheckChunkBit(dev,theChunk / dev->nChunksPerBlock,theChunk % dev->nChunksPerBlock))
3392 + yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL,tags);
3393 + if(yaffs_TagsMatch(tags,objectId,chunkInInode))
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.
3409 +static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit)
3414 + yaffs_ExtendedTags tags;
3416 + yaffs_Device *dev = in->myDev;
3426 + for(i = YAFFS_NTNODES_INTERNAL -1; allDone && i >= 0; i--)
3428 + if(tn->internal[i])
3430 + if(limit && (*limit) < 0)
3436 + allDone = yaffs_DeleteWorker(in,tn->internal[i],level - 1,
3437 + (chunkOffset << YAFFS_TNODES_INTERNAL_BITS ) + i ,limit);
3441 + yaffs_FreeTnode(dev,tn->internal[i]);
3442 + tn->internal[i] = NULL;
3447 + return (allDone) ? 1 : 0;
3449 + else if(level == 0)
3453 + for(i = YAFFS_NTNODES_LEVEL0 -1; i >= 0 && !hitLimit; i--)
3458 + chunkInInode = (chunkOffset << YAFFS_TNODES_LEVEL0_BITS ) + i;
3460 + theChunk = tn->level0[i] << dev->chunkGroupBits;
3462 + foundChunk = yaffs_FindChunkInGroup(dev,theChunk,&tags,in->objectId,chunkInInode);
3464 + if(foundChunk > 0)
3466 + yaffs_DeleteChunk(dev,foundChunk,1,__LINE__);
3467 + in->nDataChunks--;
3470 + *limit = *limit-1;
3479 + tn->level0[i] = 0;
3483 + return (i < 0) ? 1 : 0;
3495 +static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
3498 + yaffs_BlockInfo *theBlock;
3500 + T(YAFFS_TRACE_DELETION,(TSTR("soft delete chunk %d" TENDSTR),chunk));
3502 + theBlock = yaffs_GetBlockInfo(dev, chunk/dev->nChunksPerBlock);
3505 + theBlock->softDeletions++;
3506 + dev->nFreeChunks++;
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
3513 +// THus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
3515 +static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset)
3520 + yaffs_Device *dev = in->myDev;
3528 + for(i = YAFFS_NTNODES_INTERNAL -1; allDone && i >= 0; i--)
3530 + if(tn->internal[i])
3532 + allDone = yaffs_SoftDeleteWorker(in,tn->internal[i],level - 1,
3533 + (chunkOffset << YAFFS_TNODES_INTERNAL_BITS ) + i);
3536 + yaffs_FreeTnode(dev,tn->internal[i]);
3537 + tn->internal[i] = NULL;
3541 + //Hoosterman... how could this happen.
3545 + return (allDone) ? 1 : 0;
3547 + else if(level == 0)
3550 + for(i = YAFFS_NTNODES_LEVEL0 -1; i >=0; i--)
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);
3558 + yaffs_SoftDeleteChunk(dev,theChunk);
3559 + tn->level0[i] = 0;
3575 +static void yaffs_SoftDeleteFile(yaffs_Object *obj)
3577 + if(obj->deleted &&
3578 + obj->variantType == YAFFS_OBJECT_TYPE_FILE &&
3579 + !obj->softDeleted)
3581 + if(obj->nDataChunks <= 0)
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);
3591 + yaffs_SoftDeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0);
3592 + obj->softDeleted = 1;
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).
3604 +// A file should only get pruned when its size is reduced.
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.
3611 +// yaffs_PruneWorker should only be called by yaffs_PruneFileStructure()
3613 +static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn, __u32 level, int del0)
3622 + for(i = 0; i < YAFFS_NTNODES_INTERNAL; i++)
3624 + if(tn->internal[i] && level > 0)
3626 + tn->internal[i] = yaffs_PruneWorker(dev,tn->internal[i],level - 1, ( i == 0) ? del0 : 1);
3629 + if(tn->internal[i])
3635 + if(hasData == 0 && del0)
3637 + // Free and return NULL
3639 + yaffs_FreeTnode(dev,tn);
3649 +static int yaffs_PruneFileStructure(yaffs_Device *dev, yaffs_FileStructure *fStruct)
3656 + if(fStruct->topLevel > 0)
3658 + fStruct->top = yaffs_PruneWorker(dev,fStruct->top, fStruct->topLevel,0);
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)
3666 + while(fStruct->topLevel && !done)
3668 + tn = fStruct->top;
3671 + for(i = 1; i <YAFFS_NTNODES_INTERNAL; i++)
3673 + if(tn->internal[i])
3681 + fStruct->top = tn->internal[0];
3682 + fStruct->topLevel--;
3683 + yaffs_FreeTnode(dev,tn);
3699 +/////////////////////// End of File Structure functions. /////////////////
3701 +// yaffs_CreateFreeObjects creates a bunch more objects and
3702 +// adds them to the object free list.
3703 +static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
3706 + yaffs_Object *newObjects;
3707 + yaffs_ObjectList *list;
3709 + if(nObjects < 1) return YAFFS_OK;
3711 + // make these things
3713 + newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
3717 + T(YAFFS_TRACE_ALLOCATE,(TSTR("yaffs: Could not allocate more objects" TENDSTR)));
3718 + return YAFFS_FAIL;
3721 + // Hook them into the free list
3722 + for(i = 0; i < nObjects - 1; i++)
3724 + newObjects[i].siblings.next = (struct list_head *)(&newObjects[i+1]);
3727 + newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
3728 + dev->freeObjects = newObjects;
3729 + dev->nFreeObjects+= nObjects;
3730 + dev->nObjectsCreated+= nObjects;
3732 + // Now add this bunch of Objects to a list for freeing up.
3734 + list = YMALLOC(sizeof(yaffs_ObjectList));
3737 + T(YAFFS_TRACE_ALLOCATE,(TSTR("Could not add objects to management list" TENDSTR)));
3741 + list->objects = newObjects;
3742 + list->next = dev->allocatedObjectList;
3743 + dev->allocatedObjectList = list;
3752 +// AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out
3753 +static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
3755 + yaffs_Object *tn = NULL;
3757 + // If there are none left make more
3758 + if(!dev->freeObjects)
3760 + yaffs_CreateFreeObjects(dev,YAFFS_ALLOCATION_NOBJECTS);
3763 + if(dev->freeObjects)
3765 + tn = dev->freeObjects;
3766 + dev->freeObjects = (yaffs_Object *)(dev->freeObjects->siblings.next);
3767 + dev->nFreeObjects--;
3769 + // Now sweeten it up...
3771 + memset(tn,0,sizeof(yaffs_Object));
3774 + tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
3775 + INIT_LIST_HEAD(&(tn->hardLinks));
3776 + INIT_LIST_HEAD(&(tn->hashLink));
3777 + INIT_LIST_HEAD(&tn->siblings);
3779 + // Add it to the lost and found directory.
3780 + // NB Can't put root or lostNFound in lostNFound so
3781 + // check if lostNFound exists first
3782 + if(dev->lostNFoundDir)
3784 + yaffs_AddObjectToDirectory(dev->lostNFoundDir,tn);
3792 +static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev,int number,__u32 mode)
3795 + yaffs_Object *obj = yaffs_CreateNewObject(dev,number,YAFFS_OBJECT_TYPE_DIRECTORY);
3798 + obj->fake = 1; // it is fake so it has no NAND presence...
3799 + obj->renameAllowed= 0; // ... and we're not allowed to rename it...
3800 + obj->unlinkAllowed= 0; // ... or unlink it
3802 + obj->unlinked = 0;
3803 + obj->yst_mode = mode;
3805 + obj->chunkId = 0; // Not a valid chunk.
3813 +static void yaffs_UnhashObject(yaffs_Object *tn)
3816 + yaffs_Device *dev = tn->myDev;
3819 + // If it is still linked into the bucket list, free from the list
3820 + if(!list_empty(&tn->hashLink))
3822 + list_del_init(&tn->hashLink);
3823 + bucket = yaffs_HashFunction(tn->objectId);
3824 + dev->objectBucket[bucket].count--;
3830 +// FreeObject frees up a Object and puts it back on the free list
3831 +static void yaffs_FreeObject(yaffs_Object *tn)
3834 + yaffs_Device *dev = tn->myDev;
3839 + // We're still hooked up to a cached inode.
3840 + // Don't delete now, but mark for later deletion
3841 + tn->deferedFree = 1;
3846 + yaffs_UnhashObject(tn);
3848 + // Link into the free list.
3849 + tn->siblings.next = (struct list_head *)(dev->freeObjects);
3850 + dev->freeObjects = tn;
3851 + dev->nFreeObjects++;
3858 +void yaffs_HandleDeferedFree(yaffs_Object *obj)
3860 + if(obj->deferedFree)
3862 + yaffs_FreeObject(obj);
3870 +static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
3872 + // Free the list of allocated Objects
3874 + yaffs_ObjectList *tmp;
3876 + while( dev->allocatedObjectList)
3878 + tmp = dev->allocatedObjectList->next;
3879 + YFREE(dev->allocatedObjectList->objects);
3880 + YFREE(dev->allocatedObjectList);
3882 + dev->allocatedObjectList = tmp;
3885 + dev->freeObjects = NULL;
3886 + dev->nFreeObjects = 0;
3889 +static void yaffs_InitialiseObjects(yaffs_Device *dev)
3893 + dev->allocatedObjectList = NULL;
3894 + dev->freeObjects = NULL;
3895 + dev->nFreeObjects = 0;
3897 + for(i = 0; i < YAFFS_NOBJECT_BUCKETS; i++)
3899 + INIT_LIST_HEAD(&dev->objectBucket[i].list);
3900 + dev->objectBucket[i].count = 0;
3910 +static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
3915 + int lowest = 999999;
3918 + // First let's see if we can find one that's empty.
3920 + for(i = 0; i < 10 && lowest > 0; i++)
3923 + x %= YAFFS_NOBJECT_BUCKETS;
3924 + if(dev->objectBucket[x].count < lowest)
3926 + lowest = dev->objectBucket[x].count;
3932 + // If we didn't find an empty list, then try
3933 + // looking a bit further for a short one
3935 + for(i = 0; i < 10 && lowest > 3; i++)
3938 + x %= YAFFS_NOBJECT_BUCKETS;
3939 + if(dev->objectBucket[x].count < lowest)
3941 + lowest = dev->objectBucket[x].count;
3950 +static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
3952 + int bucket = yaffs_FindNiceObjectBucket(dev);
3954 + // Now find an object value that has not already been taken
3955 + // by scanning the list.
3958 + struct list_head *i;
3960 + __u32 n = (__u32)bucket;
3962 + //yaffs_CheckObjectHashSanity();
3967 + n += YAFFS_NOBJECT_BUCKETS;
3968 + if(1 ||dev->objectBucket[bucket].count > 0)
3970 + list_for_each(i,&dev->objectBucket[bucket].list)
3972 + // If there is already one in the list
3973 + if(i && list_entry(i, yaffs_Object,hashLink)->objectId == n)
3981 + //T(("bucket %d count %d inode %d\n",bucket,yaffs_objectBucket[bucket].count,n);
3986 +static void yaffs_HashObject(yaffs_Object *in)
3988 + int bucket = yaffs_HashFunction(in->objectId);
3989 + yaffs_Device *dev = in->myDev;
3991 + if(!list_empty(&in->hashLink))
3997 + list_add(&in->hashLink,&dev->objectBucket[bucket].list);
3998 + dev->objectBucket[bucket].count++;
4002 +yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev,__u32 number)
4004 + int bucket = yaffs_HashFunction(number);
4005 + struct list_head *i;
4008 + list_for_each(i,&dev->objectBucket[bucket].list)
4010 + // Look if it is in the list
4013 + in = list_entry(i, yaffs_Object,hashLink);
4014 + if(in->objectId == number)
4017 + // Don't tell the VFS about this one if it is defered free
4018 + if(in->deferedFree)
4032 +yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type)
4035 + yaffs_Object *theObject;
4039 + number = yaffs_CreateNewObjectNumber(dev);
4042 + theObject = yaffs_AllocateEmptyObject(dev);
4046 + theObject->fake = 0;
4047 + theObject->renameAllowed = 1;
4048 + theObject->unlinkAllowed = 1;
4049 + theObject->objectId = number;
4050 + yaffs_HashObject(theObject);
4051 + theObject->variantType = type;
4052 +#ifdef CONFIG_YAFFS_WINCE
4053 + yfsd_WinFileTimeNow(theObject->win_atime);
4054 + theObject->win_ctime[0] = theObject->win_mtime[0] = theObject->win_atime[0];
4055 + theObject->win_ctime[1] = theObject->win_mtime[1] = theObject->win_atime[1];
4059 + theObject->yst_atime = theObject->yst_mtime = theObject->yst_ctime = Y_CURRENT_TIME;
4063 + case YAFFS_OBJECT_TYPE_FILE:
4064 + theObject->variant.fileVariant.fileSize = 0;
4065 + theObject->variant.fileVariant.scannedFileSize = 0;
4066 + theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; // max __u32
4067 + theObject->variant.fileVariant.topLevel = 0;
4068 + theObject->variant.fileVariant.top = yaffs_GetTnode(dev);
4070 + case YAFFS_OBJECT_TYPE_DIRECTORY:
4071 + INIT_LIST_HEAD(&theObject->variant.directoryVariant.children);
4073 + case YAFFS_OBJECT_TYPE_SYMLINK:
4074 + // No action required
4076 + case YAFFS_OBJECT_TYPE_HARDLINK:
4077 + // No action required
4079 + case YAFFS_OBJECT_TYPE_SPECIAL:
4080 + // No action required
4082 + case YAFFS_OBJECT_TYPE_UNKNOWN:
4083 + // todo this should not happen
4091 +static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaffs_ObjectType type)
4093 + yaffs_Object *theObject = NULL;
4097 + theObject = yaffs_FindObjectByNumber(dev,number);
4102 + theObject = yaffs_CreateNewObject(dev,number,type);
4109 +static YCHAR *yaffs_CloneString(const YCHAR *str)
4111 + YCHAR *newStr = NULL;
4115 + newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
4116 + yaffs_strcpy(newStr,str);
4124 +// Mknod (create) a new object.
4125 +// equivalentObject only has meaning for a hard link;
4126 +// aliasString only has meaning for a sumlink.
4127 +// rdev only has meaning for devices (a subset of special objects)
4128 +static yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
4129 + yaffs_Object *parent,
4130 + const YCHAR *name,
4134 + yaffs_Object *equivalentObject,
4135 + const YCHAR *aliasString,
4140 + yaffs_Device *dev = parent->myDev;
4142 + // Check if the entry exists. If it does then fail the call since we don't want a dup.
4143 + if(yaffs_FindObjectByName(parent,name))
4148 + in = yaffs_CreateNewObject(dev,-1,type);
4154 + in->variantType = type;
4156 + in->yst_mode = mode;
4158 +#ifdef CONFIG_YAFFS_WINCE
4159 + yfsd_WinFileTimeNow(in->win_atime);
4160 + in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
4161 + in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
4164 + in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
4166 + in->yst_rdev = rdev;
4167 + in->yst_uid = uid;
4168 + in->yst_gid = gid;
4170 + in->nDataChunks = 0;
4172 + yaffs_SetObjectName(in,name);
4175 + yaffs_AddObjectToDirectory(parent,in);
4177 + in->myDev = parent->myDev;
4182 + case YAFFS_OBJECT_TYPE_SYMLINK:
4183 + in->variant.symLinkVariant.alias = yaffs_CloneString(aliasString);
4185 + case YAFFS_OBJECT_TYPE_HARDLINK:
4186 + in->variant.hardLinkVariant.equivalentObject = equivalentObject;
4187 + in->variant.hardLinkVariant.equivalentObjectId = equivalentObject->objectId;
4188 + list_add(&in->hardLinks,&equivalentObject->hardLinks);
4190 + case YAFFS_OBJECT_TYPE_FILE: // do nothing
4191 + case YAFFS_OBJECT_TYPE_DIRECTORY: // do nothing
4192 + case YAFFS_OBJECT_TYPE_SPECIAL: // do nothing
4193 + case YAFFS_OBJECT_TYPE_UNKNOWN:
4197 + if(/*yaffs_GetNumberOfFreeChunks(dev) <= 0 || */
4198 + yaffs_UpdateObjectHeader(in,name,0,0,0) < 0)
4200 + // Could not create the object header, fail the creation
4201 + yaffs_DestroyObject(in);
4210 +yaffs_Object *yaffs_MknodFile(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid)
4212 + return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE,parent,name,mode,uid,gid,NULL,NULL,0);
4215 +yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid)
4217 + return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY,parent,name,mode,uid,gid,NULL,NULL,0);
4220 +yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
4222 + return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL,parent,name,mode,uid,gid,NULL,NULL,rdev);
4225 +yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid,const YCHAR *alias)
4227 + return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK,parent,name,mode,uid,gid,NULL,alias,0);
4230 +// NB yaffs_Link returns the object id of the equivalent object.
4231 +yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name, yaffs_Object *equivalentObject)
4233 + // Get the real object in case we were fed a hard link as an equivalent object
4234 + equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
4236 + if(yaffs_MknodObject(YAFFS_OBJECT_TYPE_HARDLINK,parent,name,0,0,0,equivalentObject,NULL,0))
4238 + return equivalentObject;
4248 +static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const YCHAR *newName,int force,int shadows)
4253 + yaffs_Object * existingTarget;
4255 + if(newDir == NULL)
4257 + newDir = obj->parent; // use the old directory
4260 + if(newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
4262 + T(YAFFS_TRACE_ALWAYS,(TSTR("tragendy: yaffs_ChangeObjectName: newDir is not a directory"TENDSTR)));
4266 + // TODO: Do we need this different handling for YAFFS2 and YAFFS1??
4267 + if(obj->myDev->isYaffs2)
4269 + unlinkOp = (newDir == obj->myDev->unlinkedDir);
4273 + unlinkOp = (newDir == obj->myDev->unlinkedDir && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
4276 + deleteOp = (newDir == obj->myDev->deletedDir);
4278 + existingTarget = yaffs_FindObjectByName(newDir,newName);
4280 + // If the object is a file going into the unlinked directory, then it is OK to just stuff it in since
4281 + // duplicate names are allowed.
4282 + // Otherwise only proceed if the new name does not exist and if we're putting it into a directory.
4287 + !existingTarget) &&
4288 + newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
4290 + yaffs_SetObjectName(obj,newName);
4293 + yaffs_AddObjectToDirectory(newDir,obj);
4295 + if(unlinkOp) obj->unlinked = 1;
4297 + // If it is a deletion then we mark it as a shrink for gc purposes.
4298 + if(yaffs_UpdateObjectHeader(obj,newName,0,deleteOp,shadows) >= 0)
4304 + return YAFFS_FAIL;
4309 +int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, yaffs_Object *newDir, const YCHAR *newName)
4311 + yaffs_Object *obj;
4312 + yaffs_Object *existingTarget;
4315 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
4316 + // Special case for case insemsitive systems (eg. WinCE).
4317 + // While look-up is case insensitive, the name isn't.
4318 + // THerefore we might want to change x.txt to X.txt
4319 + if(oldDir == newDir && yaffs_strcmp(oldName,newName) == 0)
4325 + obj = yaffs_FindObjectByName(oldDir,oldName);
4327 + if(obj && obj->renameAllowed)
4330 + // Now do the handling for an existing target, if there is one
4332 + existingTarget = yaffs_FindObjectByName(newDir,newName);
4333 + if(existingTarget &&
4334 + existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
4335 + !list_empty(&existingTarget->variant.directoryVariant.children))
4337 + // There is a target that is a non-empty directory, so we have to fail
4338 + return YAFFS_FAIL; // EEXIST or ENOTEMPTY
4340 + else if(existingTarget)
4342 + // Nuke the target first, using shadowing
4343 + yaffs_ChangeObjectName(obj,newDir,newName,force,existingTarget->objectId);
4344 + yaffs_Unlink(newDir,newName);
4348 + return yaffs_ChangeObjectName(obj,newDir,newName,force,0);
4350 + return YAFFS_FAIL;
4356 +static int yaffs_CheckObjectHashSanity(yaffs_Device *dev)
4358 + // Scan the buckets and check that the lists
4359 + // have as many members as the count says there are
4362 + struct list_head *j;
4363 + int ok = YAFFS_OK;
4365 + for(bucket = 0; bucket < YAFFS_NOBJECT_BUCKETS; bucket++)
4369 + list_for_each(j,&dev->objectBucket[bucket].list)
4374 + if(countEm != dev->objectBucket[bucket].count)
4376 + T(YAFFS_TRACE_ERROR,(TSTR("Inode hash inconsistency" TENDSTR)));
4385 +void yaffs_ObjectTest(yaffs_Device *dev)
4387 + yaffs_Object *in[1000];
4389 + yaffs_Object *inold[1000];
4393 + memset(in,0,1000*sizeof(yaffs_Object *));
4394 + memset(inold,0,1000*sizeof(yaffs_Object *));
4396 + yaffs_CheckObjectHashSanity(dev);
4398 + for(j = 0; j < 10; j++)
4402 + for(i = 0; i < 1000; i++)
4404 + in[i] = yaffs_CreateNewObject(dev,-1,YAFFS_OBJECT_TYPE_FILE);
4407 + YINFO("No more inodes");
4411 + inNo[i] = in[i]->objectId;
4415 + for(i = 0; i < 1000; i++)
4417 + if(yaffs_FindObjectByNumber(dev,inNo[i]) != in[i])
4419 + //T(("Differnce in look up test\n"));
4423 + // T(("Look up ok\n"));
4427 + yaffs_CheckObjectHashSanity(dev);
4429 + for(i = 0; i < 1000; i+=3)
4431 + yaffs_FreeObject(in[i]);
4436 + yaffs_CheckObjectHashSanity(dev);
4443 +/////////////////////////// Block Management and Page Allocation ///////////////////
4446 +static int yaffs_InitialiseBlocks(yaffs_Device *dev,int nBlocks)
4448 + dev->allocationBlock = -1; // force it to get a new one
4449 + //Todo we're assuming the malloc will pass.
4450 + dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
4451 + // Set up dynamic blockinfo stuff.
4452 + dev->chunkBitmapStride = (dev->nChunksPerBlock+7)/8;
4453 + dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
4454 + if(dev->blockInfo && dev->chunkBits)
4456 + memset(dev->blockInfo,0,nBlocks * sizeof(yaffs_BlockInfo));
4457 + memset(dev->chunkBits,0,dev->chunkBitmapStride * nBlocks);
4461 + return YAFFS_FAIL;
4465 +static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
4467 + YFREE(dev->blockInfo);
4468 + dev->blockInfo = NULL;
4469 + YFREE(dev->chunkBits);
4470 + dev->chunkBits = NULL;
4474 +static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev, yaffs_BlockInfo *bi)
4478 + yaffs_BlockInfo *b;
4480 + if(!dev->isYaffs2) return 1; // disqualification only applies to yaffs2.
4482 + if(!bi->hasShrinkHeader) return 1; // can gc
4485 + // Find the oldest dirty sequence number if we don't know it and save it
4486 + // so we don't have to keep recomputing it.
4487 + if(!dev->oldestDirtySequence)
4489 + seq = dev->sequenceNumber;
4491 + for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++)
4493 + b = yaffs_GetBlockInfo(dev,i);
4494 + if(b->blockState == YAFFS_BLOCK_STATE_FULL &&
4495 + (b->pagesInUse - b->softDeletions )< dev->nChunksPerBlock &&
4496 + b->sequenceNumber < seq)
4498 + seq = b->sequenceNumber;
4501 + dev->oldestDirtySequence = seq;
4505 + // Can't do gc of this block if there are any blocks older than this one that have
4506 + // discarded pages.
4507 + return (bi->sequenceNumber <= dev->oldestDirtySequence);
4514 +// FindDiretiestBlock is used to select the dirtiest block (or close enough)
4515 +// for garbage collection.
4520 +static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,int aggressive)
4523 + int b = dev->currentDirtyChecker;
4527 + int dirtiest = -1;
4529 + yaffs_BlockInfo *bi;
4530 + static int nonAggressiveSkip = 0;
4532 + // If we're doing aggressive GC then we are happy to take a less-dirty block, and
4534 + // else (we're doing a leasurely gc), then we only bother to do this if the
4535 + // block has only a few pages in use.
4538 + nonAggressiveSkip--;
4540 + if(!aggressive &&(nonAggressiveSkip > 0))
4545 + pagesInUse = (aggressive)? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
4549 + iterations = dev->internalEndBlock - dev->internalStartBlock + 1;
4553 + iterations = dev->internalEndBlock - dev->internalStartBlock + 1;
4554 + iterations = iterations / 16;
4555 + if(iterations > 200)
4561 + for(i = 0; i <= iterations && pagesInUse > 0 ; i++)
4564 + if ( b < dev->internalStartBlock || b > dev->internalEndBlock)
4566 + b = dev->internalStartBlock;
4569 + if(b < dev->internalStartBlock || b > dev->internalEndBlock)
4571 + T(YAFFS_TRACE_ERROR,(TSTR("**>> Block %d is not valid" TENDSTR),b));
4575 + bi = yaffs_GetBlockInfo(dev,b);
4577 + if(bi->blockState == YAFFS_BLOCK_STATE_FULL &&
4578 + (bi->pagesInUse - bi->softDeletions )< pagesInUse &&
4579 + yaffs_BlockNotDisqualifiedFromGC(dev,bi))
4582 + pagesInUse = (bi->pagesInUse - bi->softDeletions);
4586 + dev->currentDirtyChecker = b;
4590 + T(YAFFS_TRACE_GC,(TSTR("GC Selected block %d with %d free" TENDSTR),dirtiest,dev->nChunksPerBlock - pagesInUse));
4593 + dev->oldestDirtySequence = 0; // clear this
4597 + nonAggressiveSkip = 4;
4604 +static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo)
4606 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,blockNo);
4610 + // If the block is still healthy erase it and mark as clean.
4611 + // If the block has had a data failure, then retire it.
4612 + bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
4614 + if(!bi->needsRetiring)
4616 + erasedOk = yaffs_EraseBlockInNAND(dev,blockNo);
4619 + dev->nErasureFailures++;
4620 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Erasure failed %d" TENDSTR),blockNo));
4624 + if(erasedOk && (yaffs_traceMask & YAFFS_TRACE_ERASE))
4627 + for(i = 0; i < dev->nChunksPerBlock; i++)
4629 + if(!yaffs_CheckChunkErased(dev,blockNo * dev->nChunksPerBlock + i))
4631 + T(YAFFS_TRACE_ERROR,(TSTR(">>Block %d erasure supposedly OK, but chunk %d not erased" TENDSTR),blockNo,i));
4639 + bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
4640 + dev->nErasedBlocks++;
4641 + bi->pagesInUse = 0;
4642 + bi->softDeletions = 0;
4643 + bi->hasShrinkHeader=0;
4644 + yaffs_ClearChunkBits(dev,blockNo);
4646 + T(YAFFS_TRACE_ERASE,(TSTR("Erased block %d" TENDSTR),blockNo));
4650 + dev->nFreeChunks -= dev->nChunksPerBlock; // We lost a block of free space
4652 + yaffs_RetireBlock(dev,blockNo);
4653 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Block %d retired" TENDSTR),blockNo));
4658 +static void yaffs_DumpBlockStats(yaffs_Device *dev)
4661 + yaffs_BlockInfo *bi;
4663 + for(i= dev->internalStartBlock; i <=dev->internalEndBlock; i++)
4665 + bi = yaffs_GetBlockInfo(dev,i);
4666 + T(YAFFS_TRACE_ALLOCATE,(TSTR("%3d state %d shrink %d inuse %d/%d seq %d pages"),i,
4667 + bi->blockState,bi->hasShrinkHeader,bi->pagesInUse,bi->softDeletions,bi->sequenceNumber));
4669 + for(j = 0; j < dev->nChunksPerBlock; j++)
4671 + if(yaffs_CheckChunkBit(dev,i,j))
4673 + T(YAFFS_TRACE_ALLOCATE,(TSTR(" %d"),j));
4677 + T(YAFFS_TRACE_ALLOCATE,(TSTR(" " TENDSTR)));
4684 +static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
4688 + yaffs_BlockInfo *bi;
4693 + if(j < 0 || j > 100)
4696 + yaffs_DumpBlockStats(dev);
4701 + if(dev->nErasedBlocks < 1)
4703 + // Hoosterman we've got a problem.
4704 + // Can't get space to gc
4705 + T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no more eraased blocks" TENDSTR)));
4710 + // Find an empty block.
4712 + for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++)
4714 + dev->allocationBlockFinder++;
4715 + if(dev->allocationBlockFinder < dev->internalStartBlock || dev->allocationBlockFinder> dev->internalEndBlock)
4717 + dev->allocationBlockFinder = dev->internalStartBlock;
4720 + bi = yaffs_GetBlockInfo(dev,dev->allocationBlockFinder);
4722 + if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
4724 + bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
4725 + dev->sequenceNumber++;
4726 + bi->sequenceNumber = dev->sequenceNumber;
4727 + dev->nErasedBlocks--;
4728 + T(YAFFS_TRACE_ALLOCATE,(TSTR("Allocated block %d, seq %d, %d left" TENDSTR),dev->allocationBlockFinder,dev->sequenceNumber, dev->nErasedBlocks));
4729 + return dev->allocationBlockFinder;
4734 + T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs tragedy: no more eraased blocks, but there should have been %d" TENDSTR),dev->nErasedBlocks));
4744 +// To determine if we have enough space we just look at the
4745 +// number of erased blocks.
4747 +static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev)
4749 + int reservedChunks = (dev->nReservedBlocks * dev->nChunksPerBlock);
4750 + return (dev->nFreeChunks > reservedChunks);
4754 +static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
4757 + yaffs_BlockInfo *bi;
4759 + if(dev->allocationBlock < 0)
4761 + // Get next block to allocate off
4762 + dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
4763 + dev->allocationPage = 0;
4766 + if(!useReserve && !yaffs_CheckSpaceForAllocation(dev))
4768 + // Not enough space to allocate unless we're allowed to use the reserve.
4772 + if(dev->nErasedBlocks < dev->nReservedBlocks && dev->allocationPage == 0)
4774 + T(YAFFS_TRACE_ALLOCATE,(TSTR("Allocating reserve" TENDSTR)));
4778 + // Next page please....
4779 + if(dev->allocationBlock >= 0)
4781 + bi = yaffs_GetBlockInfo(dev,dev->allocationBlock);
4783 + retVal = (dev->allocationBlock * dev->nChunksPerBlock) +
4784 + dev->allocationPage;
4786 + yaffs_SetChunkBit(dev,dev->allocationBlock,dev->allocationPage);
4788 + dev->allocationPage++;
4790 + dev->nFreeChunks--;
4792 + // If the block is full set the state to full
4793 + if(dev->allocationPage >= dev->nChunksPerBlock)
4795 + bi->blockState = YAFFS_BLOCK_STATE_FULL;
4796 + dev->allocationBlock = -1;
4803 + T(YAFFS_TRACE_ERROR,(TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
4811 +static int yaffs_GetErasedChunks(yaffs_Device *dev)
4815 + n = dev->nErasedBlocks * dev->nChunksPerBlock;
4817 + if(dev->allocationBlock> 0)
4819 + n += (dev->nChunksPerBlock - dev->allocationPage);
4826 +static int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
4832 + int retVal = YAFFS_OK;
4836 + int chunksBefore = yaffs_GetErasedChunks(dev);
4839 + yaffs_ExtendedTags tags;
4841 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,block);
4843 + yaffs_Object *object;
4845 + bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
4847 + T(YAFFS_TRACE_TRACING,(TSTR("Collecting block %d, in use %d, shrink %d, " TENDSTR),block,bi->pagesInUse,bi->hasShrinkHeader));
4848 + //T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits));
4850 + //yaffs_VerifyFreeChunks(dev);
4852 + bi->hasShrinkHeader = 0; // clear the flag so that the block can erase
4854 + dev->nFreeChunks -= bi->softDeletions; // Take off the number of soft deleted entries because
4855 + // they're going to get really deleted during GC.
4857 + dev->isDoingGC = 1;
4859 + if(!yaffs_StillSomeChunkBits(dev,block))
4861 + T(YAFFS_TRACE_TRACING,(TSTR("Collecting block %d that has no chunks in use" TENDSTR),block));
4862 + yaffs_BlockBecameDirty(dev,block);
4867 + __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__);
4869 + for(chunkInBlock = 0,oldChunk = block * dev->nChunksPerBlock;
4870 + chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev,block);
4871 + chunkInBlock++, oldChunk++ )
4873 + if(yaffs_CheckChunkBit(dev,block,chunkInBlock))
4876 + // This page is in use and might need to be copied off
4880 + //T(("copying page %x from %d to %d\n",mask,oldChunk,newChunk));
4882 + yaffs_InitialiseTags(&tags);
4884 + yaffs_ReadChunkWithTagsFromNAND(dev,oldChunk,buffer, &tags);
4886 + object = yaffs_FindObjectByNumber(dev,tags.objectId);
4888 + T(YAFFS_TRACE_GC_DETAIL,(TSTR("Collecting page %d, %d %d %d " TENDSTR),chunkInBlock,tags.objectId,tags.chunkId,tags.byteCount));
4892 + T(YAFFS_TRACE_ERROR,(TSTR("page %d in gc has no object " TENDSTR),oldChunk));
4895 + if(object && object->deleted && tags.chunkId != 0)
4897 + // Data chunk in a deleted file, throw it away
4898 + // It's a soft deleted data chunk,
4899 + // No need to copy this, just forget about it and fix up the
4902 + //yaffs_PutChunkIntoFile(object, tags.chunkId, 0,0);
4903 + object->nDataChunks--;
4905 + if(object->nDataChunks <= 0)
4907 + // remeber to clean up the object
4908 + dev->gcCleanupList[cleanups] = tags.objectId;
4913 + else if( 0 /* Todo object && object->deleted && object->nDataChunks == 0 */)
4915 + // Deleted object header with no data chunks.
4916 + // Can be discarded and the file deleted.
4917 + object->chunkId = 0;
4918 + yaffs_FreeTnode(object->myDev,object->variant.fileVariant.top);
4919 + object->variant.fileVariant.top = NULL;
4920 + yaffs_DoGenericObjectDeletion(object);
4925 + // It's either a data chunk in a live file or
4926 + // an ObjectHeader, so we're interested in it.
4927 + // NB Need to keep the ObjectHeaders of deleted files
4928 + // until the whole file has been deleted off
4929 + tags.serialNumber++;
4933 + if(tags.chunkId == 0)
4935 + // It is an object Id,
4936 + // We need to nuke the shrinkheader flags first
4937 + // We no longer want the shrinkHeader flag since its work is done
4938 + // and if it is left in place it will mess up scanning.
4940 + yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
4942 + tags.extraIsShrinkHeader = 0;
4945 + newChunk = yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags,1);
4949 + retVal = YAFFS_FAIL;
4954 + // Ok, now fix up the Tnodes etc.
4956 + if(tags.chunkId == 0)
4959 + object->chunkId = newChunk;
4960 + object->serial = tags.serialNumber;
4964 + // It's a data chunk
4965 + yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk,0);
4970 + yaffs_DeleteChunk(dev,oldChunk,markNAND,__LINE__);
4975 + yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
4977 + //yaffs_VerifyFreeChunks(dev);
4979 + // Do any required cleanups
4980 + for(i = 0; i < cleanups; i++)
4982 + // Time to delete the file too
4983 + object = yaffs_FindObjectByNumber(dev,dev->gcCleanupList[i]);
4986 + yaffs_FreeTnode(dev,object->variant.fileVariant.top);
4987 + object->variant.fileVariant.top = NULL;
4988 + T(YAFFS_TRACE_GC,(TSTR("yaffs: About to finally delete object %d" TENDSTR),object->objectId));
4989 + yaffs_DoGenericObjectDeletion(object);
4996 + if(chunksBefore >= (chunksAfter = yaffs_GetErasedChunks(dev)))
4998 + T(YAFFS_TRACE_GC,(TSTR("gc did not increase free chunks before %d after %d" TENDSTR),chunksBefore,chunksAfter));
5002 + dev->isDoingGC = 0;
5004 + //yaffs_VerifyFreeChunks(dev);
5010 +static yaffs_Object *yaffs_FindDeletedUnlinkedFile(yaffs_Device *dev)
5012 + // find a file to delete
5013 + struct list_head *i;
5017 + //Scan the unlinked files looking for one to delete
5018 + list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children)
5022 + l = list_entry(i, yaffs_Object,siblings);
5033 +static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev)
5035 + // This does background deletion on unlinked files.. only deleted ones.
5036 + // If we don't have a file we're working on then find one
5037 + if(!dev->unlinkedDeletion && dev->nDeletedFiles > 0)
5039 + dev->unlinkedDeletion = yaffs_FindDeletedUnlinkedFile(dev);
5042 + // OK, we're working on a file...
5043 + if(dev->unlinkedDeletion)
5045 + yaffs_Object *obj = dev->unlinkedDeletion;
5047 + int limit; // Number of chunks to delete in a file.
5048 + // NB this can be exceeded, but not by much.
5052 + delresult = yaffs_DeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0,&limit);
5054 + if(obj->nDataChunks == 0)
5056 + // Done all the deleting of data chunks.
5057 + // Now dump the header and clean up
5058 + yaffs_FreeTnode(dev,obj->variant.fileVariant.top);
5059 + obj->variant.fileVariant.top = NULL;
5060 + yaffs_DoGenericObjectDeletion(obj);
5061 + dev->nDeletedFiles--;
5062 + dev->nUnlinkedFiles--;
5063 + dev->nBackgroundDeletions++;
5064 + dev->unlinkedDeletion = NULL;
5073 +// New garbage collector
5074 +// If we're very low on erased blocks then we do aggressive garbage collection
5075 +// otherwise we do "leasurely" garbage collection.
5076 +// Aggressive gc looks further (whole array) and will accept dirtier blocks.
5077 +// Passive gc only inspects smaller areas and will only accept cleaner blocks.
5079 +// The idea is to help clear out space in a more spread-out manner.
5080 +// Dunno if it really does anything useful.
5082 +static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
5086 + int gcOk = YAFFS_OK;
5089 + //yaffs_VerifyFreeChunks(dev);
5091 + if(dev->isDoingGC)
5093 + // Bail out so we don't get recursive gc
5097 + // This loop should pass the first time.
5098 + // We'll only see looping here if the erase of the collected block fails.
5102 + if(dev->nErasedBlocks < dev->nReservedBlocks)
5104 + // We need a block soon...
5109 + // We're in no hurry
5113 + block = yaffs_FindBlockForGarbageCollection(dev,aggressive);
5117 + dev->garbageCollections++;
5120 + dev->passiveGarbageCollections++;
5123 + T(YAFFS_TRACE_GC,(TSTR("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),dev->nErasedBlocks,aggressive));
5125 + gcOk = yaffs_GarbageCollectBlock(dev,block);
5128 + if(dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0)
5130 + T(YAFFS_TRACE_GC,(TSTR("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" TENDSTR),dev->nErasedBlocks,maxTries,block));
5132 + } while((dev->nErasedBlocks < dev->nReservedBlocks) && (block > 0) && (maxTries < 2));
5134 + return aggressive ? gcOk: YAFFS_OK;
5138 +//////////////////////////// TAGS ///////////////////////////////////////
5144 +void yaffs_CalcTagsECC(yaffs_Tags *tags)
5146 + // Calculate an ecc
5148 + unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
5155 + for(i = 0; i < 8; i++)
5157 + for(j = 1; j &0xff; j<<=1)
5172 +int yaffs_CheckECCOnTags(yaffs_Tags *tags)
5174 + unsigned ecc = tags->ecc;
5176 + yaffs_CalcTagsECC(tags);
5180 + if(ecc && ecc <= 64)
5182 + // TODO: Handle the failure better. Retire?
5183 + unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
5187 + b[ecc / 8] ^= (1 << (ecc & 7));
5189 + // Now recvalc the ecc
5190 + yaffs_CalcTagsECC(tags);
5192 + return 1; // recovered error
5196 + // Wierd ecc failure value
5197 + // TODO Need to do somethiong here
5198 + return -1; //unrecovered error
5204 +static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr)
5206 + yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
5208 + yaffs_CalcTagsECC(tagsPtr);
5210 + sparePtr->tagByte0 = tu->asBytes[0];
5211 + sparePtr->tagByte1 = tu->asBytes[1];
5212 + sparePtr->tagByte2 = tu->asBytes[2];
5213 + sparePtr->tagByte3 = tu->asBytes[3];
5214 + sparePtr->tagByte4 = tu->asBytes[4];
5215 + sparePtr->tagByte5 = tu->asBytes[5];
5216 + sparePtr->tagByte6 = tu->asBytes[6];
5217 + sparePtr->tagByte7 = tu->asBytes[7];
5220 +static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr)
5222 + yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
5225 + tu->asBytes[0]= sparePtr->tagByte0;
5226 + tu->asBytes[1]= sparePtr->tagByte1;
5227 + tu->asBytes[2]= sparePtr->tagByte2;
5228 + tu->asBytes[3]= sparePtr->tagByte3;
5229 + tu->asBytes[4]= sparePtr->tagByte4;
5230 + tu->asBytes[5]= sparePtr->tagByte5;
5231 + tu->asBytes[6]= sparePtr->tagByte6;
5232 + tu->asBytes[7]= sparePtr->tagByte7;
5234 + result = yaffs_CheckECCOnTags(tagsPtr);
5237 + dev->tagsEccFixed++;
5239 + else if(result <0)
5241 + dev->tagsEccUnfixed++;
5245 +static void yaffs_SpareInitialise(yaffs_Spare *spare)
5247 + memset(spare,0xFF,sizeof(yaffs_Spare));
5253 +static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_ExtendedTags *tags, int useReserve)
5255 + // NB There must be tags, data is optional
5256 + // If there is data, then an ECC is calculated on it.
5258 + yaffs_Spare spare;
5262 + return YAFFS_FAIL;
5265 + //yaffs_SpareInitialise(&spare);
5267 + //if(!dev->useNANDECC && buffer)
5269 + // yaffs_CalcECC(buffer,&spare);
5272 + //yaffs_LoadTagsIntoSpare(&spare,tags);
5274 + return yaffs_WriteNewChunkToNAND(dev,buffer,&spare,useReserve);
5279 +static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, int chunkInObject)
5281 + return ( tags->chunkId == chunkInObject &&
5282 + tags->objectId == objectId &&
5283 + !tags->chunkDeleted) ? 1 : 0;
5287 +/////////////////////////////////////////////////////////////////////////////////////////////////////////
5290 +static int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
5292 + //Get the Tnode, then get the level 0 offset chunk offset
5294 + int theChunk = -1;
5295 + yaffs_ExtendedTags localTags;
5298 + yaffs_Device *dev = in->myDev;
5303 + // Passed a NULL, so use our own tags space
5304 + tags = &localTags;
5307 + tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
5311 + theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
5313 + retVal = yaffs_FindChunkInGroup(dev,theChunk,tags,in->objectId,chunkInInode);
5318 +static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
5320 + //Get the Tnode, then get the level 0 offset chunk offset
5322 + int theChunk = -1;
5323 + yaffs_ExtendedTags localTags;
5325 + yaffs_Device *dev = in->myDev;
5330 + // Passed a NULL, so use our own tags space
5331 + tags = &localTags;
5334 + tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
5339 + theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
5341 + retVal = yaffs_FindChunkInGroup(dev,theChunk,tags,in->objectId,chunkInInode);
5343 + // Delete the entry in the filestructure (if found)
5346 + tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = 0;
5351 + //T(("No level 0 found for %d\n", chunkInInode));
5356 + //T(("Could not find %d to delete\n",chunkInInode));
5362 +#ifdef YAFFS_PARANOID
5364 +static int yaffs_CheckFileSanity(yaffs_Object *in)
5372 + yaffs_Tags localTags;
5373 + yaffs_Tags *tags = &localTags;
5378 + if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
5380 + //T(("Object not a file\n"));
5381 + return YAFFS_FAIL;
5384 + objId = in->objectId;
5385 + fSize = in->variant.fileVariant.fileSize;
5386 + nChunks = (fSize + in->myDev->nBytesPerChunk -1)/in->myDev->nBytesPerChunk;
5388 + for(chunk = 1; chunk <= nChunks; chunk++)
5390 + tn = yaffs_FindLevel0Tnode(in->myDev,&in->variant.fileVariant, chunk);
5395 + theChunk = tn->level0[chunk & YAFFS_TNODES_LEVEL0_MASK] << in->myDev->chunkGroupBits;
5397 + if(yaffs_CheckChunkBits(dev,theChunk/dev->nChunksPerBlock,theChunk%dev->nChunksPerBlock))
5401 + yaffs_ReadChunkTagsFromNAND(in->myDev,theChunk,tags,&chunkDeleted);
5402 + if(yaffs_TagsMatch(tags,in->objectId,chunk,chunkDeleted))
5410 + //T(("File problem file [%d,%d] NAND %d tags[%d,%d]\n",
5411 + // objId,chunk,theChunk,tags->chunkId,tags->objectId);
5420 + //T(("No level 0 found for %d\n", chunk));
5424 + return failed ? YAFFS_FAIL : YAFFS_OK;
5429 +static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan)
5431 + // NB inScan is zero unless scanning. For forward scanning, inScan is > 0; for backward scanning inScan is < 0
5433 + yaffs_Device *dev = in->myDev;
5434 + int existingChunk;
5435 + yaffs_ExtendedTags existingTags;
5436 + yaffs_ExtendedTags newTags;
5437 + unsigned existingSerial, newSerial;
5439 + if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
5441 + // Just ignore an attempt at putting a chunk into a non-file during scanning
5442 + // If it is not during Scanning then something went wrong!
5445 + T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy:attempt to put data chunk into a non-file" TENDSTR)));
5449 + yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__);
5453 + tn = yaffs_AddOrFindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
5456 + return YAFFS_FAIL;
5459 + existingChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK];
5463 + // If we're scanning then we need to test for duplicates
5464 + // NB This does not need to be efficient since it should only ever
5465 + // happen when the power fails during a write, then only one
5466 + // chunk should ever be affected.
5468 + // Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
5469 + // Update: For backward scanning we don't need to re-read tags so this is quite cheap.
5473 + if(existingChunk != 0)
5475 + // NB Right now existing chunk will not be real chunkId if the device >= 32MB
5476 + // thus we have to do a FindChunkInFile to get the real chunk id.
5478 + // We have a duplicate now we need to decide which one to use:
5480 + // Backwards scanning YAFFS2: The old one is what we use, dump the new one.
5481 + // Forward scanning YAFFS2: The new one is what we use, dump the old one.
5482 + // YAFFS1: Get both sets of tags and compare serial numbers.
5488 + // Only do this for forward scanning
5489 + yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND, NULL,&newTags);
5492 + // Do a proper find
5493 + existingChunk = yaffs_FindChunkInFile(in,chunkInInode, &existingTags);
5496 + if(existingChunk <=0)
5498 + //Hoosterman - how did this happen?
5500 + T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: existing chunk < 0 in scan" TENDSTR)));
5505 + // NB The deleted flags should be false, otherwise the chunks will
5506 + // not be loaded during a scan
5508 + newSerial = newTags.serialNumber;
5509 + existingSerial = existingTags.serialNumber;
5511 + if( (inScan > 0) &&
5512 + ( in->myDev->isYaffs2 ||
5513 + existingChunk <= 0 ||
5514 + ((existingSerial+1) & 3) == newSerial))
5516 + // Forward scanning.
5518 + // Delete the old one and drop through to update the tnode
5519 + yaffs_DeleteChunk(dev,existingChunk,1,__LINE__);
5523 + // Backward scanning or we want to use the existing one
5525 + // Delete the new one and return early so that the tnode isn't changed
5526 + yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__);
5533 + if(existingChunk == 0)
5535 + in->nDataChunks++;
5538 + tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = (chunkInNAND >> dev->chunkGroupBits);
5545 +static int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffer)
5547 + int chunkInNAND = yaffs_FindChunkInFile(in,chunkInInode,NULL);
5549 + if(chunkInNAND >= 0)
5551 + return yaffs_ReadChunkWithTagsFromNAND(in->myDev,chunkInNAND,buffer,NULL);
5555 + T(YAFFS_TRACE_NANDACCESS,(TSTR("Chunk %d not found zero instead" TENDSTR),chunkInNAND));
5557 + memset(buffer,0,in->myDev->nBytesPerChunk); // get sane data if you read a hole
5564 +void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND,int lyn)
5568 + yaffs_ExtendedTags tags;
5569 + yaffs_BlockInfo *bi;
5571 + if(chunkId <= 0) return;
5573 + dev->nDeletions++;
5574 + block = chunkId / dev->nChunksPerBlock;
5575 + page = chunkId % dev->nChunksPerBlock;
5577 + bi = yaffs_GetBlockInfo(dev,block);
5579 + T(YAFFS_TRACE_DELETION,(TSTR("line %d delete of chunk %d" TENDSTR),lyn,chunkId));
5582 + bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
5585 +// yaffs_SpareInitialise(&spare);
5587 +#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
5589 + //read data before write, to ensure correct ecc
5590 + //if we're using MTD verification under Linux
5591 +// yaffs_ReadChunkFromNAND(dev,chunkId,NULL,&spare,0);
5594 + yaffs_InitialiseTags(&tags);
5596 + tags.chunkDeleted = 1;
5599 + yaffs_WriteChunkWithTagsToNAND(dev,chunkId,NULL,&tags);
5600 + yaffs_HandleUpdateChunk(dev,chunkId,&tags);
5604 + dev->nUnmarkedDeletions++;
5608 + // Pull out of the management area.
5609 + // If the whole block became dirty, this will kick off an erasure.
5610 + if( bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
5611 + bi->blockState == YAFFS_BLOCK_STATE_FULL ||
5612 + bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
5613 + bi->blockState == YAFFS_BLOCK_STATE_COLLECTING)
5615 + dev->nFreeChunks++;
5617 + yaffs_ClearChunkBit(dev,block,page);
5621 + if(bi->pagesInUse == 0 &&
5622 + !bi->hasShrinkHeader &&
5623 + bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
5624 + bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING)
5626 + yaffs_BlockBecameDirty(dev,block);
5632 + // T(("Bad news deleting chunk %d\n",chunkId));
5640 +static int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *buffer,int nBytes,int useReserve)
5642 + // Find old chunk Need to do this to get serial number
5643 + // Write new one and patch into tree.
5644 + // Invalidate old tags.
5647 + yaffs_ExtendedTags prevTags;
5650 + yaffs_ExtendedTags newTags;
5652 + yaffs_Device *dev = in->myDev;
5654 + yaffs_CheckGarbageCollection(dev);
5656 + // Get the previous chunk at this location in the file if it exists
5657 + prevChunkId = yaffs_FindChunkInFile(in,chunkInInode,&prevTags);
5659 + // Set up new tags
5660 + yaffs_InitialiseTags(&newTags);
5662 + newTags.chunkId = chunkInInode;
5663 + newTags.objectId = in->objectId;
5664 + newTags.serialNumber = (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
5665 + newTags.byteCount = nBytes;
5667 +// yaffs_CalcTagsECC(&newTags);
5669 + newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags,useReserve);
5671 + if(newChunkId >= 0)
5673 + yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId,0);
5676 + if(prevChunkId >= 0)
5678 + yaffs_DeleteChunk(dev,prevChunkId,1,__LINE__);
5682 + yaffs_CheckFileSanity(in);
5684 + return newChunkId;
5693 +// UpdateObjectHeader updates the header on NAND for an object.
5694 +// If name is not NULL, then that new name is used.
5696 +int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink,int shadows)
5699 + yaffs_BlockInfo *bi;
5701 + yaffs_Device *dev = in->myDev;
5707 + yaffs_ExtendedTags newTags;
5709 + __u8 *buffer = NULL;
5710 + YCHAR oldName[YAFFS_MAX_NAME_LENGTH+1];
5712 + // __u8 bufferOld[YAFFS_BYTES_PER_CHUNK];
5714 + yaffs_ObjectHeader *oh = NULL;
5715 + // yaffs_ObjectHeader *ohOld = (yaffs_ObjectHeader *)bufferOld;
5718 + if(!in->fake || force)
5721 + yaffs_CheckGarbageCollection(dev);
5723 + buffer = yaffs_GetTempBuffer(in->myDev,__LINE__);
5724 + oh = (yaffs_ObjectHeader *)buffer;
5726 + prevChunkId = in->chunkId;
5728 + if(prevChunkId >= 0)
5730 + yaffs_ReadChunkWithTagsFromNAND(dev,prevChunkId,buffer,NULL);
5731 + memcpy(oldName,oh->name,sizeof(oh->name));
5734 + memset(buffer,0xFF,dev->nBytesPerChunk);
5737 + oh->type = in->variantType;
5739 + oh->yst_mode = in->yst_mode;
5742 + oh->shadowsObject = shadows;
5744 +#ifdef CONFIG_YAFFS_WINCE
5745 + oh->win_atime[0] = in->win_atime[0];
5746 + oh->win_ctime[0] = in->win_ctime[0];
5747 + oh->win_mtime[0] = in->win_mtime[0];
5748 + oh->win_atime[1] = in->win_atime[1];
5749 + oh->win_ctime[1] = in->win_ctime[1];
5750 + oh->win_mtime[1] = in->win_mtime[1];
5752 + oh->yst_uid = in->yst_uid;
5753 + oh->yst_gid = in->yst_gid;
5754 + oh->yst_atime = in->yst_atime;
5755 + oh->yst_mtime = in->yst_mtime;
5756 + oh->yst_ctime = in->yst_ctime;
5757 + oh->yst_rdev = in->yst_rdev;
5761 + oh->parentObjectId = in->parent->objectId;
5765 + oh->parentObjectId = 0;
5768 + //oh->sum = in->sum;
5771 + memset(oh->name,0,sizeof(oh->name));
5772 + yaffs_strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH);
5774 + else if(prevChunkId)
5776 + memcpy(oh->name, oldName,sizeof(oh->name));
5780 + memset(oh->name,0,sizeof(oh->name));
5783 + oh->isShrink = isShrink;
5785 + switch(in->variantType)
5787 + case YAFFS_OBJECT_TYPE_UNKNOWN:
5788 + // Should not happen
5790 + case YAFFS_OBJECT_TYPE_FILE:
5791 + oh->fileSize = (oh->parentObjectId == YAFFS_OBJECTID_DELETED ||
5792 + oh->parentObjectId == YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.fileVariant.fileSize;
5794 + case YAFFS_OBJECT_TYPE_HARDLINK:
5795 + oh->equivalentObjectId = in->variant.hardLinkVariant.equivalentObjectId;
5797 + case YAFFS_OBJECT_TYPE_SPECIAL:
5800 + case YAFFS_OBJECT_TYPE_DIRECTORY:
5803 + case YAFFS_OBJECT_TYPE_SYMLINK:
5804 + yaffs_strncpy(oh->alias,in->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
5805 + oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
5810 + yaffs_InitialiseTags(&newTags);
5812 + newTags.chunkId = 0;
5813 + newTags.objectId = in->objectId;
5814 + newTags.serialNumber = in->serial;
5816 + // Add extra info for file header
5818 + newTags.extraHeaderInfoAvailable = 1;
5819 + newTags.extraParentObjectId = oh->parentObjectId;
5820 + newTags.extraFileLength = oh->fileSize;
5821 + newTags.extraIsShrinkHeader = oh->isShrink;
5822 + newTags.extraEquivalentObjectId = oh->equivalentObjectId;
5823 + newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
5824 + newTags.extraObjectType = in->variantType;
5826 + // Create new chunk in NAND
5827 + newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags, (prevChunkId >= 0) ? 1 : 0 );
5829 + if(newChunkId >= 0)
5832 + in->chunkId = newChunkId;
5834 + if(prevChunkId >= 0)
5836 + yaffs_DeleteChunk(dev,prevChunkId,1,__LINE__);
5841 + // If this was a shrink, then mark the block that the chunk lives on
5844 + bi = yaffs_GetBlockInfo(in->myDev,newChunkId / in->myDev->nChunksPerBlock);
5845 + bi->hasShrinkHeader = 1;
5850 + retVal = newChunkId;
5855 + yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
5861 +/////////////////////// Short Operations Cache ////////////////////////////////
5862 +// In many siturations where there is no high level buffering (eg WinCE) a lot of
5863 +// reads might be short sequential reads, and a lot of writes may be short
5864 +// sequential writes. eg. scanning/writing a jpeg file.
5865 +// In these cases, a short read/write cache can provide a huge perfomance benefit
5866 +// with dumb-as-a-rock code.
5867 +// There are a limited number (~10) of cache chunks per device so that we don't
5868 +// need a very intelligent search.
5874 +static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
5876 + yaffs_Device *dev = obj->myDev;
5877 + int lowest = -99; // Stop compiler whining.
5879 + yaffs_ChunkCache *cache;
5880 + int chunkWritten = 0;
5882 + int nCaches = obj->myDev->nShortOpCaches;
5889 + // Find the dirty cache for this object with the lowest chunk id.
5890 + for(i = 0; i < nCaches; i++)
5892 + if(dev->srCache[i].object == obj &&
5893 + dev->srCache[i].dirty)
5895 + if(!cache || dev->srCache[i].chunkId < lowest)
5897 + cache = &dev->srCache[i];
5898 + lowest = cache->chunkId;
5903 + if(cache && !cache->locked)
5905 + //Write it out and free it up
5908 + nBytes = cache->object->variant.fileVariant.fileSize - ((cache->chunkId -1) * YAFFS_BYTES_PER_CHUNK);
5910 + if(nBytes > YAFFS_BYTES_PER_CHUNK)
5912 + nBytes= YAFFS_BYTES_PER_CHUNK;
5915 + chunkWritten = yaffs_WriteChunkDataToObject(cache->object,
5921 + cache->object = NULL;
5924 + } while(cache && chunkWritten > 0);
5928 + //Hoosterman, disk full while writing cache out.
5929 + T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
5937 +// Grab us a chunk for use.
5938 +// First look for an empty one.
5939 +// Then look for the least recently used non-dirty one.
5940 +// Then look for the least recently used dirty one...., flush and look again.
5941 +static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
5947 + if(dev->nShortOpCaches > 0)
5949 + for(i = 0; i < dev->nShortOpCaches; i++)
5951 + if(!dev->srCache[i].object)
5953 + //T(("Grabbing empty %d\n",i));
5955 + //printf("Grabbing empty %d\n",i);
5957 + return &dev->srCache[i];
5964 + usage = 0; // just to stop the compiler grizzling
5966 + for(i = 0; i < dev->nShortOpCaches; i++)
5968 + if(!dev->srCache[i].dirty &&
5969 + ((dev->srCache[i].lastUse < usage && theOne >= 0)||
5972 + usage = dev->srCache[i].lastUse;
5977 + //T(("Grabbing non-empty %d\n",theOne));
5979 + //if(theOne >= 0) printf("Grabbed non-empty cache %d\n",theOne);
5981 + return theOne >= 0 ? &dev->srCache[theOne] : NULL;
5991 +static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
5993 + yaffs_ChunkCache *cache;
5994 + yaffs_Object *theObj;
5999 + if(dev->nShortOpCaches > 0)
6001 + // Try find a non-dirty one...
6003 + cache = yaffs_GrabChunkCacheWorker(dev);
6007 + // They were all dirty, find the last recently used object and flush
6008 + // its cache, then find again.
6009 + // NB what's here is not very accurate, we actually flush the object
6010 + // the last recently used page.
6012 + // With locking we can't assume we can use entry zero
6020 + for(i = 0; i < dev->nShortOpCaches; i++)
6022 + if( dev->srCache[i].object &&
6023 + !dev->srCache[i].locked &&
6024 + (dev->srCache[i].lastUse < usage || !cache))
6026 + usage = dev->srCache[i].lastUse;
6027 + theObj = dev->srCache[i].object;
6028 + cache = &dev->srCache[i];
6033 + if(!cache || cache->dirty)
6036 + //printf("Dirty ");
6037 + yaffs_FlushFilesChunkCache(theObj);
6040 + cache = yaffs_GrabChunkCacheWorker(dev);
6044 + //printf(" pushout %d\n",pushout);
6056 +// Find a cached chunk
6057 +static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj, int chunkId)
6059 + yaffs_Device *dev = obj->myDev;
6061 + if(dev->nShortOpCaches > 0)
6063 + for(i = 0; i < dev->nShortOpCaches; i++)
6065 + if(dev->srCache[i].object == obj &&
6066 + dev->srCache[i].chunkId == chunkId)
6070 + return &dev->srCache[i];
6077 +// Mark the chunk for the least recently used algorithym
6078 +static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache, int isAWrite)
6081 + if(dev->nShortOpCaches > 0)
6083 + if( dev->srLastUse < 0 ||
6084 + dev->srLastUse > 100000000)
6086 + // Reset the cache usages
6088 + for(i = 1; i < dev->nShortOpCaches; i++)
6090 + dev->srCache[i].lastUse = 0;
6092 + dev->srLastUse = 0;
6097 + cache->lastUse = dev->srLastUse;
6106 +// Invalidate a single cache page.
6107 +// Do this when a whole page gets written,
6108 +// ie the short cache for this page is no longer valid.
6109 +static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)
6111 + if(object->myDev->nShortOpCaches > 0)
6113 + yaffs_ChunkCache *cache = yaffs_FindChunkCache(object,chunkId);
6117 + cache->object = NULL;
6123 +// Invalidate all the cache pages associated with this object
6124 +// Do this whenever ther file is deleted or resized.
6125 +static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
6128 + yaffs_Device *dev = in->myDev;
6130 + if(dev->nShortOpCaches > 0)
6132 + // Now invalidate it.
6133 + for(i = 0; i < dev->nShortOpCaches; i++)
6135 + if(dev->srCache[i].object == in)
6137 + dev->srCache[i].object = NULL;
6147 +///////////////////////// File read/write ///////////////////////////////
6148 +// Read and write have very similar structures.
6149 +// In general the read/write has three parts to it
6150 +// * An incomplete chunk to start with (if the read/write is not chunk-aligned)
6151 +// * Some complete chunks
6152 +// * An incomplete chunk to end off with
6154 +// Curve-balls: the first chunk might also be the last chunk.
6156 +int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nBytes)
6165 + yaffs_ChunkCache *cache;
6167 + yaffs_Device *dev;
6173 + chunk = offset / dev->nBytesPerChunk + 1; // The first chunk is 1
6174 + start = offset % dev->nBytesPerChunk;
6176 + // OK now check for the curveball where the start and end are in
6177 + // the same chunk.
6178 + if( (start + n) < dev->nBytesPerChunk)
6184 + nToCopy = dev->nBytesPerChunk - start;
6187 + cache = yaffs_FindChunkCache(in,chunk);
6189 + // If the chunk is already in the cache or it is less than a whole chunk
6190 + // then use the cache (if there is caching)
6191 + // else bypass the cache.
6192 + if( cache || nToCopy != dev->nBytesPerChunk)
6194 + if(dev->nShortOpCaches > 0)
6197 + // If we can't find the data in the cache, then load it up.
6201 + cache = yaffs_GrabChunkCache(in->myDev);
6202 + cache->object = in;
6203 + cache->chunkId = chunk;
6205 + cache->locked = 0;
6206 + yaffs_ReadChunkDataFromObject(in,chunk,cache->data);
6207 + cache->nBytes = 0;
6210 + yaffs_UseChunkCache(dev,cache,0);
6212 + cache->locked = 1;
6214 +#ifdef CONFIG_YAFFS_WINCE
6215 + yfsd_UnlockYAFFS(TRUE);
6217 + memcpy(buffer,&cache->data[start],nToCopy);
6219 +#ifdef CONFIG_YAFFS_WINCE
6220 + yfsd_LockYAFFS(TRUE);
6222 + cache->locked = 0;
6226 + // Read into the local buffer then copy...
6228 + __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
6229 + yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
6230 +#ifdef CONFIG_YAFFS_WINCE
6231 + yfsd_UnlockYAFFS(TRUE);
6233 + memcpy(buffer,&localBuffer[start],nToCopy);
6235 +#ifdef CONFIG_YAFFS_WINCE
6236 + yfsd_LockYAFFS(TRUE);
6238 + yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
6244 +#ifdef CONFIG_YAFFS_WINCE
6245 + __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
6247 + // Under WinCE can't do direct transfer. Need to use a local buffer.
6248 + // This is because we otherwise screw up WinCE's memory mapper
6249 + yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
6251 +#ifdef CONFIG_YAFFS_WINCE
6252 + yfsd_UnlockYAFFS(TRUE);
6254 + memcpy(buffer,localBuffer,dev->nBytesPerChunk);
6256 +#ifdef CONFIG_YAFFS_WINCE
6257 + yfsd_LockYAFFS(TRUE);
6258 + yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
6262 + // A full chunk. Read directly into the supplied buffer.
6263 + yaffs_ReadChunkDataFromObject(in,chunk,buffer);
6268 + offset += nToCopy;
6269 + buffer += nToCopy;
6279 +int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, int nBytes, int writeThrough)
6288 + int startOfWrite = offset;
6289 + int chunkWritten = 0;
6292 + yaffs_Device *dev;
6297 + while(n > 0 && chunkWritten >= 0)
6299 + chunk = offset / dev->nBytesPerChunk + 1;
6300 + start = offset % dev->nBytesPerChunk;
6303 + // OK now check for the curveball where the start and end are in
6304 + // the same chunk.
6306 + if((start + n) < dev->nBytesPerChunk)
6310 + // Now folks, to calculate how many bytes to write back....
6311 + // If we're overwriting and not writing to then end of file then
6312 + // we need to write back as much as was there before.
6314 + nBytesRead = in->variant.fileVariant.fileSize - ((chunk -1) * dev->nBytesPerChunk);
6316 + if(nBytesRead > dev->nBytesPerChunk)
6318 + nBytesRead = dev->nBytesPerChunk;
6321 + nToWriteBack = (nBytesRead > (start + n)) ? nBytesRead : (start +n);
6326 + nToCopy = dev->nBytesPerChunk - start;
6327 + nToWriteBack = dev->nBytesPerChunk;
6330 + if(nToCopy != dev->nBytesPerChunk)
6332 + // An incomplete start or end chunk (or maybe both start and end chunk)
6333 + if(dev->nShortOpCaches > 0)
6335 + yaffs_ChunkCache *cache;
6336 + // If we can't find the data in the cache, then load it up.
6337 + cache = yaffs_FindChunkCache(in,chunk);
6338 + if(!cache && yaffs_CheckSpaceForAllocation(in->myDev))
6340 + cache = yaffs_GrabChunkCache(in->myDev);
6341 + cache->object = in;
6342 + cache->chunkId = chunk;
6344 + cache->locked = 0;
6345 + yaffs_ReadChunkDataFromObject(in,chunk,cache->data);
6350 + yaffs_UseChunkCache(dev,cache,1);
6351 + cache->locked = 1;
6352 +#ifdef CONFIG_YAFFS_WINCE
6353 + yfsd_UnlockYAFFS(TRUE);
6356 + memcpy(&cache->data[start],buffer,nToCopy);
6358 +#ifdef CONFIG_YAFFS_WINCE
6359 + yfsd_LockYAFFS(TRUE);
6361 + cache->locked = 0;
6362 + cache->nBytes = nToWriteBack;
6366 + chunkWritten = yaffs_WriteChunkDataToObject(cache->object,
6376 + chunkWritten = -1; // fail the write
6381 + // An incomplete start or end chunk (or maybe both start and end chunk)
6382 + // Read into the local buffer then copy, then copy over and write back.
6384 + __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
6386 + yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
6388 +#ifdef CONFIG_YAFFS_WINCE
6389 + yfsd_UnlockYAFFS(TRUE);
6392 + memcpy(&localBuffer[start],buffer,nToCopy);
6394 +#ifdef CONFIG_YAFFS_WINCE
6395 + yfsd_LockYAFFS(TRUE);
6397 + chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,localBuffer,nToWriteBack,0);
6399 + yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
6401 + //T(("Write with readback to chunk %d %d start %d copied %d wrote back %d\n",chunk,chunkWritten,start, nToCopy, nToWriteBack));
6408 +#ifdef CONFIG_YAFFS_WINCE
6409 + // Under WinCE can't do direct transfer. Need to use a local buffer.
6410 + // This is because we otherwise screw up WinCE's memory mapper
6411 + __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
6412 +#ifdef CONFIG_YAFFS_WINCE
6413 + yfsd_UnlockYAFFS(TRUE);
6415 + memcpy(localBuffer,buffer,dev->nBytesPerChunk);
6416 +#ifdef CONFIG_YAFFS_WINCE
6417 + yfsd_LockYAFFS(TRUE);
6419 + chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,localBuffer,dev->nBytesPerChunk,0);
6420 + yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
6422 + // A full chunk. Write directly from the supplied buffer.
6423 + chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,buffer,dev->nBytesPerChunk,0);
6425 + // Since we've overwritten the cached data, we better invalidate it.
6426 + yaffs_InvalidateChunkCache(in,chunk);
6427 + //T(("Write to chunk %d %d\n",chunk,chunkWritten));
6430 + if(chunkWritten >= 0)
6433 + offset += nToCopy;
6434 + buffer += nToCopy;
6440 + // Update file object
6442 + if((startOfWrite + nDone) > in->variant.fileVariant.fileSize)
6444 + in->variant.fileVariant.fileSize = (startOfWrite + nDone);
6452 +static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
6455 + yaffs_Device *dev = in->myDev;
6456 + int oldFileSize = in->variant.fileVariant.fileSize;
6459 + int lastDel = 1 + (oldFileSize-1)/dev->nBytesPerChunk;
6461 + int startDel = 1 + (newSize + dev->nBytesPerChunk - 1)/
6462 + dev->nBytesPerChunk;
6466 + // Delete backwards so that we don't end up with holes if
6467 + // power is lost part-way through the operation.
6468 + for(i = lastDel; i >= startDel; i--)
6470 + // NB this could be optimised somewhat,
6471 + // eg. could retrieve the tags and write them without
6472 + // using yaffs_DeleteChunk
6474 + chunkId = yaffs_FindAndDeleteChunkInFile(in,i,NULL);
6477 + if(chunkId < (dev->internalStartBlock * dev->nChunksPerBlock) ||
6478 + chunkId >= ((dev->internalEndBlock+1) * dev->nChunksPerBlock))
6480 + T(YAFFS_TRACE_ALWAYS,(TSTR("Found daft chunkId %d for %d"TENDSTR),chunkId,i));
6484 + in->nDataChunks--;
6485 + yaffs_DeleteChunk(dev,chunkId,1,__LINE__);
6492 +int yaffs_ResizeFile(yaffs_Object *in, int newSize)
6495 + int oldFileSize = in->variant.fileVariant.fileSize;
6496 + int sizeOfPartialChunk;
6497 + yaffs_Device *dev = in->myDev;
6499 + sizeOfPartialChunk = newSize % dev->nBytesPerChunk;
6502 + yaffs_FlushFilesChunkCache(in);
6503 + yaffs_InvalidateWholeChunkCache(in);
6505 + yaffs_CheckGarbageCollection(dev);
6507 + if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
6509 + return yaffs_GetFileSize(in);
6512 + if(newSize < oldFileSize)
6515 + yaffs_PruneResizedChunks(in,newSize);
6517 + if(sizeOfPartialChunk != 0)
6519 + int lastChunk = 1+ newSize/dev->nBytesPerChunk;
6520 + __u8 *localBuffer = yaffs_GetTempBuffer(dev,__LINE__);
6522 + // Got to read and rewrite the last chunk with its new size and zero pad
6523 + yaffs_ReadChunkDataFromObject(in,lastChunk,localBuffer);
6525 + memset(localBuffer + sizeOfPartialChunk,0, dev->nBytesPerChunk - sizeOfPartialChunk);
6527 + yaffs_WriteChunkDataToObject(in,lastChunk,localBuffer,sizeOfPartialChunk,1);
6529 + yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
6532 + in->variant.fileVariant.fileSize = newSize;
6534 + yaffs_PruneFileStructure(dev,&in->variant.fileVariant);
6536 + // Write a new object header to show we've shrunk the file
6537 + // Do this only if the file is not in the deleted directories.
6538 + if(in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
6539 + in->parent->objectId != YAFFS_OBJECTID_DELETED
6542 + yaffs_UpdateObjectHeader(in,NULL, 0, 1,0);
6551 + return oldFileSize;
6556 +loff_t yaffs_GetFileSize(yaffs_Object *obj)
6558 + obj = yaffs_GetEquivalentObject(obj);
6560 + switch(obj->variantType)
6562 + case YAFFS_OBJECT_TYPE_FILE:
6563 + return obj->variant.fileVariant.fileSize;
6564 + case YAFFS_OBJECT_TYPE_SYMLINK:
6565 + return yaffs_strlen(obj->variant.symLinkVariant.alias);
6573 +// yaffs_FlushFile() updates the file's
6574 +// objectId in NAND
6576 +int yaffs_FlushFile(yaffs_Object *in, int updateTime)
6581 + //T(("flushing object header\n"));
6583 + yaffs_FlushFilesChunkCache(in);
6586 +#ifdef CONFIG_YAFFS_WINCE
6587 + yfsd_WinFileTimeNow(in->win_mtime);
6590 + in->yst_mtime = Y_CURRENT_TIME;
6595 + retVal = (yaffs_UpdateObjectHeader(in,NULL,0,0,0) >= 0)? YAFFS_OK : YAFFS_FAIL;
6599 + retVal = YAFFS_OK;
6607 +static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
6610 + // First off, invalidate the file's data in the cache, without flushing.
6611 + yaffs_InvalidateWholeChunkCache(in);
6613 + if(in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir))
6615 + // Move to the unlinked directory so we have a record that it was deleted.
6616 + yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0,0);
6621 + yaffs_RemoveObjectFromDirectory(in);
6622 + yaffs_DeleteChunk(in->myDev,in->chunkId,1,__LINE__);
6628 + in->myInode->u.generic_ip = NULL;
6634 + yaffs_FreeObject(in);
6639 +// yaffs_DeleteFile deletes the whole file data
6640 +// and the inode associated with the file.
6641 +// It does not delete the links associated with the file.
6642 +static int yaffs_UnlinkFile(yaffs_Object *in)
6645 +#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND_DELETION
6647 + // Delete the file data & tnodes
6649 + yaffs_DeleteWorker(in, in->variant.fileVariant.top, in->variant.fileVariant.topLevel, 0,NULL);
6652 + yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top);
6654 + return yaffs_DoGenericObjectDeletion(in);
6657 + int immediateDeletion=0;
6661 + //in->unlinked = 1;
6662 + //in->myDev->nUnlinkedFiles++;
6663 + //in->renameAllowed = 0;
6667 + immediateDeletion = 1;
6671 + if(in->inUse <= 0)
6673 + immediateDeletion = 1;
6677 + if(immediateDeletion)
6679 + retVal = yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0,0);
6680 + T(YAFFS_TRACE_TRACING,(TSTR("yaffs: immediate deletion of file %d" TENDSTR),in->objectId));
6682 + in->myDev->nDeletedFiles++;
6683 + if( 0 && in->myDev->isYaffs2)
6685 + yaffs_ResizeFile(in,0);
6687 + yaffs_SoftDeleteFile(in);
6691 + retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL,0,0);
6701 +int yaffs_DeleteFile(yaffs_Object *in)
6703 + int retVal = YAFFS_OK;
6705 + if(in->nDataChunks > 0)
6707 + // Use soft deletion
6710 + retVal = yaffs_UnlinkFile(in);
6712 + if(retVal == YAFFS_OK &&
6717 + in->myDev->nDeletedFiles++;
6718 + yaffs_SoftDeleteFile(in);
6720 + return in->deleted ? YAFFS_OK : YAFFS_FAIL;
6724 + // The file has no data chunks so we toss it immediately
6725 + yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top);
6726 + in->variant.fileVariant.top = NULL;
6727 + yaffs_DoGenericObjectDeletion(in);
6733 +static int yaffs_DeleteDirectory(yaffs_Object *in)
6735 + //First check that the directory is empty.
6736 + if(list_empty(&in->variant.directoryVariant.children))
6738 + return yaffs_DoGenericObjectDeletion(in);
6741 + return YAFFS_FAIL;
6745 +static int yaffs_DeleteSymLink(yaffs_Object *in)
6747 + YFREE(in->variant.symLinkVariant.alias);
6749 + return yaffs_DoGenericObjectDeletion(in);
6752 +static int yaffs_DeleteHardLink(yaffs_Object *in)
6754 + // remove this hardlink from the list assocaited with the equivalent
6756 + list_del(&in->hardLinks);
6757 + return yaffs_DoGenericObjectDeletion(in);
6761 +static void yaffs_DestroyObject(yaffs_Object *obj)
6763 + switch(obj->variantType)
6765 + case YAFFS_OBJECT_TYPE_FILE: yaffs_DeleteFile(obj); break;
6766 + case YAFFS_OBJECT_TYPE_DIRECTORY: yaffs_DeleteDirectory(obj); break;
6767 + case YAFFS_OBJECT_TYPE_SYMLINK: yaffs_DeleteSymLink(obj); break;
6768 + case YAFFS_OBJECT_TYPE_HARDLINK: yaffs_DeleteHardLink(obj); break;
6769 + case YAFFS_OBJECT_TYPE_SPECIAL: yaffs_DoGenericObjectDeletion(obj); break;
6770 + case YAFFS_OBJECT_TYPE_UNKNOWN: break; // should not happen.
6775 +static int yaffs_UnlinkWorker(yaffs_Object *obj)
6779 + if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
6781 + return yaffs_DeleteHardLink(obj);
6783 + else if(!list_empty(&obj->hardLinks))
6785 + // Curve ball: We're unlinking an object that has a hardlink.
6787 + // This problem arises because we are not strictly following
6788 + // The Linux link/inode model.
6790 + // We can't really delete the object.
6791 + // Instead, we do the following:
6792 + // - Select a hardlink.
6793 + // - Unhook it from the hard links
6794 + // - Unhook it from its parent directory (so that the rename can work)
6795 + // - Rename the object to the hardlink's name.
6796 + // - Delete the hardlink
6801 + YCHAR name[YAFFS_MAX_NAME_LENGTH+1];
6803 + hl = list_entry(obj->hardLinks.next,yaffs_Object,hardLinks);
6805 + list_del_init(&hl->hardLinks);
6806 + list_del_init(&hl->siblings);
6808 + yaffs_GetObjectName(hl,name,YAFFS_MAX_NAME_LENGTH+1);
6810 + retVal = yaffs_ChangeObjectName(obj, hl->parent, name,0,0);
6812 + if(retVal == YAFFS_OK)
6814 + retVal = yaffs_DoGenericObjectDeletion(hl);
6821 + switch(obj->variantType)
6823 + case YAFFS_OBJECT_TYPE_FILE:
6824 + return yaffs_UnlinkFile(obj);
6826 + case YAFFS_OBJECT_TYPE_DIRECTORY:
6827 + return yaffs_DeleteDirectory(obj);
6829 + case YAFFS_OBJECT_TYPE_SYMLINK:
6830 + return yaffs_DeleteSymLink(obj);
6832 + case YAFFS_OBJECT_TYPE_SPECIAL:
6833 + return yaffs_DoGenericObjectDeletion(obj);
6835 + case YAFFS_OBJECT_TYPE_HARDLINK:
6836 + case YAFFS_OBJECT_TYPE_UNKNOWN:
6838 + return YAFFS_FAIL;
6843 +int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)
6845 + yaffs_Object *obj;
6847 + obj = yaffs_FindObjectByName(dir,name);
6849 + if(obj && obj->unlinkAllowed)
6851 + return yaffs_UnlinkWorker(obj);
6854 + return YAFFS_FAIL;
6858 +//////////////// Initialisation Scanning /////////////////
6861 +void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, int backwardScanning)
6867 +// For now we use the SmartMedia check.
6868 +// We look at the blockStatus byte in the first two chunks
6869 +// These must be 0xFF to pass as OK.
6870 +// todo: this function needs to be modifyable foir different NAND types
6871 +// and different chunk sizes. Suggest make this into a per-device configurable
6873 +static int yaffs_IsBlockBad(yaffs_Device *dev, int blk)
6875 + yaffsExtendedTags *tags;
6877 + yaffs_ReadChunkFromNAND(dev,blk * dev->nChunksPerBlock,NULL,&tags,1);
6879 + if(yaffs_CountBits(spare.blockStatus) < 7)
6884 + if(spare.blockStatus != 0xFF)
6889 + yaffs_ReadChunkFromNAND(dev,blk * dev->nChunksPerBlock + 1,NULL,&spare,1);
6892 + if(yaffs_CountBits(spare.blockStatus) < 7)
6897 + if(spare.blockStatus != 0xFF)
6914 +} yaffs_BlockIndex;
6918 +static int yaffs_Scan(yaffs_Device *dev)
6920 + yaffs_ExtendedTags tags;
6922 + int blockIterator;
6923 + int startIterator;
6925 + int nBlocksToScan = 0;
6930 + yaffs_BlockState state;
6931 + yaffs_Object *hardList = NULL;
6933 + yaffs_BlockInfo *bi;
6934 + int sequenceNumber;
6935 + yaffs_ObjectHeader *oh;
6937 + yaffs_Object *parent;
6938 + int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
6942 + yaffs_BlockIndex *blockIndex = NULL;
6944 + T(YAFFS_TRACE_SCAN,(TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR),dev->internalStartBlock,dev->internalEndBlock));
6946 + chunkData = yaffs_GetTempBuffer(dev,__LINE__);
6949 + dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
6953 + blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
6957 + // Scan all the blocks to determine their state
6958 + for(blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++)
6960 + bi = yaffs_GetBlockInfo(dev,blk);
6961 + yaffs_ClearChunkBits(dev,blk);
6962 + bi->pagesInUse = 0;
6963 + bi->softDeletions = 0;
6965 + yaffs_QueryInitialBlockState(dev,blk,&state,&sequenceNumber);
6967 + bi->blockState = state;
6968 + bi->sequenceNumber = sequenceNumber;
6970 + T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block scanning block %d state %d seq %d" TENDSTR),blk,state,sequenceNumber));
6972 + if(state == YAFFS_BLOCK_STATE_DEAD)
6974 + T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("block %d is bad" TENDSTR),blk));
6976 + else if(state == YAFFS_BLOCK_STATE_EMPTY)
6978 + T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block empty " TENDSTR)));
6979 + dev->nErasedBlocks++;
6980 + dev->nFreeChunks += dev->nChunksPerBlock;
6982 + else if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
6985 + // Determine the highest sequence number
6986 + if( dev->isYaffs2 &&
6987 + sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
6988 + sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER)
6991 + blockIndex[nBlocksToScan].seq = sequenceNumber;
6992 + blockIndex[nBlocksToScan].block = blk;
6996 + if(sequenceNumber >= dev->sequenceNumber)
6998 + dev->sequenceNumber = sequenceNumber;
7001 + else if(dev->isYaffs2)
7003 + // TODO: Nasty sequence number!
7004 + T(YAFFS_TRACE_SCAN,(TSTR("Block scanning block %d has bad sequence number %d" TENDSTR),blk,sequenceNumber));
7010 + // Sort the blocks
7011 + // Dungy old bubble sort for now...
7014 + yaffs_BlockIndex temp;
7018 + for(i = 0; i < nBlocksToScan; i++)
7019 + for(j = i+1; j < nBlocksToScan; j++)
7020 + if(blockIndex[i].seq > blockIndex[j].seq)
7022 + temp = blockIndex[j];
7023 + blockIndex[j] = blockIndex[i];
7024 + blockIndex[i] = temp;
7029 + // Now scan the blocks looking at the data.
7032 + startIterator = 0;
7033 + endIterator = nBlocksToScan-1;
7034 + T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("%d blocks to be scanned" TENDSTR),nBlocksToScan));
7038 + startIterator = dev->internalStartBlock;
7039 + endIterator = dev->internalEndBlock;
7042 + // For each block....
7043 + for(blockIterator = startIterator; blockIterator <= endIterator; blockIterator++)
7048 + // get the block to scan in the correct order
7049 + blk = blockIndex[blockIterator].block;
7053 + blk = blockIterator;
7057 + bi = yaffs_GetBlockInfo(dev,blk);
7058 + state = bi->blockState;
7062 + // For each chunk in each block that needs scanning....
7063 + for(c = 0; c < dev->nChunksPerBlock &&
7064 + state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++)
7066 + // Read the tags and decide what to do
7067 + chunk = blk * dev->nChunksPerBlock + c;
7069 + yaffs_ReadChunkWithTagsFromNAND(dev,chunk,NULL,&tags);
7071 + // Let's have a good look at this chunk...
7074 + if(!dev->isYaffs2 && tags.chunkDeleted)
7077 + // A deleted chunk
7079 + dev->nFreeChunks ++;
7080 + //T((" %d %d deleted\n",blk,c));
7082 + else if(!tags.chunkUsed)
7084 + // An unassigned chunk in the block
7085 + // This means that either the block is empty or
7086 + // this is the one being allocated from
7090 + // We're looking at the first chunk in the block so the block is unused
7091 + state = YAFFS_BLOCK_STATE_EMPTY;
7092 + dev->nErasedBlocks++;
7096 + // this is the block being allocated from
7097 + T(YAFFS_TRACE_SCAN,(TSTR(" Allocating from %d %d" TENDSTR),blk,c));
7098 + state = YAFFS_BLOCK_STATE_ALLOCATING;
7099 + dev->allocationBlock = blk;
7100 + dev->allocationPage = c;
7101 + dev->allocationBlockFinder = blk; // Set it to here to encourage the allocator to
7102 + // go forth from here.
7103 + //Yaffs2 sanity check:
7104 + // This should be the one with the highest sequence number
7105 + if(dev->isYaffs2 && (dev->sequenceNumber != bi->sequenceNumber))
7107 + T(YAFFS_TRACE_ALWAYS,
7108 + (TSTR("yaffs: Allocation block %d was not highest sequence id: block seq = %d, dev seq = %d" TENDSTR),
7109 + blk,bi->sequenceNumber,dev->sequenceNumber));
7113 + dev->nFreeChunks += (dev->nChunksPerBlock - c);
7115 + else if(tags.chunkId > 0)
7117 + // chunkId > 0 so it is a data chunk...
7118 + unsigned int endpos;
7120 + yaffs_SetChunkBit(dev,blk,c);
7123 + in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
7124 + // PutChunkIntoFile checks for a clash (two data chunks with
7125 + // the same chunkId).
7126 + yaffs_PutChunkIntoFile(in,tags.chunkId,chunk,1);
7127 + endpos = (tags.chunkId - 1)* dev->nBytesPerChunk + tags.byteCount;
7128 + if(in->variantType == YAFFS_OBJECT_TYPE_FILE && in->variant.fileVariant.scannedFileSize <endpos)
7130 + in->variant.fileVariant.scannedFileSize = endpos;
7131 + if(!dev->useHeaderFileSize)
7133 + in->variant.fileVariant.fileSize = in->variant.fileVariant.scannedFileSize;
7137 + //T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));
7141 + // chunkId == 0, so it is an ObjectHeader.
7142 + // Thus, we read in the object header and make the object
7143 + yaffs_SetChunkBit(dev,blk,c);
7146 + yaffs_ReadChunkWithTagsFromNAND(dev,chunk,chunkData,NULL);
7148 + oh = (yaffs_ObjectHeader *)chunkData;
7150 + in = yaffs_FindObjectByNumber(dev,tags.objectId);
7151 + if(in && in->variantType != oh->type)
7153 + // This should not happen, but somehow
7154 + // Wev'e ended up with an objectId that has been reused but not yet
7155 + // deleted, and worse still it has changed type. Delete the old object.
7157 + yaffs_DestroyObject(in);
7162 + in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type);
7164 + if(oh->shadowsObject > 0)
7166 + yaffs_HandleShadowedObject(dev,oh->shadowsObject,0);
7171 + // We have already filled this one. We have a duplicate and need to resolve it.
7173 + unsigned existingSerial = in->serial;
7174 + unsigned newSerial = tags.serialNumber;
7176 + if( dev->isYaffs2 ||
7177 + ((existingSerial+1) & 3) == newSerial)
7179 + // Use new one - destroy the exisiting one
7180 + yaffs_DeleteChunk(dev,in->chunkId,1,__LINE__);
7185 + // Use existing - destroy this one.
7186 + yaffs_DeleteChunk(dev,chunk,1,__LINE__);
7191 + (tags.objectId == YAFFS_OBJECTID_ROOT ||
7192 + tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))
7194 + // We only load some info, don't fiddle with directory structure
7196 + in->variantType = oh->type;
7198 + in->yst_mode = oh->yst_mode;
7199 +#ifdef CONFIG_YAFFS_WINCE
7200 + in->win_atime[0] = oh->win_atime[0];
7201 + in->win_ctime[0] = oh->win_ctime[0];
7202 + in->win_mtime[0] = oh->win_mtime[0];
7203 + in->win_atime[1] = oh->win_atime[1];
7204 + in->win_ctime[1] = oh->win_ctime[1];
7205 + in->win_mtime[1] = oh->win_mtime[1];
7207 + in->yst_uid = oh->yst_uid;
7208 + in->yst_gid = oh->yst_gid;
7209 + in->yst_atime = oh->yst_atime;
7210 + in->yst_mtime = oh->yst_mtime;
7211 + in->yst_ctime = oh->yst_ctime;
7212 + in->yst_rdev = oh->yst_rdev;
7214 + in->chunkId = chunk;
7217 + else if(!in->valid)
7219 + // we need to load this info
7222 + in->variantType = oh->type;
7224 + in->yst_mode = oh->yst_mode;
7225 +#ifdef CONFIG_YAFFS_WINCE
7226 + in->win_atime[0] = oh->win_atime[0];
7227 + in->win_ctime[0] = oh->win_ctime[0];
7228 + in->win_mtime[0] = oh->win_mtime[0];
7229 + in->win_atime[1] = oh->win_atime[1];
7230 + in->win_ctime[1] = oh->win_ctime[1];
7231 + in->win_mtime[1] = oh->win_mtime[1];
7233 + in->yst_uid = oh->yst_uid;
7234 + in->yst_gid = oh->yst_gid;
7235 + in->yst_atime = oh->yst_atime;
7236 + in->yst_mtime = oh->yst_mtime;
7237 + in->yst_ctime = oh->yst_ctime;
7238 + in->yst_rdev = oh->yst_rdev;
7240 + in->chunkId = chunk;
7242 + yaffs_SetObjectName(in,oh->name);
7245 + // directory stuff...
7246 + // hook up to parent
7248 + parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY);
7249 + if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN)
7251 + // Set up as a directory
7252 + parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY;
7253 + INIT_LIST_HEAD(&parent->variant.directoryVariant.children);
7255 + else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
7257 + // Hoosterman, another problem....
7258 + // We're trying to use a non-directory as a directory
7260 + T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." TENDSTR)));
7261 + parent = dev->lostNFoundDir;
7264 + yaffs_AddObjectToDirectory(parent,in);
7266 + if(0 && (parent == dev->deletedDir ||
7267 + parent == dev->unlinkedDir))
7269 + in->deleted = 1; // If it is unlinked at start up then it wants deleting
7270 + dev->nDeletedFiles++;
7273 + // Note re hardlinks.
7274 + // Since we might scan a hardlink before its equivalent object is scanned
7275 + // we put them all in a list.
7276 + // After scanning is complete, we should have all the objects, so we run through this
7277 + // list and fix up all the chains.
7279 + switch(in->variantType)
7281 + case YAFFS_OBJECT_TYPE_UNKNOWN: // Todo got a problem
7283 + case YAFFS_OBJECT_TYPE_FILE:
7284 + if(dev->isYaffs2 && oh->isShrink)
7286 + // Prune back the shrunken chunks
7287 + yaffs_PruneResizedChunks(in,oh->fileSize);
7288 + // Mark the block as having a shrinkHeader
7289 + bi->hasShrinkHeader = 1;
7292 + if(dev->useHeaderFileSize)
7294 + in->variant.fileVariant.fileSize = oh->fileSize;
7297 + case YAFFS_OBJECT_TYPE_HARDLINK:
7298 + in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId;
7299 + in->hardLinks.next = (struct list_head *)hardList;
7302 + case YAFFS_OBJECT_TYPE_DIRECTORY: // Do nothing
7304 + case YAFFS_OBJECT_TYPE_SPECIAL: // Do nothing
7306 + case YAFFS_OBJECT_TYPE_SYMLINK: // Do nothing
7307 + in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias);
7311 + if(parent == dev->deletedDir)
7313 + yaffs_DestroyObject(in);
7314 + bi->hasShrinkHeader = 1;
7316 + //T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));
7321 + if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
7323 + // If we got this far while scanning, then the block is fully allocated.
7324 + state = YAFFS_BLOCK_STATE_FULL;
7327 + bi->blockState = state;
7329 + // Now let's see if it was dirty
7330 + if( bi->pagesInUse == 0 &&
7331 + !bi->hasShrinkHeader &&
7332 + bi->blockState == YAFFS_BLOCK_STATE_FULL)
7334 + yaffs_BlockBecameDirty(dev,blk);
7341 + YFREE(blockIndex);
7344 + // Ok, we've done all the scanning.
7346 + // Fix up the hard link chains.
7347 + // We should now have scanned all the objects, now it's time to add these
7352 + hardList = (yaffs_Object *)(hardList->hardLinks.next);
7354 + in = yaffs_FindObjectByNumber(dev,hl->variant.hardLinkVariant.equivalentObjectId);
7358 + // Add the hardlink pointers
7359 + hl->variant.hardLinkVariant.equivalentObject=in;
7360 + list_add(&hl->hardLinks,&in->hardLinks);
7364 + //Todo Need to report/handle this better.
7365 + // Got a problem... hardlink to a non-existant object
7366 + hl->variant.hardLinkVariant.equivalentObject=NULL;
7367 + INIT_LIST_HEAD(&hl->hardLinks);
7373 + // Handle the unlinked files. Since they were left in an unlinked state we should
7374 + // just delete them.
7376 + struct list_head *i;
7377 + struct list_head *n;
7380 + // Soft delete all the unlinked files
7381 + list_for_each_safe(i,n,&dev->unlinkedDir->variant.directoryVariant.children)
7385 + l = list_entry(i, yaffs_Object,siblings);
7386 + yaffs_DestroyObject(l);
7391 + yaffs_ReleaseTempBuffer(dev,chunkData,__LINE__);
7393 + T(YAFFS_TRACE_SCAN,(TSTR("yaffs_Scan ends" TENDSTR)));
7399 +static int yaffs_ScanBackwards(yaffs_Device *dev)
7401 + yaffs_ExtendedTags tags;
7403 + int blockIterator;
7404 + int startIterator;
7406 + int nBlocksToScan = 0;
7411 + yaffs_BlockState state;
7412 + yaffs_Object *hardList = NULL;
7414 + yaffs_BlockInfo *bi;
7415 + int sequenceNumber;
7416 + yaffs_ObjectHeader *oh;
7418 + yaffs_Object *parent;
7419 + int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
7423 + yaffs_BlockIndex *blockIndex = NULL;
7426 + if(!dev->isYaffs2)
7428 + T(YAFFS_TRACE_SCAN,(TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR)));
7429 + return YAFFS_FAIL;
7432 + T(YAFFS_TRACE_SCAN,(TSTR("yaffs_ScanBackwards starts intstartblk %d intendblk %d..." TENDSTR),dev->internalStartBlock,dev->internalEndBlock));
7434 + chunkData = yaffs_GetTempBuffer(dev,__LINE__);
7437 + dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
7439 + blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
7442 + // Scan all the blocks to determine their state
7443 + for(blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++)
7445 + bi = yaffs_GetBlockInfo(dev,blk);
7446 + yaffs_ClearChunkBits(dev,blk);
7447 + bi->pagesInUse = 0;
7448 + bi->softDeletions = 0;
7450 + yaffs_QueryInitialBlockState(dev,blk,&state,&sequenceNumber);
7452 + bi->blockState = state;
7453 + bi->sequenceNumber = sequenceNumber;
7455 + T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block scanning block %d state %d seq %d" TENDSTR),blk,state,sequenceNumber));
7457 + if(state == YAFFS_BLOCK_STATE_DEAD)
7459 + T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("block %d is bad" TENDSTR),blk));
7461 + else if(state == YAFFS_BLOCK_STATE_EMPTY)
7463 + T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("Block empty " TENDSTR)));
7464 + dev->nErasedBlocks++;
7465 + dev->nFreeChunks += dev->nChunksPerBlock;
7467 + else if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
7470 + // Determine the highest sequence number
7471 + if( dev->isYaffs2 &&
7472 + sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
7473 + sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER)
7476 + blockIndex[nBlocksToScan].seq = sequenceNumber;
7477 + blockIndex[nBlocksToScan].block = blk;
7481 + if(sequenceNumber >= dev->sequenceNumber)
7483 + dev->sequenceNumber = sequenceNumber;
7486 + else if(dev->isYaffs2)
7488 + // TODO: Nasty sequence number!
7489 + T(YAFFS_TRACE_SCAN,(TSTR("Block scanning block %d has bad sequence number %d" TENDSTR),blk,sequenceNumber));
7495 + // Sort the blocks
7496 + // Dungy old bubble sort for now...
7498 + yaffs_BlockIndex temp;
7502 + for(i = 0; i < nBlocksToScan; i++)
7503 + for(j = i+1; j < nBlocksToScan; j++)
7504 + if(blockIndex[i].seq > blockIndex[j].seq)
7506 + temp = blockIndex[j];
7507 + blockIndex[j] = blockIndex[i];
7508 + blockIndex[i] = temp;
7513 + // Now scan the blocks looking at the data.
7514 + startIterator = 0;
7515 + endIterator = nBlocksToScan-1;
7516 + T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("%d blocks to be scanned" TENDSTR),nBlocksToScan));
7519 + // For each block.... backwards
7520 + for(blockIterator = endIterator; blockIterator >= startIterator; blockIterator--)
7523 + // get the block to scan in the correct order
7524 + blk = blockIndex[blockIterator].block;
7527 + bi = yaffs_GetBlockInfo(dev,blk);
7528 + state = bi->blockState;
7532 + if( 0 && // Disable since this is redundant.
7533 + state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
7535 + // Let's look at the first chunk in the block
7536 + chunk = blk * dev->nChunksPerBlock;
7538 + yaffs_ReadChunkWithTagsFromNAND(dev,chunk,NULL,&tags);
7540 + // Let's have a good look at this chunk...
7542 + if(!tags.chunkUsed)
7544 + // An unassigned chunk in the block
7545 + // This means that either the block is empty or
7546 + // this is the one being allocated from
7548 + // We're looking at the first chunk in the block so the block is unused
7549 + state = YAFFS_BLOCK_STATE_EMPTY;
7550 + dev->nErasedBlocks++;
7551 + dev->nFreeChunks += dev->nChunksPerBlock;
7556 + // For each chunk in each block that needs scanning....
7557 + for(c = dev->nChunksPerBlock-1; c >= 0 &&
7558 + (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
7559 + state == YAFFS_BLOCK_STATE_ALLOCATING); c--)
7561 + // Scan backwards...
7562 + // Read the tags and decide what to do
7563 + chunk = blk * dev->nChunksPerBlock + c;
7565 + yaffs_ReadChunkWithTagsFromNAND(dev,chunk,NULL,&tags);
7567 + // Let's have a good look at this chunk...
7569 + if(!tags.chunkUsed)
7571 + // An unassigned chunk in the block
7572 + // This means that either the block is empty or
7573 + // this is the one being allocated from
7577 + // We're looking at the first chunk in the block so the block is unused
7578 + state = YAFFS_BLOCK_STATE_EMPTY;
7579 + dev->nErasedBlocks++;
7583 + // this is the block being allocated from
7584 + if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
7586 + T(YAFFS_TRACE_SCAN,(TSTR(" Allocating from %d %d" TENDSTR),blk,c));
7588 + state = YAFFS_BLOCK_STATE_ALLOCATING;
7589 + dev->allocationBlock = blk;
7590 + dev->allocationPage = c;
7591 + dev->allocationBlockFinder = blk; // Set it to here to encourage the allocator to
7592 + // go forth from here.
7593 + //Yaffs2 sanity check:
7594 + // This should be the one with the highest sequence number
7595 + if(dev->isYaffs2 && (dev->sequenceNumber != bi->sequenceNumber))
7597 + T(YAFFS_TRACE_ALWAYS,
7598 + (TSTR("yaffs: Allocation block %d was not highest sequence id: block seq = %d, dev seq = %d" TENDSTR),
7599 + blk,bi->sequenceNumber,dev->sequenceNumber));
7603 + dev->nFreeChunks ++;
7605 + else if(tags.chunkId > 0)
7607 + // chunkId > 0 so it is a data chunk...
7608 + unsigned int endpos;
7610 + __u32 chunkBase = (tags.chunkId - 1)* dev->nBytesPerChunk;
7612 + yaffs_SetChunkBit(dev,blk,c);
7615 + in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
7616 + if(in->variantType == YAFFS_OBJECT_TYPE_FILE &&
7617 + chunkBase < in->variant.fileVariant.shrinkSize)
7619 + // This has not been invalidated by a resize
7620 + yaffs_PutChunkIntoFile(in,tags.chunkId,chunk,-1);
7623 + // File size is calculated by looking at the data chunks if we have not
7624 + // seen an object header yet. Stop this practice once we find an object header.
7625 + endpos = (tags.chunkId - 1)* dev->nBytesPerChunk + tags.byteCount;
7626 + if(!in->valid && // have not got an object header yet
7627 + in->variant.fileVariant.scannedFileSize <endpos)
7629 + in->variant.fileVariant.scannedFileSize = endpos;
7630 + in->variant.fileVariant.fileSize = in->variant.fileVariant.scannedFileSize;
7636 + // This chunk has been invalidated by a resize, so delete
7637 + yaffs_DeleteChunk(dev,chunk,1,__LINE__);
7641 + //T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));
7645 + // chunkId == 0, so it is an ObjectHeader.
7646 + // Thus, we read in the object header and make the object
7647 + yaffs_SetChunkBit(dev,blk,c);
7653 + if(tags.extraHeaderInfoAvailable)
7655 + in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,tags.extraObjectType);
7659 + if(!in || !in->valid)
7662 + // If we don't have valid info then we need to read the chunk
7663 + // TODO In future we can probably defer reading the chunk and
7664 + // living with invalid data until needed.
7666 + yaffs_ReadChunkWithTagsFromNAND(dev,chunk,chunkData,NULL);
7668 + oh = (yaffs_ObjectHeader *)chunkData;
7671 + in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type);
7677 + // TODO Hoosterman we have a problem!
7678 + T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: Could not make object for object %d at chunk %d during scan" TENDSTR),tags.objectId,chunk));
7684 + // We have already filled this one. We have a duplicate that will be discarded, but
7685 + // we first have to suck out resize info if it is a file.
7687 + if( (in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
7688 + ((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) ||
7689 + (tags.extraHeaderInfoAvailable && tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))
7692 + __u32 thisSize = (oh) ? oh->fileSize : tags.extraFileLength;
7693 + __u32 parentObjectId = (oh) ? oh->parentObjectId : tags.extraParentObjectId;
7694 + unsigned isShrink = (oh) ? oh->isShrink : tags.extraIsShrinkHeader;
7696 + // If it is deleted (unlinked at start also means deleted)
7697 + // we treat the file size as being zeroed at this point.
7698 + if(parentObjectId == YAFFS_OBJECTID_DELETED ||
7699 + parentObjectId == YAFFS_OBJECTID_UNLINKED)
7706 + in->variant.fileVariant.shrinkSize > thisSize)
7708 + in->variant.fileVariant.shrinkSize = thisSize;
7713 + bi->hasShrinkHeader = 1;
7717 + // Use existing - destroy this one.
7718 + yaffs_DeleteChunk(dev,chunk,1,__LINE__);
7723 + (tags.objectId == YAFFS_OBJECTID_ROOT ||
7724 + tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))
7726 + // We only load some info, don't fiddle with directory structure
7728 + in->variantType = oh->type;
7730 + in->yst_mode = oh->yst_mode;
7731 +#ifdef CONFIG_YAFFS_WINCE
7732 + in->win_atime[0] = oh->win_atime[0];
7733 + in->win_ctime[0] = oh->win_ctime[0];
7734 + in->win_mtime[0] = oh->win_mtime[0];
7735 + in->win_atime[1] = oh->win_atime[1];
7736 + in->win_ctime[1] = oh->win_ctime[1];
7737 + in->win_mtime[1] = oh->win_mtime[1];
7739 + in->yst_uid = oh->yst_uid;
7740 + in->yst_gid = oh->yst_gid;
7741 + in->yst_atime = oh->yst_atime;
7742 + in->yst_mtime = oh->yst_mtime;
7743 + in->yst_ctime = oh->yst_ctime;
7744 + in->yst_rdev = oh->yst_rdev;
7746 + in->chunkId = chunk;
7749 + else if(!in->valid)
7751 + // we need to load this info
7754 + in->variantType = oh->type;
7756 + in->yst_mode = oh->yst_mode;
7757 +#ifdef CONFIG_YAFFS_WINCE
7758 + in->win_atime[0] = oh->win_atime[0];
7759 + in->win_ctime[0] = oh->win_ctime[0];
7760 + in->win_mtime[0] = oh->win_mtime[0];
7761 + in->win_atime[1] = oh->win_atime[1];
7762 + in->win_ctime[1] = oh->win_ctime[1];
7763 + in->win_mtime[1] = oh->win_mtime[1];
7765 + in->yst_uid = oh->yst_uid;
7766 + in->yst_gid = oh->yst_gid;
7767 + in->yst_atime = oh->yst_atime;
7768 + in->yst_mtime = oh->yst_mtime;
7769 + in->yst_ctime = oh->yst_ctime;
7770 + in->yst_rdev = oh->yst_rdev;
7772 + in->chunkId = chunk;
7774 + if(oh->shadowsObject > 0)
7776 + yaffs_HandleShadowedObject(dev,oh->shadowsObject,0);
7780 + yaffs_SetObjectName(in,oh->name);
7783 + // directory stuff...
7784 + // hook up to parent
7786 + parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY);
7787 + if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN)
7789 + // Set up as a directory
7790 + parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY;
7791 + INIT_LIST_HEAD(&parent->variant.directoryVariant.children);
7793 + else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
7795 + // Hoosterman, another problem....
7796 + // We're trying to use a non-directory as a directory
7798 + T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." TENDSTR)));
7799 + parent = dev->lostNFoundDir;
7802 + yaffs_AddObjectToDirectory(parent,in);
7804 + if((parent == dev->deletedDir ||
7805 + parent == dev->unlinkedDir))
7807 + in->deleted = 1; // If it is unlinked at start up then it wants deleting
7812 + // Mark the block as having a shrinkHeader
7813 + bi->hasShrinkHeader = 1;
7817 + // Note re hardlinks.
7818 + // Since we might scan a hardlink before its equivalent object is scanned
7819 + // we put them all in a list.
7820 + // After scanning is complete, we should have all the objects, so we run through this
7821 + // list and fix up all the chains.
7823 + switch(in->variantType)
7825 + case YAFFS_OBJECT_TYPE_UNKNOWN: // Todo got a problem
7827 + case YAFFS_OBJECT_TYPE_FILE:
7830 + if(in->variant.fileVariant.scannedFileSize < oh->fileSize)
7832 + in->variant.fileVariant.fileSize = oh->fileSize;
7833 + in->variant.fileVariant.scannedFileSize = in->variant.fileVariant.fileSize;
7836 + if(oh->isShrink &&
7837 + in->variant.fileVariant.shrinkSize > oh->fileSize)
7839 + in->variant.fileVariant.shrinkSize = oh->fileSize;
7843 + case YAFFS_OBJECT_TYPE_HARDLINK:
7844 + in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId;
7845 + in->hardLinks.next = (struct list_head *)hardList;
7848 + case YAFFS_OBJECT_TYPE_DIRECTORY: // Do nothing
7850 + case YAFFS_OBJECT_TYPE_SPECIAL: // Do nothing
7852 + case YAFFS_OBJECT_TYPE_SYMLINK: // Do nothing
7853 + in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias);
7858 + if(parent == dev->deletedDir)
7860 + yaffs_DestroyObject(in);
7861 + bi->hasShrinkHeader = 1;
7864 + //T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));
7869 + if(state == YAFFS_BLOCK_STATE_NEEDS_SCANNING)
7871 + // If we got this far while scanning, then the block is fully allocated.
7872 + state = YAFFS_BLOCK_STATE_FULL;
7875 + bi->blockState = state;
7877 + // Now let's see if it was dirty
7878 + if( bi->pagesInUse == 0 &&
7879 + !bi->hasShrinkHeader &&
7880 + bi->blockState == YAFFS_BLOCK_STATE_FULL)
7882 + yaffs_BlockBecameDirty(dev,blk);
7889 + YFREE(blockIndex);
7892 + // Ok, we've done all the scanning.
7894 + // Fix up the hard link chains.
7895 + // We should now have scanned all the objects, now it's time to add these
7900 + hardList = (yaffs_Object *)(hardList->hardLinks.next);
7902 + in = yaffs_FindObjectByNumber(dev,hl->variant.hardLinkVariant.equivalentObjectId);
7906 + // Add the hardlink pointers
7907 + hl->variant.hardLinkVariant.equivalentObject=in;
7908 + list_add(&hl->hardLinks,&in->hardLinks);
7912 + //Todo Need to report/handle this better.
7913 + // Got a problem... hardlink to a non-existant object
7914 + hl->variant.hardLinkVariant.equivalentObject=NULL;
7915 + INIT_LIST_HEAD(&hl->hardLinks);
7922 + struct list_head *i;
7923 + struct list_head *n;
7927 + // Soft delete all the unlinked files
7928 + list_for_each_safe(i,n,&dev->unlinkedDir->variant.directoryVariant.children)
7932 + l = list_entry(i, yaffs_Object,siblings);
7933 + yaffs_DestroyObject(l);
7937 + // Soft delete all the deletedDir files
7938 + list_for_each_safe(i,n,&dev->deletedDir->variant.directoryVariant.children)
7942 + l = list_entry(i, yaffs_Object,siblings);
7943 + yaffs_DestroyObject(l);
7949 + yaffs_ReleaseTempBuffer(dev,chunkData,__LINE__);
7951 + T(YAFFS_TRACE_SCAN,(TSTR("yaffs_ScanBackwards ends" TENDSTR)));
7958 +////////////////////////// Directory Functions /////////////////////////
7961 +static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj)
7966 + T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: Trying to add an object to a null pointer directory" TENDSTR)));
7969 + if(directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
7971 + T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: Trying to add an object to a non-directory" TENDSTR)));
7975 + if(obj->siblings.prev == NULL)
7977 + // Not initialised
7978 + INIT_LIST_HEAD(&obj->siblings);
7981 + else if(!list_empty(&obj->siblings))
7983 + // If it is holed up somewhere else, un hook it
7984 + list_del_init(&obj->siblings);
7987 + list_add(&obj->siblings,&directory->variant.directoryVariant.children);
7988 + obj->parent = directory;
7990 + if(directory == obj->myDev->unlinkedDir || directory == obj->myDev->deletedDir)
7992 + obj->unlinked = 1;
7993 + obj->myDev->nUnlinkedFiles++;
7994 + obj->renameAllowed = 0;
7998 +static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
8000 + list_del_init(&obj->siblings);
8001 + obj->parent = NULL;
8004 +yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,const YCHAR *name)
8008 + struct list_head *i;
8009 + YCHAR buffer[YAFFS_MAX_NAME_LENGTH+1];
8020 + T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: yaffs_FindObjectByName: null pointer directory"TENDSTR)));
8023 + if(directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
8025 + T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: yaffs_FindObjectByName: non-directory"TENDSTR)));
8029 + sum = yaffs_CalcNameSum(name);
8031 + list_for_each(i,&directory->variant.directoryVariant.children)
8035 + l = list_entry(i, yaffs_Object,siblings);
8037 + // Special case for lost-n-found
8038 + if(l->objectId == YAFFS_OBJECTID_LOSTNFOUND)
8040 + if(yaffs_strcmp(name,YAFFS_LOSTNFOUND_NAME) == 0)
8045 + else if(yaffs_SumCompare(l->sum, sum)||
8046 + l->chunkId <= 0) //LostnFound cunk called Objxxx
8048 + // Do a real check
8049 + yaffs_GetObjectName(l,buffer,YAFFS_MAX_NAME_LENGTH);
8050 + if(yaffs_strcmp(name,buffer) == 0)
8063 +int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,int (*fn)(yaffs_Object *))
8065 + struct list_head *i;
8071 + T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: yaffs_FindObjectByName: null pointer directory"TENDSTR)));
8074 + if(theDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
8076 + T(YAFFS_TRACE_ALWAYS,(TSTR("tragedy: yaffs_FindObjectByName: non-directory"TENDSTR)));
8080 + list_for_each(i,&theDir->variant.directoryVariant.children)
8084 + l = list_entry(i, yaffs_Object,siblings);
8087 + return YAFFS_FAIL;
8097 +// GetEquivalentObject dereferences any hard links to get to the
8100 +yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj)
8102 + if(obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
8104 + // We want the object id of the equivalent object, not this one
8105 + obj = obj->variant.hardLinkVariant.equivalentObject;
8111 +int yaffs_GetObjectName(yaffs_Object *obj,YCHAR *name,int buffSize)
8113 + memset(name,0,buffSize * sizeof(YCHAR));
8115 + if(obj->objectId == YAFFS_OBJECTID_LOSTNFOUND)
8117 + yaffs_strncpy(name,YAFFS_LOSTNFOUND_NAME,buffSize - 1);
8119 + else if(obj->chunkId <= 0)
8121 + YCHAR locName[20];
8123 + yaffs_sprintf(locName,_Y("%s%d"),YAFFS_LOSTNFOUND_PREFIX,obj->objectId);
8124 + yaffs_strncpy(name,locName,buffSize - 1);
8127 +#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
8128 + else if(obj->shortName[0])
8130 + yaffs_strcpy(name,obj->shortName);
8135 + __u8 *buffer = yaffs_GetTempBuffer(obj->myDev,__LINE__);
8137 + yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
8139 + memset(buffer,0,obj->myDev->nBytesPerChunk);
8141 + if(obj->chunkId >= 0)
8143 + yaffs_ReadChunkWithTagsFromNAND(obj->myDev,obj->chunkId,buffer,NULL);
8145 + yaffs_strncpy(name,oh->name,buffSize - 1);
8147 + yaffs_ReleaseTempBuffer(obj->myDev,buffer,__LINE__);
8150 + return yaffs_strlen(name);
8153 +int yaffs_GetObjectFileLength(yaffs_Object *obj)
8156 + // Dereference any hard linking
8157 + obj = yaffs_GetEquivalentObject(obj);
8159 + if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
8161 + return obj->variant.fileVariant.fileSize;
8163 + if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
8165 + return yaffs_strlen(obj->variant.symLinkVariant.alias);
8169 + // Only a directory should drop through to here
8170 + return obj->myDev->nBytesPerChunk;
8174 +int yaffs_GetObjectLinkCount(yaffs_Object *obj)
8177 + struct list_head *i;
8179 + if(!obj->unlinked)
8181 + count++; // the object itself
8183 + list_for_each(i,&obj->hardLinks)
8185 + count++; // add the hard links;
8192 +int yaffs_GetObjectInode(yaffs_Object *obj)
8194 + obj = yaffs_GetEquivalentObject(obj);
8196 + return obj->objectId;
8199 +unsigned yaffs_GetObjectType(yaffs_Object *obj)
8201 + obj = yaffs_GetEquivalentObject(obj);
8203 + switch(obj->variantType)
8205 + case YAFFS_OBJECT_TYPE_FILE: return DT_REG; break;
8206 + case YAFFS_OBJECT_TYPE_DIRECTORY: return DT_DIR; break;
8207 + case YAFFS_OBJECT_TYPE_SYMLINK: return DT_LNK; break;
8208 + case YAFFS_OBJECT_TYPE_HARDLINK: return DT_REG; break;
8209 + case YAFFS_OBJECT_TYPE_SPECIAL:
8210 + if(S_ISFIFO(obj->yst_mode)) return DT_FIFO;
8211 + if(S_ISCHR(obj->yst_mode)) return DT_CHR;
8212 + if(S_ISBLK(obj->yst_mode)) return DT_BLK;
8213 + if(S_ISSOCK(obj->yst_mode)) return DT_SOCK;
8214 + default: return DT_REG; break;
8218 +YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj)
8220 + obj = yaffs_GetEquivalentObject(obj);
8221 + if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
8223 + return yaffs_CloneString(obj->variant.symLinkVariant.alias);
8227 + return yaffs_CloneString(_Y(""));
8231 +#ifndef CONFIG_YAFFS_WINCE
8233 +int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
8235 + unsigned int valid = attr->ia_valid;
8237 + if(valid & ATTR_MODE) obj->yst_mode = attr->ia_mode;
8238 + if(valid & ATTR_UID) obj->yst_uid = attr->ia_uid;
8239 + if(valid & ATTR_GID) obj->yst_gid = attr->ia_gid;
8241 + if(valid & ATTR_ATIME) obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
8242 + if(valid & ATTR_CTIME) obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
8243 + if(valid & ATTR_MTIME) obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
8245 + if(valid & ATTR_SIZE) yaffs_ResizeFile(obj,attr->ia_size);
8247 + yaffs_UpdateObjectHeader(obj,NULL,1,0,0);
8252 +int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)
8254 + unsigned int valid = 0;
8256 + attr->ia_mode = obj->yst_mode; valid |= ATTR_MODE;
8257 + attr->ia_uid = obj->yst_uid; valid |= ATTR_UID;
8258 + attr->ia_gid = obj->yst_gid; valid |= ATTR_GID;
8260 + Y_TIME_CONVERT(attr->ia_atime)= obj->yst_atime; valid |= ATTR_ATIME;
8261 + Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime; valid |= ATTR_CTIME;
8262 + Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime; valid |= ATTR_MTIME;
8264 + attr->ia_size = yaffs_GetFileSize(obj); valid |= ATTR_SIZE;
8266 + attr->ia_valid = valid;
8274 +int yaffs_DumpObject(yaffs_Object *obj)
8276 +// __u8 buffer[YAFFS_BYTES_PER_CHUNK];
8278 +// yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
8280 +// memset(buffer,0,YAFFS_BYTES_PER_CHUNK);
8282 +// if(obj->chunkId >= 0)
8284 +// yaffs_ReadChunkFromNAND(obj->myDev,obj->chunkId,buffer,NULL);
8287 + yaffs_GetObjectName(obj,name,256);
8289 + T(YAFFS_TRACE_ALWAYS,(TSTR("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d type %d size %d\n" TENDSTR),
8290 + obj->objectId,yaffs_GetObjectInode(obj), name, obj->dirty, obj->valid, obj->serial,
8291 + obj->sum, obj->chunkId, yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
8294 + YPRINTF(("Object %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d\n",
8295 + obj->objectId, oh->name, obj->dirty, obj->valid, obj->serial,
8296 + obj->sum, obj->chunkId));
8297 + switch(obj->variantType)
8299 + case YAFFS_OBJECT_TYPE_FILE:
8300 + YPRINTF((" FILE length %d\n",obj->variant.fileVariant.fileSize));
8302 + case YAFFS_OBJECT_TYPE_DIRECTORY:
8303 + YPRINTF((" DIRECTORY\n"));
8305 + case YAFFS_OBJECT_TYPE_HARDLINK: //todo
8306 + case YAFFS_OBJECT_TYPE_SYMLINK:
8307 + case YAFFS_OBJECT_TYPE_UNKNOWN:
8316 +///////////////////////// Initialisation code ///////////////////////////
8319 +static int yaffs_CheckDevFunctions(const yaffs_Device *dev)
8322 + // Common functions, gotta have
8323 + if(!dev->eraseBlockInNAND ||
8324 + !dev->initialiseNAND) return 0;
8326 +#ifdef CONFIG_YAFFS_YAFFS2
8328 + // Can use the "with tags" style interface for yaffs1 or yaffs2
8329 + if(dev->writeChunkWithTagsToNAND &&
8330 + dev->readChunkWithTagsFromNAND &&
8331 + !dev->writeChunkToNAND &&
8332 + !dev->readChunkFromNAND &&
8333 + dev->markNANDBlockBad &&
8334 + dev->queryNANDBlock) return 1;
8337 + // Can use the "spare" style interface for yaffs1
8338 + if(!dev->isYaffs2 &&
8339 + !dev->writeChunkWithTagsToNAND &&
8340 + !dev->readChunkWithTagsFromNAND &&
8341 + dev->writeChunkToNAND &&
8342 + dev->readChunkFromNAND &&
8343 + !dev->markNANDBlockBad &&
8344 + !dev->queryNANDBlock) return 1;
8350 +int yaffs_GutsInitialise(yaffs_Device *dev)
8357 + T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR)));
8358 + // Check stuff that must be set
8362 + T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Need a device" TENDSTR)));
8363 + return YAFFS_FAIL;
8366 + dev->internalStartBlock = dev->startBlock;
8367 + dev->internalEndBlock = dev->endBlock;
8368 + dev->blockOffset = 0;
8369 + dev->chunkOffset = 0;
8370 + dev->nFreeChunks = 0;
8372 + if(dev->startBlock == 0)
8374 + dev->internalStartBlock = dev->startBlock + 1;
8375 + dev->internalEndBlock = dev->endBlock + 1;
8376 + dev->blockOffset = 1;
8377 + dev->chunkOffset = dev->nChunksPerBlock;
8380 + // Check geometry parameters.
8382 + if( (dev->isYaffs2 && dev->nBytesPerChunk <1024) ||
8383 + (!dev->isYaffs2 && dev->nBytesPerChunk !=512) ||
8384 + dev->nChunksPerBlock < 2 ||
8385 + dev->nReservedBlocks < 2 ||
8386 + dev->internalStartBlock <= 0 ||
8387 + dev->internalEndBlock <= 0 ||
8388 + dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2) // otherwise it is too small
8391 + T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s " TENDSTR),
8392 + dev->nBytesPerChunk, dev->isYaffs2 ? "2" : ""));
8393 + return YAFFS_FAIL;
8396 + if(yaffs_InitialiseNAND(dev) != YAFFS_OK)
8398 + T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: InitialiseNAND failed" TENDSTR)));
8399 + return YAFFS_FAIL;
8402 + // Got the right mix of functions?
8404 + if(!yaffs_CheckDevFunctions(dev))
8406 + //Function missing
8407 + T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: device function(s) missing or wrong\n" TENDSTR)));
8409 + return YAFFS_FAIL;
8412 + // This is really a compilation check.
8413 + if(!yaffs_CheckStructures())
8415 + T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs_CheckStructures failed\n" TENDSTR)));
8416 + return YAFFS_FAIL;
8419 + if(dev->isMounted)
8421 + T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: device already mounted\n" TENDSTR)));
8422 + return YAFFS_FAIL;
8427 + // Finished with most checks. One or two more checks happen later on too.
8430 + dev->isMounted = 1;
8433 + nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
8437 + // OK now calculate a few things for the device
8438 + // Calculate chunkGroupBits.
8439 + // We need to find the next power of 2 > than internalEndBlock
8441 + x = dev->nChunksPerBlock * (dev->internalEndBlock+1);
8443 + for(bits = extraBits = 0; x > 1; bits++)
8445 + if(x & 1) extraBits++;
8449 + if(extraBits > 0) bits++;
8452 + // Level0 Tnodes are 16 bits, so if the bitwidth of the
8453 + // chunk range we're using is greater than 16 we need
8454 + // to figure out chunk shift and chunkGroupSize
8457 + dev->chunkGroupBits = 0;
8461 + dev->chunkGroupBits = bits - 16;
8464 + dev->chunkGroupSize = 1 << dev->chunkGroupBits;
8466 + if(dev->nChunksPerBlock < dev->chunkGroupSize)
8468 + // We have a problem because the soft delete won't work if
8469 + // the chunk group size > chunks per block.
8470 + // This can be remedied by using larger "virtual blocks".
8471 + T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: chunk group too large\n" TENDSTR)));
8473 + return YAFFS_FAIL;
8477 + // OK, we've finished verifying the device, lets continue with initialisation
8479 + // More device initialisation
8480 + dev->garbageCollections = 0;
8481 + dev->passiveGarbageCollections = 0;
8482 + dev->currentDirtyChecker = 0;
8483 + dev->bufferedBlock = -1;
8484 + dev->doingBufferedBlockRewrite = 0;
8485 + dev->nDeletedFiles = 0;
8486 + dev->nBackgroundDeletions=0;
8487 + dev->nUnlinkedFiles = 0;
8489 + dev->eccUnfixed=0;
8490 + dev->tagsEccFixed=0;
8491 + dev->tagsEccUnfixed=0;
8492 + dev->nErasureFailures = 0;
8493 + dev->nErasedBlocks = 0;
8494 + dev->isDoingGC = 0;
8496 + //dev->localBuffer = YMALLOC(dev->nBytesPerChunk);
8497 + // Initialise temporary buffers
8500 + for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
8502 + dev->tempBuffer[i].line = 0; // not in use
8503 + dev->tempBuffer[i].buffer = YMALLOC(dev->nBytesPerChunk);
8509 + yaffs_InitialiseBlocks(dev,nBlocks);
8511 + yaffs_InitialiseTnodes(dev);
8513 + yaffs_InitialiseObjects(dev);
8515 + dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32));
8517 + if(dev->nShortOpCaches > 0)
8521 + if(dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES)
8523 + dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
8526 + dev->srCache = YMALLOC( dev->nShortOpCaches * sizeof(yaffs_ChunkCache));
8528 + for(i=0; i < dev->nShortOpCaches; i++)
8530 + dev->srCache[i].object = NULL;
8531 + dev->srCache[i].lastUse = 0;
8532 + dev->srCache[i].dirty = 0;
8533 + dev->srCache[i].data = YMALLOC(dev->nBytesPerChunk);
8535 + dev->srLastUse = 0;
8538 + dev->cacheHits = 0;
8541 + // Initialise the unlinked, root and lost and found directories
8542 + dev->lostNFoundDir = dev->rootDir = dev->unlinkedDir = dev->deletedDir = NULL;
8544 + dev->unlinkedDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_UNLINKED, S_IFDIR);
8545 + dev->deletedDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_DELETED, S_IFDIR);
8547 + dev->rootDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_ROOT,YAFFS_ROOT_MODE | S_IFDIR);
8548 + dev->lostNFoundDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_LOSTNFOUND,YAFFS_LOSTNFOUND_MODE | S_IFDIR);
8549 + yaffs_AddObjectToDirectory(dev->rootDir,dev->lostNFoundDir);
8553 + dev->useHeaderFileSize = 1;
8556 + // Now scan the flash.
8559 + yaffs_ScanBackwards(dev);
8564 + dev->nPageReads = 0;
8565 + dev->nPageWrites = 0;
8566 + dev->nBlockErasures = 0;
8567 + dev->nGCCopies = 0;
8568 + dev->nRetriedWrites = 0;
8570 + dev->nRetiredBlocks = 0;
8572 + yaffs_VerifyFreeChunks(dev);
8574 + T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
8579 +void yaffs_Deinitialise(yaffs_Device *dev)
8581 + if(dev->isMounted)
8585 + yaffs_DeinitialiseBlocks(dev);
8586 + yaffs_DeinitialiseTnodes(dev);
8587 + yaffs_DeinitialiseObjects(dev);
8588 + if(dev->nShortOpCaches > 0)
8591 + for(i=0; i < dev->nShortOpCaches; i++)
8593 + YFREE(dev->srCache[i].data);
8596 + YFREE(dev->srCache);
8599 + YFREE(dev->gcCleanupList);
8601 + for(i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
8603 + YFREE(dev->tempBuffer[i].buffer);
8606 + dev->isMounted = 0;
8613 +int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
8615 + int nFree = dev->nFreeChunks - (dev->nChunksPerBlock * YAFFS_RESERVED_BLOCKS);
8617 + struct list_head *i;
8621 + // To the free chunks add the chunks that are in the deleted unlinked files.
8622 + list_for_each(i,&dev->deletedDir->variant.directoryVariant.children)
8624 + l = list_entry(i, yaffs_Object,siblings);
8628 + nFree += l->nDataChunks;
8633 + // printf("___________ nFreeChunks is %d nFree is %d\n",dev->nFreeChunks,nFree);
8635 + if(nFree < 0) nFree = 0;
8643 +static int yaffs_CountFreeChunks(yaffs_Device *dev)
8648 + yaffs_BlockInfo *blk;
8651 + for(nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock; b++)
8653 + blk = yaffs_GetBlockInfo(dev,b);
8655 + switch(blk->blockState)
8657 + case YAFFS_BLOCK_STATE_EMPTY:
8658 + case YAFFS_BLOCK_STATE_ALLOCATING:
8659 + case YAFFS_BLOCK_STATE_COLLECTING:
8660 + case YAFFS_BLOCK_STATE_FULL: nFree += (dev->nChunksPerBlock - blk->pagesInUse + blk->softDeletions); break;
8671 +int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
8673 + // This is what we report to the outside world
8676 + int nDirtyCacheChunks;
8679 + nFree = dev->nFreeChunks;
8681 + nFree = yaffs_CountFreeChunks(dev);
8684 + // Now count the number of dirty chunks in the cache and subtract those
8688 + for( nDirtyCacheChunks = 0,i = 0; i < dev->nShortOpCaches; i++)
8690 + if(dev->srCache[i].dirty) nDirtyCacheChunks++;
8694 + nFree -= nDirtyCacheChunks;
8696 + nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock);
8698 + if(nFree < 0) nFree = 0;
8704 +static int yaffs_freeVerificationFailures;
8706 +static void yaffs_VerifyFreeChunks(yaffs_Device *dev)
8708 + int counted = yaffs_CountFreeChunks(dev);
8710 + int difference = dev->nFreeChunks - counted;
8714 + T(YAFFS_TRACE_ALWAYS,(TSTR("Freechunks verification failure %d %d %d" TENDSTR),dev->nFreeChunks,counted,difference));
8715 + yaffs_freeVerificationFailures++;
8719 +/////////////////// YAFFS test code //////////////////////////////////
8721 +#define yaffs_CheckStruct(structure,syze, name) \
8722 + if(sizeof(structure) != syze) \
8724 + T(YAFFS_TRACE_ALWAYS,(TSTR("%s should be %d but is %d\n" TENDSTR),name,syze,sizeof(structure))); \
8725 + return YAFFS_FAIL; \
8729 +static int yaffs_CheckStructures(void)
8731 +// yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags")
8732 +// yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion")
8733 +// yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare")
8734 +#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
8735 + yaffs_CheckStruct(yaffs_Tnode,2* YAFFS_NTNODES_LEVEL0,"yaffs_Tnode")
8737 + yaffs_CheckStruct(yaffs_ObjectHeader,512,"yaffs_ObjectHeader")
8744 +void yaffs_GutsTest(yaffs_Device *dev)
8747 + if(yaffs_CheckStructures() != YAFFS_OK)
8749 + T(YAFFS_TRACE_ALWAYS,(TSTR("One or more structures malformed-- aborting\n" TENDSTR)));
8753 + yaffs_TnodeTest(dev);
8754 + yaffs_ObjectTest(dev);
8759 diff --git a/fs/yaffs/yaffs_guts.h b/fs/yaffs/yaffs_guts.h
8760 new file mode 100644
8761 index 0000000..58c52e0
8763 +++ b/fs/yaffs/yaffs_guts.h
8766 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
8767 + * yaffs_guts.h: Configuration etc for yaffs_guts
8769 + * Copyright (C) 2002 Aleph One Ltd.
8770 + * for Toby Churchill Ltd and Brightstar Engineering
8772 + * Created by Charles Manning <charles@aleph1.co.uk>
8774 + * This program is free software; you can redistribute it and/or modify
8775 + * it under the terms of the GNU Lesser General Public License version 2.1 as
8776 + * published by the Free Software Foundation.
8779 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
8781 + * $Id: yaffs_guts.h,v 1.11 2005/07/31 06:52:40 charles Exp $
8784 +#ifndef __YAFFS_GUTS_H__
8785 +#define __YAFFS_GUTS_H__
8787 +#include "devextras.h"
8788 +#include "yportenv.h"
8791 +#define YAFFS_FAIL 0
8793 +// Give us a Y=0x59,
8794 +// Give us an A=0x41,
8795 +// Give us an FF=0xFF
8796 +// Give us an S=0x53
8797 +// And what have we got...
8798 +#define YAFFS_MAGIC 0x5941FF53
8800 +#define YAFFS_NTNODES_LEVEL0 16
8801 +#define YAFFS_TNODES_LEVEL0_BITS 4
8802 +#define YAFFS_TNODES_LEVEL0_MASK 0xf
8804 +#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
8805 +#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
8806 +#define YAFFS_TNODES_INTERNAL_MASK 0x7
8807 +#define YAFFS_TNODES_MAX_LEVEL 6
8809 +#ifndef CONFIG_YAFFS_NO_YAFFS1
8810 +#define YAFFS_BYTES_PER_SPARE 16
8811 +#define YAFFS_BYTES_PER_CHUNK 512
8812 +#define YAFFS_CHUNK_SIZE_SHIFT 9
8813 +#define YAFFS_CHUNKS_PER_BLOCK 32
8814 +#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
8817 +#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
8818 +#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32
8820 +#define YAFFS_MAX_CHUNK_ID 0x000FFFFF
8822 +#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF
8824 +#define YAFFS_ALLOCATION_NOBJECTS 100
8825 +#define YAFFS_ALLOCATION_NTNODES 100
8826 +#define YAFFS_ALLOCATION_NLINKS 100
8828 +#define YAFFS_NOBJECT_BUCKETS 256
8831 +#define YAFFS_OBJECT_SPACE 0x40000
8833 +#ifdef CONFIG_YAFFS_UNICODE
8834 +#define YAFFS_MAX_NAME_LENGTH 127
8835 +#define YAFFS_MAX_ALIAS_LENGTH 79
8837 +#define YAFFS_MAX_NAME_LENGTH 255
8838 +#define YAFFS_MAX_ALIAS_LENGTH 159
8841 +#define YAFFS_SHORT_NAME_LENGTH 15
8844 +#define YAFFS_OBJECTID_ROOT 1
8845 +#define YAFFS_OBJECTID_LOSTNFOUND 2
8846 +#define YAFFS_OBJECTID_UNLINKED 3
8847 +#define YAFFS_OBJECTID_DELETED 4
8849 +#define YAFFS_MAX_SHORT_OP_CACHES 20
8851 +#define YAFFS_N_TEMP_BUFFERS 4
8853 +// Sequence numbers are used in YAFFS2 to determine block allocation order.
8854 +// The range is limited slightly to help distinguish bad numbers from good.
8855 +// This also allows us to perhaps in the future use special numbers for
8856 +// special purposes.
8857 +// EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years,
8858 +// and is a larger number than the lifetime of a 2GB device.
8860 +#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000
8861 +#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xEFFFFF00
8864 +// ChunkCache is used for short read/write operations.
8867 + struct yaffs_ObjectStruct *object;
8871 + int nBytes; // Only valid if the cache is dirty
8872 + int locked; // Can't push out or flush while locked..
8873 +#ifdef CONFIG_YAFFS_YAFFS2
8876 + __u8 data[YAFFS_BYTES_PER_CHUNK];
8878 +} yaffs_ChunkCache;
8881 +#ifndef CONFIG_YAFFS_NO_YAFFS1
8882 +// Tags structures in RAM
8883 +// NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise
8884 +// the structure size will get blown out.
8888 + unsigned chunkId:20;
8889 + unsigned serialNumber:2;
8890 + unsigned byteCount:10;
8891 + unsigned objectId:18;
8893 + unsigned unusedStuff:2;
8899 + yaffs_Tags asTags;
8907 + YAFFS_ECC_RESULT_UNKNOWN,
8908 + YAFFS_ECC_RESULT_NO_ERROR,
8909 + YAFFS_ECC_RESULT_FIXED,
8910 + YAFFS_ECC_RESULT_UNFIXED
8915 + YAFFS_OBJECT_TYPE_UNKNOWN,
8916 + YAFFS_OBJECT_TYPE_FILE,
8917 + YAFFS_OBJECT_TYPE_SYMLINK,
8918 + YAFFS_OBJECT_TYPE_DIRECTORY,
8919 + YAFFS_OBJECT_TYPE_HARDLINK,
8920 + YAFFS_OBJECT_TYPE_SPECIAL
8921 +} yaffs_ObjectType;
8927 + unsigned validMarker0;
8928 + unsigned chunkUsed; // Status of the chunk: used or unused
8929 + unsigned objectId; // If 0 then this is not part of an object (unused)
8930 + unsigned chunkId; // If 0 then this is a header, else a data chunk
8931 + unsigned byteCount; // Only valid for data chunks
8934 + // The following stuff only has meaning when we read
8935 + yaffs_ECCResult eccResult; // Only valid when we read.
8936 + unsigned blockBad; // Only valid on reading
8939 + unsigned chunkDeleted; // The chunk is marked deleted
8940 + unsigned serialNumber; // Yaffs1 2-bit serial number
8943 + unsigned sequenceNumber; // The sequence number of this block
8945 + // Extra info if this is an object header (YAFFS2 only)
8947 + unsigned extraHeaderInfoAvailable; // There is extra info available if this is not zero
8948 + unsigned extraParentObjectId; // The parent object
8949 + unsigned extraIsShrinkHeader; // Is it a shrink header?
8950 + unsigned extraShadows; // Does this shadow another object?
8952 + yaffs_ObjectType extraObjectType; // What object type?
8954 + unsigned extraFileLength; // Length if it is a file
8955 + unsigned extraEquivalentObjectId; // Equivalent object Id if it is a hard link
8957 + unsigned validMarker1;
8959 +} yaffs_ExtendedTags;
8961 +#ifndef CONFIG_YAFFS_NO_YAFFS1
8969 + __u8 pageStatus; // set to 0 to delete the chunk
8979 +//Special structure for passing through to mtd
8980 +struct yaffs_NANDSpare {
8981 + yaffs_Spare spare;
8988 +// Block data in RAM
8991 + YAFFS_BLOCK_STATE_UNKNOWN = 0,
8993 + YAFFS_BLOCK_STATE_SCANNING,
8994 + YAFFS_BLOCK_STATE_NEEDS_SCANNING,// The block might have something on it (ie it is allocating or full, perhaps empty)
8995 + // but it needs to be scanned to determine its true state.
8996 + // This state is only valid during yaffs_Scan.
8997 + // NB We tolerate empty because the pre-scanner might be incapable of deciding
8998 + // However, if this state is returned on a YAFFS2 device, then we expect a sequence number
9000 + YAFFS_BLOCK_STATE_EMPTY, // This block is empty
9002 + YAFFS_BLOCK_STATE_ALLOCATING, // This block is partially allocated.
9003 + // This is the one currently being used for page
9004 + // allocation. Should never be more than one of these
9007 + YAFFS_BLOCK_STATE_FULL, // All the pages in this block have been allocated.
9008 + // At least one page holds valid data.
9010 + YAFFS_BLOCK_STATE_DIRTY, // All pages have been allocated and deleted.
9011 + // Erase me, reuse me.
9013 + YAFFS_BLOCK_STATE_COLLECTING, // This block is being garbage collected
9015 + YAFFS_BLOCK_STATE_DEAD // This block has failed and is not in use
9017 +} yaffs_BlockState;
9025 + int softDeletions:12; // number of soft deleted pages
9026 + int pagesInUse:12; // number of pages in use
9027 + yaffs_BlockState blockState:4; // One of the above block states
9028 + __u32 needsRetiring:1; // Data has failed on this block, need to get valid data off
9029 + // and retire the block.
9030 +#ifdef CONFIG_YAFFS_YAFFS2
9031 + __u32 hasShrinkHeader:1;// This block has at least one object header that does a shrink
9032 + __u32 sequenceNumber; // block sequence number for yaffs2
9038 +//////////////////// Object structure ///////////////////////////
9039 +// This is the object structure as stored on NAND
9043 + yaffs_ObjectType type;
9045 + // Apply to everything
9046 + int parentObjectId;
9047 + __u16 sum__NoLongerUsed; // checksum of name. Calc this off the name to prevent inconsistencies
9048 + YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
9050 + // Thes following apply to directories, files, symlinks - not hard links
9051 + __u32 yst_mode; // protection
9053 +#ifdef CONFIG_YAFFS_WINCE
9054 + __u32 notForWinCE[5];
9056 + __u32 yst_uid; // user ID of owner
9057 + __u32 yst_gid; // group ID of owner
9058 + __u32 yst_atime; // time of last access
9059 + __u32 yst_mtime; // time of last modification
9060 + __u32 yst_ctime; // time of last change
9063 + // File size applies to files only
9066 + // Equivalent object id applies to hard links only.
9067 + int equivalentObjectId;
9069 + // Alias is for symlinks only.
9070 + YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
9072 + __u32 yst_rdev; // device stuff for block and char devices (maj/min)
9074 +#ifdef CONFIG_YAFFS_WINCE
9075 + __u32 win_ctime[2];
9076 + __u32 win_atime[2];
9077 + __u32 win_mtime[2];
9078 + __u32 roomToGrow[4];
9080 + __u32 roomToGrow[10];
9083 + int shadowsObject; // This object header shadows the specified object if not > 0
9085 + // isShrink applies to object headers written when we shrink the file (ie resize)
9088 +} yaffs_ObjectHeader;
9092 +//////////////////// Tnode ///////////////////////////
9094 +union yaffs_Tnode_union
9096 +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
9097 + union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL+1];
9099 + union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL];
9101 + __u16 level0[YAFFS_NTNODES_LEVEL0];
9105 +typedef union yaffs_Tnode_union yaffs_Tnode;
9107 +struct yaffs_TnodeList_struct
9109 + struct yaffs_TnodeList_struct *next;
9110 + yaffs_Tnode *tnodes;
9113 +typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
9117 +/////////////////// Object ////////////////////////////////
9118 +// An object can be one of:
9119 +// - a directory (no data, has children links
9120 +// - a regular file (data.... not prunes :->).
9121 +// - a symlink [symbolic link] (the alias).
9128 + __u32 scannedFileSize;
9132 +} yaffs_FileStructure;
9136 + struct list_head children; // list of child links
9137 +} yaffs_DirectoryStructure;
9142 +} yaffs_SymLinkStructure;
9146 + struct yaffs_ObjectStruct *equivalentObject;
9147 + __u32 equivalentObjectId;
9148 +} yaffs_HardLinkStructure;
9152 + yaffs_FileStructure fileVariant;
9153 + yaffs_DirectoryStructure directoryVariant;
9154 + yaffs_SymLinkStructure symLinkVariant;
9155 + yaffs_HardLinkStructure hardLinkVariant;
9156 +} yaffs_ObjectVariant;
9159 +struct yaffs_ObjectStruct
9161 + __u8 deleted: 1; // This should only apply to unlinked files.
9162 + __u8 softDeleted: 1; // it has also been soft deleted
9163 + __u8 unlinked: 1; // An unlinked file. The file should be in the unlinked pseudo directory.
9164 + __u8 fake:1; // A fake object has no presence on NAND.
9165 + __u8 renameAllowed:1; // Some objects are not allowed to be renamed.
9166 + __u8 unlinkAllowed:1;
9167 + __u8 dirty:1; // the object needs to be written to flash
9168 + __u8 valid:1; // When the file system is being loaded up, this
9169 + // object might be created before the data
9170 + // is available (ie. file data records appear before the header).
9171 + __u8 serial; // serial number of chunk in NAND. Store here so we don't have to
9173 + __u8 deferedFree: 1; // For Linux kernel. Object is removed from NAND, but still in the inode cache.
9174 + // Free of object is defered.
9176 + __u8 lazyLoaded; // Vital info has been loaded from tags. Not all info available.
9179 + // read back the old one to update.
9180 + __u16 sum; // sum of the name to speed searching
9182 + struct yaffs_DeviceStruct *myDev; // The device I'm on
9185 + struct list_head hashLink; // list of objects in this hash bucket
9188 + struct list_head hardLinks; // all the equivalent hard linked objects
9189 + // live on this list
9190 + // directory structure stuff
9191 + struct yaffs_ObjectStruct *parent; //my parent directory
9192 + struct list_head siblings; // siblings in a directory
9193 + // also used for linking up the free list
9195 + // Where's my object header in NAND?
9196 + int chunkId; // where it lives
9198 + int nDataChunks; // Number of data chunks attached to the file.
9200 + __u32 objectId; // the object id value
9203 + __u32 yst_mode; // protection
9205 +#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
9206 + YCHAR shortName[YAFFS_SHORT_NAME_LENGTH+1];
9213 +#ifdef CONFIG_YAFFS_WINCE
9214 + __u32 win_ctime[2];
9215 + __u32 win_mtime[2];
9216 + __u32 win_atime[2];
9218 + __u32 yst_uid; // user ID of owner
9219 + __u32 yst_gid; // group ID of owner
9220 + __u32 yst_atime; // time of last access
9221 + __u32 yst_mtime; // time of last modification
9222 + __u32 yst_ctime; // time of last change
9225 + __u32 yst_rdev; // device stuff for block and char devices
9230 + struct inode *myInode;
9236 + yaffs_ObjectType variantType;
9238 + yaffs_ObjectVariant variant;
9244 +typedef struct yaffs_ObjectStruct yaffs_Object;
9247 +struct yaffs_ObjectList_struct
9249 + yaffs_Object *objects;
9250 + struct yaffs_ObjectList_struct *next;
9253 +typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
9257 + struct list_head list;
9259 +} yaffs_ObjectBucket;
9261 +///////////////////// Temporary buffers ////////////////////
9263 +// These are chunk-sized working buffers. Each device has a few
9267 + int line; // track from whence this buffer was allocated
9269 +} yaffs_TempBuffer;
9271 +//////////////////// Device ////////////////////////////////
9273 +struct yaffs_DeviceStruct
9275 + struct list_head devList;
9278 + // Entry parameters set up way early. Yaffs sets up the rest.
9279 + int nBytesPerChunk; // Should be a power of 2 >= 512
9280 + int nChunksPerBlock; // does not need to be a power of 2
9281 + int nBytesPerSpare; // spare area size
9282 + int startBlock; // Start block we're allowed to use
9283 + int endBlock; // End block we're allowed to use
9284 + int nReservedBlocks; // We want this tuneable so that we can reduce
9285 + // reserved blocks on NOR and RAM.
9287 + int nShortOpCaches; // If <= 0, then short op caching is disabled, else
9288 + // the number of short op caches (don't use too many).
9290 + int useHeaderFileSize; // Flag to determine if we should use file sizes from the header
9292 + int useNANDECC; // Flag to decide whether or not to use NANDECC
9295 + void *genericDevice; // Pointer to device context
9296 + // On an mtd this holds the mtd pointer.
9298 + // NAND access functions (Must be set before calling YAFFS)
9301 + int (*writeChunkToNAND)(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, const yaffs_Spare *spare);
9302 + int (*readChunkFromNAND)(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);
9303 + int (*eraseBlockInNAND)(struct yaffs_DeviceStruct *dev,int blockInNAND);
9304 + int (*initialiseNAND)(struct yaffs_DeviceStruct *dev);
9306 +#ifdef CONFIG_YAFFS_YAFFS2
9307 + int (*writeChunkWithTagsToNAND)(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *tags);
9308 + int (*readChunkWithTagsFromNAND)(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags);
9309 + int (*markNANDBlockBad)(struct yaffs_DeviceStruct *dev, int blockNo);
9310 + int (*queryNANDBlock)(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber);
9315 + // End of stuff that must be set before initialisation.
9317 + // Runtime parameters. Set up by YAFFS.
9319 + __u16 chunkGroupBits; // 0 for devices <= 32MB. else log2(nchunks) - 16
9320 + __u16 chunkGroupSize; // == 2^^chunkGroupBits
9324 + struct semaphore sem;// Semaphore for waiting on erasure.
9325 + struct semaphore grossLock; // Gross locking semaphore
9326 + __u8 * spareBuffer; // For mtdif2 use. Don't know the size of the buffer at compile time so we have to allocate it.
9327 + void (*putSuperFunc)(struct super_block *sb);
9332 + // Stuff to support block offsetting to support start block zero
9333 + int internalStartBlock;
9334 + int internalEndBlock;
9339 + yaffs_BlockInfo *blockInfo;
9340 + __u8 *chunkBits; // bitmap of chunks in use
9341 + int chunkBitmapStride; // Number of bytes of chunkBits per block.
9342 + // Must be consistent with nChunksPerBlock.
9345 + int nErasedBlocks;
9346 + int allocationBlock; // Current block being allocated off
9347 + __u32 allocationPage;
9348 + int allocationBlockFinder; // Used to search for next allocation block
9351 + int nTnodesCreated;
9352 + yaffs_Tnode *freeTnodes;
9354 + yaffs_TnodeList *allocatedTnodeList;
9358 + int nObjectsCreated;
9359 + yaffs_Object *freeObjects;
9362 + yaffs_ObjectList *allocatedObjectList;
9364 + yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS];
9368 + int currentDirtyChecker; // Used to find current dirtiest block
9370 + __u32 *gcCleanupList; // objects to delete at the end of a GC.
9372 + // Operations since mount
9375 + int nBlockErasures;
9376 + int nErasureFailures;
9378 + int garbageCollections;
9379 + int passiveGarbageCollections;
9380 + int nRetriedWrites;
9381 + int nRetiredBlocks;
9385 + int tagsEccUnfixed;
9387 + int nUnmarkedDeletions;
9389 + yaffs_Object *rootDir;
9390 + yaffs_Object *lostNFoundDir;
9392 + // Buffer areas for storing data to recover from write failures
9393 +// __u8 bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];
9394 +// yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK];
9395 + int bufferedBlock; // Which block is buffered here?
9396 + int doingBufferedBlockRewrite;
9398 + yaffs_ChunkCache *srCache;
9403 + // Stuff for background deletion and unlinked files.
9404 + yaffs_Object *unlinkedDir; // Directory where unlinked and deleted files live.
9405 + yaffs_Object *deletedDir; // Directory where deleted objects are sent to disappear.
9406 + yaffs_Object *unlinkedDeletion; // Current file being background deleted.
9407 + int nDeletedFiles; // Count of files awaiting deletion;
9408 + int nUnlinkedFiles; // Count of unlinked files.
9409 + int nBackgroundDeletions; // Count of background deletions.
9411 + //__u8 *localBuffer;
9413 + yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
9415 + int unmanagedTempAllocations;
9416 + int unmanagedTempDeallocations;
9418 + // yaffs2 runtime stuff
9419 + unsigned sequenceNumber; //Sequence number of currently allocating block
9420 + unsigned oldestDirtySequence;
9424 +typedef struct yaffs_DeviceStruct yaffs_Device;
9427 +// Function to manipulate block info
9428 +static Y_INLINE yaffs_BlockInfo* yaffs_GetBlockInfo(yaffs_Device *dev, int blk)
9430 + if(blk < dev->internalStartBlock || blk > dev->internalEndBlock)
9432 + T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),blk));
9435 + return &dev->blockInfo[blk - dev->internalStartBlock];
9439 +//////////// YAFFS Functions //////////////////
9441 +int yaffs_GutsInitialise(yaffs_Device *dev);
9442 +void yaffs_Deinitialise(yaffs_Device *dev);
9444 +int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev);
9448 +int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, yaffs_Object *newDir, const YCHAR *newName);
9450 +// generic Object functions
9451 +int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name);
9452 +int yaffs_DeleteFile(yaffs_Object *obj);
9454 +// Object access functions.
9455 +int yaffs_GetObjectName(yaffs_Object *obj,YCHAR *name,int buffSize);
9456 +int yaffs_GetObjectFileLength(yaffs_Object *obj);
9457 +int yaffs_GetObjectInode(yaffs_Object *obj);
9458 +unsigned yaffs_GetObjectType(yaffs_Object *obj);
9459 +int yaffs_GetObjectLinkCount(yaffs_Object *obj);
9461 +// Change inode attributes
9462 +int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr);
9463 +int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr);
9466 +int yaffs_ReadDataFromFile(yaffs_Object *obj, __u8 *buffer, __u32 offset, int nBytes);
9467 +int yaffs_WriteDataToFile(yaffs_Object *obj, const __u8 *buffer, __u32 offset, int nBytes, int writeThrough);
9468 +int yaffs_ResizeFile(yaffs_Object *obj, int newSize);
9470 +yaffs_Object *yaffs_MknodFile(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid);
9471 +int yaffs_FlushFile(yaffs_Object *obj,int updateTime);
9474 +// Directory operations
9475 +yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid);
9476 +yaffs_Object *yaffs_FindObjectByName(yaffs_Object *theDir,const YCHAR *name);
9477 +int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,int (*fn)(yaffs_Object *));
9479 +yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev,__u32 number);
9482 +yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name, yaffs_Object *equivalentObject);
9484 +yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj);
9486 +// Symlink operations
9487 +yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name, __u32 mode, __u32 uid, __u32 gid, const YCHAR *alias);
9488 +YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj);
9490 +// Special inodes (fifos, sockets and devices)
9491 +yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent,const YCHAR *name, __u32 mode, __u32 uid, __u32 gid,__u32 rdev);
9494 +// Special directories
9495 +yaffs_Object *yaffs_Root(yaffs_Device *dev);
9496 +yaffs_Object *yaffs_LostNFound(yaffs_Device *dev);
9498 +#ifdef CONFIG_YAFFS_WINCE
9499 +// CONFIG_YAFFS_WINCE special stuff
9500 +void yfsd_WinFileTimeNow(__u32 target[2]);
9505 +void yaffs_HandleDeferedFree(yaffs_Object *obj);
9512 +int yaffs_DumpObject(yaffs_Object *obj);
9515 +void yaffs_GutsTest(yaffs_Device *dev);
9518 +void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
9519 +void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND,int lyn);
9520 +int yaffs_CheckFF(__u8 *buffer,int nBytes);
9524 diff --git a/fs/yaffs/yaffs_mtdif.c b/fs/yaffs/yaffs_mtdif.c
9525 new file mode 100644
9526 index 0000000..90146fb
9528 +++ b/fs/yaffs/yaffs_mtdif.c
9531 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
9532 + * yaffs_mtdif.c NAND mtd wrapper functions.
9534 + * Copyright (C) 2002 Aleph One Ltd.
9535 + * for Toby Churchill Ltd and Brightstar Engineering
9537 + * Created by Charles Manning <charles@aleph1.co.uk>
9539 + * This program is free software; you can redistribute it and/or modify
9540 + * it under the terms of the GNU General Public License version 2 as
9541 + * published by the Free Software Foundation.
9545 +const char *yaffs_mtdif_c_version = "$Id: yaffs_mtdif.c,v 1.7 2005/08/01 20:52:35 luc Exp $";
9547 +#include "yportenv.h"
9549 +#ifdef CONFIG_YAFFS_YAFFS1
9551 +#include "yaffs_mtdif.h"
9553 +#include "linux/mtd/mtd.h"
9554 +#include "linux/types.h"
9555 +#include "linux/time.h"
9556 +#include "linux/mtd/nand.h"
9558 +static struct nand_oobinfo yaffs_oobinfo = {
9561 + .eccpos = {8, 9, 10, 13, 14, 15}
9564 +static struct nand_oobinfo yaffs_noeccinfo = {
9569 +int nandmtd_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare)
9571 + struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
9575 + loff_t addr = ((loff_t)chunkInNAND) * dev->nBytesPerChunk;
9577 + __u8 *spareAsBytes = (__u8 *)spare;
9581 + if(dev->useNANDECC)
9582 + retval = mtd->write_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,spareAsBytes,&yaffs_oobinfo);
9584 + retval = mtd->write_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,spareAsBytes,&yaffs_noeccinfo);
9589 + retval = mtd->write(mtd,addr,dev->nBytesPerChunk,&dummy,data);
9591 + retval = mtd->write_oob(mtd,addr,YAFFS_BYTES_PER_SPARE,&dummy,spareAsBytes);
9597 + return YAFFS_FAIL;
9600 +int nandmtd_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare)
9602 + struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
9606 + loff_t addr = ((loff_t)chunkInNAND) * dev->nBytesPerChunk;
9608 + __u8 *spareAsBytes = (__u8 *)spare;
9612 + if(dev->useNANDECC)
9613 + { // Careful, this call adds 2 ints to the end of the spare data. Calling function should
9614 + // allocate enough memory for spare, i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)].
9615 + retval = mtd->read_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,spareAsBytes,&yaffs_oobinfo);
9619 + retval = mtd->read_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,spareAsBytes,&yaffs_noeccinfo);
9625 + retval = mtd->read(mtd,addr,dev->nBytesPerChunk,&dummy,data);
9627 + retval = mtd->read_oob(mtd,addr,YAFFS_BYTES_PER_SPARE,&dummy,spareAsBytes);
9633 + return YAFFS_FAIL;
9636 +// Callback not needed for NAND
9638 +static void nandmtd_EraseCallback(struct erase_info *ei)
9640 + yaffs_Device *dev = (yaffs_Device *)ei->priv;
9646 +int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
9648 + struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
9649 + __u32 addr = ((loff_t) blockNumber) * dev->nBytesPerChunk * dev->nChunksPerBlock;
9650 + struct erase_info ei;
9655 + ei.len = dev->nBytesPerChunk * dev->nChunksPerBlock;
9658 + ei.callback = NULL;
9659 + ei.priv = (u_long)dev;
9661 + // Todo finish off the ei if required
9663 + sema_init(&dev->sem,0);
9665 + retval = mtd->erase(mtd,&ei);
9667 + //No need for callback
9668 + // down(&dev->sem); // Wait for the erasure to complete
9673 + return YAFFS_FAIL;
9676 +int nandmtd_InitialiseNAND(yaffs_Device *dev)
9681 +#endif // CONFIG_YAFFS_YAFFS1
9683 diff --git a/fs/yaffs/yaffs_mtdif.h b/fs/yaffs/yaffs_mtdif.h
9684 new file mode 100644
9685 index 0000000..8846828
9687 +++ b/fs/yaffs/yaffs_mtdif.h
9690 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
9691 + * yaffs_mtdif.h NAND mtd interface wrappers
9693 + * Copyright (C) 2002 Aleph One Ltd.
9694 + * for Toby Churchill Ltd and Brightstar Engineering
9696 + * Created by Charles Manning <charles@aleph1.co.uk>
9698 + * This program is free software; you can redistribute it and/or modify
9699 + * it under the terms of the GNU Lesser General Public License version 2.1 as
9700 + * published by the Free Software Foundation.
9703 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
9705 + * $Id: yaffs_mtdif.h,v 1.2 2005/07/19 20:41:59 charles Exp $
9708 +#ifndef __YAFFS_MTDIF_H__
9709 +#define __YAFFS_MTDIF_H__
9711 +#include "yaffs_guts.h"
9713 +int nandmtd_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare);
9714 +int nandmtd_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);
9715 +int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
9716 +int nandmtd_InitialiseNAND(yaffs_Device *dev);
9722 diff --git a/fs/yaffs/yaffs_mtdif2.c b/fs/yaffs/yaffs_mtdif2.c
9723 new file mode 100644
9724 index 0000000..0c4cc39
9726 +++ b/fs/yaffs/yaffs_mtdif2.c
9729 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
9730 + * yaffs_mtdif.c NAND mtd wrapper functions.
9732 + * Copyright (C) 2002 Aleph One Ltd.
9733 + * for Toby Churchill Ltd and Brightstar Engineering
9735 + * Created by Charles Manning <charles@aleph1.co.uk>
9737 + * This program is free software; you can redistribute it and/or modify
9738 + * it under the terms of the GNU General Public License version 2 as
9739 + * published by the Free Software Foundation.
9743 +// mtd interface for YAFFS2
9745 +const char *yaffs_mtdif2_c_version = "$Id: yaffs_mtdif2.c,v 1.6 2005/08/01 20:52:35 luc Exp $";
9747 +#include "yportenv.h"
9749 +#ifdef CONFIG_YAFFS_YAFFS2
9751 +#include "yaffs_mtdif2.h"
9753 +#include "linux/mtd/mtd.h"
9754 +#include "linux/types.h"
9755 +#include "linux/time.h"
9757 +#include "yaffs_packedtags2.h"
9762 +int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags)
9764 + struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
9769 + loff_t addr = ((loff_t)chunkInNAND) * dev->nBytesPerChunk;
9771 + yaffs_PackedTags2 pt;
9773 + T(YAFFS_TRACE_MTD,(TSTR("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p" TENDSTR),chunkInNAND,data,tags));
9777 + yaffs_PackTags2(&pt,tags);
9782 + if(dev->useNANDECC)
9783 + retval = mtd->write_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,(__u8 *)&pt,NULL);
9785 + retval = mtd->write_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,(__u8 *)&pt,NULL);
9790 + retval = mtd->write(mtd,addr,dev->nBytesPerChunk,&dummy,data);
9792 + retval = mtd->write_oob(mtd,addr,mtd->oobsize,&dummy,(__u8 *)&pt);
9799 + return YAFFS_FAIL;
9802 +int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags)
9804 + struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
9809 + loff_t addr = ((loff_t)chunkInNAND) * dev->nBytesPerChunk;
9811 + yaffs_PackedTags2 pt;
9813 + T(YAFFS_TRACE_MTD,(TSTR("nandmtd2_ReadChunkWithTagsToNAND chunk %d data %p tags %p" TENDSTR),chunkInNAND,data,tags));
9817 + if(dev->useNANDECC)
9819 + retval = mtd->read_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,dev->spareBuffer,NULL);
9823 + retval = mtd->read_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,dev->spareBuffer,NULL);
9825 + memcpy(&pt,dev->spareBuffer,sizeof(pt));
9830 + retval = mtd->read(mtd,addr,dev->nBytesPerChunk,&dummy,data);
9832 + retval = mtd->read_oob(mtd,addr,mtd->oobsize,&dummy,dev->spareBuffer);
9833 + memcpy(&pt, mtd->oobinfo.oobfree[0][0] + (char *)dev->spareBuffer, sizeof(pt));
9838 + yaffs_UnpackTags2(tags,&pt);
9843 + return YAFFS_FAIL;
9846 +int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
9848 + struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
9850 + T(YAFFS_TRACE_MTD,(TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR),blockNo));
9853 + retval = mtd->block_markbad(mtd,blockNo * dev->nChunksPerBlock * dev->nBytesPerChunk);
9858 + return YAFFS_FAIL;
9862 +int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber)
9864 + struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
9867 + T(YAFFS_TRACE_MTD,(TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR),blockNo));
9868 + retval = mtd->block_isbad(mtd,blockNo* dev->nChunksPerBlock * dev->nBytesPerChunk);
9872 + T(YAFFS_TRACE_MTD,(TSTR("block is bad" TENDSTR)));
9874 + *state = YAFFS_BLOCK_STATE_DEAD;
9875 + *sequenceNumber = 0;
9879 + yaffs_ExtendedTags t;
9880 + nandmtd2_ReadChunkWithTagsFromNAND(dev,blockNo * dev->nChunksPerBlock,NULL, &t);
9884 + *sequenceNumber = t.sequenceNumber;
9885 + *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
9889 + *sequenceNumber = 0;
9890 + *state = YAFFS_BLOCK_STATE_EMPTY;
9893 + T(YAFFS_TRACE_MTD,(TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,*state));
9898 + return YAFFS_FAIL;
9905 diff --git a/fs/yaffs/yaffs_mtdif2.h b/fs/yaffs/yaffs_mtdif2.h
9906 new file mode 100644
9907 index 0000000..5b308ee
9909 +++ b/fs/yaffs/yaffs_mtdif2.h
9912 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
9913 + * yaffs_mtdif.c NAND mtd wrapper functions.
9915 + * Copyright (C) 2002 Aleph One Ltd.
9916 + * for Toby Churchill Ltd and Brightstar Engineering
9918 + * Created by Charles Manning <charles@aleph1.co.uk>
9920 + * This program is free software; you can redistribute it and/or modify
9921 + * it under the terms of the GNU General Public License version 2 as
9922 + * published by the Free Software Foundation.
9927 +#ifndef __YAFFS_MTDIF2_H__
9928 +#define __YAFFS_MTDIF2_H__
9931 +#include "yaffs_guts.h"
9932 +int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags);
9933 +int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags);
9934 +int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
9935 +int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber);
9938 diff --git a/fs/yaffs/yaffs_nandemul2k.h b/fs/yaffs/yaffs_nandemul2k.h
9939 new file mode 100644
9940 index 0000000..b35d474
9942 +++ b/fs/yaffs/yaffs_nandemul2k.h
9945 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
9947 + * Copyright (C) 2002 Aleph One Ltd.
9948 + * for Toby Churchill Ltd and Brightstar Engineering
9950 + * Created by Charles Manning <charles@aleph1.co.uk>
9952 + * This program is free software; you can redistribute it and/or modify
9953 + * it under the terms of the GNU Lesser General Public License version 2.1 as
9954 + * published by the Free Software Foundation.
9957 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
9959 + * yaffs_nandemul2k.h: Interface to emulated NAND functions (2k page size)
9961 + * $Id: yaffs_nandemul2k.h,v 1.1 2004/12/17 04:39:04 charles Exp $
9964 +#ifndef __YAFFS_NANDEMUL2K_H__
9965 +#define __YAFFS_NANDEMUL2K_H__
9967 +#include "yaffs_guts.h"
9970 +int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_ExtendedTags *tags);
9971 +int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags);
9972 +int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
9973 +int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber);
9974 +int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND);
9975 +int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);
9976 +int nandemul2k_GetBytesPerChunk(void);
9977 +int nandemul2k_GetChunksPerBlock(void);
9978 +int nandemul2k_GetNumberOfBlocks(void);
9982 diff --git a/fs/yaffs/yaffs_packedtags1.c b/fs/yaffs/yaffs_packedtags1.c
9983 new file mode 100644
9984 index 0000000..bab338f
9986 +++ b/fs/yaffs/yaffs_packedtags1.c
9988 +#include "yaffs_packedtags1.h"
9989 +#include "yportenv.h"
9991 +void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t)
9993 + pt->chunkId = t->chunkId;
9994 + pt->serialNumber = t->serialNumber;
9995 + pt->byteCount = t->byteCount;
9996 + pt->objectId = t->objectId;
9998 + pt->deleted = (t->chunkDeleted) ? 0 : 1;
9999 + pt->unusedStuff = 0;
10000 + pt->shouldBeFF = 0xFFFFFFFF;
10004 +void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt)
10006 + static const __u8 allFF[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,0xff, 0xff, 0xff, 0xff};
10008 + if(memcmp(allFF,pt,sizeof(yaffs_PackedTags1)))
10011 + if(pt->shouldBeFF != 0xFFFFFFFF)
10015 + t->chunkUsed = 1;
10016 + t->objectId = pt->objectId;
10017 + t->chunkId = pt->chunkId;
10018 + t->byteCount = pt->byteCount;
10019 + t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
10020 + t->chunkDeleted = (pt->deleted) ? 0 : 1;
10021 + t->serialNumber = pt->serialNumber;
10025 + memset(t,0,sizeof(yaffs_ExtendedTags));
10030 diff --git a/fs/yaffs/yaffs_packedtags1.h b/fs/yaffs/yaffs_packedtags1.h
10031 new file mode 100644
10032 index 0000000..0f76615
10034 +++ b/fs/yaffs/yaffs_packedtags1.h
10036 +// This is used to pack YAFFS1 tags, not YAFFS2 tags.
10038 +#ifndef __YAFFS_PACKEDTAGS1_H__
10039 +#define __YAFFS_PACKEDTAGS1_H__
10042 +#include "yaffs_guts.h"
10046 + unsigned chunkId:20;
10047 + unsigned serialNumber:2;
10048 + unsigned byteCount:10;
10049 + unsigned objectId:18;
10051 + unsigned deleted:1;
10052 + unsigned unusedStuff:1;
10053 + unsigned shouldBeFF;
10055 +} yaffs_PackedTags1;
10059 +void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t);
10060 +void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt);
10064 diff --git a/fs/yaffs/yaffs_packedtags2.c b/fs/yaffs/yaffs_packedtags2.c
10065 new file mode 100644
10066 index 0000000..f4de18d
10068 +++ b/fs/yaffs/yaffs_packedtags2.c
10071 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
10073 + * yaffs_packedtags2.c: Tags packing for YAFFS2
10075 + * Copyright (C) 2002 Aleph One Ltd.
10077 + * Created by Charles Manning <charles@aleph1.co.uk>
10080 + * This program is free software; you can redistribute it and/or
10081 + * modify it under the terms of the GNU Lesser General Public License
10082 + * version 2.1 as published by the Free Software Foundation.
10085 +#include "yaffs_packedtags2.h"
10086 +#include "yportenv.h"
10087 +#include "yaffs_tagsvalidity.h"
10091 +// This code packs a set of extended tags into a binary structure for NAND storage
10093 +// Some of the information is "extra" struff which can be packed in to speed scanning
10094 +// This is defined by having the EXTRA_HEADER_INFO_FLAG set.
10097 +// Extra flags applied to chunkId
10099 +#define EXTRA_HEADER_INFO_FLAG 0x80000000
10100 +#define EXTRA_SHRINK_FLAG 0x40000000
10101 +#define EXTRA_SHADOWS_FLAG 0x20000000
10102 +#define EXTRA_SPARE_FLAGS 0x10000000
10104 +#define ALL_EXTRA_FLAGS 0xF0000000
10108 +// Also, the top 4 bits of the object Id are set to the object type.
10109 +#define EXTRA_OBJECT_TYPE_SHIFT (28)
10110 +#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)
10114 +static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 *pt)
10116 + T(YAFFS_TRACE_MTD,(TSTR("packed tags obj %d chunk %d byte %d seq %d"TENDSTR),pt->t.objectId,pt->t.chunkId,pt->t.byteCount,pt->t.sequenceNumber));
10119 +static void yaffs_DumpTags2(const yaffs_ExtendedTags *t)
10121 + T(YAFFS_TRACE_MTD,(TSTR("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d"TENDSTR),
10122 + t->eccResult, t->blockBad, t->chunkUsed, t->objectId, t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber, t->sequenceNumber));
10126 +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t)
10128 + pt->t.chunkId = t->chunkId;
10129 + pt->t.sequenceNumber = t->sequenceNumber;
10130 + pt->t.byteCount = t->byteCount;
10131 + pt->t.objectId = t->objectId;
10133 + if(t->chunkId == 0 && t->extraHeaderInfoAvailable)
10135 + // Store the extra header info instead
10136 + pt->t.chunkId = EXTRA_HEADER_INFO_FLAG | t->extraParentObjectId; // We save the parent object in the chunkId
10137 + if(t->extraIsShrinkHeader)
10139 + pt->t.chunkId |= EXTRA_SHRINK_FLAG;
10141 + if(t->extraShadows)
10143 + pt->t.chunkId |= EXTRA_SHADOWS_FLAG;
10146 + pt->t.objectId &= ~EXTRA_OBJECT_TYPE_MASK;
10147 + pt->t.objectId |= (t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
10149 + if(t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)
10151 + pt->t.byteCount = t->extraEquivalentObjectId;
10153 + else if(t->extraObjectType == YAFFS_OBJECT_TYPE_FILE)
10155 + pt->t.byteCount = t->extraFileLength;
10159 + pt->t.byteCount = 0;
10163 + yaffs_DumpPackedTags2(pt);
10164 + yaffs_DumpTags2(t);
10166 +#ifndef YAFFS_IGNORE_TAGS_ECC
10168 + yaffs_ECCCalculateOther((unsigned char *)&pt->t,sizeof(yaffs_PackedTags2TagsPart),&pt->ecc);
10173 +void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt)
10177 + memset(t,0,sizeof(yaffs_ExtendedTags));
10179 + yaffs_InitialiseTags(t);
10181 + if(pt->t.sequenceNumber != 0xFFFFFFFF)
10183 + // Page is in use
10184 +#ifdef YAFFS_IGNORE_TAGS_ECC
10186 + t->eccResult = 0;
10190 + yaffs_ECCOther ecc;
10191 + yaffs_ECCCalculateOther((unsigned char *)&pt->t,sizeof(yaffs_PackedTags2TagsPart),&ecc);
10192 + t->eccResult = yaffs_ECCCorrectOther((unsigned char *)&pt->t,sizeof(yaffs_PackedTags2TagsPart),&pt->ecc,&ecc);
10196 + t->chunkUsed = 1;
10197 + t->objectId = pt->t.objectId;
10198 + t->chunkId = pt->t.chunkId;
10199 + t->byteCount = pt->t.byteCount;
10200 + t->chunkDeleted = 0;
10201 + t->serialNumber = 0;
10202 + t->sequenceNumber = pt->t.sequenceNumber;
10204 + // Do extra header info stuff
10206 + if(pt->t.chunkId & EXTRA_HEADER_INFO_FLAG)
10209 + t->byteCount = 0;
10211 + t->extraHeaderInfoAvailable = 1;
10212 + t->extraParentObjectId = pt->t.chunkId & (~(ALL_EXTRA_FLAGS));
10213 + t->extraIsShrinkHeader = (pt->t.chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
10214 + t->extraShadows = (pt->t.chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
10215 + t->extraObjectType = pt->t.objectId >> EXTRA_OBJECT_TYPE_SHIFT;
10216 + t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
10218 + if(t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)
10220 + t->extraEquivalentObjectId = pt->t.byteCount;
10224 + t->extraFileLength = pt->t.byteCount;
10229 + yaffs_DumpPackedTags2(pt);
10230 + yaffs_DumpTags2(t);
10234 diff --git a/fs/yaffs/yaffs_packedtags2.h b/fs/yaffs/yaffs_packedtags2.h
10235 new file mode 100644
10236 index 0000000..564dd58
10238 +++ b/fs/yaffs/yaffs_packedtags2.h
10240 +// This is used to pack YAFFS2 tags, not YAFFS1tags.
10242 +#ifndef __YAFFS_PACKEDTAGS2_H__
10243 +#define __YAFFS_PACKEDTAGS2_H__
10246 +#include "yaffs_guts.h"
10247 +#include "yaffs_ecc.h"
10252 + unsigned sequenceNumber;
10253 + unsigned objectId;
10254 + unsigned chunkId;
10255 + unsigned byteCount;
10256 +} yaffs_PackedTags2TagsPart;
10260 + yaffs_PackedTags2TagsPart t;
10261 + yaffs_ECCOther ecc;
10262 +} yaffs_PackedTags2;
10265 +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t);
10266 +void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt);
10270 diff --git a/fs/yaffs/yaffs_tagscompat.c b/fs/yaffs/yaffs_tagscompat.c
10271 new file mode 100644
10272 index 0000000..fdf1cbc
10274 +++ b/fs/yaffs/yaffs_tagscompat.c
10277 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
10278 + * yaffs_tagscompat.h: Tags compatability layer to use YAFFS1 formatted NAND.
10280 + * Copyright (C) 2002 Aleph One Ltd.
10282 + * Created by Charles Manning <charles@aleph1.co.uk>
10284 + * This program is free software; you can redistribute it and/or modify
10285 + * it under the terms of the GNU General Public License version 2 as
10286 + * published by the Free Software Foundation.
10288 + * $Id: yaffs_tagscompat.c,v 1.3 2005/07/31 06:47:12 marty Exp $
10291 +#include "yaffs_guts.h"
10292 +#include "yaffs_tagscompat.h"
10293 +#include "yaffs_ecc.h"
10295 +static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND);
10297 +static void yaffs_CheckWrittenBlock(yaffs_Device *dev,int chunkInNAND);
10298 +static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare);
10299 +static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_Spare *spare);
10300 +static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND);
10304 +static const char yaffs_countBitsTable[256] =
10306 +0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
10307 +1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
10308 +1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
10309 +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
10310 +1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
10311 +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
10312 +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
10313 +3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
10314 +1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
10315 +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
10316 +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
10317 +3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
10318 +2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
10319 +3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
10320 +3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
10321 +4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
10324 +static int yaffs_CountBits(__u8 x)
10327 + retVal = yaffs_countBitsTable[x];
10332 +/////////////// Tags ECC calculations ///////////////////
10334 +void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
10336 + yaffs_ECCCalculate(data , spare->ecc1);
10337 + yaffs_ECCCalculate(&data[256] , spare->ecc2);
10340 +void yaffs_CalcTagsECC(yaffs_Tags *tags)
10342 + // Calculate an ecc
10344 + unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
10346 + unsigned ecc = 0;
10347 + unsigned bit = 0;
10351 + for(i = 0; i < 8; i++)
10353 + for(j = 1; j &0xff; j<<=1)
10368 +int yaffs_CheckECCOnTags(yaffs_Tags *tags)
10370 + unsigned ecc = tags->ecc;
10372 + yaffs_CalcTagsECC(tags);
10374 + ecc ^= tags->ecc;
10376 + if(ecc && ecc <= 64)
10378 + // TODO: Handle the failure better. Retire?
10379 + unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
10383 + b[ecc / 8] ^= (1 << (ecc & 7));
10385 + // Now recvalc the ecc
10386 + yaffs_CalcTagsECC(tags);
10388 + return 1; // recovered error
10392 + // Wierd ecc failure value
10393 + // TODO Need to do somethiong here
10394 + return -1; //unrecovered error
10400 +//////////////////////////// Tags ///////////////////////////////////////
10402 +static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr)
10404 + yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
10406 + yaffs_CalcTagsECC(tagsPtr);
10408 + sparePtr->tagByte0 = tu->asBytes[0];
10409 + sparePtr->tagByte1 = tu->asBytes[1];
10410 + sparePtr->tagByte2 = tu->asBytes[2];
10411 + sparePtr->tagByte3 = tu->asBytes[3];
10412 + sparePtr->tagByte4 = tu->asBytes[4];
10413 + sparePtr->tagByte5 = tu->asBytes[5];
10414 + sparePtr->tagByte6 = tu->asBytes[6];
10415 + sparePtr->tagByte7 = tu->asBytes[7];
10418 +static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr)
10420 + yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
10423 + tu->asBytes[0]= sparePtr->tagByte0;
10424 + tu->asBytes[1]= sparePtr->tagByte1;
10425 + tu->asBytes[2]= sparePtr->tagByte2;
10426 + tu->asBytes[3]= sparePtr->tagByte3;
10427 + tu->asBytes[4]= sparePtr->tagByte4;
10428 + tu->asBytes[5]= sparePtr->tagByte5;
10429 + tu->asBytes[6]= sparePtr->tagByte6;
10430 + tu->asBytes[7]= sparePtr->tagByte7;
10432 + result = yaffs_CheckECCOnTags(tagsPtr);
10435 + dev->tagsEccFixed++;
10437 + else if(result <0)
10439 + dev->tagsEccUnfixed++;
10443 +static void yaffs_SpareInitialise(yaffs_Spare *spare)
10445 + memset(spare,0xFF,sizeof(yaffs_Spare));
10451 +static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)
10453 + if(chunkInNAND < dev->startBlock * dev->nChunksPerBlock)
10455 + T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),chunkInNAND));
10456 + return YAFFS_FAIL;
10459 + dev->nPageWrites++;
10460 + return dev->writeChunkToNAND(dev,chunkInNAND,data,spare);
10465 +static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
10468 + yaffs_Spare *spare,
10469 + yaffs_ECCResult *eccResult,
10470 + int doErrorCorrection)
10473 + yaffs_Spare localSpare;
10475 + dev->nPageReads++;
10480 + if(!spare && data)
10482 + // If we don't have a real spare, then we use a local one.
10483 + // Need this for the calculation of the ecc
10484 + spare = &localSpare;
10488 + if(!dev->useNANDECC)
10490 + retVal = dev->readChunkFromNAND(dev,chunkInNAND,data,spare);
10491 + if(data && doErrorCorrection)
10493 + // Do ECC correction
10494 + //Todo handle any errors
10495 + int eccResult1,eccResult2;
10498 + yaffs_ECCCalculate(data,calcEcc);
10499 + eccResult1 = yaffs_ECCCorrect (data,spare->ecc1, calcEcc);
10500 + yaffs_ECCCalculate(&data[256],calcEcc);
10501 + eccResult2 = yaffs_ECCCorrect(&data[256],spare->ecc2, calcEcc);
10505 + T(YAFFS_TRACE_ERROR, (TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND));
10508 + else if(eccResult1<0)
10510 + T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND));
10511 + dev->eccUnfixed++;
10516 + T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND));
10519 + else if(eccResult2<0)
10521 + T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND));
10522 + dev->eccUnfixed++;
10525 + if(eccResult1 || eccResult2)
10527 + // Hoosterman, we had a data problem on this page
10528 + yaffs_HandleReadDataError(dev,chunkInNAND);
10531 + if(eccResult1 < 0 || eccResult2 < 0)
10532 + *eccResult = YAFFS_ECC_RESULT_UNFIXED;
10533 + else if(eccResult1 > 0 || eccResult2 > 0)
10534 + *eccResult = YAFFS_ECC_RESULT_FIXED;
10536 + *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
10541 + // Must allocate enough memory for spare+2*sizeof(int) for ecc results from device.
10542 + struct yaffs_NANDSpare nspare;
10543 + retVal = dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare*)&nspare);
10544 + memcpy (spare, &nspare, sizeof(yaffs_Spare));
10545 + if(data && doErrorCorrection)
10547 + if(nspare.eccres1>0)
10549 + T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND));
10551 + else if(nspare.eccres1<0)
10553 + T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND));
10556 + if(nspare.eccres2>0)
10558 + T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND));
10560 + else if(nspare.eccres2<0)
10562 + T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND));
10565 + if(nspare.eccres1 || nspare.eccres2)
10567 + // Hoosterman, we had a data problem on this page
10568 + yaffs_HandleReadDataError(dev,chunkInNAND);
10571 + if(nspare.eccres1 < 0 || nspare.eccres2 < 0)
10572 + *eccResult = YAFFS_ECC_RESULT_UNFIXED;
10573 + else if(nspare.eccres1 > 0 || nspare.eccres2 > 0)
10574 + *eccResult = YAFFS_ECC_RESULT_FIXED;
10576 + *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
10585 +static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND)
10588 + static int init = 0;
10589 + static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
10590 + static __u8 data[YAFFS_BYTES_PER_CHUNK];
10591 + // Might as well always allocate the larger size for dev->useNANDECC == true;
10592 + static __u8 spare[sizeof(struct yaffs_NANDSpare)];
10594 + dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare *)spare);
10598 + memset(cmpbuf,0xff,YAFFS_BYTES_PER_CHUNK);
10602 + if(memcmp(cmpbuf,data,YAFFS_BYTES_PER_CHUNK)) return YAFFS_FAIL;
10603 + if(memcmp(cmpbuf,spare,16)) return YAFFS_FAIL;
10612 +int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
10614 + dev->nBlockErasures++;
10615 + return dev->eraseBlockInNAND(dev,blockInNAND);
10618 +int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
10620 + return dev->initialiseNAND(dev);
10626 +static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8 *data, yaffs_Spare *spare,int useReserve)
10631 + int attempts = 0;
10633 + unsigned char rbData[YAFFS_BYTES_PER_CHUNK];
10634 + yaffs_Spare rbSpare;
10637 + chunk = yaffs_AllocateChunk(dev,useReserve);
10642 + // First check this chunk is erased...
10643 +#ifndef CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
10644 + writeOk = yaffs_CheckChunkErased(dev,chunk);
10648 + T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d was not erased" TENDSTR),chunk));
10652 + writeOk = yaffs_WriteChunkToNAND(dev,chunk,data,spare);
10657 + // Readback & verify
10658 + // If verify fails, then delete this chunk and try again
10659 + // To verify we compare everything except the block and
10660 + // page status bytes.
10661 + // NB We check a raw read without ECC correction applied
10662 + yaffs_ReadChunkFromNAND(dev,chunk,rbData,&rbSpare,0);
10664 +#ifndef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
10665 + if(!yaffs_VerifyCompare(data,rbData,spare,&rbSpare))
10668 + T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs write verify failed on chunk %d" TENDSTR), chunk));
10677 + // Copy the data into the write buffer.
10678 + // NB We do this at the end to prevent duplicates in the case of a write error.
10680 + yaffs_HandleWriteChunkOk(dev,chunk,data,spare);
10684 + yaffs_HandleWriteChunkError(dev,chunk);
10688 + } while(chunk >= 0 && ! writeOk);
10692 + T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs write required %d attempts" TENDSTR),attempts));
10693 + dev->nRetriedWrites+= (attempts - 1);
10702 +// Functions for robustisizing
10707 +static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND)
10709 + // Ding the blockStatus in the first two pages of the block.
10711 + yaffs_Spare spare;
10713 + memset(&spare, 0xff,sizeof(yaffs_Spare));
10715 + spare.blockStatus = 0;
10717 + // TODO change this retirement marking for other NAND types
10718 + yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL , &spare);
10719 + yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1, NULL , &spare);
10721 + yaffs_GetBlockInfo(dev,blockInNAND)->blockState = YAFFS_BLOCK_STATE_DEAD;
10722 + dev->nRetiredBlocks++;
10728 +static int yaffs_RewriteBufferedBlock(yaffs_Device *dev)
10730 + dev->doingBufferedBlockRewrite = 1;
10732 + // Remove erased chunks
10733 + // Rewrite existing chunks to a new block
10734 + // Set current write block to the new block
10736 + dev->doingBufferedBlockRewrite = 0;
10743 +static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND)
10745 + int blockInNAND = chunkInNAND/dev->nChunksPerBlock;
10747 + // Mark the block for retirement
10748 + yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
10749 + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>>Block %d marked for retirement" TENDSTR),blockInNAND));
10753 + // Just do a garbage collection on the affected block then retire the block
10759 +static void yaffs_CheckWrittenBlock(yaffs_Device *dev,int chunkInNAND)
10763 +static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare)
10767 +static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_Spare *spare)
10771 +static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND)
10773 + int blockInNAND = chunkInNAND/dev->nChunksPerBlock;
10775 + // Mark the block for retirement
10776 + yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
10777 + // Delete the chunk
10778 + yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__);
10784 +static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1)
10788 + if( memcmp(d0,d1,YAFFS_BYTES_PER_CHUNK) != 0 ||
10789 + s0->tagByte0 != s1->tagByte0 ||
10790 + s0->tagByte1 != s1->tagByte1 ||
10791 + s0->tagByte2 != s1->tagByte2 ||
10792 + s0->tagByte3 != s1->tagByte3 ||
10793 + s0->tagByte4 != s1->tagByte4 ||
10794 + s0->tagByte5 != s1->tagByte5 ||
10795 + s0->tagByte6 != s1->tagByte6 ||
10796 + s0->tagByte7 != s1->tagByte7 ||
10797 + s0->ecc1[0] != s1->ecc1[0] ||
10798 + s0->ecc1[1] != s1->ecc1[1] ||
10799 + s0->ecc1[2] != s1->ecc1[2] ||
10800 + s0->ecc2[0] != s1->ecc2[0] ||
10801 + s0->ecc2[1] != s1->ecc2[1] ||
10802 + s0->ecc2[2] != s1->ecc2[2] )
10809 +#endif /* NOTYET */
10815 + unsigned validMarker0;
10816 + unsigned chunkUsed; // Status of the chunk: used or unused
10817 + unsigned objectId; // If 0 then this is not part of an object (unused)
10818 + unsigned chunkId; // If 0 then this is a header
10819 + unsigned byteCount; // Only valid for data chunks
10820 + // The following stuff only has meaning when we read
10821 + yaffs_ECCResult eccResult; // Only valid when we read.
10822 + unsigned blockBad; // Only valid on reading
10825 + unsigned chunkDeleted; // The chunk is marked deleted
10826 + unsigned serialNumber; // Yaffs1 2-bit serial number
10829 + unsigned sequenceNumber; // The sequence number of this block
10831 + unsigned validMarker1;
10833 +} yaffs_ExtendedTags;
10838 + unsigned chunkId:20;
10839 + unsigned serialNumber:2;
10840 + unsigned byteCount:10;
10841 + unsigned objectId:18;
10843 + unsigned unusedStuff:2;
10849 +int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *eTags)
10851 + yaffs_Spare spare;
10854 + yaffs_SpareInitialise(&spare);
10856 + if(eTags->chunkDeleted)
10858 + spare.pageStatus = 0;
10862 + tags.objectId = eTags->objectId;
10863 + tags.chunkId = eTags->chunkId;
10864 + tags.byteCount = eTags->byteCount;
10865 + tags.serialNumber = eTags->serialNumber;
10868 + if (!dev->useNANDECC && data)
10870 + yaffs_CalcECC(data,&spare);
10874 + yaffs_LoadTagsIntoSpare(&spare,&tags);
10878 + return yaffs_WriteChunkToNAND(dev,chunkInNAND,data,&spare);
10882 +int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *eTags)
10885 + yaffs_Spare spare;
10887 + yaffs_ECCResult eccResult;
10890 + static yaffs_Spare spareFF;
10895 + memset(&spareFF,0xFF,sizeof(spareFF));
10899 + if(yaffs_ReadChunkFromNAND(dev,chunkInNAND,data,&spare,&eccResult,1))
10901 +// added NCB - eTags may be NULL
10904 + int deleted = (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
10906 + yaffs_GetTagsFromSpare(dev,&spare,&tags);
10908 + eTags->chunkDeleted = deleted;
10909 + eTags->objectId = tags.objectId;
10910 + eTags->chunkId = tags.chunkId;
10911 + eTags->byteCount = tags.byteCount;
10912 + eTags->serialNumber = tags.serialNumber;
10913 + eTags->eccResult = eccResult;
10914 + eTags->blockBad = 0; // We're reading it therefore it is not a bad block
10916 +// NCB added 18/2/2005
10917 + eTags->chunkUsed = (memcmp(&spareFF,&spare,sizeof(spareFF)) != 0) ? 1:0;
10924 + return YAFFS_FAIL;
10928 +int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockInNAND)
10931 + yaffs_Spare spare;
10933 + memset(&spare, 0xff,sizeof(yaffs_Spare));
10935 + spare.blockStatus = 0;
10937 + yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL , &spare);
10938 + yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1, NULL , &spare);
10945 +int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber)
10948 + yaffs_Spare spare0,spare1;
10949 + static yaffs_Spare spareFF;
10951 + yaffs_ECCResult dummy;
10955 + memset(&spareFF,0xFF,sizeof(spareFF));
10959 + *sequenceNumber = 0;
10961 + yaffs_ReadChunkFromNAND(dev,blockNo * dev->nChunksPerBlock,NULL,&spare0,&dummy,1);
10962 + yaffs_ReadChunkFromNAND(dev,blockNo * dev->nChunksPerBlock + 1,NULL,&spare1,&dummy,1);
10964 + if(yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
10965 + *state = YAFFS_BLOCK_STATE_DEAD;
10966 + else if(memcmp(&spareFF,&spare0,sizeof(spareFF)) == 0)
10967 + *state = YAFFS_BLOCK_STATE_EMPTY;
10969 + *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
10974 diff --git a/fs/yaffs/yaffs_tagscompat.h b/fs/yaffs/yaffs_tagscompat.h
10975 new file mode 100644
10976 index 0000000..20b627f
10978 +++ b/fs/yaffs/yaffs_tagscompat.h
10981 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
10982 + * yaffs_ramdisk.h: yaffs ram disk component
10984 + * Copyright (C) 2002 Aleph One Ltd.
10986 + * Created by Charles Manning <charles@aleph1.co.uk>
10988 + * This program is free software; you can redistribute it and/or modify
10989 + * it under the terms of the GNU General Public License version 2 as
10990 + * published by the Free Software Foundation.
10992 + * $Id: yaffs_tagscompat.h,v 1.1 2004/11/03 08:14:07 charles Exp $
10995 +// This provides a rma disk under yaffs.
10996 +// NB this is not intended for NAND emulation.
10997 +// Use this with dev->useNANDECC enabled, then ECC overheads are not required.
10999 +#ifndef __YAFFS_TAGSCOMPAT_H__
11000 +#define __YAFFS_TAGSCOMPAT_H__
11003 +#include "yaffs_guts.h"
11004 +int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags);
11005 +int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags);
11006 +int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
11007 +int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber);
11010 diff --git a/fs/yaffs/yaffs_tagsvalidity.c b/fs/yaffs/yaffs_tagsvalidity.c
11011 new file mode 100644
11012 index 0000000..2cbbeaa
11014 +++ b/fs/yaffs/yaffs_tagsvalidity.c
11018 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
11020 + * Copyright (C) 2002 Aleph One Ltd.
11021 + * for Toby Churchill Ltd and Brightstar Engineering
11023 + * Created by Charles Manning <charles@aleph1.co.uk>
11025 + * This program is free software; you can redistribute it and/or modify
11026 + * it under the terms of the GNU General Public License version 2 as
11027 + * published by the Free Software Foundation.
11029 + * $Id: yaffs_tagsvalidity.c,v 1.1 2005/04/29 18:09:16 charles Exp $
11031 +//yaffs_tagsvalidity.c
11033 +#include "yaffs_tagsvalidity.h"
11037 +void yaffs_InitialiseTags(yaffs_ExtendedTags *tags)
11039 + memset(tags,0,sizeof(yaffs_ExtendedTags));
11040 + tags->validMarker0 = 0xAAAAAAAA;
11041 + tags->validMarker1 = 0x55555555;
11044 +int yaffs_ValidateTags(yaffs_ExtendedTags *tags)
11046 + return (tags->validMarker0 == 0xAAAAAAAA &&
11047 + tags->validMarker1 == 0x55555555);
11051 diff --git a/fs/yaffs/yaffs_tagsvalidity.h b/fs/yaffs/yaffs_tagsvalidity.h
11052 new file mode 100644
11053 index 0000000..26673d1
11055 +++ b/fs/yaffs/yaffs_tagsvalidity.h
11059 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
11061 + * Copyright (C) 2002 Aleph One Ltd.
11062 + * for Toby Churchill Ltd and Brightstar Engineering
11064 + * Created by Charles Manning <charles@aleph1.co.uk>
11066 + * This program is free software; you can redistribute it and/or modify
11067 + * it under the terms of the GNU General Public License version 2 as
11068 + * published by the Free Software Foundation.
11070 + * $Id: yaffs_tagsvalidity.h,v 1.1 2005/04/29 18:09:16 charles Exp $
11072 +//yaffs_tagsvalidity.h
11075 +#ifndef __YAFFS_TAGS_VALIDITY_H__
11076 +#define __YAFFS_TAGS_VALIDITY_H__
11078 +#include "yaffs_guts.h"
11080 +void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
11081 +int yaffs_ValidateTags(yaffs_ExtendedTags *tags);
11084 diff --git a/fs/yaffs/yaffsinterface.h b/fs/yaffs/yaffsinterface.h
11085 new file mode 100644
11086 index 0000000..e4b0ff1
11088 +++ b/fs/yaffs/yaffsinterface.h
11091 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
11092 + * yaffsinterface.h: Interface to the guts of yaffs.
11094 + * Copyright (C) 2002 Aleph One Ltd.
11095 + * for Toby Churchill Ltd and Brightstar Engineering
11097 + * Created by Charles Manning <charles@aleph1.co.uk>
11099 + * This program is free software; you can redistribute it and/or modify
11100 + * it under the terms of the GNU Lesser General Public License version 2.1 as
11101 + * published by the Free Software Foundation.
11103 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
11107 +#ifndef __YAFFSINTERFACE_H__
11108 +#define __YAFFSINTERFACE_H__
11111 +int yaffs_Initialise(unsigned nBlocks);
11115 diff --git a/fs/yaffs/yportenv.h b/fs/yaffs/yportenv.h
11116 new file mode 100644
11117 index 0000000..13c63bb
11119 +++ b/fs/yaffs/yportenv.h
11122 + * YAFFS: Yet another FFS. A NAND-flash specific file system.
11123 + * yportenv.h: Portable services used by yaffs. This is done to allow
11124 + * simple migration from kernel space into app space for testing.
11126 + * Copyright (C) 2002 Aleph One Ltd.
11127 + * for Toby Churchill Ltd and Brightstar Engineering
11129 + * Created by Charles Manning <charles@aleph1.co.uk>
11131 + * This program is free software; you can redistribute it and/or modify
11132 + * it under the terms of the GNU Lesser General Public License version 2.1 as
11133 + * published by the Free Software Foundation.
11136 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
11138 + * $Id: yportenv.h,v 1.6 2005/07/31 00:26:57 charles Exp $
11142 +#ifndef __YPORTENV_H__
11143 +#define __YPORTENV_H__
11146 +#if defined CONFIG_YAFFS_WINCE
11148 +#include "ywinceenv.h"
11150 +#elif defined __KERNEL__
11155 +#include <linux/config.h>
11156 +#include <linux/kernel.h>
11157 +#include <linux/version.h>
11158 +#include <linux/mm.h>
11159 +#include <linux/string.h>
11160 +#include <linux/slab.h>
11162 +#define YCHAR char
11163 +#define YUCHAR unsigned char
11165 +#define yaffs_strcpy(a,b) strcpy(a,b)
11166 +#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
11167 +#define yaffs_strlen(s) strlen(s)
11168 +#define yaffs_sprintf sprintf
11169 +#define yaffs_toupper(a) toupper(a)
11171 +#define Y_INLINE inline
11173 +#define YAFFS_LOSTNFOUND_NAME "lost+found"
11174 +#define YAFFS_LOSTNFOUND_PREFIX "obj"
11176 +//#define YPRINTF(x) printk x
11177 +#define YMALLOC(x) kmalloc(x,GFP_KERNEL)
11178 +#define YFREE(x) kfree(x)
11180 +#define YAFFS_ROOT_MODE 0666
11181 +#define YAFFS_LOSTNFOUND_MODE 0666
11183 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
11184 +#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
11185 +#define Y_TIME_CONVERT(x) (x).tv_sec
11187 +#define Y_CURRENT_TIME CURRENT_TIME
11188 +#define Y_TIME_CONVERT(x) (x)
11191 +#define yaffs_SumCompare(x,y) ((x) == (y))
11192 +#define yaffs_strcmp(a,b) strcmp(a,b)
11194 +#define TENDSTR "\n"
11195 +#define TSTR(x) KERN_WARNING x
11196 +#define TOUT(p) printk p
11199 +#elif defined CONFIG_YAFFS_DIRECT
11201 +// Direct interface
11202 +#include "ydirectenv.h"
11204 +#elif defined CONFIG_YAFFS_UTIL
11206 +// Stuff for YAFFS utilities
11208 +#include "stdlib.h"
11209 +#include "stdio.h"
11210 +#include "string.h"
11212 +#include "devextras.h"
11214 +#define YMALLOC(x) malloc(x)
11215 +#define YFREE(x) free(x)
11218 +#define YCHAR char
11219 +#define YUCHAR unsigned char
11221 +#define yaffs_strcpy(a,b) strcpy(a,b)
11222 +#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
11223 +#define yaffs_strlen(s) strlen(s)
11224 +#define yaffs_sprintf sprintf
11225 +#define yaffs_toupper(a) toupper(a)
11227 +#define Y_INLINE inline
11229 +//#define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s))
11230 +//#define YALERT(s) YINFO(s)
11233 +#define TENDSTR "\n"
11235 +#define TOUT(p) printf p
11238 +#define YAFFS_LOSTNFOUND_NAME "lost+found"
11239 +#define YAFFS_LOSTNFOUND_PREFIX "obj"
11240 +//#define YPRINTF(x) printf x
11243 +#define YAFFS_ROOT_MODE 0666
11244 +#define YAFFS_LOSTNFOUND_MODE 0666
11246 +#define yaffs_SumCompare(x,y) ((x) == (y))
11247 +#define yaffs_strcmp(a,b) strcmp(a,b)
11250 +// Should have specified a configuration type
11251 +#error Unknown configuration
11256 +extern unsigned yaffs_traceMask;
11258 +#define YAFFS_TRACE_ERROR 0x00000001
11259 +#define YAFFS_TRACE_OS 0x00000002
11260 +#define YAFFS_TRACE_ALLOCATE 0x00000004
11261 +#define YAFFS_TRACE_SCAN 0x00000008
11262 +#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
11263 +#define YAFFS_TRACE_ERASE 0x00000020
11264 +#define YAFFS_TRACE_GC 0x00000040
11265 +#define YAFFS_TRACE_WRITE 0x00000080
11266 +#define YAFFS_TRACE_TRACING 0x00000100
11267 +#define YAFFS_TRACE_DELETION 0x00000200
11268 +#define YAFFS_TRACE_BUFFERS 0x00000400
11269 +#define YAFFS_TRACE_NANDACCESS 0x00000800
11270 +#define YAFFS_TRACE_GC_DETAIL 0x00001000
11271 +#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
11272 +#define YAFFS_TRACE_MTD 0x00004000
11273 +#define YAFFS_TRACE_ALWAYS 0x40000000
11274 +#define YAFFS_TRACE_BUG 0x80000000
11276 +#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ERROR)) TOUT(p);} while(0)
11279 +#ifndef CONFIG_YAFFS_WINCE
11280 +#define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__))